Tizen 2.1 base
authorJinkun Jang <jinkun.jang@samsung.com>
Tue, 12 Mar 2013 16:53:34 +0000 (01:53 +0900)
committerJinkun Jang <jinkun.jang@samsung.com>
Tue, 12 Mar 2013 16:53:34 +0000 (01:53 +0900)
355 files changed:
ABOUT-NLS [new file with mode: 0755]
AUTHORS [new file with mode: 0644]
COPYING [new file with mode: 0644]
ChangeLog [new file with mode: 0644]
INSTALL [new file with mode: 0644]
LGPL.LICENSE [new file with mode: 0644]
Makefile.am [new file with mode: 0755]
NEWS [new file with mode: 0644]
OPENSOLARIS.LICENSE [new file with mode: 0644]
README [new file with mode: 0644]
SConstruct [new file with mode: 0755]
TODO [new file with mode: 0644]
bootstrap [new file with mode: 0755]
build/Makefile [new file with mode: 0644]
build/SConscript [new file with mode: 0644]
config.rpath [new file with mode: 0755]
configure.ac [new file with mode: 0755]
configure.conf [new file with mode: 0644]
data/Makefile [new file with mode: 0644]
data/cnpunc.png [new file with mode: 0644]
data/cnpunc.svg [new file with mode: 0644]
data/eng.png [new file with mode: 0644]
data/eng.svg [new file with mode: 0644]
data/enpunc.png [new file with mode: 0644]
data/enpunc.svg [new file with mode: 0644]
data/fullwidth.png [new file with mode: 0644]
data/fullwidth.svg [new file with mode: 0644]
data/halfwidth.png [new file with mode: 0644]
data/halfwidth.svg [new file with mode: 0644]
data/han.png [new file with mode: 0644]
data/han.svg [new file with mode: 0644]
data/setup.svg [new file with mode: 0644]
data/sunpinyin_logo.xpm [new file with mode: 0644]
doc/AuxRequire.txt [new file with mode: 0644]
doc/README [new file with mode: 0644]
doc/genpyt.pod [new file with mode: 0644]
doc/getWordFreq.pod [new file with mode: 0644]
doc/idngram_merge.pod [new file with mode: 0644]
doc/ids2ngram.pod [new file with mode: 0644]
doc/mmseg.pod [new file with mode: 0644]
doc/slmbuild.pod [new file with mode: 0644]
doc/slminfo.pod [new file with mode: 0644]
doc/slmprune.pod [new file with mode: 0644]
doc/slmseg.pod [new file with mode: 0644]
doc/slmthread.pod [new file with mode: 0644]
doc/tslmendian.pod [new file with mode: 0644]
doc/tslminfo.pod [new file with mode: 0644]
doc/tslmpack.pod [new file with mode: 0644]
m4/Makefile.am [new file with mode: 0755]
mkinstalldirs [new file with mode: 0755]
packaging/sunpinyin.changes [new file with mode: 0644]
packaging/sunpinyin.spec [new file with mode: 0755]
po/ChangeLog [new file with mode: 0755]
po/Makefile.in.in [new file with mode: 0755]
po/POTFILES.in [new file with mode: 0755]
po/de.po [new file with mode: 0755]
po/de_DE.po [new file with mode: 0755]
po/el_GR.po [new file with mode: 0755]
po/en.po [new file with mode: 0755]
po/es_ES.po [new file with mode: 0755]
po/fr.po [new file with mode: 0755]
po/fr_FR.po [new file with mode: 0755]
po/it_IT.po [new file with mode: 0755]
po/ja.po [new file with mode: 0755]
po/ja_JP.po [new file with mode: 0755]
po/ko.po [new file with mode: 0755]
po/ko_KR.po [new file with mode: 0755]
po/nl.po [new file with mode: 0755]
po/nl_NL.po [new file with mode: 0755]
po/pa.po [new file with mode: 0755]
po/pt_PT.po [new file with mode: 0755]
po/ru_RU.po [new file with mode: 0755]
po/tr_TR.po [new file with mode: 0755]
po/update-po.sh [new file with mode: 0755]
po/zh_CN.po [new file with mode: 0755]
po/zh_HK.po [new file with mode: 0755]
po/zh_TW.po [new file with mode: 0755]
python/imdict.py [new file with mode: 0755]
python/importer/import_fcitx_userdict.py [new file with mode: 0755]
python/importer/import_fit_userdict.py [new file with mode: 0755]
python/importer/import_google_userdict.py [new file with mode: 0755]
python/importer/import_qim_userdict.py [new file with mode: 0755]
python/importer/import_qq_userdict.py [new file with mode: 0755]
python/importer/import_sogou_celldict.py [new file with mode: 0755]
python/importer/import_sogou_userdict.py [new file with mode: 0755]
python/importer/import_ziguang_userdict.py [new file with mode: 0755]
python/importer/importer.py [new file with mode: 0644]
python/mmseg.py [new file with mode: 0755]
python/pinyin_data.py [new file with mode: 0755]
python/pyslm.pyx [new file with mode: 0644]
python/pytrie.pyx [new file with mode: 0644]
python/setup.py [new file with mode: 0644]
python/test.py [new file with mode: 0644]
python/trie.py [new file with mode: 0755]
python/trie.pyc [new file with mode: 0644]
python/utils.py [new file with mode: 0644]
raw/Makefile.am [new file with mode: 0755]
raw/lm_sc.t3g [new file with mode: 0755]
raw/pydict_sc.bin [new file with mode: 0644]
src/Makefile.am [new file with mode: 0755]
src/ime-core/Makefile.am [new file with mode: 0755]
src/ime-core/ic_history.cpp [new file with mode: 0644]
src/ime-core/ic_history.h [new file with mode: 0644]
src/ime-core/imi_context.cpp [new file with mode: 0644]
src/ime-core/imi_context.h [new file with mode: 0644]
src/ime-core/imi_data.cpp [new file with mode: 0644]
src/ime-core/imi_data.h [new file with mode: 0644]
src/ime-core/imi_defines.h [new file with mode: 0644]
src/ime-core/imi_funcobjs.cpp [new file with mode: 0644]
src/ime-core/imi_funcobjs.h [new file with mode: 0644]
src/ime-core/imi_glibHandler.h [new file with mode: 0644]
src/ime-core/imi_keys.h [new file with mode: 0644]
src/ime-core/imi_option_event.cpp [new file with mode: 0644]
src/ime-core/imi_option_event.h [new file with mode: 0644]
src/ime-core/imi_option_keys.h [new file with mode: 0644]
src/ime-core/imi_options.cpp [new file with mode: 0644]
src/ime-core/imi_options.h [new file with mode: 0644]
src/ime-core/imi_plugin.cpp [new file with mode: 0644]
src/ime-core/imi_plugin.h [new file with mode: 0644]
src/ime-core/imi_uiobjects.cpp [new file with mode: 0644]
src/ime-core/imi_uiobjects.h [new file with mode: 0644]
src/ime-core/imi_view.cpp [new file with mode: 0644]
src/ime-core/imi_view.h [new file with mode: 0644]
src/ime-core/imi_view_classic.cpp [new file with mode: 0644]
src/ime-core/imi_view_classic.h [new file with mode: 0644]
src/ime-core/imi_winHandler.cpp [new file with mode: 0644]
src/ime-core/imi_winHandler.h [new file with mode: 0644]
src/ime-core/lattice_states.cpp [new file with mode: 0644]
src/ime-core/lattice_states.h [new file with mode: 0644]
src/ime-core/userdict.cpp [new file with mode: 0644]
src/ime-core/userdict.h [new file with mode: 0644]
src/ime-core/utils.h [new file with mode: 0644]
src/lexicon/Makefile.am [new file with mode: 0755]
src/lexicon/genPYT.cpp [new file with mode: 0644]
src/lexicon/pytrie.cpp [new file with mode: 0644]
src/lexicon/pytrie.h [new file with mode: 0644]
src/lexicon/pytrie_gen.cpp [new file with mode: 0644]
src/lexicon/pytrie_gen.h [new file with mode: 0644]
src/lexicon/trie_writer.cpp [new file with mode: 0644]
src/lexicon/trie_writer.h [new file with mode: 0644]
src/pinyin/Makefile.am [new file with mode: 0755]
src/pinyin/datrie.h [new file with mode: 0644]
src/pinyin/datrie_impl.h [new file with mode: 0644]
src/pinyin/hunpin_seg.cpp [new file with mode: 0644]
src/pinyin/hunpin_seg.h [new file with mode: 0644]
src/pinyin/pinyin_data.cpp [new file with mode: 0644]
src/pinyin/pinyin_data.h [new file with mode: 0644]
src/pinyin/pinyin_seg.cpp [new file with mode: 0644]
src/pinyin/pinyin_seg.h [new file with mode: 0644]
src/pinyin/quanpin_trie.h [new file with mode: 0644]
src/pinyin/segmentor.h [new file with mode: 0644]
src/pinyin/shuangpin_data.cpp [new file with mode: 0644]
src/pinyin/shuangpin_data.h [new file with mode: 0644]
src/pinyin/shuangpin_seg.cpp [new file with mode: 0644]
src/pinyin/shuangpin_seg.h [new file with mode: 0644]
src/pinyin/syllable.h [new file with mode: 0644]
src/portability.cpp [new file with mode: 0644]
src/portability.h [new file with mode: 0644]
src/slm/Makefile.am [new file with mode: 0755]
src/slm/getWordFreq/getWordFreq.cpp [new file with mode: 0644]
src/slm/ids2ngram/idngram.h [new file with mode: 0644]
src/slm/ids2ngram/idngram_merge.cpp [new file with mode: 0644]
src/slm/ids2ngram/idngram_merge.h [new file with mode: 0644]
src/slm/ids2ngram/ids2ngram.cpp [new file with mode: 0644]
src/slm/mmseg/mmseg.cpp [new file with mode: 0644]
src/slm/sim_dict.cpp [new file with mode: 0644]
src/slm/sim_dict.h [new file with mode: 0644]
src/slm/sim_fmerge.h [new file with mode: 0644]
src/slm/sim_sen.cpp [new file with mode: 0644]
src/slm/sim_sen.h [new file with mode: 0644]
src/slm/sim_slm.cpp [new file with mode: 0644]
src/slm/sim_slm.h [new file with mode: 0644]
src/slm/sim_slmbuilder.cpp [new file with mode: 0644]
src/slm/sim_slmbuilder.h [new file with mode: 0644]
src/slm/slm.cpp [new file with mode: 0644]
src/slm/slm.h [new file with mode: 0644]
src/slm/slmbuild/slmbuild.cpp [new file with mode: 0644]
src/slm/slminfo/slminfo.cpp [new file with mode: 0644]
src/slm/slmprune/slmprune.cpp [new file with mode: 0644]
src/slm/slmseg/slmseg.cpp [new file with mode: 0644]
src/slm/thread/ValueCompress.cpp [new file with mode: 0644]
src/slm/thread/ValueCompress.h [new file with mode: 0644]
src/slm/thread/slmthread.cpp [new file with mode: 0644]
src/slm/thread/test_vc.cpp [new file with mode: 0644]
src/slm/tools/clean_rmrb.cpp [new file with mode: 0644]
src/slm/tools/dumpdict.cpp [new file with mode: 0644]
src/slm/tslmendian/slm_endian.cpp [new file with mode: 0644]
src/slm/tslmendian/slm_file.cpp [new file with mode: 0644]
src/slm/tslmendian/slm_file.h [new file with mode: 0644]
src/slm/tslmendian/writer.cpp [new file with mode: 0644]
src/slm/tslmendian/writer.h [new file with mode: 0644]
src/slm/tslminfo/tslminfo.cpp [new file with mode: 0644]
src/slm/tslmpack/arpa_conv.cpp [new file with mode: 0644]
src/slm/tslmpack/arpa_conv.h [new file with mode: 0644]
src/slm/tslmpack/arpa_slm.cpp [new file with mode: 0644]
src/slm/tslmpack/arpa_slm.h [new file with mode: 0644]
src/slm/tslmpack/common.h [new file with mode: 0644]
src/slm/tslmpack/slmpack.cpp [new file with mode: 0644]
src/sunpinyin.h [new file with mode: 0644]
sunpinyin-2.0.pc.in [new file with mode: 0644]
swap/README [new file with mode: 0644]
wrapper/ibus/CMakeLists.txt [new file with mode: 0644]
wrapper/ibus/COPYING [new file with mode: 0644]
wrapper/ibus/LGPL.LICENSE [new file with mode: 0644]
wrapper/ibus/OPENSOLARIS.LICENSE [new file with mode: 0644]
wrapper/ibus/README [new file with mode: 0644]
wrapper/ibus/SConstruct [new file with mode: 0644]
wrapper/ibus/cmake/modules/FindSunPinyin.cmake [new file with mode: 0644]
wrapper/ibus/cmake/modules/FindiBus.cmake [new file with mode: 0644]
wrapper/ibus/cmake/modules/Gettext.cmake [new file with mode: 0644]
wrapper/ibus/cmake/modules/LibFindMacros.cmake [new file with mode: 0644]
wrapper/ibus/cmake/modules/Paths.cmake [new file with mode: 0644]
wrapper/ibus/data/CMakeLists.txt [new file with mode: 0644]
wrapper/ibus/data/sunpinyin.xml.in [new file with mode: 0644]
wrapper/ibus/icons/cnpunc.svg [new file with mode: 0644]
wrapper/ibus/icons/eng.svg [new file with mode: 0644]
wrapper/ibus/icons/enpunc.svg [new file with mode: 0644]
wrapper/ibus/icons/fullwidth.svg [new file with mode: 0644]
wrapper/ibus/icons/halfwidth.svg [new file with mode: 0644]
wrapper/ibus/icons/han.svg [new file with mode: 0644]
wrapper/ibus/icons/setup.svg [new file with mode: 0644]
wrapper/ibus/icons/sunpinyin-logo.png [new file with mode: 0644]
wrapper/ibus/po/CMakeLists.txt [new file with mode: 0644]
wrapper/ibus/po/ibus-sunpinyin.po [new file with mode: 0644]
wrapper/ibus/po/zh_CN.po [new file with mode: 0644]
wrapper/ibus/setup/CMakeLists.txt [new file with mode: 0644]
wrapper/ibus/setup/config.py.in [new file with mode: 0644]
wrapper/ibus/setup/ibus-setup-sunpinyin.in [new file with mode: 0644]
wrapper/ibus/setup/main.py [new file with mode: 0644]
wrapper/ibus/setup/setup.xml [new file with mode: 0644]
wrapper/ibus/src/CMakeLists.txt [new file with mode: 0644]
wrapper/ibus/src/debug.cpp [new file with mode: 0644]
wrapper/ibus/src/debug.h [new file with mode: 0644]
wrapper/ibus/src/engine.cpp [new file with mode: 0644]
wrapper/ibus/src/engine.h [new file with mode: 0644]
wrapper/ibus/src/ibus_common.h [new file with mode: 0644]
wrapper/ibus/src/ibus_portable.cpp [new file with mode: 0644]
wrapper/ibus/src/ibus_portable.h [new file with mode: 0644]
wrapper/ibus/src/imi_ibus_win.cpp [new file with mode: 0644]
wrapper/ibus/src/imi_ibus_win.h [new file with mode: 0644]
wrapper/ibus/src/main.cpp [new file with mode: 0644]
wrapper/ibus/src/pointer.h [new file with mode: 0644]
wrapper/ibus/src/sunpinyin_config.cpp [new file with mode: 0644]
wrapper/ibus/src/sunpinyin_config.h [new file with mode: 0644]
wrapper/ibus/src/sunpinyin_config_keys.h [new file with mode: 0644]
wrapper/ibus/src/sunpinyin_engine.cpp [new file with mode: 0644]
wrapper/ibus/src/sunpinyin_engine.h [new file with mode: 0644]
wrapper/ibus/src/sunpinyin_engine_proxy.cpp [new file with mode: 0644]
wrapper/ibus/src/sunpinyin_engine_proxy.h [new file with mode: 0644]
wrapper/ibus/src/sunpinyin_lookup_table.cpp [new file with mode: 0644]
wrapper/ibus/src/sunpinyin_lookup_table.h [new file with mode: 0644]
wrapper/ibus/src/sunpinyin_property.cpp [new file with mode: 0644]
wrapper/ibus/src/sunpinyin_property.h [new file with mode: 0644]
wrapper/scim/COPYING [new file with mode: 0644]
wrapper/scim/LGPL.LICENSE [new file with mode: 0644]
wrapper/scim/Makefile.am [new file with mode: 0755]
wrapper/scim/OPENSOLARIS.LICENSE [new file with mode: 0644]
wrapper/scim/README [new file with mode: 0644]
wrapper/scim/SConstruct [new file with mode: 0644]
wrapper/scim/config.log [new file with mode: 0644]
wrapper/scim/configure.conf [new file with mode: 0644]
wrapper/scim/data/Makefile.am [new file with mode: 0755]
wrapper/scim/data/sunpinyin_logo.png [new file with mode: 0644]
wrapper/scim/src/Makefile.am [new file with mode: 0755]
wrapper/scim/src/imi_scimwin.cpp [new file with mode: 0644]
wrapper/scim/src/imi_scimwin.h [new file with mode: 0644]
wrapper/scim/src/sunpinyin_imengine.cpp [new file with mode: 0644]
wrapper/scim/src/sunpinyin_imengine.h [new file with mode: 0755]
wrapper/scim/src/sunpinyin_imengine_config_keys.h [new file with mode: 0644]
wrapper/scim/src/sunpinyin_imengine_setup.cpp [new file with mode: 0644]
wrapper/scim/src/sunpinyin_keycode.h [new file with mode: 0644]
wrapper/scim/src/sunpinyin_lookup_table.cpp [new file with mode: 0644]
wrapper/scim/src/sunpinyin_lookup_table.h [new file with mode: 0644]
wrapper/scim/src/sunpinyin_private.h [new file with mode: 0644]
wrapper/scim/src/sunpinyin_utils.cpp [new file with mode: 0644]
wrapper/scim/src/sunpinyin_utils.h [new file with mode: 0644]
wrapper/xim/COPYING [new file with mode: 0644]
wrapper/xim/IMdkit/FrameMgr.c [new file with mode: 0644]
wrapper/xim/IMdkit/FrameMgr.h [new file with mode: 0644]
wrapper/xim/IMdkit/IMConn.c [new file with mode: 0644]
wrapper/xim/IMdkit/IMMethod.c [new file with mode: 0644]
wrapper/xim/IMdkit/IMValues.c [new file with mode: 0644]
wrapper/xim/IMdkit/IMdkit.h [new file with mode: 0644]
wrapper/xim/IMdkit/Xi18n.h [new file with mode: 0644]
wrapper/xim/IMdkit/Xi18nX.h [new file with mode: 0644]
wrapper/xim/IMdkit/XimFunc.h [new file with mode: 0644]
wrapper/xim/IMdkit/XimProto.h [new file with mode: 0644]
wrapper/xim/IMdkit/i18nAttr.c [new file with mode: 0644]
wrapper/xim/IMdkit/i18nClbk.c [new file with mode: 0644]
wrapper/xim/IMdkit/i18nIMProto.c [new file with mode: 0644]
wrapper/xim/IMdkit/i18nIc.c [new file with mode: 0644]
wrapper/xim/IMdkit/i18nMethod.c [new file with mode: 0644]
wrapper/xim/IMdkit/i18nPtHdr.c [new file with mode: 0644]
wrapper/xim/IMdkit/i18nUtil.c [new file with mode: 0644]
wrapper/xim/IMdkit/i18nX.c [new file with mode: 0644]
wrapper/xim/LGPL.LICENSE [new file with mode: 0644]
wrapper/xim/OPENSOLARIS.LICENSE [new file with mode: 0644]
wrapper/xim/README [new file with mode: 0644]
wrapper/xim/SConstruct [new file with mode: 0644]
wrapper/xim/common.h [new file with mode: 0644]
wrapper/xim/data/chnpunc.png [new file with mode: 0644]
wrapper/xim/data/eng.png [new file with mode: 0644]
wrapper/xim/data/eng.svg [new file with mode: 0644]
wrapper/xim/data/engpunc.png [new file with mode: 0644]
wrapper/xim/data/full.png [new file with mode: 0644]
wrapper/xim/data/half.png [new file with mode: 0644]
wrapper/xim/data/han.png [new file with mode: 0644]
wrapper/xim/data/han.svg [new file with mode: 0644]
wrapper/xim/data/settings_ui.xml [new file with mode: 0644]
wrapper/xim/data/skins/modern/eng-hover.png [new file with mode: 0644]
wrapper/xim/data/skins/modern/eng-press.png [new file with mode: 0644]
wrapper/xim/data/skins/modern/eng-punc-hover.png [new file with mode: 0644]
wrapper/xim/data/skins/modern/eng-punc-press.png [new file with mode: 0644]
wrapper/xim/data/skins/modern/eng-punc.png [new file with mode: 0644]
wrapper/xim/data/skins/modern/eng.png [new file with mode: 0644]
wrapper/xim/data/skins/modern/full-hover.png [new file with mode: 0644]
wrapper/xim/data/skins/modern/full-press.png [new file with mode: 0644]
wrapper/xim/data/skins/modern/full.png [new file with mode: 0644]
wrapper/xim/data/skins/modern/half-hover.png [new file with mode: 0644]
wrapper/xim/data/skins/modern/half-press.png [new file with mode: 0644]
wrapper/xim/data/skins/modern/half.png [new file with mode: 0644]
wrapper/xim/data/skins/modern/han-hover.png [new file with mode: 0644]
wrapper/xim/data/skins/modern/han-press.png [new file with mode: 0644]
wrapper/xim/data/skins/modern/han-punc-hover.png [new file with mode: 0644]
wrapper/xim/data/skins/modern/han-punc-press.png [new file with mode: 0644]
wrapper/xim/data/skins/modern/han-punc.png [new file with mode: 0644]
wrapper/xim/data/skins/modern/han.png [new file with mode: 0644]
wrapper/xim/data/skins/modern/icbar.png [new file with mode: 0644]
wrapper/xim/data/skins/modern/info [new file with mode: 0644]
wrapper/xim/data/skins/modern/preedit.png [new file with mode: 0644]
wrapper/xim/data/sunpinyin-logo-big.png [new file with mode: 0644]
wrapper/xim/data/sunpinyin-logo.png [new file with mode: 0644]
wrapper/xim/data/xim_config_default [new file with mode: 0644]
wrapper/xim/ic.c [new file with mode: 0644]
wrapper/xim/ic.h [new file with mode: 0644]
wrapper/xim/ic_gtk.c [new file with mode: 0644]
wrapper/xim/ic_skin.c [new file with mode: 0644]
wrapper/xim/im-switch/xsunpinyin [new file with mode: 0644]
wrapper/xim/main.c [new file with mode: 0644]
wrapper/xim/preferences.c [new file with mode: 0644]
wrapper/xim/settings.c [new file with mode: 0644]
wrapper/xim/settings.h [new file with mode: 0644]
wrapper/xim/skin.c [new file with mode: 0644]
wrapper/xim/skin.h [new file with mode: 0644]
wrapper/xim/sunpinyin_preedit.cc [new file with mode: 0644]
wrapper/xim/sunpinyin_preedit_gtk.cc [new file with mode: 0644]
wrapper/xim/sunpinyin_preedit_skin.cc [new file with mode: 0644]
wrapper/xim/sunpinyin_preedit_ui.h [new file with mode: 0644]
wrapper/xim/ui.c [new file with mode: 0644]
wrapper/xim/ui.h [new file with mode: 0644]
wrapper/xim/xim.c [new file with mode: 0644]
wrapper/xim/xim.h [new file with mode: 0644]
wrapper/xim/xim_trigger.c [new file with mode: 0644]
wrapper/xim/xmisc.c [new file with mode: 0644]
wrapper/xim/xmisc.h [new file with mode: 0644]

diff --git a/ABOUT-NLS b/ABOUT-NLS
new file mode 100755 (executable)
index 0000000..83bc72e
--- /dev/null
+++ b/ABOUT-NLS
@@ -0,0 +1,1068 @@
+1 Notes on the Free Translation Project
+***************************************
+
+Free software is going international!  The Free Translation Project is
+a way to get maintainers of free software, translators, and users all
+together, so that free software will gradually become able to speak many
+languages.  A few packages already provide translations for their
+messages.
+
+   If you found this `ABOUT-NLS' file inside a distribution, you may
+assume that the distributed package does use GNU `gettext' internally,
+itself available at your nearest GNU archive site.  But you do _not_
+need to install GNU `gettext' prior to configuring, installing or using
+this package with messages translated.
+
+   Installers will find here some useful hints.  These notes also
+explain how users should proceed for getting the programs to use the
+available translations.  They tell how people wanting to contribute and
+work on translations can contact the appropriate team.
+
+   When reporting bugs in the `intl/' directory or bugs which may be
+related to internationalization, you should tell about the version of
+`gettext' which is used.  The information can be found in the
+`intl/VERSION' file, in internationalized packages.
+
+1.1 Quick configuration advice
+==============================
+
+If you want to exploit the full power of internationalization, you
+should configure it using
+
+     ./configure --with-included-gettext
+
+to force usage of internationalizing routines provided within this
+package, despite the existence of internationalizing capabilities in the
+operating system where this package is being installed.  So far, only
+the `gettext' implementation in the GNU C library version 2 provides as
+many features (such as locale alias, message inheritance, automatic
+charset conversion or plural form handling) as the implementation here.
+It is also not possible to offer this additional functionality on top
+of a `catgets' implementation.  Future versions of GNU `gettext' will
+very likely convey even more functionality.  So it might be a good idea
+to change to GNU `gettext' as soon as possible.
+
+   So you need _not_ provide this option if you are using GNU libc 2 or
+you have installed a recent copy of the GNU gettext package with the
+included `libintl'.
+
+1.2 INSTALL Matters
+===================
+
+Some packages are "localizable" when properly installed; the programs
+they contain can be made to speak your own native language.  Most such
+packages use GNU `gettext'.  Other packages have their own ways to
+internationalization, predating GNU `gettext'.
+
+   By default, this package will be installed to allow translation of
+messages.  It will automatically detect whether the system already
+provides the GNU `gettext' functions.  If not, the included GNU
+`gettext' library will be used.  This library is wholly contained
+within this package, usually in the `intl/' subdirectory, so prior
+installation of the GNU `gettext' package is _not_ required.
+Installers may use special options at configuration time for changing
+the default behaviour.  The commands:
+
+     ./configure --with-included-gettext
+     ./configure --disable-nls
+
+will, respectively, bypass any pre-existing `gettext' to use the
+internationalizing routines provided within this package, or else,
+_totally_ disable translation of messages.
+
+   When you already have GNU `gettext' installed on your system and run
+configure without an option for your new package, `configure' will
+probably detect the previously built and installed `libintl.a' file and
+will decide to use this.  This might not be desirable.  You should use
+the more recent version of the GNU `gettext' library.  I.e. if the file
+`intl/VERSION' shows that the library which comes with this package is
+more recent, you should use
+
+     ./configure --with-included-gettext
+
+to prevent auto-detection.
+
+   The configuration process will not test for the `catgets' function
+and therefore it will not be used.  The reason is that even an
+emulation of `gettext' on top of `catgets' could not provide all the
+extensions of the GNU `gettext' library.
+
+   Internationalized packages usually have many `po/LL.po' files, where
+LL gives an ISO 639 two-letter code identifying the language.  Unless
+translations have been forbidden at `configure' time by using the
+`--disable-nls' switch, all available translations are installed
+together with the package.  However, the environment variable `LINGUAS'
+may be set, prior to configuration, to limit the installed set.
+`LINGUAS' should then contain a space separated list of two-letter
+codes, stating which languages are allowed.
+
+1.3 Using This Package
+======================
+
+As a user, if your language has been installed for this package, you
+only have to set the `LANG' environment variable to the appropriate
+`LL_CC' combination.  If you happen to have the `LC_ALL' or some other
+`LC_xxx' environment variables set, you should unset them before
+setting `LANG', otherwise the setting of `LANG' will not have the
+desired effect.  Here `LL' is an ISO 639 two-letter language code, and
+`CC' is an ISO 3166 two-letter country code.  For example, let's
+suppose that you speak German and live in Germany.  At the shell
+prompt, merely execute `setenv LANG de_DE' (in `csh'),
+`export LANG; LANG=de_DE' (in `sh') or `export LANG=de_DE' (in `bash').
+This can be done from your `.login' or `.profile' file, once and for
+all.
+
+   You might think that the country code specification is redundant.
+But in fact, some languages have dialects in different countries.  For
+example, `de_AT' is used for Austria, and `pt_BR' for Brazil.  The
+country code serves to distinguish the dialects.
+
+   The locale naming convention of `LL_CC', with `LL' denoting the
+language and `CC' denoting the country, is the one use on systems based
+on GNU libc.  On other systems, some variations of this scheme are
+used, such as `LL' or `LL_CC.ENCODING'.  You can get the list of
+locales supported by your system for your language by running the
+command `locale -a | grep '^LL''.
+
+   Not all programs have translations for all languages.  By default, an
+English message is shown in place of a nonexistent translation.  If you
+understand other languages, you can set up a priority list of languages.
+This is done through a different environment variable, called
+`LANGUAGE'.  GNU `gettext' gives preference to `LANGUAGE' over `LANG'
+for the purpose of message handling, but you still need to have `LANG'
+set to the primary language; this is required by other parts of the
+system libraries.  For example, some Swedish users who would rather
+read translations in German than English for when Swedish is not
+available, set `LANGUAGE' to `sv:de' while leaving `LANG' to `sv_SE'.
+
+   Special advice for Norwegian users: The language code for Norwegian
+bokma*l changed from `no' to `nb' recently (in 2003).  During the
+transition period, while some message catalogs for this language are
+installed under `nb' and some older ones under `no', it's recommended
+for Norwegian users to set `LANGUAGE' to `nb:no' so that both newer and
+older translations are used.
+
+   In the `LANGUAGE' environment variable, but not in the `LANG'
+environment variable, `LL_CC' combinations can be abbreviated as `LL'
+to denote the language's main dialect.  For example, `de' is equivalent
+to `de_DE' (German as spoken in Germany), and `pt' to `pt_PT'
+(Portuguese as spoken in Portugal) in this context.
+
+1.4 Translating Teams
+=====================
+
+For the Free Translation Project to be a success, we need interested
+people who like their own language and write it well, and who are also
+able to synergize with other translators speaking the same language.
+Each translation team has its own mailing list.  The up-to-date list of
+teams can be found at the Free Translation Project's homepage,
+`http://translationproject.org/', in the "Teams" area.
+
+   If you'd like to volunteer to _work_ at translating messages, you
+should become a member of the translating team for your own language.
+The subscribing address is _not_ the same as the list itself, it has
+`-request' appended.  For example, speakers of Swedish can send a
+message to `sv-request@li.org', having this message body:
+
+     subscribe
+
+   Keep in mind that team members are expected to participate
+_actively_ in translations, or at solving translational difficulties,
+rather than merely lurking around.  If your team does not exist yet and
+you want to start one, or if you are unsure about what to do or how to
+get started, please write to `coordinator@translationproject.org' to
+reach the coordinator for all translator teams.
+
+   The English team is special.  It works at improving and uniformizing
+the terminology in use.  Proven linguistic skills are praised more than
+programming skills, here.
+
+1.5 Available Packages
+======================
+
+Languages are not equally supported in all packages.  The following
+matrix shows the current state of internationalization, as of November
+2007.  The matrix shows, in regard of each package, for which languages
+PO files have been submitted to translation coordination, with a
+translation percentage of at least 50%.
+
+     Ready PO files       af am ar az be bg bs ca cs cy da de el en en_GB eo
+                        +----------------------------------------------------+
+     Compendium         |                      []       [] []        []      |
+     a2ps               |             []                [] [] []     []      |
+     aegis              |                                  ()                |
+     ant-phone          |                                  ()                |
+     anubis             |                                  []                |
+     ap-utils           |                                                    |
+     aspell             |                      [] []    [] []        []      |
+     bash               |                                                 [] |
+     bfd                |                                                    |
+     bibshelf           |                                  []                |
+     binutils           |                                                    |
+     bison              |                               [] []                |
+     bison-runtime      |                                  []                |
+     bluez-pin          | []                      []       [] []          [] |
+     cflow              |                               []                   |
+     clisp              |                               [] []    []          |
+     console-tools      |                         []       []                |
+     coreutils          |                []    [] []       []                |
+     cpio               |                                                    |
+     cpplib             |                      []       [] []                |
+     cryptonit          |                                  []                |
+     dialog             |                                                    |
+     diffutils          |                      [] []    [] [] []          [] |
+     doodle             |                                  []                |
+     e2fsprogs          |                         []       []                |
+     enscript           |                      []       [] []        []      |
+     fetchmail          |                      []       [] () []     []      |
+     findutils          |                []                                  |
+     findutils_stable   |                []    []       []                   |
+     flex               |                      []       [] []                |
+     fslint             |                                                    |
+     gas                |                                                    |
+     gawk               |                      []       [] []                |
+     gcal               |                      []                            |
+     gcc                |                                  []                |
+     gettext-examples   | []                   []          [] []          [] |
+     gettext-runtime    |             []       []       [] []             [] |
+     gettext-tools      |                      []          []                |
+     gip                |                []                                  |
+     gliv               |                []                []                |
+     glunarclock        |                []                                  |
+     gmult              | []                               []                |
+     gnubiff            |                                  ()                |
+     gnucash            |                      [] []       () ()     []      |
+     gnuedu             |                                                    |
+     gnulib             |                []                                  |
+     gnunet             |                                                    |
+     gnunet-gtk         |                                                    |
+     gnutls             |                                  []                |
+     gpe-aerial         |                         []       []                |
+     gpe-beam           |                         []       []                |
+     gpe-calendar       |                                                    |
+     gpe-clock          |                         []       []                |
+     gpe-conf           |                         []       []                |
+     gpe-contacts       |                                                    |
+     gpe-edit           |                         []                         |
+     gpe-filemanager    |                                                    |
+     gpe-go             |                         []                         |
+     gpe-login          |                         []       []                |
+     gpe-ownerinfo      |                         []       []                |
+     gpe-package        |                                                    |
+     gpe-sketchbook     |                         []       []                |
+     gpe-su             |                         []       []                |
+     gpe-taskmanager    |                         []       []                |
+     gpe-timesheet      |                         []                         |
+     gpe-today          |                         []       []                |
+     gpe-todo           |                                                    |
+     gphoto2            |                         []    [] []        []      |
+     gprof              |                               [] []                |
+     gpsdrive           |                                                    |
+     gramadoir          | []                               []                |
+     grep               |                         []                      [] |
+     gretl              |                                  ()                |
+     gsasl              |                                                    |
+     gss                |                                                    |
+     gst-plugins-bad    |                []             []                   |
+     gst-plugins-base   |                []             []                   |
+     gst-plugins-good   |                []    []       []                   |
+     gst-plugins-ugly   |                []             []                   |
+     gstreamer          | []             []    [] []    [] []        []      |
+     gtick              |                                  ()                |
+     gtkam              |             []          []    [] []                |
+     gtkorphan          |                []                []                |
+     gtkspell           |             []                   [] []          [] |
+     gutenprint         |                               []                   |
+     hello              |                []    []       [] []             [] |
+     herrie             |                                  []                |
+     hylafax            |                                                    |
+     idutils            |                               [] []                |
+     indent             |                      [] []       []             [] |
+     iso_15924          |                                                    |
+     iso_3166           |       []    [] [] [] [] [] [] [] [] []          [] |
+     iso_3166_2         |                                                    |
+     iso_4217           |                         []    [] []                |
+     iso_639            |                         []    [] []             [] |
+     jpilot             |                         []                         |
+     jtag               |                                                    |
+     jwhois             |                                                    |
+     kbd                |                         []    [] [] []             |
+     keytouch           |                      []          []                |
+     keytouch-editor    |                                  []                |
+     keytouch-keyboa... |                      []                            |
+     latrine            |                                  ()                |
+     ld                 |                               []                   |
+     leafpad            |                []    [] []       [] []             |
+     libc               |                      [] []    [] []                |
+     libexif            |                                  []                |
+     libextractor       |                                  []                |
+     libgpewidget       |                         []    [] []                |
+     libgpg-error       |                                  []                |
+     libgphoto2         |                               [] []                |
+     libgphoto2_port    |                               [] []                |
+     libgsasl           |                                                    |
+     libiconv           |                                  []             [] |
+     libidn             |                         []    []                [] |
+     lifelines          |                               [] ()                |
+     lilypond           |                                  []                |
+     lingoteach         |                                                    |
+     lprng              |                                                    |
+     lynx               |                      [] []    [] []                |
+     m4                 |                         []    [] [] []             |
+     mailfromd          |                                                    |
+     mailutils          |                      []                            |
+     make               |                               [] []                |
+     man-db             |                      []       [] []                |
+     minicom            |                         []    [] []                |
+     nano               |                []    []          []                |
+     opcodes            |                                  []                |
+     parted             |                         []       []                |
+     pilot-qof          |                                                    |
+     popt               |                         []    [] []                |
+     psmisc             |                []                                  |
+     pwdutils           |                                                    |
+     qof                |                                                    |
+     radius             |                      []                            |
+     recode             |             []       []       [] [] []          [] |
+     rpm                |                               []                   |
+     screem             |                                                    |
+     scrollkeeper       |          [] []       [] [] [] [] []        []      |
+     sed                |                      []          []             [] |
+     shared-mime-info   |                []    [] []    [] () []     []   [] |
+     sharutils          |                []    [] []    [] [] []             |
+     shishi             |                                                    |
+     skencil            |                               [] ()                |
+     solfege            |                                                    |
+     soundtracker       |                               [] []                |
+     sp                 |                                  []                |
+     system-tools-ba... |       []       [] [] [] []    [] [] []     []      |
+     tar                |                []                []                |
+     texinfo            |                               [] []             [] |
+     tin                |                                  ()        ()      |
+     tuxpaint           | []             []             [] []        []   [] |
+     unicode-han-tra... |                                                    |
+     unicode-transla... |                                                    |
+     util-linux         |                      [] []    [] []                |
+     util-linux-ng      |                      [] []    [] []                |
+     vorbis-tools       |                         []                         |
+     wastesedge         |                                  ()                |
+     wdiff              |                      []       [] []        []      |
+     wget               |                      [] []       []                |
+     xchat              |             [] []    [] []       [] []     []      |
+     xkeyboard-config   |                []                                  |
+     xpad               |                []             []           []      |
+                        +----------------------------------------------------+
+                          af am ar az be bg bs ca cs cy da de el en en_GB eo
+                           6  0  2  1  8 26  2 40 48  2 56 88 15  1  15   18
+
+                          es et eu fa fi fr  ga gl gu he hi hr hu id is it
+                        +--------------------------------------------------+
+     Compendium         | []          [] []  []                []          |
+     a2ps               |    []       [] []                             () |
+     aegis              |                                                  |
+     ant-phone          |                []                                |
+     anubis             |                []                                |
+     ap-utils           |             [] []                                |
+     aspell             |                []  []                         [] |
+     bash               | []                                               |
+     bfd                | []          []                                   |
+     bibshelf           | []                 []                         [] |
+     binutils           | []          [] []                                |
+     bison              | [] []          []  []                   []    [] |
+     bison-runtime      |    []          []  []                   []    [] |
+     bluez-pin          |             [] []  []                [] []       |
+     cflow              |                    []                            |
+     clisp              | []             []                                |
+     console-tools      |                                                  |
+     coreutils          | [] []       [] []  []                []          |
+     cpio               | []             []  []                            |
+     cpplib             | []             []                                |
+     cryptonit          |                []                                |
+     dialog             |       []           []                         [] |
+     diffutils          | []          [] []  [] []    []       [] []    [] |
+     doodle             |                    []                         [] |
+     e2fsprogs          | []             []                             [] |
+     enscript           |                []  []             []             |
+     fetchmail          | []                                               |
+     findutils          |    []              []                []          |
+     findutils_stable   |    []          []  []                []          |
+     flex               | []             []  []                            |
+     fslint             |                                                  |
+     gas                | []             []                                |
+     gawk               | []             []  []       []                () |
+     gcal               | []             []                                |
+     gcc                | []                                               |
+     gettext-examples   | []          [] []  []                [] []    [] |
+     gettext-runtime    | []          [] []  []                   []    [] |
+     gettext-tools      | []    []       []                             [] |
+     gip                | []    []       []  []                            |
+     gliv               |                ()                                |
+     glunarclock        |             []     []                []          |
+     gmult              |       []       []                             [] |
+     gnubiff            |                ()                             () |
+     gnucash            | ()             ()                    ()          |
+     gnuedu             | []                                               |
+     gnulib             | [] []              []                            |
+     gnunet             |                                                  |
+     gnunet-gtk         |                                                  |
+     gnutls             |                                                  |
+     gpe-aerial         | []             []                                |
+     gpe-beam           | []             []                                |
+     gpe-calendar       |                                                  |
+     gpe-clock          | []          [] []                    []          |
+     gpe-conf           |                []                                |
+     gpe-contacts       | []             []                                |
+     gpe-edit           | []             []                    [] []       |
+     gpe-filemanager    | []                                               |
+     gpe-go             | []             []                    []          |
+     gpe-login          | []             []                    []          |
+     gpe-ownerinfo      | []          [] []                    [] []       |
+     gpe-package        | []                                               |
+     gpe-sketchbook     | []             []                                |
+     gpe-su             | []          [] []                    []          |
+     gpe-taskmanager    | []          [] []                                |
+     gpe-timesheet      | []             []  []                   []       |
+     gpe-today          | []          [] []  []                            |
+     gpe-todo           | []                                               |
+     gphoto2            | []          [] []                    []       [] |
+     gprof              | []          [] []  []                   []       |
+     gpsdrive           |    []                                            |
+     gramadoir          |                []  []                            |
+     grep               | []          []     []                            |
+     gretl              | []    []       []                             () |
+     gsasl              |                    []                   []       |
+     gss                |                []  []                            |
+     gst-plugins-bad    | []          []                       []       [] |
+     gst-plugins-base   | []          []                       []       [] |
+     gst-plugins-good   | []    []    []                       []       [] |
+     gst-plugins-ugly   | []          []                       []       [] |
+     gstreamer          |             []                       []       [] |
+     gtick              |             []     []                         [] |
+     gtkam              | []             []                    []       [] |
+     gtkorphan          |                []                             [] |
+     gtkspell           | []    []    [] []  []                []       [] |
+     gutenprint         |                                      []          |
+     hello              | [] [] [] [] [] []  [] []    []    [] [] []    [] |
+     herrie             |                    []                            |
+     hylafax            |                                                  |
+     idutils            |                []  []                [] []    [] |
+     indent             | [] [] []    [] []  [] []             [] []    [] |
+     iso_15924          |                []                                |
+     iso_3166           | [] [] []    [] []     [] [] [] [] [] [] []    [] |
+     iso_3166_2         |                []                                |
+     iso_4217           | [] []       [] []                    []       [] |
+     iso_639            | []       [] [] []  []                []          |
+     jpilot             | []             []                                |
+     jtag               |                []                                |
+     jwhois             | []             []                    [] []    [] |
+     kbd                | []             []                                |
+     keytouch           |                []  []                         [] |
+     keytouch-editor    |                    []                            |
+     keytouch-keyboa... |                    []                         [] |
+     latrine            |                    []                         [] |
+     ld                 | []          [] []  []                            |
+     leafpad            | []             []  []       []       []       [] |
+     libc               | []          [] []     []             []          |
+     libexif            | []                                               |
+     libextractor       |                    []                            |
+     libgpewidget       | []             []  []                [] []       |
+     libgpg-error       |                []                                |
+     libgphoto2         | []             []                             [] |
+     libgphoto2_port    |                []                             [] |
+     libgsasl           |                []  []                            |
+     libiconv           |    []       []     []                            |
+     libidn             |                []                             [] |
+     lifelines          |                ()                                |
+     lilypond           | []          [] []                                |
+     lingoteach         |                []                       []    [] |
+     lprng              |                                                  |
+     lynx               |    []                                []       [] |
+     m4                 |                []  [] []                []       |
+     mailfromd          |                                                  |
+     mailutils          | []             []                                |
+     make               | []          [] []  [] []    []    []    []       |
+     man-db             |                                               [] |
+     minicom            | []          [] []                    []          |
+     nano               | []    []       []  [] []             []       [] |
+     opcodes            | []          [] []  []                            |
+     parted             |                []                       []    [] |
+     pilot-qof          |                                                  |
+     popt               |                []  [] []                   []    |
+     psmisc             |                                      []       [] |
+     pwdutils           |                                                  |
+     qof                |                                         []       |
+     radius             | []             []                                |
+     recode             | []             []  [] []    []       [] []    [] |
+     rpm                |                []                       []       |
+     screem             |                                                  |
+     scrollkeeper       | []          []                       []          |
+     sed                | [] []          []  []                []          |
+     shared-mime-info   | []    []    [] []                    []       [] |
+     sharutils          | [] []       [] []  [] []             []       [] |
+     shishi             |                []                                |
+     skencil            | []             []                                |
+     solfege            |                                               [] |
+     soundtracker       | []             []                             [] |
+     sp                 |                []                                |
+     system-tools-ba... | []    []    [] []  []             [] [] []    [] |
+     tar                |    [] []    []     []                []          |
+     texinfo            |                []           []       []          |
+     tin                |    []          ()                                |
+     tuxpaint           |                    []                []          |
+     unicode-han-tra... |                                                  |
+     unicode-transla... |                []  []                            |
+     util-linux         | [] []       [] []                    [] []    [] |
+     util-linux-ng      | [] []       [] []                    [] []    [] |
+     vorbis-tools       |                                                  |
+     wastesedge         |                ()                                |
+     wdiff              | [] []          []  [] []             [] []    [] |
+     wget               |    []       [] []  []             [] [] []    [] |
+     xchat              | []          [] []        []    []    []       [] |
+     xkeyboard-config   | []          [] []                    []          |
+     xpad               | []                 []                []          |
+                        +--------------------------------------------------+
+                          es et eu fa fi fr  ga gl gu he hi hr hu id is it
+                          85 22 14  2 48 101 61 12  2  8  2  6 53 29  1 52
+
+                          ja ka ko ku ky lg lt lv mk mn ms mt nb ne nl  nn
+                        +--------------------------------------------------+
+     Compendium         |                                           []     |
+     a2ps               |       ()                      []          []     |
+     aegis              |                                           ()     |
+     ant-phone          |                                           []     |
+     anubis             |                               []    []    []     |
+     ap-utils           |                               []                 |
+     aspell             |                            []             []     |
+     bash               |                                           []     |
+     bfd                |                                                  |
+     bibshelf           |                               []                 |
+     binutils           |                                                  |
+     bison              |                               []    []    []     |
+     bison-runtime      |                               []    []    []     |
+     bluez-pin          |          []                   []          []     |
+     cflow              |                                                  |
+     clisp              |                                           []     |
+     console-tools      |                                                  |
+     coreutils          |                                           []     |
+     cpio               |                                           []     |
+     cpplib             |                                           []     |
+     cryptonit          |                                           []     |
+     dialog             |                               []          []     |
+     diffutils          | []                            []          []     |
+     doodle             |                                                  |
+     e2fsprogs          |                                           []     |
+     enscript           |                                           []     |
+     fetchmail          | []                                        []     |
+     findutils          |                                           []     |
+     findutils_stable   |                                           []     |
+     flex               |       []                                  []     |
+     fslint             |                                                  |
+     gas                |                                                  |
+     gawk               | []                                        []     |
+     gcal               |                                                  |
+     gcc                |                                                  |
+     gettext-examples   | []                            []          []     |
+     gettext-runtime    | []    []                                  []     |
+     gettext-tools      | []    []                                         |
+     gip                |                               []          []     |
+     gliv               |                                           []     |
+     glunarclock        |                               []          []     |
+     gmult              | []                            []          []     |
+     gnubiff            |                                                  |
+     gnucash            | ()                                  () ()        |
+     gnuedu             |                                                  |
+     gnulib             | []                                        []     |
+     gnunet             |                                                  |
+     gnunet-gtk         |                                                  |
+     gnutls             |                               []                 |
+     gpe-aerial         |                                           []     |
+     gpe-beam           |                                           []     |
+     gpe-calendar       | []                                               |
+     gpe-clock          | []    []                                  []     |
+     gpe-conf           | []    []                                  []     |
+     gpe-contacts       |       []                                         |
+     gpe-edit           | []    []                                  []     |
+     gpe-filemanager    | []    []                                         |
+     gpe-go             | []    []                                  []     |
+     gpe-login          | []    []                                  []     |
+     gpe-ownerinfo      | []                                        []     |
+     gpe-package        | []    []                                         |
+     gpe-sketchbook     |       []                                  []     |
+     gpe-su             | []    []                                  []     |
+     gpe-taskmanager    | []    [] []                               []     |
+     gpe-timesheet      |                                           []     |
+     gpe-today          | []                                        []     |
+     gpe-todo           | []                                               |
+     gphoto2            | []                                        []     |
+     gprof              |                               []                 |
+     gpsdrive           |                                           []     |
+     gramadoir          |                                           ()     |
+     grep               |             []                            []     |
+     gretl              |                                                  |
+     gsasl              |                                           []     |
+     gss                |                                                  |
+     gst-plugins-bad    |                                           []     |
+     gst-plugins-base   |                                           []     |
+     gst-plugins-good   |                                           []     |
+     gst-plugins-ugly   |                                           []     |
+     gstreamer          |                                           []     |
+     gtick              |                                           []     |
+     gtkam              | []                                        []     |
+     gtkorphan          |                                           []     |
+     gtkspell           |                            []             []     |
+     gutenprint         |                                           []     |
+     hello              | [] [] []                      []    []    []  [] |
+     herrie             |                                           []     |
+     hylafax            |                                                  |
+     idutils            |                                           []     |
+     indent             | []                                        []     |
+     iso_15924          |                                           []     |
+     iso_3166           | []    [] []       []    []          []    []  [] |
+     iso_3166_2         |                                           []     |
+     iso_4217           | []                []                      []     |
+     iso_639            | []                []                      []  [] |
+     jpilot             | ()                                        ()     |
+     jtag               |                                                  |
+     jwhois             |                                           []     |
+     kbd                |                                           []     |
+     keytouch           |                                           []     |
+     keytouch-editor    |                                           []     |
+     keytouch-keyboa... |                                                  |
+     latrine            |                                           []     |
+     ld                 |                                                  |
+     leafpad            | []                []                             |
+     libc               | []    []                                  []     |
+     libexif            |                                                  |
+     libextractor       |                                                  |
+     libgpewidget       |                                           []     |
+     libgpg-error       |                                                  |
+     libgphoto2         | []                                               |
+     libgphoto2_port    | []                                               |
+     libgsasl           |                                           []     |
+     libiconv           |                                           []     |
+     libidn             | []                                        []     |
+     lifelines          |                                           []     |
+     lilypond           |                                           []     |
+     lingoteach         |                                           []     |
+     lprng              |                                                  |
+     lynx               | []                                        []     |
+     m4                 | []                                        []     |
+     mailfromd          |                                                  |
+     mailutils          |                                                  |
+     make               | []    []                                  []     |
+     man-db             |                                                  |
+     minicom            | []                                               |
+     nano               |                               []    []    []     |
+     opcodes            |                                           []     |
+     parted             | []                                        []     |
+     pilot-qof          |                                                  |
+     popt               | []    []                                  []     |
+     psmisc             | []                                  []    []     |
+     pwdutils           |                                                  |
+     qof                |                                                  |
+     radius             |                                                  |
+     recode             |                                           []     |
+     rpm                | []    []                                         |
+     screem             | []                                               |
+     scrollkeeper       |                                     [] [] []  [] |
+     sed                | []                                        []     |
+     shared-mime-info   | []    []          []          []    []    []  [] |
+     sharutils          | []                                        []     |
+     shishi             |                                                  |
+     skencil            |                                                  |
+     solfege            |                                     ()        () |
+     soundtracker       |                                                  |
+     sp                 | ()                                               |
+     system-tools-ba... | []    []          []                      []     |
+     tar                | []          []                            []     |
+     texinfo            |                                     []    []     |
+     tin                |                                                  |
+     tuxpaint           |                                     ()    []  [] |
+     unicode-han-tra... |                                                  |
+     unicode-transla... |                                                  |
+     util-linux         | []                                        []     |
+     util-linux-ng      | []                                        []     |
+     vorbis-tools       |                                                  |
+     wastesedge         |                                           []     |
+     wdiff              |                               []    []           |
+     wget               | []                                        []     |
+     xchat              | []    []                []                []     |
+     xkeyboard-config   |    [] []                                  []     |
+     xpad               |       []                      []          []     |
+                        +--------------------------------------------------+
+                          ja ka ko ku ky lg lt lv mk mn ms mt nb ne nl  nn
+                          51  2 25  3  2  0  6  0  2  2 20  0 11  1 103  6
+
+                          or pa pl pt pt_BR rm ro ru rw sk sl sq sr sv  ta
+                        +--------------------------------------------------+
+     Compendium         |          []  []      []       []          []     |
+     a2ps               |       ()     []      [] []       []    [] []     |
+     aegis              |                      () ()                       |
+     ant-phone          |                      []                   []     |
+     anubis             |       []             [] []                       |
+     ap-utils           |       ()                                         |
+     aspell             |                      [] []    []                 |
+     bash               |       []                      []                 |
+     bfd                |                                                  |
+     bibshelf           |                                           []     |
+     binutils           |                         []    []                 |
+     bison              |       []     []      [] []                []     |
+     bison-runtime      |       []     []      []          []       []     |
+     bluez-pin          |       []     []   [] [] []    [] []    [] []     |
+     cflow              |       []                                         |
+     clisp              |                         []                       |
+     console-tools      |                         []                       |
+     coreutils          |       []                []       []       []     |
+     cpio               |       []                []                []     |
+     cpplib             |                                           []     |
+     cryptonit          |              []                           []     |
+     dialog             |                                           []     |
+     diffutils          |       []     []      [] []             [] []     |
+     doodle             |                                     []    []     |
+     e2fsprogs          |       []                                  []     |
+     enscript           |              []      [] []       []       []     |
+     fetchmail          |       []                []          []           |
+     findutils          |       [] []                               []     |
+     findutils_stable   |       [] []          []       [] []       []     |
+     flex               |       []     []      [] []                []     |
+     fslint             |                                           []     |
+     gas                |                                                  |
+     gawk               |       []     []      []                   []     |
+     gcal               |                                           []     |
+     gcc                |                                        [] []     |
+     gettext-examples   |       [] []          [] []    [] []    [] []     |
+     gettext-runtime    |       [] []          [] []    [] []    [] []     |
+     gettext-tools      |       []             [] []    [] []    [] []     |
+     gip                |                   []          []       [] []     |
+     gliv               |       []     []      [] []    []          []     |
+     glunarclock        |              []      [] []    []       [] []     |
+     gmult              |                   [] []                [] []     |
+     gnubiff            |                      ()                   []     |
+     gnucash            |       ()                                  []     |
+     gnuedu             |                                                  |
+     gnulib             |       []                         []       []     |
+     gnunet             |                                                  |
+     gnunet-gtk         |                                           []     |
+     gnutls             |       []                                  []     |
+     gpe-aerial         |          []  []      [] []       []    [] []     |
+     gpe-beam           |          []  []      [] []       []    [] []     |
+     gpe-calendar       |                         []       []    [] []     |
+     gpe-clock          |          []  []      [] []    [] []    [] []     |
+     gpe-conf           |          []  []      [] []    [] []       []     |
+     gpe-contacts       |                      [] []       []    [] []     |
+     gpe-edit           |       [] []  []      [] []    [] []    [] []     |
+     gpe-filemanager    |                                  []       []     |
+     gpe-go             |       []     []      [] []    [] []    [] []     |
+     gpe-login          |          []  []      [] []    [] []    [] []     |
+     gpe-ownerinfo      |          []  []      [] []    [] []    [] []     |
+     gpe-package        |                                  []       []     |
+     gpe-sketchbook     |          []  []      [] []    [] []    [] []     |
+     gpe-su             |          []  []      [] []    [] []    [] []     |
+     gpe-taskmanager    |          []  []      [] []    [] []    [] []     |
+     gpe-timesheet      |          []  []      [] []    [] []    [] []     |
+     gpe-today          |          []  []      [] []    [] []    [] []     |
+     gpe-todo           |                         []       []    [] []     |
+     gphoto2            |    [] []             []       []       [] []     |
+     gprof              |              []      []                   []     |
+     gpsdrive           |                         []                []     |
+     gramadoir          |                               []          []     |
+     grep               |       []                      [] []       []     |
+     gretl              |       [] []  []                                  |
+     gsasl              |       []                               [] []     |
+     gss                |       []             []       []          []     |
+     gst-plugins-bad    |       []     []                           []     |
+     gst-plugins-base   |       []                                  []     |
+     gst-plugins-good   |       []                                  []     |
+     gst-plugins-ugly   |       []     []                           []     |
+     gstreamer          |       []                            [] [] []     |
+     gtick              |                         []                       |
+     gtkam              |    [] []     []         []                []     |
+     gtkorphan          |                                           []     |
+     gtkspell           |              []   [] [] []    [] []    [] []     |
+     gutenprint         |                                           []     |
+     hello              |       []     []      [] []    [] []    [] []     |
+     herrie             |       []                []                []     |
+     hylafax            |                                                  |
+     idutils            |       []     []      [] []                []     |
+     indent             |       []     []      [] []    []       [] []     |
+     iso_15924          |                                                  |
+     iso_3166           |    [] [] []  []      [] [] [] [] [] [] [] []  [] |
+     iso_3166_2         |                                                  |
+     iso_4217           |       [] []             [] []    []    [] []     |
+     iso_639            |       []                [] [] [] []    [] []     |
+     jpilot             |                                                  |
+     jtag               |                               []                 |
+     jwhois             |       []     []      []                   []     |
+     kbd                |       []             []                   []     |
+     keytouch           |                                           []     |
+     keytouch-editor    |                                           []     |
+     keytouch-keyboa... |                                           []     |
+     latrine            |                                                  |
+     ld                 |                                           []     |
+     leafpad            |       [] []             []    []          []  [] |
+     libc               |       []                []    []          []     |
+     libexif            |       []                      []                 |
+     libextractor       |                      []                   []     |
+     libgpewidget       |       [] []  []      []       [] []    [] []     |
+     libgpg-error       |       []             []                   []     |
+     libgphoto2         |       []                                         |
+     libgphoto2_port    |       []                []                []     |
+     libgsasl           |       []             []                [] []     |
+     libiconv           |                                  []    [] []     |
+     libidn             |       []                               [] ()     |
+     lifelines          |       []                                  []     |
+     lilypond           |                                                  |
+     lingoteach         |              []                                  |
+     lprng              |       []                                         |
+     lynx               |              []         []                []     |
+     m4                 |       []     []      [] []                []     |
+     mailfromd          |       []                                         |
+     mailutils          |       []                []                []     |
+     make               |       []     []         []                []     |
+     man-db             |       []             [] []                []     |
+     minicom            |       []     []      [] []                []     |
+     nano               |              []      [] []                []     |
+     opcodes            |                      []                   []     |
+     parted             |       []                                         |
+     pilot-qof          |                                                  |
+     popt               |       [] []             []                []     |
+     psmisc             |       []                                  []     |
+     pwdutils           |       []                                  []     |
+     qof                |              []                           []     |
+     radius             |       []                []                       |
+     recode             |       [] []  []      [] []       []       []     |
+     rpm                |       [] []             []                []     |
+     screem             |                                                  |
+     scrollkeeper       |       []             [] []    []    [] [] []     |
+     sed                |       [] []  []      [] []    [] []    [] []     |
+     shared-mime-info   |       [] []  []                     [] [] []     |
+     sharutils          |       []                []             [] []     |
+     shishi             |       []                                         |
+     skencil            |          []  []                           []     |
+     solfege            |              []                                  |
+     soundtracker       |                               []          []     |
+     sp                 |                                                  |
+     system-tools-ba... |    [] [] []  []      []             [] [] []  [] |
+     tar                |       []                []       []       []     |
+     texinfo            |       []             [] []                []     |
+     tin                |                         ()                       |
+     tuxpaint           |       [] []                      [] [] [] []     |
+     unicode-han-tra... |                                                  |
+     unicode-transla... |                                                  |
+     util-linux         |              []         []       []       []     |
+     util-linux-ng      |              []         []       []       []     |
+     vorbis-tools       |                         []                       |
+     wastesedge         |                                                  |
+     wdiff              |       []     []      [] []    [] []       []     |
+     wget               |          []             []    []          []     |
+     xchat              |    []                   []    [] [] [] [] []     |
+     xkeyboard-config   |                               [] []       []     |
+     xpad               |                               [] []       []     |
+                        +--------------------------------------------------+
+                          or pa pl pt pt_BR rm ro ru rw sk sl sq sr sv  ta
+                           0  5 77 31  53    4 58 72  3 45 46  9 45 122  3
+
+                          tg th tk tr uk ven vi  wa xh zh_CN zh_HK zh_TW zu
+                        +---------------------------------------------------+
+     Compendium         |          []        []         []          []      | 19
+     a2ps               |          [] []     []                             | 19
+     aegis              |                    []                             |  1
+     ant-phone          |          []        []                             |  6
+     anubis             |          [] []     []                             | 11
+     ap-utils           |             ()     []                             |  4
+     aspell             |             []     []  []                         | 16
+     bash               |          []                                       |  6
+     bfd                |                                                   |  2
+     bibshelf           |                    []                             |  7
+     binutils           |          [] []     []                     []      |  9
+     bison              |          [] []     []                     []      | 20
+     bison-runtime      |             []     []         []          []      | 18
+     bluez-pin          |          [] []     []  []     []          []      | 28
+     cflow              |             []     []                             |  5
+     clisp              |                                                   |  9
+     console-tools      |          []        []                             |  5
+     coreutils          |          [] []     []                             | 18
+     cpio               |          [] []     []         []                  | 11
+     cpplib             |          [] []     []         []          []      | 12
+     cryptonit          |                    []                             |  6
+     dialog             |                    []  []     []                  |  9
+     diffutils          |          [] []     []         []          []      | 29
+     doodle             |                    []                             |  6
+     e2fsprogs          |          []        []                             | 10
+     enscript           |          [] []     []                             | 16
+     fetchmail          |          []        []                             | 12
+     findutils          |          [] []     []                             | 11
+     findutils_stable   |          [] []     []                     []      | 18
+     flex               |          []        []                             | 15
+     fslint             |                    []                             |  2
+     gas                |          []                                       |  3
+     gawk               |          []        []         []                  | 16
+     gcal               |          []                                       |  5
+     gcc                |          []                   []          []      |  7
+     gettext-examples   |          [] []     []         []    []    []      | 29
+     gettext-runtime    |          [] []     []         []    []    []      | 28
+     gettext-tools      |          [] []     []         []          []      | 20
+     gip                |                    []                     []      | 13
+     gliv               |          []        []                             | 11
+     glunarclock        |                    []  []                 []      | 15
+     gmult              |          []        []         []          []      | 16
+     gnubiff            |                    []                             |  2
+     gnucash            |          () []                                    |  5
+     gnuedu             |                    []                             |  2
+     gnulib             |                    []                             | 10
+     gnunet             |                                                   |  0
+     gnunet-gtk         |          []        []                             |  3
+     gnutls             |                                                   |  4
+     gpe-aerial         |                    []         []                  | 14
+     gpe-beam           |                    []         []                  | 14
+     gpe-calendar       |                    []  []                         |  7
+     gpe-clock          |          []        []  []     []                  | 21
+     gpe-conf           |                    []  []     []                  | 16
+     gpe-contacts       |                    []         []                  | 10
+     gpe-edit           |          []        []  []     []          []      | 22
+     gpe-filemanager    |                    []  []                         |  7
+     gpe-go             |          []        []  []     []                  | 19
+     gpe-login          |          []        []  []     []          []      | 21
+     gpe-ownerinfo      |          []        []         []          []      | 21
+     gpe-package        |                    []                             |  6
+     gpe-sketchbook     |          []        []                             | 16
+     gpe-su             |          []        []  []     []                  | 21
+     gpe-taskmanager    |          []        []  []     []                  | 21
+     gpe-timesheet      |          []        []         []          []      | 18
+     gpe-today          |          []        []  []     []          []      | 21
+     gpe-todo           |                    []  []                         |  8
+     gphoto2            |             []     []         []          []      | 21
+     gprof              |          []        []                             | 13
+     gpsdrive           |                    []                             |  5
+     gramadoir          |                    []                             |  7
+     grep               |                    []                             | 12
+     gretl              |                                                   |  6
+     gsasl              |                    []         []          []      |  9
+     gss                |                    []                             |  7
+     gst-plugins-bad    |             []     []         []                  | 13
+     gst-plugins-base   |             []     []                             | 11
+     gst-plugins-good   |             []     []         []    []    []      | 16
+     gst-plugins-ugly   |             []     []         []                  | 13
+     gstreamer          |          [] []     []                             | 18
+     gtick              |             []     []                             |  7
+     gtkam              |                    []                             | 16
+     gtkorphan          |                    []                             |  7
+     gtkspell           |             []     []  []     []    []    []      | 27
+     gutenprint         |                                                   |  4
+     hello              |          [] []     []         []          []      | 38
+     herrie             |          []        []                             |  8
+     hylafax            |                                                   |  0
+     idutils            |          []        []                             | 15
+     indent             |          [] []     []         []          []      | 28
+     iso_15924          |                    []         []                  |  4
+     iso_3166           |    [] [] [] []     []  []     []    []    []      | 54
+     iso_3166_2         |                    []         []                  |  4
+     iso_4217           |    []    []        []         []    []            | 24
+     iso_639            |             []     []  []     []    []            | 26
+     jpilot             |          [] []     []         []                  |  7
+     jtag               |                    []                             |  3
+     jwhois             |          []        []                     []      | 13
+     kbd                |          [] []     []                             | 13
+     keytouch           |                    []                             |  8
+     keytouch-editor    |                    []                             |  5
+     keytouch-keyboa... |                    []                             |  5
+     latrine            |          []        []                             |  5
+     ld                 |          []        []         []          []      | 10
+     leafpad            |          [] []     []         []          []      | 24
+     libc               |          []                   []          []      | 19
+     libexif            |                    []                             |  5
+     libextractor       |                    []                             |  5
+     libgpewidget       |                    []  []     []                  | 20
+     libgpg-error       |                    []                             |  6
+     libgphoto2         |             []     []                             |  9
+     libgphoto2_port    |             []     []                     []      | 11
+     libgsasl           |                    []                             |  8
+     libiconv           |                    []  []                         | 11
+     libidn             |                    []         []                  | 11
+     lifelines          |                                                   |  4
+     lilypond           |                    []                             |  6
+     lingoteach         |                    []                             |  6
+     lprng              |                    []                             |  2
+     lynx               |          [] []     []                             | 15
+     m4                 |                    []         []          []      | 18
+     mailfromd          |             []     []                             |  3
+     mailutils          |             []     []                             |  8
+     make               |          []        []         []                  | 20
+     man-db             |                    []                             |  9
+     minicom            |                    []                             | 14
+     nano               |                    []         []          []      | 20
+     opcodes            |          []        []                             | 10
+     parted             |          [] []                            []      | 11
+     pilot-qof          |                    []                             |  1
+     popt               |          []        []         []          []      | 18
+     psmisc             |                    []         []                  | 10
+     pwdutils           |                    []                             |  3
+     qof                |                    []                             |  4
+     radius             |             []     []                             |  7
+     recode             |          []        []         []                  | 25
+     rpm                |          [] []     []                     []      | 13
+     screem             |                    []                             |  2
+     scrollkeeper       |          [] []     []                     []      | 26
+     sed                |          []        []         []          []      | 23
+     shared-mime-info   |             []     []         []                  | 29
+     sharutils          |          []        []                     []      | 23
+     shishi             |                    []                             |  3
+     skencil            |                    []                             |  7
+     solfege            |                    []                             |  3
+     soundtracker       |          []        []                             |  9
+     sp                 |          []                                       |  3
+     system-tools-ba... |    []    [] []     []     []  []          []      | 38
+     tar                |          [] []     []                             | 17
+     texinfo            |          []        []         []                  | 15
+     tin                |                                                   |  1
+     tuxpaint           |                    []  []                 []      | 19
+     unicode-han-tra... |                                                   |  0
+     unicode-transla... |                                                   |  2
+     util-linux         |          [] []     []                             | 20
+     util-linux-ng      |          [] []     []                             | 20
+     vorbis-tools       |             []     []                             |  4
+     wastesedge         |                                                   |  1
+     wdiff              |          []        []                             | 23
+     wget               |          []        []                     []      | 20
+     xchat              |             []     []         []          []      | 29
+     xkeyboard-config   |          [] []     []                             | 14
+     xpad               |                    []         []          []      | 15
+                        +---------------------------------------------------+
+       76 teams           tg th tk tr uk ven vi  wa xh zh_CN zh_HK zh_TW zu
+      163 domains          0  3  1 74 51  0  143 21  1  57     7    45    0  2036
+
+   Some counters in the preceding matrix are higher than the number of
+visible blocks let us expect.  This is because a few extra PO files are
+used for implementing regional variants of languages, or language
+dialects.
+
+   For a PO file in the matrix above to be effective, the package to
+which it applies should also have been internationalized and
+distributed as such by its maintainer.  There might be an observable
+lag between the mere existence a PO file and its wide availability in a
+distribution.
+
+   If November 2007 seems to be old, you may fetch a more recent copy
+of this `ABOUT-NLS' file on most GNU archive sites.  The most
+up-to-date matrix with full percentage details can be found at
+`http://translationproject.org/extra/matrix.html'.
+
+1.6 Using `gettext' in new packages
+===================================
+
+If you are writing a freely available program and want to
+internationalize it you are welcome to use GNU `gettext' in your
+package.  Of course you have to respect the GNU Library General Public
+License which covers the use of the GNU `gettext' library.  This means
+in particular that even non-free programs can use `libintl' as a shared
+library, whereas only free software can use `libintl' as a static
+library or use modified versions of `libintl'.
+
+   Once the sources are changed appropriately and the setup can handle
+the use of `gettext' the only thing missing are the translations.  The
+Free Translation Project is also available for packages which are not
+developed inside the GNU project.  Therefore the information given above
+applies also for every other Free Software Project.  Contact
+`coordinator@translationproject.org' to make the `.pot' files available
+to the translation teams.
+
diff --git a/AUTHORS b/AUTHORS
new file mode 100644 (file)
index 0000000..c28a06d
--- /dev/null
+++ b/AUTHORS
@@ -0,0 +1,10 @@
+Lei Zhang <phill.zhang@sun.com>
+Ervin Yan <ervin.yan@sun.com>
+Yong Sun <mail@yongsun.me>
+Kefu Chai <tchaikov@gmail.com>
+Wei Xue <wei.xue@sun.com>
+Leo Zheng <zym361@gmail.com>
+chumsdock <vorbei@gmail.com>
+Mike Qin<mikeandmore@gmail.com>
+Li Zhang<li2012.zhang@samsung.com>
+
diff --git a/COPYING b/COPYING
new file mode 100644 (file)
index 0000000..a82e03e
--- /dev/null
+++ b/COPYING
@@ -0,0 +1 @@
+Refer to LGPL.LICENSE and OPENSOLARIS.LICENSE.
diff --git a/ChangeLog b/ChangeLog
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/INSTALL b/INSTALL
new file mode 100644 (file)
index 0000000..a1e89e1
--- /dev/null
+++ b/INSTALL
@@ -0,0 +1,370 @@
+Installation Instructions
+*************************
+
+Copyright (C) 1994-1996, 1999-2002, 2004-2011 Free Software Foundation,
+Inc.
+
+   Copying and distribution of this file, with or without modification,
+are permitted in any medium without royalty provided the copyright
+notice and this notice are preserved.  This file is offered as-is,
+without warranty of any kind.
+
+Basic Installation
+==================
+
+   Briefly, the shell commands `./configure; make; make install' should
+configure, build, and install this package.  The following
+more-detailed instructions are generic; see the `README' file for
+instructions specific to this package.  Some packages provide this
+`INSTALL' file but do not implement all of the features documented
+below.  The lack of an optional feature in a given package is not
+necessarily a bug.  More recommendations for GNU packages can be found
+in *note Makefile Conventions: (standards)Makefile Conventions.
+
+   The `configure' shell script attempts to guess correct values for
+various system-dependent variables used during compilation.  It uses
+those values to create a `Makefile' in each directory of the package.
+It may also create one or more `.h' files containing system-dependent
+definitions.  Finally, it creates a shell script `config.status' that
+you can run in the future to recreate the current configuration, and a
+file `config.log' containing compiler output (useful mainly for
+debugging `configure').
+
+   It can also use an optional file (typically called `config.cache'
+and enabled with `--cache-file=config.cache' or simply `-C') that saves
+the results of its tests to speed up reconfiguring.  Caching is
+disabled by default to prevent problems with accidental use of stale
+cache files.
+
+   If you need to do unusual things to compile the package, please try
+to figure out how `configure' could check whether to do them, and mail
+diffs or instructions to the address given in the `README' so they can
+be considered for the next release.  If you are using the cache, and at
+some point `config.cache' contains results you don't want to keep, you
+may remove or edit it.
+
+   The file `configure.ac' (or `configure.in') is used to create
+`configure' by a program called `autoconf'.  You need `configure.ac' if
+you want to change it or regenerate `configure' using a newer version
+of `autoconf'.
+
+   The simplest way to compile this package is:
+
+  1. `cd' to the directory containing the package's source code and type
+     `./configure' to configure the package for your system.
+
+     Running `configure' might take a while.  While running, it prints
+     some messages telling which features it is checking for.
+
+  2. Type `make' to compile the package.
+
+  3. Optionally, type `make check' to run any self-tests that come with
+     the package, generally using the just-built uninstalled binaries.
+
+  4. Type `make install' to install the programs and any data files and
+     documentation.  When installing into a prefix owned by root, it is
+     recommended that the package be configured and built as a regular
+     user, and only the `make install' phase executed with root
+     privileges.
+
+  5. Optionally, type `make installcheck' to repeat any self-tests, but
+     this time using the binaries in their final installed location.
+     This target does not install anything.  Running this target as a
+     regular user, particularly if the prior `make install' required
+     root privileges, verifies that the installation completed
+     correctly.
+
+  6. You can remove the program binaries and object files from the
+     source code directory by typing `make clean'.  To also remove the
+     files that `configure' created (so you can compile the package for
+     a different kind of computer), type `make distclean'.  There is
+     also a `make maintainer-clean' target, but that is intended mainly
+     for the package's developers.  If you use it, you may have to get
+     all sorts of other programs in order to regenerate files that came
+     with the distribution.
+
+  7. Often, you can also type `make uninstall' to remove the installed
+     files again.  In practice, not all packages have tested that
+     uninstallation works correctly, even though it is required by the
+     GNU Coding Standards.
+
+  8. Some packages, particularly those that use Automake, provide `make
+     distcheck', which can by used by developers to test that all other
+     targets like `make install' and `make uninstall' work correctly.
+     This target is generally not run by end users.
+
+Compilers and Options
+=====================
+
+   Some systems require unusual options for compilation or linking that
+the `configure' script does not know about.  Run `./configure --help'
+for details on some of the pertinent environment variables.
+
+   You can give `configure' initial values for configuration parameters
+by setting variables in the command line or in the environment.  Here
+is an example:
+
+     ./configure CC=c99 CFLAGS=-g LIBS=-lposix
+
+   *Note Defining Variables::, for more details.
+
+Compiling For Multiple Architectures
+====================================
+
+   You can compile the package for more than one kind of computer at the
+same time, by placing the object files for each architecture in their
+own directory.  To do this, you can use GNU `make'.  `cd' to the
+directory where you want the object files and executables to go and run
+the `configure' script.  `configure' automatically checks for the
+source code in the directory that `configure' is in and in `..'.  This
+is known as a "VPATH" build.
+
+   With a non-GNU `make', it is safer to compile the package for one
+architecture at a time in the source code directory.  After you have
+installed the package for one architecture, use `make distclean' before
+reconfiguring for another architecture.
+
+   On MacOS X 10.5 and later systems, you can create libraries and
+executables that work on multiple system types--known as "fat" or
+"universal" binaries--by specifying multiple `-arch' options to the
+compiler but only a single `-arch' option to the preprocessor.  Like
+this:
+
+     ./configure CC="gcc -arch i386 -arch x86_64 -arch ppc -arch ppc64" \
+                 CXX="g++ -arch i386 -arch x86_64 -arch ppc -arch ppc64" \
+                 CPP="gcc -E" CXXCPP="g++ -E"
+
+   This is not guaranteed to produce working output in all cases, you
+may have to build one architecture at a time and combine the results
+using the `lipo' tool if you have problems.
+
+Installation Names
+==================
+
+   By default, `make install' installs the package's commands under
+`/usr/local/bin', include files under `/usr/local/include', etc.  You
+can specify an installation prefix other than `/usr/local' by giving
+`configure' the option `--prefix=PREFIX', where PREFIX must be an
+absolute file name.
+
+   You can specify separate installation prefixes for
+architecture-specific files and architecture-independent files.  If you
+pass the option `--exec-prefix=PREFIX' to `configure', the package uses
+PREFIX as the prefix for installing programs and libraries.
+Documentation and other data files still use the regular prefix.
+
+   In addition, if you use an unusual directory layout you can give
+options like `--bindir=DIR' to specify different values for particular
+kinds of files.  Run `configure --help' for a list of the directories
+you can set and what kinds of files go in them.  In general, the
+default for these options is expressed in terms of `${prefix}', so that
+specifying just `--prefix' will affect all of the other directory
+specifications that were not explicitly provided.
+
+   The most portable way to affect installation locations is to pass the
+correct locations to `configure'; however, many packages provide one or
+both of the following shortcuts of passing variable assignments to the
+`make install' command line to change installation locations without
+having to reconfigure or recompile.
+
+   The first method involves providing an override variable for each
+affected directory.  For example, `make install
+prefix=/alternate/directory' will choose an alternate location for all
+directory configuration variables that were expressed in terms of
+`${prefix}'.  Any directories that were specified during `configure',
+but not in terms of `${prefix}', must each be overridden at install
+time for the entire installation to be relocated.  The approach of
+makefile variable overrides for each directory variable is required by
+the GNU Coding Standards, and ideally causes no recompilation.
+However, some platforms have known limitations with the semantics of
+shared libraries that end up requiring recompilation when using this
+method, particularly noticeable in packages that use GNU Libtool.
+
+   The second method involves providing the `DESTDIR' variable.  For
+example, `make install DESTDIR=/alternate/directory' will prepend
+`/alternate/directory' before all installation names.  The approach of
+`DESTDIR' overrides is not required by the GNU Coding Standards, and
+does not work on platforms that have drive letters.  On the other hand,
+it does better at avoiding recompilation issues, and works well even
+when some directory options were not specified in terms of `${prefix}'
+at `configure' time.
+
+Optional Features
+=================
+
+   If the package supports it, you can cause programs to be installed
+with an extra prefix or suffix on their names by giving `configure' the
+option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'.
+
+   Some packages pay attention to `--enable-FEATURE' options to
+`configure', where FEATURE indicates an optional part of the package.
+They may also pay attention to `--with-PACKAGE' options, where PACKAGE
+is something like `gnu-as' or `x' (for the X Window System).  The
+`README' should mention any `--enable-' and `--with-' options that the
+package recognizes.
+
+   For packages that use the X Window System, `configure' can usually
+find the X include and library files automatically, but if it doesn't,
+you can use the `configure' options `--x-includes=DIR' and
+`--x-libraries=DIR' to specify their locations.
+
+   Some packages offer the ability to configure how verbose the
+execution of `make' will be.  For these packages, running `./configure
+--enable-silent-rules' sets the default to minimal output, which can be
+overridden with `make V=1'; while running `./configure
+--disable-silent-rules' sets the default to verbose, which can be
+overridden with `make V=0'.
+
+Particular systems
+==================
+
+   On HP-UX, the default C compiler is not ANSI C compatible.  If GNU
+CC is not installed, it is recommended to use the following options in
+order to use an ANSI C compiler:
+
+     ./configure CC="cc -Ae -D_XOPEN_SOURCE=500"
+
+and if that doesn't work, install pre-built binaries of GCC for HP-UX.
+
+   HP-UX `make' updates targets which have the same time stamps as
+their prerequisites, which makes it generally unusable when shipped
+generated files such as `configure' are involved.  Use GNU `make'
+instead.
+
+   On OSF/1 a.k.a. Tru64, some versions of the default C compiler cannot
+parse its `<wchar.h>' header file.  The option `-nodtk' can be used as
+a workaround.  If GNU CC is not installed, it is therefore recommended
+to try
+
+     ./configure CC="cc"
+
+and if that doesn't work, try
+
+     ./configure CC="cc -nodtk"
+
+   On Solaris, don't put `/usr/ucb' early in your `PATH'.  This
+directory contains several dysfunctional programs; working variants of
+these programs are available in `/usr/bin'.  So, if you need `/usr/ucb'
+in your `PATH', put it _after_ `/usr/bin'.
+
+   On Haiku, software installed for all users goes in `/boot/common',
+not `/usr/local'.  It is recommended to use the following options:
+
+     ./configure --prefix=/boot/common
+
+Specifying the System Type
+==========================
+
+   There may be some features `configure' cannot figure out
+automatically, but needs to determine by the type of machine the package
+will run on.  Usually, assuming the package is built to be run on the
+_same_ architectures, `configure' can figure that out, but if it prints
+a message saying it cannot guess the machine type, give it the
+`--build=TYPE' option.  TYPE can either be a short name for the system
+type, such as `sun4', or a canonical name which has the form:
+
+     CPU-COMPANY-SYSTEM
+
+where SYSTEM can have one of these forms:
+
+     OS
+     KERNEL-OS
+
+   See the file `config.sub' for the possible values of each field.  If
+`config.sub' isn't included in this package, then this package doesn't
+need to know the machine type.
+
+   If you are _building_ compiler tools for cross-compiling, you should
+use the option `--target=TYPE' to select the type of system they will
+produce code for.
+
+   If you want to _use_ a cross compiler, that generates code for a
+platform different from the build platform, you should specify the
+"host" platform (i.e., that on which the generated programs will
+eventually be run) with `--host=TYPE'.
+
+Sharing Defaults
+================
+
+   If you want to set default values for `configure' scripts to share,
+you can create a site shell script called `config.site' that gives
+default values for variables like `CC', `cache_file', and `prefix'.
+`configure' looks for `PREFIX/share/config.site' if it exists, then
+`PREFIX/etc/config.site' if it exists.  Or, you can set the
+`CONFIG_SITE' environment variable to the location of the site script.
+A warning: not all `configure' scripts look for a site script.
+
+Defining Variables
+==================
+
+   Variables not defined in a site shell script can be set in the
+environment passed to `configure'.  However, some packages may run
+configure again during the build, and the customized values of these
+variables may be lost.  In order to avoid this problem, you should set
+them in the `configure' command line, using `VAR=value'.  For example:
+
+     ./configure CC=/usr/local2/bin/gcc
+
+causes the specified `gcc' to be used as the C compiler (unless it is
+overridden in the site shell script).
+
+Unfortunately, this technique does not work for `CONFIG_SHELL' due to
+an Autoconf bug.  Until the bug is fixed you can use this workaround:
+
+     CONFIG_SHELL=/bin/bash /bin/bash ./configure CONFIG_SHELL=/bin/bash
+
+`configure' Invocation
+======================
+
+   `configure' recognizes the following options to control how it
+operates.
+
+`--help'
+`-h'
+     Print a summary of all of the options to `configure', and exit.
+
+`--help=short'
+`--help=recursive'
+     Print a summary of the options unique to this package's
+     `configure', and exit.  The `short' variant lists options used
+     only in the top level, while the `recursive' variant lists options
+     also present in any nested packages.
+
+`--version'
+`-V'
+     Print the version of Autoconf used to generate the `configure'
+     script, and exit.
+
+`--cache-file=FILE'
+     Enable the cache: use and save the results of the tests in FILE,
+     traditionally `config.cache'.  FILE defaults to `/dev/null' to
+     disable caching.
+
+`--config-cache'
+`-C'
+     Alias for `--cache-file=config.cache'.
+
+`--quiet'
+`--silent'
+`-q'
+     Do not print messages saying which checks are being made.  To
+     suppress all normal output, redirect it to `/dev/null' (any error
+     messages will still be shown).
+
+`--srcdir=DIR'
+     Look for the package's source code in directory DIR.  Usually
+     `configure' can determine that directory automatically.
+
+`--prefix=DIR'
+     Use DIR as the installation prefix.  *note Installation Names::
+     for more details, including other options available for fine-tuning
+     the installation locations.
+
+`--no-create'
+`-n'
+     Run the configure checks, but stop before creating any output
+     files.
+
+`configure' also accepts some other, not widely useful, options.  Run
+`configure --help' for more details.
+
diff --git a/LGPL.LICENSE b/LGPL.LICENSE
new file mode 100644 (file)
index 0000000..5b9dd3b
--- /dev/null
@@ -0,0 +1,516 @@
+                 GNU LESSER GENERAL PUBLIC LICENSE
+                      Version 2.1, February 1999
+
+ Copyright (C) 1991, 1999 Free Software Foundation, Inc.
+ 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the Lesser GPL.  It also counts
+ as the successor of the GNU Library Public License, version 2, hence
+ the version number 2.1.]
+
+                           Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+  This license, the Lesser General Public License, applies to some
+specially designated software packages--typically libraries--of the
+Free Software Foundation and other authors who decide to use it.  You
+can use it too, but we suggest you first think carefully about whether
+this license or the ordinary General Public License is the better
+strategy to use in any particular case, based on the explanations below.
+
+  When we speak of free software, we are referring to freedom of use,
+not price.  Our General Public Licenses are designed to make sure that
+you have the freedom to distribute copies of free software (and charge
+for this service if you wish); that you receive source code or can get
+it if you want it; that you can change the software and use pieces of
+it in new free programs; and that you are informed that you can do
+these things.
+
+  To protect your rights, we need to make restrictions that forbid
+distributors to deny you these rights or to ask you to surrender these
+rights.  These restrictions translate to certain responsibilities for
+you if you distribute copies of the library or if you modify it.
+
+  For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you.  You must make sure that they, too, receive or can get the source
+code.  If you link other code with the library, you must provide
+complete object files to the recipients, so that they can relink them
+with the library after making changes to the library and recompiling
+it.  And you must show them these terms so they know their rights.
+
+  We protect your rights with a two-step method: (1) we copyright the
+library, and (2) we offer you this license, which gives you legal
+permission to copy, distribute and/or modify the library.
+
+  To protect each distributor, we want to make it very clear that
+there is no warranty for the free library.  Also, if the library is
+modified by someone else and passed on, the recipients should know
+that what they have is not the original version, so that the original
+author's reputation will not be affected by problems that might be
+introduced by others.
+\f
+  Finally, software patents pose a constant threat to the existence of
+any free program.  We wish to make sure that a company cannot
+effectively restrict the users of a free program by obtaining a
+restrictive license from a patent holder.  Therefore, we insist that
+any patent license obtained for a version of the library must be
+consistent with the full freedom of use specified in this license.
+
+  Most GNU software, including some libraries, is covered by the
+ordinary GNU General Public License.  This license, the GNU Lesser
+General Public License, applies to certain designated libraries, and
+is quite different from the ordinary General Public License.  We use
+this license for certain libraries in order to permit linking those
+libraries into non-free programs.
+
+  When a program is linked with a library, whether statically or using
+a shared library, the combination of the two is legally speaking a
+combined work, a derivative of the original library.  The ordinary
+General Public License therefore permits such linking only if the
+entire combination fits its criteria of freedom.  The Lesser General
+Public License permits more lax criteria for linking other code with
+the library.
+
+  We call this license the "Lesser" General Public License because it
+does Less to protect the user's freedom than the ordinary General
+Public License.  It also provides other free software developers Less
+of an advantage over competing non-free programs.  These disadvantages
+are the reason we use the ordinary General Public License for many
+libraries.  However, the Lesser license provides advantages in certain
+special circumstances.
+
+  For example, on rare occasions, there may be a special need to
+encourage the widest possible use of a certain library, so that it becomes
+a de-facto standard.  To achieve this, non-free programs must be
+allowed to use the library.  A more frequent case is that a free
+library does the same job as widely used non-free libraries.  In this
+case, there is little to gain by limiting the free library to free
+software only, so we use the Lesser General Public License.
+
+  In other cases, permission to use a particular library in non-free
+programs enables a greater number of people to use a large body of
+free software.  For example, permission to use the GNU C Library in
+non-free programs enables many more people to use the whole GNU
+operating system, as well as its variant, the GNU/Linux operating
+system.
+
+  Although the Lesser General Public License is Less protective of the
+users' freedom, it does ensure that the user of a program that is
+linked with the Library has the freedom and the wherewithal to run
+that program using a modified version of the Library.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.  Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library".  The
+former contains code derived from the library, whereas the latter must
+be combined with the library in order to run.
+\f
+                 GNU LESSER GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License Agreement applies to any software library or other
+program which contains a notice placed by the copyright holder or
+other authorized party saying it may be distributed under the terms of
+this Lesser General Public License (also called "this License").
+Each licensee is addressed as "you".
+
+  A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+  The "Library", below, refers to any such software library or work
+which has been distributed under these terms.  A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language.  (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+  "Source code" for a work means the preferred form of the work for
+making modifications to it.  For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+  Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it).  Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+  
+  1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+  You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+\f
+  2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) The modified work must itself be a software library.
+
+    b) You must cause the files modified to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    c) You must cause the whole of the work to be licensed at no
+    charge to all third parties under the terms of this License.
+
+    d) If a facility in the modified Library refers to a function or a
+    table of data to be supplied by an application program that uses
+    the facility, other than as an argument passed when the facility
+    is invoked, then you must make a good faith effort to ensure that,
+    in the event an application does not supply such function or
+    table, the facility still operates, and performs whatever part of
+    its purpose remains meaningful.
+
+    (For example, a function in a library to compute square roots has
+    a purpose that is entirely well-defined independent of the
+    application.  Therefore, Subsection 2d requires that any
+    application-supplied function or table used by this function must
+    be optional: if the application does not supply it, the square
+    root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library.  To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License.  (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.)  Do not make any other change in
+these notices.
+\f
+  Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+  This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+  4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+  If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library".  Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+  However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library".  The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+  When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library.  The
+threshold for this to be true is not precisely defined by law.
+
+  If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work.  (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+  Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+\f
+  6. As an exception to the Sections above, you may also combine or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+  You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License.  You must supply a copy of this License.  If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License.  Also, you must do one
+of these things:
+
+    a) Accompany the work with the complete corresponding
+    machine-readable source code for the Library including whatever
+    changes were used in the work (which must be distributed under
+    Sections 1 and 2 above); and, if the work is an executable linked
+    with the Library, with the complete machine-readable "work that
+    uses the Library", as object code and/or source code, so that the
+    user can modify the Library and then relink to produce a modified
+    executable containing the modified Library.  (It is understood
+    that the user who changes the contents of definitions files in the
+    Library will not necessarily be able to recompile the application
+    to use the modified definitions.)
+
+    b) Use a suitable shared library mechanism for linking with the
+    Library.  A suitable mechanism is one that (1) uses at run time a
+    copy of the library already present on the user's computer system,
+    rather than copying library functions into the executable, and (2)
+    will operate properly with a modified version of the library, if
+    the user installs one, as long as the modified version is
+    interface-compatible with the version that the work was made with.
+
+    c) Accompany the work with a written offer, valid for at
+    least three years, to give the same user the materials
+    specified in Subsection 6a, above, for a charge no more
+    than the cost of performing this distribution.
+
+    d) If distribution of the work is made by offering access to copy
+    from a designated place, offer equivalent access to copy the above
+    specified materials from the same place.
+
+    e) Verify that the user has already received a copy of these
+    materials or that you have already sent this user a copy.
+
+  For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it.  However, as a special exception,
+the materials to be distributed need not include anything that is
+normally distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+  It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system.  Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+\f
+  7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+    a) Accompany the combined library with a copy of the same work
+    based on the Library, uncombined with any other library
+    facilities.  This must be distributed under the terms of the
+    Sections above.
+
+    b) Give prominent notice with the combined library of the fact
+    that part of it is a work based on the Library, and explaining
+    where to find the accompanying uncombined form of the same work.
+
+  8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License.  Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License.  However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+  9. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Library or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+  10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties with
+this License.
+\f
+  11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded.  In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+  13. The Free Software Foundation may publish revised and/or new
+versions of the Lesser General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation.  If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+\f
+  14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission.  For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this.  Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+                           NO WARRANTY
+
+  15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU.  SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+  16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+                    END OF TERMS AND CONDITIONS
+\f
+           How to Apply These Terms to Your New Libraries
+
+  If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change.  You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+  To apply these terms, attach the following notices to the library.  It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the library's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with this library; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the
+  library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+  <signature of Ty Coon>, 1 April 1990
+  Ty Coon, President of Vice
+
+That's all there is to it!
+
+--------------------------------------------------------------------
+
+NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND
+DISTRIBUTION LICENSE (CDDL)
+
+For Covered Software in this distribution, this License shall
+be governed by the laws of the State of California (excluding
+conflict-of-law provisions).
+
+Any litigation relating to this License shall be subject to the
+jurisdiction of the Federal Courts of the Northern District of
+California and the state courts of the State of California, with
+venue lying in Santa Clara County, California.
diff --git a/Makefile.am b/Makefile.am
new file mode 100755 (executable)
index 0000000..8078eca
--- /dev/null
@@ -0,0 +1,49 @@
+## Makefile.am -- Process this file with automake to produce Makefile.in
+## Copyright (C) 2002 James Su
+##
+## This program is free software; you can redistribute it and/or modify
+## it under the terms of the GNU General Public License as published by
+## the Free Software Foundation; either version 2, or (at your option)
+## any later version.
+##
+## This program is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+## GNU General Public License for more details.
+##
+## You should have received a copy of the GNU General Public License
+## along with this program; if not, write to the Free Software
+## Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+AUX_DIST = $(ac_aux_dir)/config.guess \
+               $(ac_aux_dir)/config.sub \
+               $(ac_aux_dir)/install-sh \
+               $(ac_aux_dir)/ltconfig \
+               $(ac_aux_dir)/ltmain.sh \
+               $(ac_aux_dir)/missing \
+               $(ac_aux_dir)/depcomp
+
+EXTRA_DIST = ChangeLog \
+       README  \
+       config.rpath    \
+       bootstrap
+
+
+AUTOMAKE_OPTIONS       = gnu
+
+SUBDIRS                = po m4 src wrapper/scim raw
+
+MAINTAINERCLEANFILES   = Makefile.in aclocal.m4 configure config.h.in $(AUX_DIST)
+
+CLEANFILES             = *.bak src/*.bak
+
+## docdir                      = $(top_builddir)/doc
+pkgconfigdir            = $(libdir)/pkgconfig
+pkgconfig_DATA          = sunpinyin-2.0.pc
+ACLOCAL                        = aclocal -I m4
+ACLOCAL_AMFLAGS = -I m4
+
+.PHONY: ChangeLog
+
+ChangeLog:
+       svn2cl --include-rev --authors=$(top_srcdir)/developers -f $(top_srcdir)/$@
diff --git a/NEWS b/NEWS
new file mode 100644 (file)
index 0000000..ca27c0e
--- /dev/null
+++ b/NEWS
@@ -0,0 +1,47 @@
+Release 2.0.3
+=============
+
+2.0.3 release is containing a lot of major fix compare to last release.  User should update to this release as soon as possible.  It fixed many inconveniet bugs.  Changes compare to 2.0.2 are described below:
+
+Build
+-----
+
+* CFLAGS, CXXFLAGS and LDFLAGS are recongnized.
+* Scons scripts now will remember the configuration arguments in configure.conf.
+* Ported to ARMEL architecture.
+* Able to build on FreeBSD.
+
+libsunpinyin
+------------
+
+* New LOGO!
+* History cache focus more on recent commits.
+* Supports --libdir and --libdatadir as configuration arguments.
+* Hunpin support. (Contributed by Hanjie Xu)
+* Fixed weird behavior of history with a single character.
+* Fixed a potential issue for candidate ranking.
+
+ibus-sunpinyin
+--------------
+
+* Supports --libdir, --datadir, --execdir as configuration arguments.
+* Alt+num key as the candidate delete key for ibus-sunpinyin.
+* Able to build on IBus-1.4
+
+xsunpinyin
+----------
+
+* Synchronized the version between xsunpinyin and libsunpinyin project.
+* Fixed startup crash with empty directory.
+* Fixed position problem on multi-screen.
+* Fixed crash on exit, which caused history information lost.
+* Refact UI system
+* Added skin support
+* Fixed text overbound when pinyin are too long.
+* Fixed ignorance of ShuangPin setting.
+* Fixed weird behavior of fast switch to english. (Issue 213).
+
+scim-sunpinyin
+--------------
+
+* Add legacy support for scim (Thanks to liangguo)
diff --git a/OPENSOLARIS.LICENSE b/OPENSOLARIS.LICENSE
new file mode 100644 (file)
index 0000000..d838932
--- /dev/null
@@ -0,0 +1,377 @@
+COMMON DEVELOPMENT AND DISTRIBUTION LICENSE Version 1.0
+
+1. Definitions.
+
+    1.1. "Contributor" means each individual or entity that creates
+         or contributes to the creation of Modifications.
+
+    1.2. "Contributor Version" means the combination of the Original
+         Software, prior Modifications used by a Contributor (if any),
+         and the Modifications made by that particular Contributor.
+
+    1.3. "Covered Software" means (a) the Original Software, or (b)
+         Modifications, or (c) the combination of files containing
+         Original Software with files containing Modifications, in
+         each case including portions thereof.
+
+    1.4. "Executable" means the Covered Software in any form other
+         than Source Code.
+
+    1.5. "Initial Developer" means the individual or entity that first
+         makes Original Software available under this License.
+
+    1.6. "Larger Work" means a work which combines Covered Software or
+         portions thereof with code not governed by the terms of this
+         License.
+
+    1.7. "License" means this document.
+
+    1.8. "Licensable" means having the right to grant, to the maximum
+         extent possible, whether at the time of the initial grant or
+         subsequently acquired, any and all of the rights conveyed
+         herein.
+
+    1.9. "Modifications" means the Source Code and Executable form of
+         any of the following:
+
+        A. Any file that results from an addition to, deletion from or
+           modification of the contents of a file containing Original
+           Software or previous Modifications;
+
+        B. Any new file that contains any part of the Original
+           Software or previous Modifications; or
+
+        C. Any new file that is contributed or otherwise made
+           available under the terms of this License.
+
+    1.10. "Original Software" means the Source Code and Executable
+          form of computer software code that is originally released
+          under this License.
+
+    1.11. "Patent Claims" means any patent claim(s), now owned or
+          hereafter acquired, including without limitation, method,
+          process, and apparatus claims, in any patent Licensable by
+          grantor.
+
+    1.12. "Source Code" means (a) the common form of computer software
+          code in which modifications are made and (b) associated
+          documentation included in or with such code.
+
+    1.13. "You" (or "Your") means an individual or a legal entity
+          exercising rights under, and complying with all of the terms
+          of, this License.  For legal entities, "You" includes any
+          entity which controls, is controlled by, or is under common
+          control with You.  For purposes of this definition,
+          "control" means (a) the power, direct or indirect, to cause
+          the direction or management of such entity, whether by
+          contract or otherwise, or (b) ownership of more than fifty
+          percent (50%) of the outstanding shares or beneficial
+          ownership of such entity.
+
+2. License Grants.
+
+    2.1. The Initial Developer Grant.
+
+    Conditioned upon Your compliance with Section 3.1 below and
+    subject to third party intellectual property claims, the Initial
+    Developer hereby grants You a world-wide, royalty-free,
+    non-exclusive license:
+
+        (a) under intellectual property rights (other than patent or
+            trademark) Licensable by Initial Developer, to use,
+            reproduce, modify, display, perform, sublicense and
+            distribute the Original Software (or portions thereof),
+            with or without Modifications, and/or as part of a Larger
+            Work; and
+
+        (b) under Patent Claims infringed by the making, using or
+            selling of Original Software, to make, have made, use,
+            practice, sell, and offer for sale, and/or otherwise
+            dispose of the Original Software (or portions thereof).
+
+        (c) The licenses granted in Sections 2.1(a) and (b) are
+            effective on the date Initial Developer first distributes
+            or otherwise makes the Original Software available to a
+            third party under the terms of this License.
+
+        (d) Notwithstanding Section 2.1(b) above, no patent license is
+            granted: (1) for code that You delete from the Original
+            Software, or (2) for infringements caused by: (i) the
+            modification of the Original Software, or (ii) the
+            combination of the Original Software with other software
+            or devices.
+
+    2.2. Contributor Grant.
+
+    Conditioned upon Your compliance with Section 3.1 below and
+    subject to third party intellectual property claims, each
+    Contributor hereby grants You a world-wide, royalty-free,
+    non-exclusive license:
+
+        (a) under intellectual property rights (other than patent or
+            trademark) Licensable by Contributor to use, reproduce,
+            modify, display, perform, sublicense and distribute the
+            Modifications created by such Contributor (or portions
+            thereof), either on an unmodified basis, with other
+            Modifications, as Covered Software and/or as part of a
+            Larger Work; and
+
+        (b) under Patent Claims infringed by the making, using, or
+            selling of Modifications made by that Contributor either
+            alone and/or in combination with its Contributor Version
+            (or portions of such combination), to make, use, sell,
+            offer for sale, have made, and/or otherwise dispose of:
+            (1) Modifications made by that Contributor (or portions
+            thereof); and (2) the combination of Modifications made by
+            that Contributor with its Contributor Version (or portions
+            of such combination).
+
+        (c) The licenses granted in Sections 2.2(a) and 2.2(b) are
+            effective on the date Contributor first distributes or
+            otherwise makes the Modifications available to a third
+            party.
+
+        (d) Notwithstanding Section 2.2(b) above, no patent license is
+            granted: (1) for any code that Contributor has deleted
+            from the Contributor Version; (2) for infringements caused
+            by: (i) third party modifications of Contributor Version,
+            or (ii) the combination of Modifications made by that
+            Contributor with other software (except as part of the
+            Contributor Version) or other devices; or (3) under Patent
+            Claims infringed by Covered Software in the absence of
+            Modifications made by that Contributor.
+
+3. Distribution Obligations.
+
+    3.1. Availability of Source Code.
+
+    Any Covered Software that You distribute or otherwise make
+    available in Executable form must also be made available in Source
+    Code form and that Source Code form must be distributed only under
+    the terms of this License.  You must include a copy of this
+    License with every copy of the Source Code form of the Covered
+    Software You distribute or otherwise make available.  You must
+    inform recipients of any such Covered Software in Executable form
+    as to how they can obtain such Covered Software in Source Code
+    form in a reasonable manner on or through a medium customarily
+    used for software exchange.
+
+    3.2. Modifications.
+
+    The Modifications that You create or to which You contribute are
+    governed by the terms of this License.  You represent that You
+    believe Your Modifications are Your original creation(s) and/or
+    You have sufficient rights to grant the rights conveyed by this
+    License.
+
+    3.3. Required Notices.
+
+    You must include a notice in each of Your Modifications that
+    identifies You as the Contributor of the Modification.  You may
+    not remove or alter any copyright, patent or trademark notices
+    contained within the Covered Software, or any notices of licensing
+    or any descriptive text giving attribution to any Contributor or
+    the Initial Developer.
+
+    3.4. Application of Additional Terms.
+
+    You may not offer or impose any terms on any Covered Software in
+    Source Code form that alters or restricts the applicable version
+    of this License or the recipients' rights hereunder.  You may
+    choose to offer, and to charge a fee for, warranty, support,
+    indemnity or liability obligations to one or more recipients of
+    Covered Software.  However, you may do so only on Your own behalf,
+    and not on behalf of the Initial Developer or any Contributor.
+    You must make it absolutely clear that any such warranty, support,
+    indemnity or liability obligation is offered by You alone, and You
+    hereby agree to indemnify the Initial Developer and every
+    Contributor for any liability incurred by the Initial Developer or
+    such Contributor as a result of warranty, support, indemnity or
+    liability terms You offer.
+
+    3.5. Distribution of Executable Versions.
+
+    You may distribute the Executable form of the Covered Software
+    under the terms of this License or under the terms of a license of
+    Your choice, which may contain terms different from this License,
+    provided that You are in compliance with the terms of this License
+    and that the license for the Executable form does not attempt to
+    limit or alter the recipient's rights in the Source Code form from
+    the rights set forth in this License.  If You distribute the
+    Covered Software in Executable form under a different license, You
+    must make it absolutely clear that any terms which differ from
+    this License are offered by You alone, not by the Initial
+    Developer or Contributor.  You hereby agree to indemnify the
+    Initial Developer and every Contributor for any liability incurred
+    by the Initial Developer or such Contributor as a result of any
+    such terms You offer.
+
+    3.6. Larger Works.
+
+    You may create a Larger Work by combining Covered Software with
+    other code not governed by the terms of this License and
+    distribute the Larger Work as a single product.  In such a case,
+    You must make sure the requirements of this License are fulfilled
+    for the Covered Software.
+
+4. Versions of the License.
+
+    4.1. New Versions.
+
+    Sun Microsystems, Inc. is the initial license steward and may
+    publish revised and/or new versions of this License from time to
+    time.  Each version will be given a distinguishing version number.
+    Except as provided in Section 4.3, no one other than the license
+    steward has the right to modify this License.
+
+    4.2. Effect of New Versions.
+
+    You may always continue to use, distribute or otherwise make the
+    Covered Software available under the terms of the version of the
+    License under which You originally received the Covered Software.
+    If the Initial Developer includes a notice in the Original
+    Software prohibiting it from being distributed or otherwise made
+    available under any subsequent version of the License, You must
+    distribute and make the Covered Software available under the terms
+    of the version of the License under which You originally received
+    the Covered Software.  Otherwise, You may also choose to use,
+    distribute or otherwise make the Covered Software available under
+    the terms of any subsequent version of the License published by
+    the license steward.
+
+    4.3. Modified Versions.
+
+    When You are an Initial Developer and You want to create a new
+    license for Your Original Software, You may create and use a
+    modified version of this License if You: (a) rename the license
+    and remove any references to the name of the license steward
+    (except to note that the license differs from this License); and
+    (b) otherwise make it clear that the license contains terms which
+    differ from this License.
+
+5. DISCLAIMER OF WARRANTY.
+
+    COVERED SOFTWARE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS"
+    BASIS, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED,
+    INCLUDING, WITHOUT LIMITATION, WARRANTIES THAT THE COVERED
+    SOFTWARE IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR
+    PURPOSE OR NON-INFRINGING.  THE ENTIRE RISK AS TO THE QUALITY AND
+    PERFORMANCE OF THE COVERED SOFTWARE IS WITH YOU.  SHOULD ANY
+    COVERED SOFTWARE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT THE
+    INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE COST OF ANY
+    NECESSARY SERVICING, REPAIR OR CORRECTION.  THIS DISCLAIMER OF
+    WARRANTY CONSTITUTES AN ESSENTIAL PART OF THIS LICENSE.  NO USE OF
+    ANY COVERED SOFTWARE IS AUTHORIZED HEREUNDER EXCEPT UNDER THIS
+    DISCLAIMER.
+
+6. TERMINATION.
+
+    6.1. This License and the rights granted hereunder will terminate
+    automatically if You fail to comply with terms herein and fail to
+    cure such breach within 30 days of becoming aware of the breach.
+    Provisions which, by their nature, must remain in effect beyond
+    the termination of this License shall survive.
+
+    6.2. If You assert a patent infringement claim (excluding
+    declaratory judgment actions) against Initial Developer or a
+    Contributor (the Initial Developer or Contributor against whom You
+    assert such claim is referred to as "Participant") alleging that
+    the Participant Software (meaning the Contributor Version where
+    the Participant is a Contributor or the Original Software where
+    the Participant is the Initial Developer) directly or indirectly
+    infringes any patent, then any and all rights granted directly or
+    indirectly to You by such Participant, the Initial Developer (if
+    the Initial Developer is not the Participant) and all Contributors
+    under Sections 2.1 and/or 2.2 of this License shall, upon 60 days
+    notice from Participant terminate prospectively and automatically
+    at the expiration of such 60 day notice period, unless if within
+    such 60 day period You withdraw Your claim with respect to the
+    Participant Software against such Participant either unilaterally
+    or pursuant to a written agreement with Participant.
+
+    6.3. In the event of termination under Sections 6.1 or 6.2 above,
+    all end user licenses that have been validly granted by You or any
+    distributor hereunder prior to termination (excluding licenses
+    granted to You by any distributor) shall survive termination.
+
+7. LIMITATION OF LIABILITY.
+
+    UNDER NO CIRCUMSTANCES AND UNDER NO LEGAL THEORY, WHETHER TORT
+    (INCLUDING NEGLIGENCE), CONTRACT, OR OTHERWISE, SHALL YOU, THE
+    INITIAL DEVELOPER, ANY OTHER CONTRIBUTOR, OR ANY DISTRIBUTOR OF
+    COVERED SOFTWARE, OR ANY SUPPLIER OF ANY OF SUCH PARTIES, BE
+    LIABLE TO ANY PERSON FOR ANY INDIRECT, SPECIAL, INCIDENTAL, OR
+    CONSEQUENTIAL DAMAGES OF ANY CHARACTER INCLUDING, WITHOUT
+    LIMITATION, DAMAGES FOR LOST PROFITS, LOSS OF GOODWILL, WORK
+    STOPPAGE, COMPUTER FAILURE OR MALFUNCTION, OR ANY AND ALL OTHER
+    COMMERCIAL DAMAGES OR LOSSES, EVEN IF SUCH PARTY SHALL HAVE BEEN
+    INFORMED OF THE POSSIBILITY OF SUCH DAMAGES.  THIS LIMITATION OF
+    LIABILITY SHALL NOT APPLY TO LIABILITY FOR DEATH OR PERSONAL
+    INJURY RESULTING FROM SUCH PARTY'S NEGLIGENCE TO THE EXTENT
+    APPLICABLE LAW PROHIBITS SUCH LIMITATION.  SOME JURISDICTIONS DO
+    NOT ALLOW THE EXCLUSION OR LIMITATION OF INCIDENTAL OR
+    CONSEQUENTIAL DAMAGES, SO THIS EXCLUSION AND LIMITATION MAY NOT
+    APPLY TO YOU.
+
+8. U.S. GOVERNMENT END USERS.
+
+    The Covered Software is a "commercial item," as that term is
+    defined in 48 C.F.R. 2.101 (Oct. 1995), consisting of "commercial
+    computer software" (as that term is defined at 48
+    C.F.R. 252.227-7014(a)(1)) and "commercial computer software
+    documentation" as such terms are used in 48 C.F.R. 12.212
+    (Sept. 1995).  Consistent with 48 C.F.R. 12.212 and 48
+    C.F.R. 227.7202-1 through 227.7202-4 (June 1995), all
+    U.S. Government End Users acquire Covered Software with only those
+    rights set forth herein.  This U.S. Government Rights clause is in
+    lieu of, and supersedes, any other FAR, DFAR, or other clause or
+    provision that addresses Government rights in computer software
+    under this License.
+
+9. MISCELLANEOUS.
+
+    This License represents the complete agreement concerning subject
+    matter hereof.  If any provision of this License is held to be
+    unenforceable, such provision shall be reformed only to the extent
+    necessary to make it enforceable.  This License shall be governed
+    by the law of the jurisdiction specified in a notice contained
+    within the Original Software (except to the extent applicable law,
+    if any, provides otherwise), excluding such jurisdiction's
+    conflict-of-law provisions.  Any litigation relating to this
+    License shall be subject to the jurisdiction of the courts located
+    in the jurisdiction and venue specified in a notice contained
+    within the Original Software, with the losing party responsible
+    for costs, including, without limitation, court costs and
+    reasonable attorneys' fees and expenses.  The application of the
+    United Nations Convention on Contracts for the International Sale
+    of Goods is expressly excluded.  Any law or regulation which
+    provides that the language of a contract shall be construed
+    against the drafter shall not apply to this License.  You agree
+    that You alone are responsible for compliance with the United
+    States export administration regulations (and the export control
+    laws and regulation of any other countries) when You use,
+    distribute or otherwise make available any Covered Software.
+
+10. RESPONSIBILITY FOR CLAIMS.
+
+    As between Initial Developer and the Contributors, each party is
+    responsible for claims and damages arising, directly or
+    indirectly, out of its utilization of rights under this License
+    and You agree to work with Initial Developer and Contributors to
+    distribute such responsibility on an equitable basis.  Nothing
+    herein is intended or shall be deemed to constitute any admission
+    of liability.
+
+--------------------------------------------------------------------
+
+NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND
+DISTRIBUTION LICENSE (CDDL)
+
+For Covered Software in this distribution, this License shall
+be governed by the laws of the State of California (excluding
+conflict-of-law provisions).
+
+Any litigation relating to this License shall be subject to the
+jurisdiction of the Federal Courts of the Northern District of
+California and the state courts of the State of California, with
+venue lying in Santa Clara County, California.
diff --git a/README b/README
new file mode 100644 (file)
index 0000000..7d80d37
--- /dev/null
+++ b/README
@@ -0,0 +1,9 @@
+SunPinyin
+===
+
+SunPinyin is an SLM (Statistical Language Model) based input method
+engine. To model the Chinese language, it use a backoff bigram and
+trigram language model. 
+
+Currently, SunPinyin 2.0 is available on IBus, SCIM, and as a 
+standalone XIM Server.
diff --git a/SConstruct b/SConstruct
new file mode 100755 (executable)
index 0000000..3163338
--- /dev/null
@@ -0,0 +1,439 @@
+import platform
+import os
+import sys
+
+version="2.0.4"
+abi_major = 3
+abi_minor = 0
+
+cflags = '-g -Wall'
+
+slmsource = [
+    #'src/slm/ids2ngram/ids2ngram.cpp',
+    #'src/slm/ids2ngram/idngram_merge.cpp',
+    #'src/slm/mmseg/mmseg.cpp',
+    #'src/slm/tslminfo/tslminfo.cpp',
+    #'src/slm/tslmpack/arpa_slm.cpp',
+    #'src/slm/tslmpack/arpa_conv.cpp',
+    #'src/slm/tslmpack/slmpack.cpp',
+    'src/slm/slm.cpp',
+    #'src/slm/slminfo/slminfo.cpp',
+    #'src/slm/sim_sen.cpp',
+    #'src/slm/sim_slm.cpp',
+    #'src/slm/getWordFreq/getWordFreq.cpp',
+    #'src/slm/slmseg/slmseg.cpp',
+    #'src/slm/thread/slmthread.cpp',
+    #'src/slm/thread/test_vc.cpp',
+    #'src/slm/thread/ValueCompress.cpp',
+    #'src/slm/slmbuild/slmbuild.cpp',
+    #'src/slm/slmprune/slmprune.cpp',
+    #'src/slm/sim_slmbuilder.cpp',
+    #'src/slm/tslmendian/slm_endian.cpp',
+    #'src/slm/tslmendian/writer.cpp',
+    #'src/slm/tslmendian/slm_file.cpp',
+    #'src/slm/sim_dict.cpp',
+    'src/portability.cpp',
+    'src/lexicon/trie_writer.cpp',
+    'src/lexicon/genPYT.cpp',
+    'src/lexicon/pytrie_gen.cpp',
+    'src/lexicon/pytrie.cpp',
+    'src/pinyin/pinyin_data.cpp',
+    ]
+
+imesource = [
+    'src/portability.cpp',
+    'src/slm/slm.cpp',
+    'src/lexicon/pytrie.cpp',
+    'src/pinyin/pinyin_data.cpp',
+    'src/pinyin/pinyin_seg.cpp',
+    'src/pinyin/shuangpin_data.cpp',
+    'src/pinyin/shuangpin_seg.cpp',
+    'src/pinyin/hunpin_seg.cpp',
+    'src/ime-core/imi_context.cpp',
+    'src/ime-core/imi_data.cpp',
+    'src/ime-core/lattice_states.cpp',
+    'src/ime-core/imi_view.cpp',
+    'src/ime-core/imi_uiobjects.cpp',
+    'src/ime-core/imi_view_classic.cpp',
+    'src/ime-core/imi_winHandler.cpp',
+    'src/ime-core/ic_history.cpp',
+    'src/ime-core/imi_funcobjs.cpp',
+    'src/ime-core/imi_options.cpp',
+    'src/ime-core/imi_option_event.cpp',
+    'src/ime-core/userdict.cpp',
+    ]
+
+headers = [
+    #'src/slm/ids2ngram/idngram.h',
+    #'src/slm/ids2ngram/idngram_merge.h',
+    'src/slm/slm.h',
+    #'src/slm/tslmpack/arpa_slm.h',
+    #'src/slm/tslmpack/common.h',
+    #'src/slm/tslmpack/arpa_conv.h',
+    #'src/slm/sim_dict.h',
+    #'src/slm/sim_sen.h',
+    #'src/slm/sim_slm.h',
+    #'src/slm/thread/ValueCompress.h',
+    #'src/slm/sim_fmerge.h',
+    #'src/slm/sim_slmbuilder.h',
+    #'src/slm/tslmendian/slm_file.h',
+    #'src/slm/tslmendian/writer.h',
+    'src/lexicon/pytrie_gen.h',
+    'src/lexicon/trie_writer.h',
+    'src/lexicon/pytrie.h',
+    'src/ime-core/imi_view_classic.h',
+    'src/ime-core/imi_uiobjects.h',
+    'src/ime-core/lattice_states.h',
+    'src/ime-core/ic_history.h',
+    'src/ime-core/imi_funcobjs.h',
+    'src/ime-core/imi_context.h',
+    'src/ime-core/imi_winHandler.h',
+    'src/ime-core/imi_glibHandler.h',
+    'src/ime-core/userdict.h',
+    'src/ime-core/imi_option_event.h',
+    'src/ime-core/imi_data.h',
+    'src/ime-core/utils.h',
+    'src/ime-core/imi_keys.h',
+    'src/ime-core/imi_option_keys.h',
+    'src/ime-core/imi_options.h',
+    'src/ime-core/imi_defines.h',
+    'src/ime-core/imi_view.h',
+    'src/portability.h',
+    'src/pinyin/segmentor.h',
+    'src/pinyin/shuangpin_seg.h',
+    'src/pinyin/datrie.h',
+    'src/pinyin/quanpin_trie.h',
+    'src/pinyin/pinyin_seg.h',
+    'src/pinyin/pinyin_data.h',
+    'src/pinyin/syllable.h',
+    'src/pinyin/shuangpin_data.h',
+    'src/pinyin/hunpin_seg.h',
+    'src/pinyin/datrie_impl.h',
+    'src/sunpinyin.h',
+    ]
+
+# source of plugin module, it's off by default
+# and this module depends on Python
+imesource_plugin = [
+    'src/ime-core/imi_plugin.cpp',
+    ]
+
+headers_plugin = [
+    'src/ime-core/imi_plugin.h',
+    ]
+
+# options
+AddOption('--prefix', dest='prefix', metavar='DIR',
+          help='installation prefix')
+
+AddOption('--libdir', dest='libdir', metavar='DIR',
+          help='installation libdir')
+
+AddOption('--libdatadir', dest='libdatadir', metavar='DIR',
+          help='installation libdata dir')
+
+AddOption('--rpath', dest='rpath', metavar='DIR',
+          help='encode rpath in the executables')
+
+AddOption('--enable-plugins', dest='enable_plugins', action='store_true',
+          default=False, help='enable plugin mechanism at libsunpinyin layer')
+
+AddOption('--disable-plugins', dest='enable_plugins', action='store_false',
+          default=False, help='disable plugin mechanism at libsunpinyin layer')
+
+# save the options
+opts = Variables('configure.conf')
+opts.Add('PREFIX', default='/usr/local')
+opts.Add('LIBDIR', default='/usr/local/lib')
+opts.Add('LIBDATADIR', default='/usr/local/lib')
+opts.Add('ENABLE_PLUGINS', default=False)
+
+#
+#==============================environment==============================
+#
+#
+def allinc():
+    inc=[]
+    for root, dirs, files in os.walk('src'):
+        inc.append(root)
+    return inc
+
+def GetOS():
+    return platform.uname()[0]
+
+def CreateEnvironment():
+    tar = 'tar'
+    make = 'make'
+    wget = 'wget'
+    if GetOS() == 'Darwin':
+        wget = 'curl -O'
+    elif GetOS() == 'FreeBSD':
+        wget = 'fetch'
+        make = 'gmake'
+    elif GetOS() == 'SunOS':
+        tar = 'gtar'
+        make = 'gmake'
+
+    libln_builder = Builder(action='ln -s ${SOURCE.name} ${TARGET.name}',
+                            chdir=True)
+    env = Environment(ENV=os.environ, CFLAGS=cflags, CXXFLAGS=cflags,
+                      TAR=tar, MAKE=make, WGET=wget,
+                      CPPPATH=['.'] + allinc(),
+                      tools=['default', 'textfile'])
+    env.Append(BUILDERS={'InstallAsSymlink': libln_builder})
+    return env
+
+def PassVariables(envvar, env):
+    for (x, y) in envvar:
+        if x in os.environ:
+            print 'Warning: you\'ve set %s in the environmental variable!' % x
+            env[y] = os.environ[x]
+
+env = CreateEnvironment()
+opts.Update(env)
+
+if GetOption('prefix') is not None:
+    env['PREFIX'] = GetOption('prefix')
+    env['LIBDATADIR'] = os.path.join(env['PREFIX'], 'lib')
+    env['LIBDIR'] = os.path.join(env['PREFIX'], 'lib')
+
+if GetOption('libdir') is not None:
+    env['LIBDIR'] = GetOption('libdir')
+
+if GetOption('libdatadir') is not None:
+    env['LIBDATADIR'] = GetOption('libdatadir')
+
+env['ENABLE_PLUGINS'] = GetOption('enable_plugins')
+
+opts.Save('configure.conf', env)
+
+libdir = env['LIBDIR']
+libdatadir = os.path.join(env['LIBDATADIR'], 'sunpinyin/data')
+headersdir = os.path.join(env['PREFIX'], 'include/sunpinyin-2.0')
+
+# pass through environmental variables
+envvar = [('CC', 'CC'),
+          ('CXX', 'CXX'),
+          ('CFLAGS', 'CFLAGS'),
+          ('CXXFLAGS', 'CXXFLAGS'),
+          ('LDFLAGS', 'LINKFLAGS'),
+          ('TAR', 'TAR'),
+          ('MAKE', 'MAKE'),
+          ('WGET', 'WGET')]
+PassVariables(envvar, env)
+
+# append the source and headers
+if env['ENABLE_PLUGINS']:
+    imesource += imesource_plugin
+    headers += headers_plugin
+
+# merge some of critical compile flags
+env.MergeFlags(['-pipe -DHAVE_CONFIG_H',
+                '-DSUNPINYIN_DATA_DIR=\\\'\\"%s\\"\\\'' % libdatadir])
+
+if GetOption('rpath') is not None and GetOS() != 'Darwin':
+    env.MergeFlags('-Wl,-R -Wl,%s' % GetOption('rpath'))
+
+#
+#==============================configure================================
+#
+def CheckPKGConfig(context, version='0.12.0'):
+    context.Message('Checking for pkg-config... ')
+    ret = context.TryAction('pkg-config --atleast-pkgconfig-version=%s' % version)[0]
+    context.Result(ret)
+    return ret
+
+def CheckPKG(context, name):
+    context.Message('Checking for %s... ' % name)
+    ret = context.TryAction('pkg-config --exists \'%s\'' % name)[0]
+    context.Result(ret)
+    return ret
+
+def CheckPython(context):
+    context.Message('Checking for Python library...')
+    ret = context.TryAction('python-config --prefix')[0]
+    context.Result(ret)
+    if ret:
+        context.env.MergeFlags(['!python-config --includes',
+                                '!python-config --libs'])
+    return ret
+
+def AppendEndianCheck(conf):
+    conf.config_h_text += r'''
+
+#if defined(_BIG_ENDIAN) && !defined(_LITTLE_ENDIAN)
+# define WORDS_BIGENDIAN 1
+
+#elif defined(_LITTLE_ENDIAN) && !defined(_BIG_ENDIAN)
+# undef WORDS_BIGENDIAN
+
+#elif defined(__sparc) || defined(__sparc__) \
+  || defined(_POWER)   || defined(__powerpc__) \
+  || defined(__ppc__)  || defined(__hpux) || defined(__hppa) \
+  || defined(_MIPSEB)  || defined(_POWER) \
+  || defined(__s390__) || (defined(__sh__) && defined(__BIG_ENDIAN__))
+# define WORDS_BIGENDIAN 1
+
+#elif defined(__i386__) || defined(__i386) \
+  || defined(__ia64)    || defined(__ia64__) \
+  || defined(_M_IX86)   || defined(_M_IA64) \
+  || defined(_M_ALPHA)  || defined(__amd64) \
+  || defined(__amd64__) || defined(_M_AMD64) \
+  || defined(__x86_64)  || defined(__x86_64__) \
+  || defined(_M_X64)    || defined(__bfin__) \
+  || defined(__alpha__) || defined(__ARMEL__) \
+  || defined(_MIPSEL)   || (defined(__sh__) && defined(__LITTLE_ENDIAN__))
+# undef WORDS_BIGENDIAN
+
+#else
+# error can not detect the endianness!
+#endif
+'''
+
+conf = env.Configure(clean=False, help=False, config_h='config.h',
+                     custom_tests={'CheckPKGConfig' : CheckPKGConfig,
+                                   'CheckPKG' : CheckPKG,
+                                   'CheckPython': CheckPython})
+
+def DoConfigure():
+    if GetOS() == 'Darwin':
+        if not conf.CheckLibWithHeader('sqlite3', 'sqlite3.h', 'C'):
+            Exit(1)
+        if not conf.CheckLibWithHeader('iconv', 'iconv.h', 'C'):
+            Exit(1)
+    else:
+        if not conf.CheckPKGConfig():
+            Exit(1)
+        if not conf.CheckPKG('sqlite3'):
+            Exit(1)
+
+    if conf.env['ENABLE_PLUGINS']:
+        if not conf.CheckPython():
+            Exit(1)
+        conf.Define('ENABLE_PLUGINS')
+
+    conf.Define('ENABLE_NLS', 1)
+    conf.Define('GETTEXT_PACKAGE', '"sunpinyin2"')
+    conf.CheckCHeader('assert.h')
+    conf.CheckFunc('bind_textdomain_codeset')
+    conf.CheckFunc('dcgettext')
+    conf.CheckCHeader('dlfcn.h')
+    conf.CheckFunc('exp2')
+    conf.CheckCHeader('fcntl.h')
+    conf.CheckCHeader('getopt.h')
+    conf.CheckFunc('getopt_long')
+    conf.CheckFunc('getpagesize')
+    conf.CheckFunc('get_opt')
+    conf.CheckCHeader('iconv.h')
+    conf.CheckCHeader('inttypes.h')
+    conf.CheckCHeader('locale.h')
+    conf.CheckCHeader('libintl.h')
+    conf.CheckCHeader('limits.h')
+    conf.CheckCHeader('locale.h')
+    conf.CheckFunc('log2')
+    conf.CheckCHeader('memory.h')
+    conf.CheckFunc('memset')
+    conf.CheckFunc('mmap')
+    conf.CheckFunc('munmap')
+    conf.CheckFunc('setlocale')
+    conf.CheckFunc('strndup')
+    conf.CheckCHeader('sys/mman.h')
+    conf.CheckCHeader('sys/param.h')
+    conf.CheckCHeader('sys/stat.h')
+    conf.CheckCHeader('sys/types.h')
+    conf.CheckCHeader('unistd.h')
+    conf.CheckCHeader('wchar.h')
+
+    # add essential package requirements
+    conf.Define('PACKAGE', '"sunpinyin"')
+    conf.Define('PACKAGE_NAME', '"sunpinyin"')
+    conf.Define('PACKAGE_STRING', '"sunpinyin 2.0"')
+    conf.Define('PACKAGE_TARNAME', '"sunpinyin"')
+    conf.Define('PACKAGE_VERSION', '"2.0"')
+    conf.Define('VRESION', '"2.0"')
+
+    # append endianness checking defines
+    AppendEndianCheck(conf)
+    env = conf.Finish()
+    # generate sunpinyin.pc
+    env.Substfile('sunpinyin-2.0.pc.in', SUBST_DICT={
+            '@PREFIX@': env['PREFIX'],
+            '@LIBDIR@': env['LIBDIR'],
+            '@VERSION@': version,
+            '@CFLAGS@': reduce(lambda a, b: a + ' ' + b,
+                               map(lambda x: '-I$${includedir}' + x[3:],
+                                   allinc())),
+            })
+
+    if GetOS() != 'Darwin':
+        env.ParseConfig('pkg-config sqlite3 --libs --cflags')
+
+if not GetOption('clean') and not GetOption('help'):
+    DoConfigure()
+
+#
+#==============================compile==============================
+#
+#env.Command('src/pinyin/quanpin_trie.h', 'python/pinyin_data.py',
+#            './pinyin_data.py > /dev/null', chdir = 'python')
+#env.Object(slmsource)
+
+#SConscript(['build/SConscript'], exports='env')
+
+libname_default = '%ssunpinyin%s' % (env.subst('${SHLIBPREFIX}'),
+                                     env.subst('${SHLIBSUFFIX}'))
+libname_link = libname_default
+libname_soname = '%s.%d' % (libname_link, abi_major)
+libname = '%s.%d' % (libname_soname, abi_minor)
+lib = None
+
+if GetOS() != 'Darwin':
+    lib = env.SharedLibrary(libname, SHLIBSUFFIX='', source=imesource,
+                            parse_flags='-Wl,-soname=%s' % libname_soname)
+else:
+    # TODO: add install_name on Darwin?
+    lib = env.SharedLibrary('sunpinyin', source=imesource)
+
+#env.Command('rawlm', 'build/tslmpack',
+#            '$MAKE -C raw WGET="$WGET" TAR="$TAR"')
+
+#env.Command('lm', 'rawlm',
+#            '$MAKE -C data WGET="$WGET" TAR="$TAR"')
+
+if GetOption('clean'):
+    os.environ['TAR'] = env['TAR']
+    os.environ['MAKE'] = env['MAKE']
+    os.system('$MAKE -C raw clean WGET="$WGET" TAR="$TAR"')
+    os.system('$MAKE -C data clean WGET="$WGET" TAR="$TAR"')
+
+def DoInstall():
+    lib_target = None
+    if GetOS() == 'Darwin':
+        lib_target = env.Install(libdir, lib)
+    else:
+        lib_target_bin = env.Install(libdir, lib)
+        # where does it goes
+        install_path = os.path.dirname(str(lib_target_bin[0]))
+        lib_target = [
+            lib_target_bin,
+            env.InstallAsSymlink(os.path.join(install_path, libname_soname),
+                                 lib_target_bin),
+            env.InstallAsSymlink(os.path.join(install_path, libname_link),
+                                 lib_target_bin),
+            ]
+
+    lib_pkgconfig_target = env.Install(os.path.join(libdir, 'pkgconfig'),
+                                       ['sunpinyin-2.0.pc'])
+    libdata_target = env.Install(libdatadir,
+                                 ['data/lm_sc.t3g',
+                                  'data/pydict_sc.bin'])
+    header_targets = []
+    for header in headers:
+        header_targets.append(env.InstallAs(headersdir + header[3:], header))
+    env.Alias('install-headers', header_targets)
+    env.Alias('install-lib', lib_target + [lib_pkgconfig_target])
+    env.Alias('install-libdata', libdata_target)
+    env.Depends('install-libdata', 'install-lib')
+
+DoInstall()
+env.Alias('install', ['install-lib', 'install-libdata', 'install-headers'])
diff --git a/TODO b/TODO
new file mode 100644 (file)
index 0000000..f74efdf
--- /dev/null
+++ b/TODO
@@ -0,0 +1,21 @@
+Todo:
+
+    * make slm and sunpinyin-ime-core available as shared libraries
+    * add API and UI for user-defined words
+    * support Traditional Chinese, dict and corpus
+    * support fuzzy Pinyin and more Pinyin schemes, such as double-pinyin
+    * more configuration options, such as keybindings, number of candidates per page etc.
+    * improve the candidate selecting for user selections
+    * new language bindings for slm, such as Java, and Ruby
+    * leverage Sogou's dict and corpus
+
+In process:
+
+    * Python binding for SunPinyin's SLM [80%]
+
+Done:
+
+    * fix the multi-phonetic bug in pytrie
+    * porting to SCIM platform
+    * porting to Mac OS X
+
diff --git a/bootstrap b/bootstrap
new file mode 100755 (executable)
index 0000000..712fd35
--- /dev/null
+++ b/bootstrap
@@ -0,0 +1,9 @@
+#! /bin/sh
+
+set -x
+aclocal -I ./m4
+autoheader
+libtoolize -c --automake --force
+automake --add-missing --copy --include-deps
+autoconf
+## @end 1
diff --git a/build/Makefile b/build/Makefile
new file mode 100644 (file)
index 0000000..e9b9d0f
--- /dev/null
@@ -0,0 +1,133 @@
+SLM_SRC_DIR = ../src/slm
+LEXICON_SRC_DIR = ../src/lexicon
+PINYIN_SRC_DIR = ../src/pinyin
+
+CORPUS_DIR = ../raw
+SWAP_DIR = ../swap
+RESULT_DIR = ../data
+
+DICTFILE = ${CORPUS_DIR}/dict.utf8
+CORPUSFILE = ${CORPUS_DIR}/corpus.utf8
+TEST_CORPUSFILE = ${CORPUS_DIR}/test.utf8
+REAL_CORPUSFILE = ${CORPUS_DIR}/BIGCORPUS
+
+LMTARGET = lm_sc
+IDS_FILE = ${SWAP_DIR}/${LMTARGET}.ids
+SWAP_FILE = ${SWAP_DIR}/swap
+
+#FILE NAMES for BIGRAM model
+IDNGRAM_FILE = ${SWAP_DIR}/${LMTARGET}.id2gram
+RAW_LM_FILE = ${SWAP_DIR}/${LMTARGET}.2gram 
+SLM_FILE = ${SWAP_DIR}/${LMTARGET}.2gm 
+SLM_INFO_FILE = ${SWAP_DIR}/${LMTARGET}.2gm.arpa 
+TSLM_FILE = ${RESULT_DIR}/${LMTARGET}.t2g
+TSLM_INFO_FILE = ${SWAP_DIR}/${LMTARGET}.t2g.arpa
+
+#FILE NAMES for TRIGRAM model
+IDNGRAM_FILE3 = ${SWAP_DIR}/${LMTARGET}.id3gram
+RAW_LM_FILE3 = ${SWAP_DIR}/${LMTARGET}.3gram 
+SLM_FILE3 = ${SWAP_DIR}/${LMTARGET}.3gm 
+SLM_INFO_FILE3 = ${SWAP_DIR}/${LMTARGET}.3gm.arpa 
+TSLM_FILE3 = ${RESULT_DIR}/${LMTARGET}.t3g
+TSLM_INFO_FILE3 = ${SWAP_DIR}/${LMTARGET}.t3g.arpa
+TSLM_REPACKED_FILE3 = ${SWAP_DIR}/${LMTARGET}.t3g.repacked
+TSLM_UNPACKED_FILE3 = ${SWAP_DIR}/${LMTARGET}.t3g.arpa.unpacked
+
+#Lexicon FILE names (raw resource and others)
+PINYIN_TEXTFILE = ${CORPUS_DIR}/dict.utf8
+PINYIN_NMP_TEXTFILE = ${SWAP_DIR}/dict_nmp.utf8
+PYTRIE_FILE = ${RESULT_DIR}/pydict_sc.bin
+PYTRIE_PRINTOUT = ${SWAP_DIR}/pydict_sc.log.utf8
+
+test_corpus :
+       if [ -e ${CORPUSFILE} ]; then unlink ${CORPUSFILE}; fi
+       ln -s ${TEST_CORPUSFILE} ${CORPUSFILE}
+
+real_corpus :
+       if [ -e ${CORPUSFILE} ]; then unlink ${CORPUSFILE}; fi
+       ln -s ${REAL_CORPUSFILE} ${CORPUSFILE}
+
+ids :
+       ./mmseg -d ${DICTFILE} -f bin -s 10 -a 9 ${CORPUSFILE} >${IDS_FILE}
+
+slmids3:
+       ./slmseg -d ${DICTFILE} -f bin -s 10 -m ${TSLM_FILE3} ${CORPUSFILE} >${IDS_FILE}
+       cp ${TSLM_FILE3} ${TSLM_FILE3}.normal
+
+slmids:
+       ./slmseg -d ${DICTFILE} -f bin -s 10 -m ${TSLM_FILE} ${CORPUSFILE} >${IDS_FILE}
+       cp ${TSLM_FILE} ${TSLM_FILE}.normal
+
+#second round bootstrap bigram
+bs_bigram : slmids m2_idngram m2_slm m2_prune m2_thread m2_tslminfo
+
+#second round bootstrap bigram from a trigram model
+bs_bigram3 : slmids3 m2_idngram m2_slm m2_prune m2_thread m2_tslminfo
+
+#This is the command to make a bigram model
+bigram : ids m2_idngram m2_slm m2_prune m2_thread m2_tslminfo
+
+m2_idngram : 
+       ./ids2ngram -n 2 -s ${SWAP_FILE} -o ${IDNGRAM_FILE} -p 20000000 ${IDS_FILE}
+       rm -f ${SWAP_FILE}
+
+m2_slm:        
+       ./slmbuild -n 2 -o ${RAW_LM_FILE} -w 200000 -c 0,2 -d ABS,0.005 -d ABS -b 10 -e 9 ${IDNGRAM_FILE}
+
+m2_prune: 
+       ./slmprune ${RAW_LM_FILE} ${SLM_FILE} R 100000 200000
+
+m2_thread :
+       ./slmthread ${SLM_FILE} ${TSLM_FILE}
+
+m2_tslminfo :
+       ./tslminfo -v -l ${DICTFILE} ${TSLM_FILE} >${TSLM_INFO_FILE}
+
+#Use this to generate bigram non-threaded lm arpa information if needed
+m2_info :
+       ./slminfo -p -v -l ${DICTFILE} ${SLM_FILE} >${SLM_INFO_FILE}
+
+#second round bootstrap to make trigram model
+bs_trigram : slmids3 m3_idngram m3_slm m3_prune m3_thread m3_tslminfo
+
+#This is the command to make a trigram model
+trigram : ids m3_idngram m3_slm m3_prune m3_thread m3_tslminfo
+
+m3_idngram : 
+       ./ids2ngram -n 3 -s ${SWAP_FILE} -o ${IDNGRAM_FILE3} -p 20000000 ${IDS_FILE}
+       rm -f ${SWAP_FILE}
+
+m3_slm:        
+       ./slmbuild -n 3 -o ${RAW_LM_FILE3} -w 200000 -c 0,2,2 -d ABS,0.0005 -d ABS -d ABS -b 10 -e 9 ${IDNGRAM_FILE3}
+
+m3_prune: 
+       ./slmprune ${RAW_LM_FILE3} ${SLM_FILE3} R 100000 2500000 1000000
+
+m3_thread :
+       ./slmthread ${SLM_FILE3} ${TSLM_FILE3}
+
+m3_tslminfo :
+       ./tslminfo -p -v -l ${DICTFILE} ${TSLM_FILE3} >${TSLM_INFO_FILE3}
+
+m3_tslmpack :
+       ./tslmpack ${TSLM_INFO_FILE3} ${DICTFILE} ${TSLM_REPACKED_FILE3}
+
+m3_tslmunpack :
+       ./tslminfo -p -v -l ${DICTFILE} ${TSLM_REPACKED_FILE3} >${TSLM_UNPACKED_FILE3}
+
+#Use this to generate trigram non-threaded lm arpa information if needed
+m3_info :
+       ./slminfo -p -v -l ${DICTFILE} ${SLM_FILE3} >${SLM_INFO_FILE3}
+
+#clean all intermedian file for building the model
+model_clean :
+       rm -f ${IDS_FILE}
+       rm -f ${SWAP_FILE}
+       rm -f ${IDNGRAM_FILE} ${RAW_LM_FILE}
+       rm -f ${IDNGRAM_FILE3} ${RAW_LM_FILE3}
+
+lexicon :
+       ./genpyt -i ${PINYIN_TEXTFILE} -o ${PYTRIE_FILE} -l ${PYTRIE_PRINTOUT} -s ${TSLM_FILE3}
+
+lexicon2 :
+       ./genpyt -i ${PINYIN_TEXTFILE} -o ${PYTRIE_FILE} -l ${PYTRIE_PRINTOUT} -s ${TSLM_FILE}
diff --git a/build/SConscript b/build/SConscript
new file mode 100644 (file)
index 0000000..f920de6
--- /dev/null
@@ -0,0 +1,54 @@
+import os
+
+Import('env')
+
+def program(name, objlist):
+    src = ['../src/' + obj for obj in objlist]
+    return env.Program(name, source=src,
+                       CPPPATH=['..'] + env['CPPPATH'])
+
+program('genpyt', ['portability.o', 'slm/slm.o', 'slm/tslmendian/writer.o',
+                   'lexicon/trie_writer.o', 'lexicon/genPYT.o',
+                   'lexicon/pytrie.o', 'lexicon/pytrie_gen.o',
+                   'pinyin/pinyin_data.o'])
+        
+program('slmthread', ['portability.o', 'slm/sim_slm.o',
+                      'slm/thread/ValueCompress.o', 'slm/thread/slmthread.o'])
+
+program('testvc', ['slm/thread/ValueCompress.o', 'slm/thread/test_vc.o'])
+
+program('tslminfo', ['portability.o', 'slm/slm.o', 'slm/tslminfo/tslminfo.o'])
+
+program('tslmpack', ['portability.o', 'slm/slm.o',
+                     'slm/thread/ValueCompress.o', 'slm/tslmpack/slmpack.o',
+                     'slm/tslmpack/arpa_conv.o', 'slm/tslmpack/arpa_slm.o'])
+
+program('tslmendian', ['slm/tslmendian/slm_file.o',
+                       'slm/tslmendian/slm_endian.o',
+                       'slm/tslmendian/writer.o'])
+
+program('slminfo', ['portability.o', 'slm/slminfo/slminfo.o'])
+
+program('slmprune', ['portability.o', 'slm/sim_slm.o',
+                     'slm/slmprune/slmprune.o'])
+
+program('getWordFreq', ['portability.o', 'slm/slm.o',
+                        'slm/getWordFreq/getWordFreq.o'])
+
+program('slmbuild', ['portability.o', 'slm/sim_slmbuilder.o',
+                     'slm/slmbuild/slmbuild.o'])
+
+program('mmseg', ['portability.o', 'slm/sim_dict.o', 'slm/sim_sen.o',
+                  'slm/mmseg/mmseg.o'])
+
+program('slmseg', ['portability.o', 'slm/sim_dict.o', 'slm/sim_sen.o',
+                   'slm/slm.o', 'slm/slmseg/slmseg.o'])
+
+program('ids2ngram', ['portability.o', 'slm/ids2ngram/ids2ngram.o'])
+
+program('idngram_merge', ['portability.o', 'slm/ids2ngram/idngram_merge.o'])
+
+Command("../data/tslmpack", "tslmpack", Copy("$TARGET", "$SOURCE"))
+Command("../data/tslmendian", "tslmendian", Copy("$TARGET", "$SOURCE"))
+Command("../data/genpyt", "genpyt", Copy("$TARGET", "$SOURCE"))
+
diff --git a/config.rpath b/config.rpath
new file mode 100755 (executable)
index 0000000..c547c68
--- /dev/null
@@ -0,0 +1,666 @@
+#! /bin/sh
+# Output a system dependent set of variables, describing how to set the
+# run time search path of shared libraries in an executable.
+#
+#   Copyright 1996-2007 Free Software Foundation, Inc.
+#   Taken from GNU libtool, 2001
+#   Originally by Gordon Matzigkeit <gord@gnu.ai.mit.edu>, 1996
+#
+#   This file is free software; the Free Software Foundation gives
+#   unlimited permission to copy and/or distribute it, with or without
+#   modifications, as long as this notice is preserved.
+#
+# The first argument passed to this file is the canonical host specification,
+#    CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM
+# or
+#    CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM
+# The environment variables CC, GCC, LDFLAGS, LD, with_gnu_ld
+# should be set by the caller.
+#
+# The set of defined variables is at the end of this script.
+
+# Known limitations:
+# - On IRIX 6.5 with CC="cc", the run time search patch must not be longer
+#   than 256 bytes, otherwise the compiler driver will dump core. The only
+#   known workaround is to choose shorter directory names for the build
+#   directory and/or the installation directory.
+
+# All known linkers require a `.a' archive for static linking (except MSVC,
+# which needs '.lib').
+libext=a
+shrext=.so
+
+host="$1"
+host_cpu=`echo "$host" | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'`
+host_vendor=`echo "$host" | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'`
+host_os=`echo "$host" | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'`
+
+# Code taken from libtool.m4's _LT_CC_BASENAME.
+
+for cc_temp in $CC""; do
+  case $cc_temp in
+    compile | *[\\/]compile | ccache | *[\\/]ccache ) ;;
+    distcc | *[\\/]distcc | purify | *[\\/]purify ) ;;
+    \-*) ;;
+    *) break;;
+  esac
+done
+cc_basename=`echo "$cc_temp" | sed -e 's%^.*/%%'`
+
+# Code taken from libtool.m4's AC_LIBTOOL_PROG_COMPILER_PIC.
+
+wl=
+if test "$GCC" = yes; then
+  wl='-Wl,'
+else
+  case "$host_os" in
+    aix*)
+      wl='-Wl,'
+      ;;
+    darwin*)
+      case $cc_basename in
+        xlc*)
+          wl='-Wl,'
+          ;;
+      esac
+      ;;
+    mingw* | cygwin* | pw32* | os2*)
+      ;;
+    hpux9* | hpux10* | hpux11*)
+      wl='-Wl,'
+      ;;
+    irix5* | irix6* | nonstopux*)
+      wl='-Wl,'
+      ;;
+    newsos6)
+      ;;
+    linux* | k*bsd*-gnu)
+      case $cc_basename in
+        icc* | ecc*)
+          wl='-Wl,'
+          ;;
+        pgcc | pgf77 | pgf90)
+          wl='-Wl,'
+          ;;
+        ccc*)
+          wl='-Wl,'
+          ;;
+        como)
+          wl='-lopt='
+          ;;
+        *)
+          case `$CC -V 2>&1 | sed 5q` in
+            *Sun\ C*)
+              wl='-Wl,'
+              ;;
+          esac
+          ;;
+      esac
+      ;;
+    osf3* | osf4* | osf5*)
+      wl='-Wl,'
+      ;;
+    rdos*)
+      ;;
+    solaris*)
+      wl='-Wl,'
+      ;;
+    sunos4*)
+      wl='-Qoption ld '
+      ;;
+    sysv4 | sysv4.2uw2* | sysv4.3*)
+      wl='-Wl,'
+      ;;
+    sysv4*MP*)
+      ;;
+    sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*)
+      wl='-Wl,'
+      ;;
+    unicos*)
+      wl='-Wl,'
+      ;;
+    uts4*)
+      ;;
+  esac
+fi
+
+# Code taken from libtool.m4's AC_LIBTOOL_PROG_LD_SHLIBS.
+
+hardcode_libdir_flag_spec=
+hardcode_libdir_separator=
+hardcode_direct=no
+hardcode_minus_L=no
+
+case "$host_os" in
+  cygwin* | mingw* | pw32*)
+    # FIXME: the MSVC++ port hasn't been tested in a loooong time
+    # When not using gcc, we currently assume that we are using
+    # Microsoft Visual C++.
+    if test "$GCC" != yes; then
+      with_gnu_ld=no
+    fi
+    ;;
+  interix*)
+    # we just hope/assume this is gcc and not c89 (= MSVC++)
+    with_gnu_ld=yes
+    ;;
+  openbsd*)
+    with_gnu_ld=no
+    ;;
+esac
+
+ld_shlibs=yes
+if test "$with_gnu_ld" = yes; then
+  # Set some defaults for GNU ld with shared library support. These
+  # are reset later if shared libraries are not supported. Putting them
+  # here allows them to be overridden if necessary.
+  # Unlike libtool, we use -rpath here, not --rpath, since the documented
+  # option of GNU ld is called -rpath, not --rpath.
+  hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
+  case "$host_os" in
+    aix3* | aix4* | aix5*)
+      # On AIX/PPC, the GNU linker is very broken
+      if test "$host_cpu" != ia64; then
+        ld_shlibs=no
+      fi
+      ;;
+    amigaos*)
+      hardcode_libdir_flag_spec='-L$libdir'
+      hardcode_minus_L=yes
+      # Samuel A. Falvo II <kc5tja@dolphin.openprojects.net> reports
+      # that the semantics of dynamic libraries on AmigaOS, at least up
+      # to version 4, is to share data among multiple programs linked
+      # with the same dynamic library.  Since this doesn't match the
+      # behavior of shared libraries on other platforms, we cannot use
+      # them.
+      ld_shlibs=no
+      ;;
+    beos*)
+      if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then
+        :
+      else
+        ld_shlibs=no
+      fi
+      ;;
+    cygwin* | mingw* | pw32*)
+      # hardcode_libdir_flag_spec is actually meaningless, as there is
+      # no search path for DLLs.
+      hardcode_libdir_flag_spec='-L$libdir'
+      if $LD --help 2>&1 | grep 'auto-import' > /dev/null; then
+        :
+      else
+        ld_shlibs=no
+      fi
+      ;;
+    interix[3-9]*)
+      hardcode_direct=no
+      hardcode_libdir_flag_spec='${wl}-rpath,$libdir'
+      ;;
+    gnu* | linux* | k*bsd*-gnu)
+      if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then
+        :
+      else
+        ld_shlibs=no
+      fi
+      ;;
+    netbsd*)
+      ;;
+    solaris*)
+      if $LD -v 2>&1 | grep 'BFD 2\.8' > /dev/null; then
+        ld_shlibs=no
+      elif $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then
+        :
+      else
+        ld_shlibs=no
+      fi
+      ;;
+    sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*)
+      case `$LD -v 2>&1` in
+        *\ [01].* | *\ 2.[0-9].* | *\ 2.1[0-5].*)
+          ld_shlibs=no
+          ;;
+        *)
+          if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then
+            hardcode_libdir_flag_spec='`test -z "$SCOABSPATH" && echo ${wl}-rpath,$libdir`'
+          else
+            ld_shlibs=no
+          fi
+          ;;
+      esac
+      ;;
+    sunos4*)
+      hardcode_direct=yes
+      ;;
+    *)
+      if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then
+        :
+      else
+        ld_shlibs=no
+      fi
+      ;;
+  esac
+  if test "$ld_shlibs" = no; then
+    hardcode_libdir_flag_spec=
+  fi
+else
+  case "$host_os" in
+    aix3*)
+      # Note: this linker hardcodes the directories in LIBPATH if there
+      # are no directories specified by -L.
+      hardcode_minus_L=yes
+      if test "$GCC" = yes; then
+        # Neither direct hardcoding nor static linking is supported with a
+        # broken collect2.
+        hardcode_direct=unsupported
+      fi
+      ;;
+    aix4* | aix5*)
+      if test "$host_cpu" = ia64; then
+        # On IA64, the linker does run time linking by default, so we don't
+        # have to do anything special.
+        aix_use_runtimelinking=no
+      else
+        aix_use_runtimelinking=no
+        # Test if we are trying to use run time linking or normal
+        # AIX style linking. If -brtl is somewhere in LDFLAGS, we
+        # need to do runtime linking.
+        case $host_os in aix4.[23]|aix4.[23].*|aix5*)
+          for ld_flag in $LDFLAGS; do
+            if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then
+              aix_use_runtimelinking=yes
+              break
+            fi
+          done
+          ;;
+        esac
+      fi
+      hardcode_direct=yes
+      hardcode_libdir_separator=':'
+      if test "$GCC" = yes; then
+        case $host_os in aix4.[012]|aix4.[012].*)
+          collect2name=`${CC} -print-prog-name=collect2`
+          if test -f "$collect2name" && \
+            strings "$collect2name" | grep resolve_lib_name >/dev/null
+          then
+            # We have reworked collect2
+            :
+          else
+            # We have old collect2
+            hardcode_direct=unsupported
+            hardcode_minus_L=yes
+            hardcode_libdir_flag_spec='-L$libdir'
+            hardcode_libdir_separator=
+          fi
+          ;;
+        esac
+      fi
+      # Begin _LT_AC_SYS_LIBPATH_AIX.
+      echo 'int main () { return 0; }' > conftest.c
+      ${CC} ${LDFLAGS} conftest.c -o conftest
+      aix_libpath=`dump -H conftest 2>/dev/null | sed -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0  *\(.*\)$/\1/; p; }
+}'`
+      if test -z "$aix_libpath"; then
+        aix_libpath=`dump -HX64 conftest 2>/dev/null | sed -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0  *\(.*\)$/\1/; p; }
+}'`
+      fi
+      if test -z "$aix_libpath"; then
+        aix_libpath="/usr/lib:/lib"
+      fi
+      rm -f conftest.c conftest
+      # End _LT_AC_SYS_LIBPATH_AIX.
+      if test "$aix_use_runtimelinking" = yes; then
+        hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath"
+      else
+        if test "$host_cpu" = ia64; then
+          hardcode_libdir_flag_spec='${wl}-R $libdir:/usr/lib:/lib'
+        else
+          hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath"
+        fi
+      fi
+      ;;
+    amigaos*)
+      hardcode_libdir_flag_spec='-L$libdir'
+      hardcode_minus_L=yes
+      # see comment about different semantics on the GNU ld section
+      ld_shlibs=no
+      ;;
+    bsdi[45]*)
+      ;;
+    cygwin* | mingw* | pw32*)
+      # When not using gcc, we currently assume that we are using
+      # Microsoft Visual C++.
+      # hardcode_libdir_flag_spec is actually meaningless, as there is
+      # no search path for DLLs.
+      hardcode_libdir_flag_spec=' '
+      libext=lib
+      ;;
+    darwin* | rhapsody*)
+      hardcode_direct=no
+      if test "$GCC" = yes ; then
+        :
+      else
+        case $cc_basename in
+          xlc*)
+            ;;
+          *)
+            ld_shlibs=no
+            ;;
+        esac
+      fi
+      ;;
+    dgux*)
+      hardcode_libdir_flag_spec='-L$libdir'
+      ;;
+    freebsd1*)
+      ld_shlibs=no
+      ;;
+    freebsd2.2*)
+      hardcode_libdir_flag_spec='-R$libdir'
+      hardcode_direct=yes
+      ;;
+    freebsd2*)
+      hardcode_direct=yes
+      hardcode_minus_L=yes
+      ;;
+    freebsd* | dragonfly*)
+      hardcode_libdir_flag_spec='-R$libdir'
+      hardcode_direct=yes
+      ;;
+    hpux9*)
+      hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir'
+      hardcode_libdir_separator=:
+      hardcode_direct=yes
+      # hardcode_minus_L: Not really in the search PATH,
+      # but as the default location of the library.
+      hardcode_minus_L=yes
+      ;;
+    hpux10*)
+      if test "$with_gnu_ld" = no; then
+        hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir'
+        hardcode_libdir_separator=:
+        hardcode_direct=yes
+        # hardcode_minus_L: Not really in the search PATH,
+        # but as the default location of the library.
+        hardcode_minus_L=yes
+      fi
+      ;;
+    hpux11*)
+      if test "$with_gnu_ld" = no; then
+        hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir'
+        hardcode_libdir_separator=:
+        case $host_cpu in
+          hppa*64*|ia64*)
+            hardcode_direct=no
+            ;;
+          *)
+            hardcode_direct=yes
+            # hardcode_minus_L: Not really in the search PATH,
+            # but as the default location of the library.
+            hardcode_minus_L=yes
+            ;;
+        esac
+      fi
+      ;;
+    irix5* | irix6* | nonstopux*)
+      hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
+      hardcode_libdir_separator=:
+      ;;
+    netbsd*)
+      hardcode_libdir_flag_spec='-R$libdir'
+      hardcode_direct=yes
+      ;;
+    newsos6)
+      hardcode_direct=yes
+      hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
+      hardcode_libdir_separator=:
+      ;;
+    openbsd*)
+      if test -f /usr/libexec/ld.so; then
+        hardcode_direct=yes
+        if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
+          hardcode_libdir_flag_spec='${wl}-rpath,$libdir'
+        else
+          case "$host_os" in
+            openbsd[01].* | openbsd2.[0-7] | openbsd2.[0-7].*)
+              hardcode_libdir_flag_spec='-R$libdir'
+              ;;
+            *)
+              hardcode_libdir_flag_spec='${wl}-rpath,$libdir'
+              ;;
+          esac
+        fi
+      else
+        ld_shlibs=no
+      fi
+      ;;
+    os2*)
+      hardcode_libdir_flag_spec='-L$libdir'
+      hardcode_minus_L=yes
+      ;;
+    osf3*)
+      hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
+      hardcode_libdir_separator=:
+      ;;
+    osf4* | osf5*)
+      if test "$GCC" = yes; then
+        hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
+      else
+        # Both cc and cxx compiler support -rpath directly
+        hardcode_libdir_flag_spec='-rpath $libdir'
+      fi
+      hardcode_libdir_separator=:
+      ;;
+    solaris*)
+      hardcode_libdir_flag_spec='-R$libdir'
+      ;;
+    sunos4*)
+      hardcode_libdir_flag_spec='-L$libdir'
+      hardcode_direct=yes
+      hardcode_minus_L=yes
+      ;;
+    sysv4)
+      case $host_vendor in
+        sni)
+          hardcode_direct=yes # is this really true???
+          ;;
+        siemens)
+          hardcode_direct=no
+          ;;
+        motorola)
+          hardcode_direct=no #Motorola manual says yes, but my tests say they lie
+          ;;
+      esac
+      ;;
+    sysv4.3*)
+      ;;
+    sysv4*MP*)
+      if test -d /usr/nec; then
+        ld_shlibs=yes
+      fi
+      ;;
+    sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[01].[10]* | unixware7* | sco3.2v5.0.[024]*)
+      ;;
+    sysv5* | sco3.2v5* | sco5v6*)
+      hardcode_libdir_flag_spec='`test -z "$SCOABSPATH" && echo ${wl}-R,$libdir`'
+      hardcode_libdir_separator=':'
+      ;;
+    uts4*)
+      hardcode_libdir_flag_spec='-L$libdir'
+      ;;
+    *)
+      ld_shlibs=no
+      ;;
+  esac
+fi
+
+# Check dynamic linker characteristics
+# Code taken from libtool.m4's AC_LIBTOOL_SYS_DYNAMIC_LINKER.
+# Unlike libtool.m4, here we don't care about _all_ names of the library, but
+# only about the one the linker finds when passed -lNAME. This is the last
+# element of library_names_spec in libtool.m4, or possibly two of them if the
+# linker has special search rules.
+library_names_spec=      # the last element of library_names_spec in libtool.m4
+libname_spec='lib$name'
+case "$host_os" in
+  aix3*)
+    library_names_spec='$libname.a'
+    ;;
+  aix4* | aix5*)
+    library_names_spec='$libname$shrext'
+    ;;
+  amigaos*)
+    library_names_spec='$libname.a'
+    ;;
+  beos*)
+    library_names_spec='$libname$shrext'
+    ;;
+  bsdi[45]*)
+    library_names_spec='$libname$shrext'
+    ;;
+  cygwin* | mingw* | pw32*)
+    shrext=.dll
+    library_names_spec='$libname.dll.a $libname.lib'
+    ;;
+  darwin* | rhapsody*)
+    shrext=.dylib
+    library_names_spec='$libname$shrext'
+    ;;
+  dgux*)
+    library_names_spec='$libname$shrext'
+    ;;
+  freebsd1*)
+    ;;
+  freebsd* | dragonfly*)
+    case "$host_os" in
+      freebsd[123]*)
+        library_names_spec='$libname$shrext$versuffix' ;;
+      *)
+        library_names_spec='$libname$shrext' ;;
+    esac
+    ;;
+  gnu*)
+    library_names_spec='$libname$shrext'
+    ;;
+  hpux9* | hpux10* | hpux11*)
+    case $host_cpu in
+      ia64*)
+        shrext=.so
+        ;;
+      hppa*64*)
+        shrext=.sl
+        ;;
+      *)
+        shrext=.sl
+        ;;
+    esac
+    library_names_spec='$libname$shrext'
+    ;;
+  interix[3-9]*)
+    library_names_spec='$libname$shrext'
+    ;;
+  irix5* | irix6* | nonstopux*)
+    library_names_spec='$libname$shrext'
+    case "$host_os" in
+      irix5* | nonstopux*)
+        libsuff= shlibsuff=
+        ;;
+      *)
+        case $LD in
+          *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ") libsuff= shlibsuff= ;;
+          *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ") libsuff=32 shlibsuff=N32 ;;
+          *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ") libsuff=64 shlibsuff=64 ;;
+          *) libsuff= shlibsuff= ;;
+        esac
+        ;;
+    esac
+    ;;
+  linux*oldld* | linux*aout* | linux*coff*)
+    ;;
+  linux* | k*bsd*-gnu)
+    library_names_spec='$libname$shrext'
+    ;;
+  knetbsd*-gnu)
+    library_names_spec='$libname$shrext'
+    ;;
+  netbsd*)
+    library_names_spec='$libname$shrext'
+    ;;
+  newsos6)
+    library_names_spec='$libname$shrext'
+    ;;
+  nto-qnx*)
+    library_names_spec='$libname$shrext'
+    ;;
+  openbsd*)
+    library_names_spec='$libname$shrext$versuffix'
+    ;;
+  os2*)
+    libname_spec='$name'
+    shrext=.dll
+    library_names_spec='$libname.a'
+    ;;
+  osf3* | osf4* | osf5*)
+    library_names_spec='$libname$shrext'
+    ;;
+  rdos*)
+    ;;
+  solaris*)
+    library_names_spec='$libname$shrext'
+    ;;
+  sunos4*)
+    library_names_spec='$libname$shrext$versuffix'
+    ;;
+  sysv4 | sysv4.3*)
+    library_names_spec='$libname$shrext'
+    ;;
+  sysv4*MP*)
+    library_names_spec='$libname$shrext'
+    ;;
+  sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*)
+    library_names_spec='$libname$shrext'
+    ;;
+  uts4*)
+    library_names_spec='$libname$shrext'
+    ;;
+esac
+
+sed_quote_subst='s/\(["`$\\]\)/\\\1/g'
+escaped_wl=`echo "X$wl" | sed -e 's/^X//' -e "$sed_quote_subst"`
+shlibext=`echo "$shrext" | sed -e 's,^\.,,'`
+escaped_libname_spec=`echo "X$libname_spec" | sed -e 's/^X//' -e "$sed_quote_subst"`
+escaped_library_names_spec=`echo "X$library_names_spec" | sed -e 's/^X//' -e "$sed_quote_subst"`
+escaped_hardcode_libdir_flag_spec=`echo "X$hardcode_libdir_flag_spec" | sed -e 's/^X//' -e "$sed_quote_subst"`
+
+LC_ALL=C sed -e 's/^\([a-zA-Z0-9_]*\)=/acl_cv_\1=/' <<EOF
+
+# How to pass a linker flag through the compiler.
+wl="$escaped_wl"
+
+# Static library suffix (normally "a").
+libext="$libext"
+
+# Shared library suffix (normally "so").
+shlibext="$shlibext"
+
+# Format of library name prefix.
+libname_spec="$escaped_libname_spec"
+
+# Library names that the linker finds when passed -lNAME.
+library_names_spec="$escaped_library_names_spec"
+
+# Flag to hardcode \$libdir into a binary during linking.
+# This must work even if \$libdir does not exist.
+hardcode_libdir_flag_spec="$escaped_hardcode_libdir_flag_spec"
+
+# Whether we need a single -rpath flag with a separated argument.
+hardcode_libdir_separator="$hardcode_libdir_separator"
+
+# Set to yes if using DIR/libNAME.so during linking hardcodes DIR into the
+# resulting binary.
+hardcode_direct="$hardcode_direct"
+
+# Set to yes if using the -LDIR flag during linking hardcodes DIR into the
+# resulting binary.
+hardcode_minus_L="$hardcode_minus_L"
+
+EOF
diff --git a/configure.ac b/configure.ac
new file mode 100755 (executable)
index 0000000..77017c4
--- /dev/null
@@ -0,0 +1,137 @@
+#-*- Autoconf -*-
+# Process this file with autoconf to produce a configure script.
+AC_INIT([sunpinyin],[0.0.1223], [mail@yongsun.me])
+AC_PREREQ([2.59])
+AC_CONFIG_SRCDIR([configure.ac])
+AC_CONFIG_MACRO_DIR([m4])
+AC_CONFIG_HEADERS([config.h])
+
+AM_INIT_AUTOMAKE
+
+GETTEXT_PACKAGE=sunpinyin
+AC_SUBST(GETTEXT_PACKAGE)
+AC_DEFINE_UNQUOTED(GETTEXT_PACKAGE,"$GETTEXT_PACKAGE", [The gettext domain])
+
+# Init gettext
+ALL_LINGUAS="ko_KR en zh_CN zh_HK zh_TW de_DE nl_NL es_ES pt_PT el_GR it_IT fr_FR tr_TR ja_JP ru_RU"
+AM_GNU_GETTEXT([external])
+
+# Init libtool
+AC_DISABLE_STATIC
+AC_LIBTOOL_DLOPEN
+AC_PROG_LIBTOOL
+AC_LIB_LTDL
+AC_SUBST(LIBTOOL_DEPS)
+
+#AM_MKINSTALLDIRS
+AC_CANONICAL_HOST
+# Checks for programs.
+AC_PROG_CXX
+AC_PROG_CC
+AC_LANG(C++)
+AC_C_CONST
+AC_TYPE_SIZE_T
+#IT_PROG_INTLTOOL([0.33], [no-xml])
+# Checks for libraries.
+# Checks for header files.
+AC_HEADER_STDC
+# Checks for header files.
+AC_CHECK_HEADERS([fcntl.h stddef.h stdlib.h string.h wchar.h iconv.h assert.h dlfcn.h fcntl.h getopt.h inttypes.h locale.h libintl.h limits.h locale.h memory.h sys/mman.h sys/param.h sys/stat.h sys/types.h unistd.h])
+# Checks for library functions.
+AC_CHECK_FUNCS([memset pow sqrt bind_textdomain_codeset dcgettext exp2 getopt_long getpagesize get_opt log2 mmap munmap setlocale strndup])
+
+case $host_cpu in
+  *arm* ) TARGET=ARM;;
+  * ) TARGET=X86;;
+esac
+AM_CONDITIONAL(ARM, test x$TARGET = xARM)
+
+ISF_VERSION=1.0.0
+
+PKG_CHECK_MODULES(ISF,[isf >= $ISF_VERSION])
+PKG_CHECK_MODULES(SQLITE, [sqlite3 >= 0.0])
+PKG_CHECK_MODULES(GLIB, [glib-2.0 >= 2.0])
+
+# Check if we should build setup module
+PKG_CHECK_MODULES(ISF_GTKUTILS,[isf-gtkutils >= $ISF_VERSION],
+                               [ISF_HAS_GTKUTILS=yes],
+                               [ISF_HAS_GTKUTILS=no])
+
+
+AC_SUBST(ISF_VERSION)
+
+AM_CONDITIONAL(ISF_BUILD_SETUP, [test "$ISF_HAS_GTKUTILS" = "yes"])
+
+if test "$ISF_HAS_GTKUTILS" = "yes"; then
+  ISF_BUILD_SETUP=1
+else
+  ISF_BUILD_SETUP=0
+fi
+
+AC_SUBST(ISF_BUILD_SETUP)
+
+# Checks for library functions.
+AC_SUBST(ac_aux_dir)
+
+# libtool option to control which symbols are exported
+# right now, symbols starting with _ are not exported
+#LIBTOOL_EXPORT_OPTIONS='-export-symbols-regex "^[[^_]].*"'
+#AC_SUBST(LIBTOOL_EXPORT_OPTIONS)
+
+# Extra args.
+AC_ARG_ENABLE(debug,
+             [  --enable-debug          Turn on debugging],
+             enable_debug=yes,
+             enable_debug=no)
+if test "$enable_debug" = "yes"; then
+    AC_DEFINE(ENABLE_DEBUG, 1 ,[Define this to enable the debug facility in libscim])
+    CFLAGS="$CFLAGS -g"
+    CXXFLAGS="$CXXFLAGS -g"
+fi
+
+ISF_ICONDIR=`$PKG_CONFIG --variable=icondir scim`
+ISF_MODULEDIR=`$PKG_CONFIG --variable=moduledir scim`
+ISF_DATADIR=`$PKG_CONFIG --variable=scimdatadir scim`
+ISF_LIBDIR=`$PKG_CONFIG --variable=libdir scim`
+
+if test "x$ISF_ICONDIR" = "x"; then
+  ISF_ICONDIR=${datadir}/scim/icons
+fi
+
+if test "x$ISF_MODULEDIR" = "x"; then
+  ISF_MODULEDIR=${libdir}/scim-1.0
+fi
+
+if test "x$ISF_DATADIR" = "x"; then
+  ISF_DATADIR=${datadir}/scim
+fi
+
+if test "x$ISF_LIBDIR" = "x"; then
+  ISF_LIBDIR=${libdir}
+fi
+
+SUNPINYIN_ICON_DIR=${ISF_ICONDIR}
+SUNPINYIN_MODULE_DIR=${ISF_MODULEDIR}
+SUNPINYIN_DATA_DIR=${ISF_DATADIR}/ise-engine-sunpinyin
+SUNPINYIN_LIB_DIR=${ISF_LIBDIR}
+
+AC_SUBST(SUNPINYIN_ICON_DIR)
+AC_SUBST(SUNPINYIN_MODULE_DIR)
+AC_SUBST(SUNPINYIN_DATA_DIR)
+AC_SUBST(SUNPINYIN_LIBD_IR)
+
+
+AC_CONFIG_FILES([Makefile
+         po/Makefile.in
+         raw/Makefile
+         m4/Makefile
+                src/Makefile
+                src/ime-core/Makefile
+                src/lexicon/Makefile
+                src/pinyin/Makefile
+                src/slm/Makefile
+                wrapper/scim/Makefile
+                wrapper/scim/data/Makefile
+                wrapper/scim/src/Makefile
+                sunpinyin-2.0.pc])
+AC_OUTPUT
diff --git a/configure.conf b/configure.conf
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/data/Makefile b/data/Makefile
new file mode 100644 (file)
index 0000000..7073ff0
--- /dev/null
@@ -0,0 +1,29 @@
+LM_SC_ARPA = ../raw/lm_sc.t3g.arpa
+DICTFILE = ../raw/dict.utf8
+PYTRIE_LOG = pydict_sc.log.utf8
+LM_SC_BIN = lm_sc.t3g
+
+all: pydict_sc.bin pydict_sc.bin.le pydict_sc.bin.be lm_sc.t3g.le lm_sc.t3g.be
+       @echo done
+
+$(LM_SC_BIN): $(LM_SC_ARPA) $(DICTFILE)
+       ./tslmpack $(LM_SC_ARPA) $(DICTFILE) $@
+
+pydict_sc.bin: $(DICTFILE) $(LM_SC_BIN)
+       ./genpyt -i $(DICTFILE) -o $@ -l $(PYTRIE_LOG) -s $(LM_SC_BIN)
+
+pydict_sc.bin.le: $(DICTFILE) $(LM_SC_BIN)
+       ./genpyt -e le -i $(DICTFILE) -o $@ -l $(PYTRIE_LOG) -s $(LM_SC_BIN)
+
+pydict_sc.bin.be: $(DICTFILE) $(LM_SC_BIN)
+       ./genpyt -e be -i $(DICTFILE) -o $@ -l $(PYTRIE_LOG) -s $(LM_SC_BIN)
+
+lm_sc.t3g.le: lm_sc.t3g
+       ./tslmendian -e le -i $(LM_SC_BIN) -o $@
+
+lm_sc.t3g.be: lm_sc.t3g
+       ./tslmendian -e be -i $(LM_SC_BIN) -o $@
+
+clean:
+       @rm -f pydict_sc.bin pydict_sc.bin.le pydict_sc.bin.be lm_sc.t3g lm_sc.t3g.le lm_sc.t3g.be pydict_sc.log.utf8
+       @echo cleaned
diff --git a/data/cnpunc.png b/data/cnpunc.png
new file mode 100644 (file)
index 0000000..3a1538a
Binary files /dev/null and b/data/cnpunc.png differ
diff --git a/data/cnpunc.svg b/data/cnpunc.svg
new file mode 100644 (file)
index 0000000..3c87c8a
--- /dev/null
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   version="1.0"
+   width="64"
+   height="64"
+   id="svg2383">
+  <defs
+     id="defs2385" />
+  <g
+     id="layer1">
+    <path
+       d="M 45.959044,31.180906 C 45.794763,37.094985 42.016314,43.666204 36.595072,48.101764 L 39.387836,51.387368 C 45.959037,46.951808 52.694531,39.230622 52.694531,27.23818 C 52.694531,20.99554 49.901762,16.395688 44.15196,16.395688 C 39.387841,16.395688 35.773671,20.009858 35.773671,24.938258 C 35.773671,30.359498 39.059279,32.823707 41.852039,32.823707 C 43.166279,32.823707 45.137643,32.495145 45.794763,31.180906 L 45.959044,31.180906"
+       id="text2395"
+       style="font-size:116.15293884px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#fffcfc;fill-opacity:1;stroke:#35556b;stroke-width:2.56687784px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Adobe Kaiti Std;-inkscape-font-specification:Adobe Kaiti Std" />
+    <path
+       d="M 16,36.272728 C 16,39.335398 13.517215,41.818183 10.454545,41.818183 C 7.3918752,41.818183 4.9090905,39.335398 4.9090905,36.272728 C 4.9090905,33.210058 7.3918752,30.727273 10.454545,30.727273 C 13.517215,30.727273 16,33.210058 16,36.272728 z"
+       transform="matrix(1.7010723,0,0,1.7010723,1.4887892,-28.087496)"
+       id="path3235"
+       style="opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:#35556b;stroke-width:1.73880613;stroke-linecap:square;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
+  </g>
+</svg>
diff --git a/data/eng.png b/data/eng.png
new file mode 100644 (file)
index 0000000..4aef9af
Binary files /dev/null and b/data/eng.png differ
diff --git a/data/eng.svg b/data/eng.svg
new file mode 100644 (file)
index 0000000..2627d79
--- /dev/null
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   version="1.0"
+   width="48"
+   height="48"
+   id="svg2710">
+  <defs
+     id="defs2712">
+    <filter
+       id="filter4889">
+      <feGaussianBlur
+         id="feGaussianBlur4891"
+         stdDeviation="0.8789348"
+         inkscape:collect="always" />
+    </filter>
+  </defs>
+  <g
+     id="layer1">
+    <text
+       x="-2.4050589"
+       y="43"
+       id="text2720"
+       xml:space="preserve"
+       style="font-size:48px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#35556b;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Adobe Kaiti Std;-inkscape-font-specification:Adobe Kaiti Std"><tspan
+         x="-2.4050589"
+         y="43"
+         id="tspan2722">英</tspan></text>
+    <text
+       x="-0.94521457"
+       y="43.750927"
+       id="text3520"
+       xml:space="preserve"
+       style="font-size:48px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;opacity:1;fill:#36556b;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;filter:url(#filter4889);font-family:Adobe Kaiti Std;-inkscape-font-specification:Adobe Kaiti Std"><tspan
+         x="-0.94521457"
+         y="43.750927"
+         id="tspan3522">英</tspan></text>
+  </g>
+</svg>
diff --git a/data/enpunc.png b/data/enpunc.png
new file mode 100644 (file)
index 0000000..1529d77
Binary files /dev/null and b/data/enpunc.png differ
diff --git a/data/enpunc.svg b/data/enpunc.svg
new file mode 100644 (file)
index 0000000..e320bb7
--- /dev/null
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   version="1.0"
+   width="64"
+   height="64"
+   id="svg2383">
+  <defs
+     id="defs2385" />
+  <g
+     id="layer1">
+    <text
+       x="31.421482"
+       y="37.179684"
+       transform="scale(1.0226118,0.9778882)"
+       id="text3788"
+       xml:space="preserve"
+       style="font-size:101.39350891px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#35556b;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Adobe Heiti Std;-inkscape-font-specification:Adobe Heiti Std"><tspan
+         x="31.421482"
+         y="37.179684"
+         id="tspan3790">,</tspan></text>
+    <text
+       x="7.2146564"
+       y="44.207535"
+       transform="scale(1.0206497,0.9797681)"
+       id="text3800"
+       xml:space="preserve"
+       style="font-size:85.94076538px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#35556b;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Adobe Heiti Std;-inkscape-font-specification:Adobe Heiti Std"><tspan
+         x="7.2146564"
+         y="44.207535"
+         id="tspan3802">.</tspan></text>
+  </g>
+</svg>
diff --git a/data/fullwidth.png b/data/fullwidth.png
new file mode 100644 (file)
index 0000000..e6711ec
Binary files /dev/null and b/data/fullwidth.png differ
diff --git a/data/fullwidth.svg b/data/fullwidth.svg
new file mode 100644 (file)
index 0000000..a290d8e
--- /dev/null
@@ -0,0 +1,76 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="64px"
+   height="64px"
+   id="svg2383"
+   sodipodi:version="0.32"
+   inkscape:version="0.46"
+   sodipodi:docname="full.plain.svg"
+   inkscape:output_extension="org.inkscape.output.svg.inkscape">
+  <defs
+     id="defs2385">
+    <inkscape:perspective
+       sodipodi:type="inkscape:persp3d"
+       inkscape:vp_x="0 : 32 : 1"
+       inkscape:vp_y="0 : 1000 : 0"
+       inkscape:vp_z="64 : 32 : 1"
+       inkscape:persp3d-origin="32 : 21.333333 : 1"
+       id="perspective2391" />
+  </defs>
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     inkscape:pageopacity="0.0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="4"
+     inkscape:cx="-52.887062"
+     inkscape:cy="40.538214"
+     inkscape:current-layer="layer1"
+     showgrid="true"
+     inkscape:document-units="px"
+     inkscape:grid-bbox="true"
+     inkscape:window-width="1540"
+     inkscape:window-height="930"
+     inkscape:window-x="126"
+     inkscape:window-y="111">
+    <inkscape:grid
+       type="xygrid"
+       id="grid2662" />
+  </sodipodi:namedview>
+  <metadata
+     id="metadata2388">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     id="layer1"
+     inkscape:label="Layer 1"
+     inkscape:groupmode="layer">
+    <path
+       sodipodi:type="arc"
+       style="opacity:1;fill:#fbfbfb;fill-opacity:1;fill-rule:nonzero;stroke:#35556b;stroke-width:5;stroke-linecap:square;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+       id="path5120"
+       sodipodi:cx="29.168156"
+       sodipodi:cy="35.185398"
+       sodipodi:rx="24.925514"
+       sodipodi:ry="24.925514"
+       d="M 54.09367,35.185398 A 24.925514,24.925514 0 1 1 4.2426414,35.185398 A 24.925514,24.925514 0 1 1 54.09367,35.185398 z"
+       transform="translate(3.1003586,-3.4999123)" />
+  </g>
+</svg>
diff --git a/data/halfwidth.png b/data/halfwidth.png
new file mode 100644 (file)
index 0000000..7b4a543
Binary files /dev/null and b/data/halfwidth.png differ
diff --git a/data/halfwidth.svg b/data/halfwidth.svg
new file mode 100644 (file)
index 0000000..defe4c3
--- /dev/null
@@ -0,0 +1,114 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:xlink="http://www.w3.org/1999/xlink"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="64px"
+   height="64px"
+   id="svg2383"
+   sodipodi:version="0.32"
+   inkscape:version="0.46"
+   sodipodi:docname="half.plain.svg"
+   inkscape:output_extension="org.inkscape.output.svg.inkscape">
+  <defs
+     id="defs2385">
+    <linearGradient
+       inkscape:collect="always"
+       id="linearGradient3720">
+      <stop
+         style="stop-color:#000000;stop-opacity:1;"
+         offset="0"
+         id="stop3722" />
+      <stop
+         style="stop-color:#000000;stop-opacity:0;"
+         offset="1"
+         id="stop3724" />
+    </linearGradient>
+    <inkscape:perspective
+       sodipodi:type="inkscape:persp3d"
+       inkscape:vp_x="0 : 32 : 1"
+       inkscape:vp_y="0 : 1000 : 0"
+       inkscape:vp_z="64 : 32 : 1"
+       inkscape:persp3d-origin="32 : 21.333333 : 1"
+       id="perspective2391" />
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3720"
+       id="radialGradient3726"
+       cx="30.727272"
+       cy="38"
+       fx="30.727272"
+       fy="38"
+       r="34.19318"
+       gradientUnits="userSpaceOnUse" />
+    <filter
+       inkscape:collect="always"
+       id="filter4052">
+      <feGaussianBlur
+         inkscape:collect="always"
+         stdDeviation="0.73699187"
+         id="feGaussianBlur4054" />
+    </filter>
+  </defs>
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     inkscape:pageopacity="0.0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="1"
+     inkscape:cx="-106.19267"
+     inkscape:cy="-30.87384"
+     inkscape:current-layer="layer1"
+     showgrid="true"
+     inkscape:document-units="px"
+     inkscape:grid-bbox="true"
+     inkscape:window-width="1392"
+     inkscape:window-height="1026"
+     inkscape:window-x="15"
+     inkscape:window-y="123"
+     inkscape:snap-global="false"
+     showguides="true"
+     inkscape:guide-bbox="true">
+    <inkscape:grid
+       type="xygrid"
+       id="grid2662" />
+  </sodipodi:namedview>
+  <metadata
+     id="metadata2388">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     id="layer1"
+     inkscape:label="Layer 1"
+     inkscape:groupmode="layer">
+    <path
+       sodipodi:type="arc"
+       style="opacity:0;fill:#e76f00;fill-opacity:1;fill-rule:nonzero;stroke:url(#radialGradient3726);stroke-width:4.02272700999999966;stroke-linecap:square;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+       id="path3510"
+       sodipodi:cx="30.727272"
+       sodipodi:cy="38"
+       sodipodi:rx="32.181816"
+       sodipodi:ry="32.181816"
+       d="M 62.909088,38 A 32.181816,32.181816 0 1 1 -1.4545441,38 A 32.181816,32.181816 0 1 1 62.909088,38 z"
+       transform="matrix(0.932937,0,0,0.9328223,3.4133581,-3.5235232)" />
+    <path
+       style="opacity:1;fill:#ffffff;fill-opacity:0.94117647000000004;fill-rule:nonzero;stroke:#35556f;stroke-width:4;stroke-linecap:square;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate;filter:url(#filter4052)"
+       d="M 32.28125 6.75 C 18.522366 6.75 7.3437501 17.928616 7.34375 31.6875 C 7.34375 45.446384 18.522368 56.625 32.28125 56.625 C 39.359772 56.625 45.74252 53.649821 50.28125 48.90625 C 48.227055 49.761823 45.987941 50.25 43.625 50.25 C 34.034 50.249999 26.25 42.466001 26.25 32.875 C 26.25 23.284 34.034 15.5 43.625 15.5 C 47.277542 15.5 50.670476 16.634772 53.46875 18.5625 C 49.072067 11.474848 41.229515 6.75 32.28125 6.75 z "
+       id="path5120" />
+  </g>
+</svg>
diff --git a/data/han.png b/data/han.png
new file mode 100644 (file)
index 0000000..3ad79a7
Binary files /dev/null and b/data/han.png differ
diff --git a/data/han.svg b/data/han.svg
new file mode 100644 (file)
index 0000000..13a4574
--- /dev/null
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   version="1.0"
+   width="48"
+   height="48"
+   id="svg2710">
+  <defs
+     id="defs2712">
+    <filter
+       id="filter4889">
+      <feGaussianBlur
+         id="feGaussianBlur4891"
+         stdDeviation="0.8789348"
+         inkscape:collect="always" />
+    </filter>
+  </defs>
+  <g
+     id="layer1">
+    <text
+       x="-2.4050589"
+       y="43"
+       id="text2720"
+       xml:space="preserve"
+       style="font-size:48px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#35556b;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:AR PL UKai CN;-inkscape-font-specification:AR PL UKai CN"><tspan
+         x="-2.4050589"
+         y="43"
+         id="tspan2722">汉</tspan></text>
+    <text
+       x="-0.94521457"
+       y="43.750927"
+       id="text3520"
+       xml:space="preserve"
+       style="font-size:48px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;opacity:1;fill:#36556b;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;filter:url(#filter4889);font-family:AR PL UKai CN;-inkscape-font-specification:AR PL UKai CN"><tspan
+         x="-0.94521457"
+         y="43.750927"
+         id="tspan3522">汉</tspan></text>
+  </g>
+</svg>
diff --git a/data/setup.svg b/data/setup.svg
new file mode 100644 (file)
index 0000000..da8c585
--- /dev/null
@@ -0,0 +1,193 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:xlink="http://www.w3.org/1999/xlink"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   inkscape:export-ydpi="90.000000"
+   inkscape:export-xdpi="90.000000"
+   inkscape:export-filename="/home/jimmac/Desktop/wi-fi.png"
+   width="48px"
+   height="48px"
+   id="svg11300"
+   sodipodi:version="0.32"
+   inkscape:version="0.46"
+   sodipodi:docbase="/home/tigert/cvs/freedesktop.org/tango-icon-theme/scalable/emblems"
+   sodipodi:docname="setup.svg"
+   inkscape:output_extension="org.inkscape.output.svg.inkscape">
+  <defs
+     id="defs3">
+    <inkscape:perspective
+       sodipodi:type="inkscape:persp3d"
+       inkscape:vp_x="0 : 24 : 1"
+       inkscape:vp_y="0 : 1000 : 0"
+       inkscape:vp_z="48 : 24 : 1"
+       inkscape:persp3d-origin="24 : 16 : 1"
+       id="perspective22" />
+    <linearGradient
+       id="linearGradient3264">
+      <stop
+         style="stop-color: rgb(201, 201, 201); stop-opacity: 1;"
+         offset="0"
+         id="stop3266" />
+      <stop
+         id="stop3276"
+         offset="0.25"
+         style="stop-color: rgb(248, 248, 248); stop-opacity: 1;" />
+      <stop
+         id="stop3272"
+         offset="0.5"
+         style="stop-color: rgb(226, 226, 226); stop-opacity: 1;" />
+      <stop
+         style="stop-color: rgb(176, 176, 176); stop-opacity: 1;"
+         offset="0.75"
+         id="stop3274" />
+      <stop
+         style="stop-color: rgb(201, 201, 201); stop-opacity: 1;"
+         offset="1"
+         id="stop3268" />
+    </linearGradient>
+    <linearGradient
+       inkscape:collect="always"
+       id="linearGradient3256">
+      <stop
+         style="stop-color: rgb(0, 0, 0); stop-opacity: 1;"
+         offset="0"
+         id="stop3258" />
+      <stop
+         style="stop-color: rgb(0, 0, 0); stop-opacity: 0;"
+         offset="1"
+         id="stop3260" />
+    </linearGradient>
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3256"
+       id="radialGradient3262"
+       cx="25.455845"
+       cy="39.161163"
+       fx="25.455845"
+       fy="39.161163"
+       r="19.622213"
+       gradientTransform="matrix(1, 0, 0, 0.315315, 0, 26.813)"
+       gradientUnits="userSpaceOnUse" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3264"
+       id="linearGradient3281"
+       gradientUnits="userSpaceOnUse"
+       x1="14.462892"
+       y1="12.284524"
+       x2="34.534348"
+       y2="39.684914"
+       gradientTransform="matrix(1.24194, 0, 0, 1.24194, -5.02751, -7.20899)" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3264"
+       id="linearGradient3291"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(1.2419415,0,0,1.241848,-5.0275463,-7.1988722)"
+       x1="14.462892"
+       y1="12.284524"
+       x2="34.534348"
+       y2="39.684914" />
+  </defs>
+  <sodipodi:namedview
+     stroke="#ef2929"
+     fill="#eeeeec"
+     id="base"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="0.25490196"
+     inkscape:pageopacity="0.0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="8"
+     inkscape:cx="40.773744"
+     inkscape:cy="23.823982"
+     inkscape:current-layer="layer1"
+     showgrid="false"
+     inkscape:grid-bbox="true"
+     inkscape:document-units="px"
+     inkscape:showpageshadow="false"
+     inkscape:window-width="1555"
+     inkscape:window-height="1025"
+     inkscape:window-x="133"
+     inkscape:window-y="104"
+     inkscape:snap-global="false">
+    <inkscape:grid
+       type="xygrid"
+       id="grid3176" />
+  </sodipodi:namedview>
+  <metadata
+     id="metadata4">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:creator>
+          <cc:Agent>
+            <dc:title>Jakub Steiner</dc:title>
+          </cc:Agent>
+        </dc:creator>
+        <dc:source>http://jimmac.musichall.cz</dc:source>
+        <cc:license
+           rdf:resource="http://creativecommons.org/licenses/by-sa/2.0/" />
+        <dc:title>Emblem System</dc:title>
+        <dc:subject>
+          <rdf:Bag>
+            <rdf:li>emblem</rdf:li>
+            <rdf:li>system</rdf:li>
+            <rdf:li>library</rdf:li>
+            <rdf:li>crucial</rdf:li>
+            <rdf:li>base</rdf:li>
+          </rdf:Bag>
+        </dc:subject>
+      </cc:Work>
+      <cc:License
+         rdf:about="http://creativecommons.org/licenses/by-sa/2.0/">
+        <cc:permits
+           rdf:resource="http://web.resource.org/cc/Reproduction" />
+        <cc:permits
+           rdf:resource="http://web.resource.org/cc/Distribution" />
+        <cc:requires
+           rdf:resource="http://web.resource.org/cc/Notice" />
+        <cc:requires
+           rdf:resource="http://web.resource.org/cc/Attribution" />
+        <cc:permits
+           rdf:resource="http://web.resource.org/cc/DerivativeWorks" />
+        <cc:requires
+           rdf:resource="http://web.resource.org/cc/ShareAlike" />
+      </cc:License>
+    </rdf:RDF>
+  </metadata>
+  <g
+     id="layer1"
+     inkscape:label="Layer 1"
+     inkscape:groupmode="layer">
+    <path
+       style="opacity:1;fill:url(#linearGradient3291);fill-opacity:1;fill-rule:nonzero;stroke:#36556b;stroke-width:1.6;stroke-linecap:butt;stroke-linejoin:miter;marker:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
+       d="M 23.249999,0.4782989 C 22.784559,0.51014282 22.332163,0.58222588 21.874997,0.63453732 L 21.843747,0.63453732 L 20.749995,6.6028448 C 18.967268,7.0088046 17.290082,7.6977551 15.781239,8.6339442 L 10.874983,5.102956 C 9.5486934,6.1325702 8.3417817,7.3333859 7.2812288,8.6339442 L 10.687483,13.602326 C 9.6532488,15.182724 8.8755125,16.987299 8.4374802,18.883184 C 8.4374052,18.892147 8.4374193,18.91287 8.4374802,18.914432 L 2.4999729,19.851862 C 2.3914194,20.73843 2.3437227,21.654668 2.3437227,22.570411 C 2.3437228,23.319655 2.3644121,24.058889 2.4374728,24.788996 L 8.3749801,25.851418 C 8.7972597,27.913157 9.5994404,29.838634 10.718733,31.538496 L 7.1874787,36.381887 C 8.198806,37.637312 9.3663731,38.780325 10.624983,39.787884 L 15.624989,36.350639 C 17.372424,37.465273 19.323077,38.246872 21.437496,38.63172 L 22.374997,44.537532 C 23.041181,44.598166 23.724348,44.600027 24.40625,44.600027 C 25.368936,44.600026 26.288489,44.563547 27.218753,44.443789 L 28.343755,38.412986 C 30.351318,37.913422 32.237229,37.046797 33.875012,35.881924 L 38.687518,39.381664 C 39.935547,38.319946 41.076798,37.099577 42.062522,35.788181 L 38.562518,30.726056 C 39.510372,29.089187 40.167149,27.28317 40.50002,25.351455 L 46.406277,24.414024 C 46.458071,23.797724 46.468777,23.200027 46.468777,22.570411 C 46.468777,21.476278 46.341595,20.403487 46.187527,19.351899 L 40.18752,18.258231 C 39.717325,16.522135 38.945842,14.902377 37.968767,13.446087 L 41.500021,8.6026965 C 40.405447,7.2641886 39.15684,6.0277062 37.781267,4.9779653 L 32.68751,8.4777058 C 31.223512,7.6119326 29.648043,6.9476371 27.937504,6.5715971 L 27.000003,0.63453732 C 26.146703,0.53416937 25.28638,0.4782989 24.40625,0.4782989 C 24.168378,0.47829891 23.923565,0.47081486 23.687499,0.4782989 C 23.572416,0.48194744 23.458533,0.4716045 23.343749,0.4782989 C 23.312661,0.48011197 23.281028,0.47617597 23.249999,0.4782989 z M 24.0625,15.664673 C 24.176666,15.65888 24.290652,15.664673 24.40625,15.664673 C 28.105382,15.664673 31.125008,18.684073 31.125008,22.382925 C 31.125009,26.081776 28.105381,29.069929 24.40625,29.069929 C 20.70712,29.06993 17.718742,26.081776 17.718742,22.382925 C 17.718743,18.799663 20.523345,15.844252 24.0625,15.664673 z"
+       id="path3243" />
+    <path
+       id="path3285"
+       d="M 22.557788,1.6501132 L 21.679599,7.4291233 C 20.008601,7.8096689 16.934874,8.9735344 15.520595,9.8511162 L 10.848562,6.3639293 C 9.6053938,7.3290873 9.5201391,7.3945394 8.5260544,8.6136804 L 11.904107,13.623634 C 10.934692,15.105095 9.7703031,17.745129 9.3522336,19.631722 C 9.3522336,19.631722 3.4328248,20.629563 3.4328248,20.629563 C 3.3310749,21.460629 3.3799751,23.239361 3.4484569,23.923761 L 9.1027005,24.942349 C 9.4985145,26.875018 10.979731,29.985937 12.028874,31.579383 L 8.4532981,36.303427 C 9.4012426,37.480259 9.5909623,37.587948 10.770691,38.532432 L 15.551859,35.029612 C 17.189777,36.074467 20.440892,37.345498 22.422794,37.706253 L 23.207481,43.412507 C 23.831913,43.469346 25.556962,43.628788 26.428924,43.516527 L 27.307112,37.576373 C 29.188855,37.108084 32.440272,35.773413 33.97541,34.681463 L 38.751465,38.132271 C 39.921276,37.13702 39.931757,36.987055 40.855703,35.757755 L 37.316505,30.727054 C 38.204954,29.192656 39.353733,26.191831 39.665742,24.381045 L 45.460384,23.419582 C 45.508931,22.841863 45.511294,21.230793 45.366882,20.245037 L 39.463105,19.226449 C 39.022378,17.599038 37.509894,14.666467 36.594056,13.301345 L 40.346408,8.5773019 C 39.320436,7.3225876 38.938964,7.150431 37.649602,6.1664065 L 32.707289,9.7056032 C 31.335043,8.8940304 28.598675,7.6568558 26.995341,7.3043568 L 26.122266,1.6501132 C 25.322445,1.5560285 23.014871,1.5978075 22.557788,1.6501132 z"
+       style="overflow:visible;marker:none;opacity:0.34659099999999998;color:rgb(0, 0, 0);fill:none;fill-opacity:1;fill-rule:nonzero;stroke:#365000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0pt;stroke-opacity:0;visibility:visible;display:inline"
+       sodipodi:nodetypes="ccccccccccccccccccccccccccccccccc" />
+    <path
+       sodipodi:type="arc"
+       style="opacity:0.64772704;fill:none;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:2.47313356;stroke-linecap:butt;stroke-linejoin:miter;marker:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
+       id="path3283"
+       sodipodi:cx="23.511301"
+       sodipodi:cy="23.781593"
+       sodipodi:rx="12.727922"
+       sodipodi:ry="12.727922"
+       d="M 36.239223,23.781593 A 12.727922,12.727922 0 1 1 10.783379,23.781593 A 12.727922,12.727922 0 1 1 36.239223,23.781593 z"
+       transform="matrix(0.6516355,0,0,0.6520284,9.0841979,6.8678522)" />
+  </g>
+</svg>
diff --git a/data/sunpinyin_logo.xpm b/data/sunpinyin_logo.xpm
new file mode 100644 (file)
index 0000000..e3c7cb6
--- /dev/null
@@ -0,0 +1,26 @@
+/* XPM */
+static char * sunpinyin_logo_xpm[] = {
+"18 18 5 1",
+"      c None",
+".     c #0000E0",
+"+     c #000000",
+"@     c #FF0000",
+"#     c #FFFF00",
+"                  ",
+" .......  . . ... ",
+" .        . . . . ",
+" .......  . . . . ",
+"  ++++++ +++. +++ ",
+" +@@@@@@+###++### ",
+"  +@@++@@+##++##+ ",
+" .+@@++@@++##+#+. ",
+"  +@@++@@++###+   ",
+"  +@@@@@+  +##+   ",
+" .+@@+++  .+##+.. ",
+" .+@@++.  .+##+   ",
+" +@@@@@+  +####+. ",
+" .+++++.   ++++   ",
+" . . . .  ....... ",
+" . . . .        . ",
+" ... . .  ....... ",
+"                  "};
diff --git a/doc/AuxRequire.txt b/doc/AuxRequire.txt
new file mode 100644 (file)
index 0000000..8c4484c
--- /dev/null
@@ -0,0 +1,53 @@
+1. Status Bar Aux Window
+  1.1 Easy setting up buttons:
+      a) Buttons and their images, orders.
+      b) Buttons and their status
+      c) Buttons and their Events or Actions
+
+  1.2 Menus
+      a) easy to define menu - submenu
+      b) menu item and their items
+
+  1.3 Style: user define or predefined good look and feel.
+
+2. Preedit Area 
+  2.1 Following the cursor position of (im client).
+  2.2 Preedit Area Data transfer:
+       1. nChar
+        2. Cursor Char Index. [0-nChar]
+        3. char* to UTF-8 char buf. (nChar, zero terminated)
+        4. void* to decoration[nChar+1]
+  2.3 Preedit Area window could stick with Status window.
+        +---------------------+--------------+
+        |  Preedit            |  Status      |
+        +---------------------+--------------+
+  2.4 Preedit Window style:
+        1. font, color, background image, etc.
+
+3. Candidate Area
+   3.1 Could following the cursor position of the preedit area or sticky with the Preedit Area:
+        following cursor:    +-----------------------------------+
+                             |        !                          |
+                             +-----------------------------------+
+                                      +-------------------------------------+
+                                      |   Candidates                        | (Candidates area could be vertical)
+                                      +-------------------------------------+
+        sticky               +-----------------------+---------+
+                             | Preedit               | Status  |  (Status area is optional)
+                             +-----------------------+---------+
+                             | Candidates                      |
+                             +---------------------------------+
+   3.2 Candidate data API.
+        1. nCandidate
+        2. pointer to nCandidate of :
+              a). nChar
+              b). char * to UTF8 string
+              c). void * to decoration array.
+
+   3.3 Candidate window style
+        font, color, background image, etc.
+
+4. CLE option for IME to tell it using new Aux windows
+        How could it works ?  Need Ervin to design it out.
+
+
diff --git a/doc/README b/doc/README
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/doc/genpyt.pod b/doc/genpyt.pod
new file mode 100644 (file)
index 0000000..11abfcf
--- /dev/null
@@ -0,0 +1,52 @@
+=head1 NAME
+
+genpyt - generate the PINYIN lexicon
+
+=head1 SYNOPSIS
+
+B<genpyt> I<lexicon-file> I<result-file> I<log-file> I<slm-file>
+
+=head1 DESCRIPTION
+
+B<genpyt> is used to generate the PINYIN lexicon. 
+It only works on zh_CN.UTF-8 locale.
+
+=head1 ARGUMENTS
+
+=over 4
+
+=item I<lexicon-file>
+
+Specify a dictionary file. It should be a line-based text file in utf-8 encoding
+. Each line looks like:
+
+   CCC  id  [pinyin'pinyin'pinyin]*
+
+A default dictionary file can be found at F</usr/share/sunpinyin/dict.utf8>.
+
+
+=item I<result-file>
+
+The output binary PINYIN lexicon file. This lexicon contains a trie presenting the key tree of PINYIN. And all of the candiate words are sorted using the unigram in I<slm-file>. This file can be used with sunpinyin input method engines.
+
+
+=item I<log-file>
+
+Specify the file to where the log goes. The I<log-file> can be seen as the human-readble presentation of the binary output file.
+
+
+=item I<slm-file>
+
+The language model from which the unigram information are retrieved. Typically, the I<slm-file> is generated by B<slmthread>.
+
+=back
+
+=head1 AUTHOR
+
+Originally written by Phill.Zhang E<lt>phill.zhang@sun.comE<gt>.
+Currently maintained by Kov.Chai E<lt>tchaikov@gmail.comE<gt>.
+
+=head1 SEE ALSO
+
+B<slmthread>(1).
+
diff --git a/doc/getWordFreq.pod b/doc/getWordFreq.pod
new file mode 100644 (file)
index 0000000..228b64f
--- /dev/null
@@ -0,0 +1,50 @@
+=head1 NAME
+
+getWordFreq - print word freq information from language model
+
+=head1 SYNOPSIS
+
+B<getWordFreq> [I<option>]... B<-m> I<slm-file> B<-l> I<lexicon>
+
+=head1 DESCRIPTION
+
+B<getWordFreq> prints out the word string and its freq of all words in a language model.
+
+=head1 OPTIONS
+
+=over 4
+
+=item B<-s> I<corpus-size>
+Specify the training corpus's size. The default I<corpus-size> is 300000000 if not given.
+
+
+=item B<-v>
+
+Be verbose, output other information after word and freq for each line.
+
+
+=item B<-e>
+
+Give format for ervin.
+
+
+=item B<-m> I<slm-file>
+
+Specify language model file.
+
+
+=item B<-l> I<lexicon>
+
+Specify the lexicon file. A default lexicon could be found at F</usr/share/sunpinyin-slm/dict.utf8>.
+
+=back
+
+=head1 AUTHOR
+
+Originally written by Phill.Zhang E<lt>phill.zhang@sun.comE<gt>.
+Currently maintained by Kov.Chai E<lt>tchaikov@gmail.comE<gt>.
+
+=head1 SEE ALSO
+
+B<slmthread>(1).
+
diff --git a/doc/idngram_merge.pod b/doc/idngram_merge.pod
new file mode 100644 (file)
index 0000000..c3812cc
--- /dev/null
@@ -0,0 +1,47 @@
+=head1 NAME
+
+idngram_merge - merge idngram file into one
+
+=head1 SYNOPSIS
+
+B<idngram_merge> [I<option>]... I<idngram_file>...
+
+=head1 DESCRIPTION
+
+B<idngram_merge> merge multiple idngram file, each of them are sorted
+[id1,...,idN,freq] array, into one idngram file. For those id1..idN which 
+appear in more than one files, only one item will appear in the final file, 
+and its freq are summed. The idngram files are original generated by 
+B<ids2ngram>.
+
+=head1 OPTIONS
+All the following options are mandatory.
+
+=over 4
+
+=item B<-n>, B<--NMax> I<N>
+
+Specify the N-gram of source data file.
+
+=item B<-o>, B<--out> I<output-file>
+
+Specifiy the final merged idngram file.
+
+=back
+
+
+=head1 EXAMPLE
+
+Following example merge 2 id3gram files into a large one:
+
+    B<idngram_merge -n3 -o all.id3gram first.id3gram second.id3gram>
+
+=head1 AUTHOR
+
+Originally written by Phill.Zhang E<lt>phill.zhang@sun.comE<gt>.
+Currently maintained by Kov.Chai E<lt>tchaikov@gmail.comE<gt>.
+
+=head1 SEE ALSO
+
+B<ids2ngram>(1).
+
diff --git a/doc/ids2ngram.pod b/doc/ids2ngram.pod
new file mode 100644 (file)
index 0000000..0de7870
--- /dev/null
@@ -0,0 +1,60 @@
+=head1 NAME
+
+ids2ngram - generate n-gram data file from ids file
+
+=head1 SYNOPSIS
+
+ids2ngram [I<option>]... I<ids_file>...
+
+=head1 DESCRIPTION
+
+B<ids2ngram> generates idngram file, which is a sorted [id1,..,idN,freq] array, from binary id stream files. Here, the id stream files are always generated by B<mmseg> or B<slmseg>. Basically, it finds all occurrence of n-words tuples (i.e. the tuple of (id1,..,idN)), and sorts these tuples by the lexicographic order of the ids make up the tuples, then write them to specified output file.
+
+=head1 INPUT
+
+The input file is presented as a binary id stream, which looks like:
+    [id0,...,idX]
+
+=head1 OPTIONS
+
+All the following options are mandatory.
+
+=over 4
+
+=item B<-n>,B<--NMax> I<N>
+
+Generates I<N>-gram result. B<ids2ngram> does only support uni-gram, bi-gram, and trigram, so any number not in the range of 1..3 is not valid.
+
+=item B<-s>,B<--swap> I<swap-file>
+
+Specify the temporary intermediate file.
+
+
+=item B<-o>, B<--out> I<output-file>
+
+Specify the result idngram file, e.g. the array of [id1, ..., idN, freq]
+
+
+=item B<-p>, B<--para> I<N>
+
+Specify the maximum n-gram items per paragraph. B<ids2ngram> writes to the temporary file on a per-paragraph basis. Every time it writes a paragraph out, it frees the corresponding memory allocated for it. When your computer system permits, a higher I<N> is suggested. This can speed up the processing speed because of less I/O.
+
+
+=back
+
+
+=head1 EXAMPLE
+
+Following example will use three input idstream file idsfile[1,2,3] to generate the idngram file all.id3gram. Each para (internal map size or hash size) would be 1024000, using swap file for temp result. All temp para result would eventually be merged to got the final result.
+
+B<ids2ngram -n 3 -s /tmp/swap -o all.id3gram -p 1024000 idsfile1 idsfile2 idsfile3>
+
+=head1 AUTHOR
+
+Originally written by Phill.Zhang E<lt>phill.zhang@sun.comE<gt>.
+Currently maintained by Kov.Chai E<lt>tchaikov@gmail.comE<gt>.
+
+=head1 SEE ALSO
+
+B<mmseg>(1), B<slmseg>(1), B<slmbuild> (1).
+
diff --git a/doc/mmseg.pod b/doc/mmseg.pod
new file mode 100644 (file)
index 0000000..7051a6d
--- /dev/null
@@ -0,0 +1,64 @@
+=head1 NAME
+
+mmseg - maximum matching segment Chinese text.
+
+=head1 SYNOPSIS
+
+B<mmseg> -d I<dict_file> [I<option>]... [I<corpus_file>]...
+
+=head1 DESCRIPTION
+
+B<mmseg> is a tool for segmenting Chinese text into words using maximum matching algorithm. B<mmseg> segments I<corpus_file>, or standard input if no filename is specified, and write the segmented result to standard output.
+
+
+=head1 OPTIONS
+
+=over 4
+
+=item B<-d> I<dict_file>
+
+Use I<dict_file> as lexicon. A default lexicon can be found at F</usr/share/sunpinyin-slm/dict.utf8>.
+
+
+=item B<-f>,B<--format> (B<text>|B<bin>)
+
+Output Format, can be 'text' or 'bin'. default 'bin'.
+Normally, in text mode, word text are output, while in binary mode,
+binary short integer of the word-ids are written to stdout.
+
+
+=item B<-s>, B<--stok> I<STOK_ID>
+
+Sentence token id. Default 10.
+It will be written to output in binary mode after every sentence.
+
+
+=item B<-i>, B<--show-id>
+
+Show Id info. Under text output format mode, attach id after known words. 
+If under binary mode, print id(s) in text.
+
+
+=item B<-a>, B<--ambiguious-id> I<AMBI-ID>
+
+Ambiguious means I<ABC> => I<A> I<BC> or I<AB> I<C>. If specified (I<AMBI-ID> != 0), 
+The sequence I<ABC> will not be segmented, in binary mode, the I<AMBI-ID> is written out; in text mode, C<E<lt>ambiE<gt>ABCE<lt>/ambiE<gt>> will be output. Default is 0.
+
+
+=back
+
+
+=head1 NOTES
+
+Under B<binary> mode, consecutive id of 0 are merged into one 0.
+Under B<text> mode, no space are inserted between unknown-words. 
+
+=head1 AUTHOR
+
+Originally written by Phill.Zhang E<lt>phill.zhang@sun.comE<gt>.
+Currently maintained by Kov.Chai E<lt>tchaikov@gmail.comE<gt>.
+
+=head1 SEE ALSO
+
+B<slmseg>(1), B<ids2ngram> (1).
+
diff --git a/doc/slmbuild.pod b/doc/slmbuild.pod
new file mode 100644 (file)
index 0000000..2609590
--- /dev/null
@@ -0,0 +1,108 @@
+=head1 NAME
+
+slmbuild - generate language model from idngram file
+
+=head1 SYNOPSIS
+
+slmbuild [I<option>]... I<idngram_file>...
+
+=head1 DESCRIPTION
+
+B<slmbuild> generates a back-off smoothing language model from a given idngram file. Generally, the I<idngram_file> is created by B<ids2ngram>.
+
+
+=head1 OPTIONS
+All the following options are mandatory.
+
+=over 4
+
+=item B<-n>,B<--NMax> I<N>
+
+1 for unigram, 2 for bigram, 3 for trigram. Any number not in the range of 1..3 is not valid.
+
+
+=item B<-o>, B<--out> I<output-file>
+
+Specify the output xfilei name.
+
+
+=item B<-l>, B<--log>
+
+using I<-log(pr)>, use I<pr> directly by default.
+
+
+=item B<-w>, B<--wordcount> I<N>
+
+Lexican size, number of different words.
+
+
+=item B<-b>, B<--brk> I<id>...
+
+Set the ids which should be treated as breaker.
+
+
+=item B<-e>, B<--e> I<id>...
+
+Set the ids which should not be put into LM.
+
+
+=item B<-c>, B<--cut> I<c>...
+
+k-grams whose freq <= c[k] are dropped.
+
+
+=item B<-d>, B<--discount> I<method>, I<param>...
+
+The k-th B<-d> parm specifies the discount method
+
+For k-gram, possibble values for method/param are:
+
+      B<GT>,I<R>,I<dis>  : B<GT> discount for r E<lt>= I<R>, r is the freq of a ngram.
+                  Linear discount for those r E<gt> I<R>, i.e. r'=r*dis
+                  0 E<lt>E<lt> dis E<lt> 1.0, for example 0.999 
+      B<ABS>,[I<dis>] : Absolute discount r'=r-I<dis>. And I<dis> is optional
+                  0 E<lt>E<lt> I<dis> E<lt> cut[k]+1.0, normally I<dis> E<lt> 1.0.
+      LIN,[I<dis>] : Linear discount r'=r*dis. And dis is optional
+                  0 E<lt> dis E<lt> 1.0
+
+=back
+
+
+=head1 NOTE
+
+B<-n> must be given before B<-c> B<-b>. And B<-c> must give right number of cut-off,
+also B<-d>s must appear exactly N times specifying the discounts for 1-gram, 2-gram..., 
+respectively.
+
+BREAKER-IDs could be SentenceTokens or ParagraphTokens. Conceptually,
+these ids have no meaning when they appeared in the middle of n-gram.
+
+EXCLUDE-IDs could be ambiguious-ids. Conceptually, n-grams which
+contain those ids are meaningless.
+
+We can not erase ngrams according to BREAKER-IDS and EXCLUDE-IDs directly
+from IDNGRAM file, because some low-level information is still useful in it.
+
+
+=head1 EXAMPLE
+
+Following example read 'all.id3gram' and write trigram model 'all.slm'.
+
+At 1-gram level, use Good-Turing discount with cut-off 0, i<R>=8, I<dis>=0.9995. At
+2-gram level, use Absolute discount with cut-off 3, dis auto-calc. At 3-gram
+level, use Absolute discount with cut-off 2, dis auto-calc. Word id 10,11,12
+are breakers (sentence/para/paper breaker, etc). Exclude-ID is 9. Lexicon 
+contains 200000 words. The result languagme model uses -log(pr).
+
+B<slmbuild -l -n 3 -o all.slm -w 200000 -c 0,3,2 -d GT,8,0.9995 -d ABS -d ABS -b 10,11,12 -e 9 all.id3gram>
+
+
+=head1 AUTHOR
+
+Originally written by Phill.Zhang E<lt>phill.zhang@sun.comE<gt>.
+Currently maintained by Kov.Chai E<lt>tchaikov@gmail.comE<gt>.
+
+=head1 SEE ALSO
+
+B<ids2ngram>(1), B<slmprune>(1).
+
diff --git a/doc/slminfo.pod b/doc/slminfo.pod
new file mode 100644 (file)
index 0000000..2c1f787
--- /dev/null
@@ -0,0 +1,44 @@
+=head1 NAME
+
+slminfo - get information of a back-off language model
+
+=head1 SYNOPSIS
+
+B<slminfo> [I<option>]... I<slm_file>
+
+=head1 DESCRIPTION
+
+B<slminfo> tells information of back-off language model 'I<slm_file>'. It can 
+also print the model to ARPA format.
+When no option is given, slminfo will only print number of items in each level 
+of the language model.
+
+=head1 OPTIONS
+
+=over 4
+
+=item B<-v>,B<--verbose>
+
+Turn on verbose mode, printing arpa format.
+
+
+=item B<-p>,B<--pr>
+
+Prefer normal probability than -log(Pr) which is default. Valid under B<-v> option.
+
+
+=item B<-l>,B<--lexicon> I<dict_file>
+
+Specify the lexicon. Valid under B<-v> option. Substitute the word-id with word-text in the output.
+
+=back
+
+=head1 AUTHOR
+
+Originally written by Phill.Zhang E<lt>phill.zhang@sun.comE<gt>.
+Currently maintained by Kov.Chai E<lt>tchaikov@gmail.comE<gt>.
+
+=head1 SEE ALSO
+
+B<slmprune>(1).
+
diff --git a/doc/slmprune.pod b/doc/slmprune.pod
new file mode 100644 (file)
index 0000000..2cbae9b
--- /dev/null
@@ -0,0 +1,40 @@
+=head1 NAME
+
+slmprune - prune the back-off language model to a reasonable size
+
+=head1 SYNOPSIS
+
+B<slmprune> I<input_slm> I<result_slm> I<cut_option> I<num>...
+
+=head1 DESCRIPTION
+
+This program uses entropy-based method to prune the size of back-off 
+language model 'I<input_slm>' to a specific size and write to 'I<result_slm>'. 
+
+the third parameter I<cut_option> can be [B<R>|B<C>]. It means the following numbers is the number for
+(B<R>)eserve or (B<C>)ut. If (B<C>)ut, the num[k] means how many items in level K
+would be cut. If (B<R>)eserve, num[k] means how many item would be reserved
+in level k. 
+
+Note that we do not ensure that during pruning process,  exactly the
+the given number of items are cut or reserved, because some items may 
+contains high level children, so could not be cut. 
+
+Also it's your responsiblity to give right number of arguments based
+on 'input_slm'.
+
+
+=head1 NOTE
+
+To get information of the back-off language model, try 'B<slminfo>'.
+
+
+=head1 AUTHOR
+
+Originally written by Phill.Zhang E<lt>phill.zhang@sun.comE<gt>.
+Currently maintained by Kov.Chai E<lt>tchaikov@gmail.comE<gt>.
+
+=head1 SEE ALSO
+
+B<slminfo>(1), B<slmthread>(1).
+
diff --git a/doc/slmseg.pod b/doc/slmseg.pod
new file mode 100644 (file)
index 0000000..77c8dbc
--- /dev/null
@@ -0,0 +1,61 @@
+=head1 NAME
+
+slmseg - maximum matching segment Chinese text.
+
+=head1 SYNOPSIS
+
+B<slmseg> -d I<dict_file> [I<option>]... [I<corpus_file>]...
+
+=head1 DESCRIPTION
+
+B<slmseg> is a tool for segmenting Chinese text into words using maximum matching algorithm. B<slmseg> segments I<corpus_file>, or standard input if no filename is specified, and write the segmented result to standard output.
+
+
+=head1 OPTIONS
+
+=over 4
+
+=item B<-d> I<dict_file>
+
+Use I<dict_file> as lexicon. A default lexicon can be found at F</usr/share/sunpinyin-slm/dict.utf8>.
+
+
+=item B<-f>,B<--format> (B<text>|B<bin>)
+
+Output Format, can be 'text' or 'bin'. default 'bin'.
+Normally, in text mode, word text are output, while in binary mode,
+binary short integer of the word-ids are written to stdout.
+
+
+=item B<-s>, B<--stok> I<STOK_ID>
+
+Sentence token id. Default 10.
+It will be written to output in binary mode after every sentence.
+
+
+=item B<-i>, B<--show-id>
+
+Show Id info. Under text output format mode, attach id after known words. 
+If under binary mode, print id(s) in text.
+
+
+=item B<-m>, B<--model> I<language-model-file>
+Speficy the language model file. This file is always generated by B<slmthread>.
+
+=back
+
+
+=head1 NOTES
+
+Under B<binary> mode, consecutive id of 0 are merged into one 0.
+Under B<text> mode, no space are inserted between unknown-words. 
+
+=head1 AUTHOR
+
+Originally written by Phill.Zhang E<lt>phill.zhang@sun.comE<gt>.
+Currently maintained by Kov.Chai E<lt>tchaikov@gmail.comE<gt>.
+
+=head1 SEE ALSO
+
+B<mmseg>(1), B<ids2ngram> (1).
+
diff --git a/doc/slmthread.pod b/doc/slmthread.pod
new file mode 100644 (file)
index 0000000..f316592
--- /dev/null
@@ -0,0 +1,27 @@
+=head1 NAME
+
+slmthread - threads the language model
+
+=head1 SYNOPSIS
+
+B<slmthread> I<primitive_slm> I<threaded_slm>
+
+=head1 DESCRIPTION
+
+B<slmthread> add back-off-state for each slm node in the I<primitive_slm>. 
+Also it compresses 32-bit float into 16 bit representation. These processing 
+speeds up the looking up.
+
+The I<primitive_slm> is always genreated by B<slmprune>. And 
+the I<threaded_slm> can be used to feed B<slmseg> as a reference to segment 
+Chinese text.
+
+=head1 AUTHOR
+
+Originally written by Phill.Zhang E<lt>phill.zhang@sun.comE<gt>.
+Currently maintained by Kov.Chai E<lt>tchaikov@gmail.comE<gt>.
+
+=head1 SEE ALSO
+
+B<slmprune>(1), B<slmseg>(1).
+
diff --git a/doc/tslmendian.pod b/doc/tslmendian.pod
new file mode 100644 (file)
index 0000000..c7a8a96
--- /dev/null
@@ -0,0 +1,50 @@
+=head1 NAME
+
+tslmendian - change the byte-order of sunpinyin's threaded back-off language model
+
+=head1 SYNOPSIS
+
+B<tslmendian> [I<option>]
+
+=head1 DESCRIPTION
+
+B<slmendian> converts the binary language model files used by SunPinyin from big-endian to small-endian or vice versa.
+
+=head1 OPTIONS
+
+=over 4
+
+=item B<-e> I<endian>
+
+Specify the I<output-lm-file>'s endian-ness. It can be B<le> or B<ge>. If not given, B<tslmendian> uses the host's endian-ness.
+
+=item B<-v>
+
+Prints out the endian-ness of B<input-lm-file>.
+
+=item B<-i> I<input-lm-file>
+
+Identify the input file of convert. Generally, this file is generated by B<slmthread> or B<tslmpack>.
+
+
+=item B<-o> I<out-lm-file>
+
+Identify the output file of convert.
+
+=back
+
+=head1 NOTES
+
+The converted output file is equivalent to the input. But if you compare the output of B<tslminfo> of both files, the ARPA file generated by B<tslminfo> may different. This is due to the different precision in different machines.
+
+And due to uninitialized padding data in data structure, the checksum of the original data file may different from the converted-back file, even though they are identical from SunPinyin's point of view.
+
+=head1 AUTHOR
+
+Originally written by Kov. Chai E<lt>tchaikov.gmail.comE<gt>.
+Currently maintained by Kov.Chai E<lt>tchaikov@gmail.comE<gt>.
+
+=head1 SEE ALSO
+
+B<slmthread>(1). B<tslminfo>, B<tslmpack>.
+
diff --git a/doc/tslminfo.pod b/doc/tslminfo.pod
new file mode 100644 (file)
index 0000000..9ea7f68
--- /dev/null
@@ -0,0 +1,43 @@
+=head1 NAME
+
+tslminfo - get information of a threaded back-off language model
+
+=head1 SYNOPSIS
+
+B<tslminfo> [I<option>]... I<threaded_slm_file>
+
+=head1 DESCRIPTION
+
+B<slminfo> tells information of back-off language model 'I<threaded_slm_file>'. It can also print the model to ARPA format.
+When no option is given, slminfo will only print number of items in each level 
+of the language model.
+
+=head1 OPTIONS
+
+=over 4
+
+=item B<-v>,B<--verbose>
+
+Turn on verbose mode, printing arpa format.
+
+
+=item B<-p>,B<--pr>
+
+Prefer normal probability than -log(Pr) which is default. Valid under B<-v> option.
+
+
+=item B<-l>,B<--lexicon> I<dict_file>
+
+Specify the lexicon. Valid under B<-v> option. Substitute the word-id with word-text in the output.
+
+=back
+
+=head1 AUTHOR
+
+Originally written by Phill.Zhang E<lt>phill.zhang@sun.comE<gt>.
+Currently maintained by Kov.Chai E<lt>tchaikov@gmail.comE<gt>.
+
+=head1 SEE ALSO
+
+B<slminfo>(1).
+
diff --git a/doc/tslmpack.pod b/doc/tslmpack.pod
new file mode 100644 (file)
index 0000000..639f2f8
--- /dev/null
@@ -0,0 +1,31 @@
+=head1 NAME
+
+tslmpack - convert the ARPA format of SunPinyin back-off language model to its binary representation
+
+=head1 SYNOPSIS
+
+B<tslmpack> I<arpa_file> I<dict_file> I<binary_slm_file>
+
+=head1 DESCRIPTION
+
+B<tslmpack> converts the ARPA format of a threaded SunPinyin back-off
+language model to its binary representation.
+
+=head1 NOTE
+
+If you convert a language model to ARPA format using B<tslminfo>, and
+then convert it back using B<tslmpack>, the check-sum of generated
+binary file may be different from that of the original one. The reason
+is the padding bits in the n-gram instances are not initialized before 
+writing the data out.
+
+
+=head1 AUTHOR
+
+Originally written by Kov.Chai E<lt>tchaikov@gmail.comE<gt>.
+Currently maintained by Kov.Chai E<lt>tchaikov@gmail.comE<gt>.
+
+=head1 SEE ALSO
+
+B<tslminfo>(1).
+
diff --git a/m4/Makefile.am b/m4/Makefile.am
new file mode 100755 (executable)
index 0000000..602fdbb
--- /dev/null
@@ -0,0 +1,3 @@
+MAINTAINERCLEANFILES   = Makefile.in
+
+EXTRA_DIST = codeset.m4 gettext.m4 glibc21.m4 iconv.m4 intdiv0.m4 intmax.m4 inttypes.m4 inttypes_h.m4 inttypes-pri.m4 isc-posix.m4 lcmessage.m4 lib-ld.m4 lib-link.m4 lib-prefix.m4 longdouble.m4 longlong.m4 nls.m4 po.m4 printf-posix.m4 progtest.m4 signed.m4 size_max.m4 stdint_h.m4 uintmax_t.m4 ulonglong.m4 wchar_t.m4 wint_t.m4 xsize.m4 intltool.m4
diff --git a/mkinstalldirs b/mkinstalldirs
new file mode 100755 (executable)
index 0000000..6fbe5e1
--- /dev/null
@@ -0,0 +1,150 @@
+#! /bin/sh
+# mkinstalldirs --- make directory hierarchy
+
+scriptversion=2004-02-15.20
+
+# Original author: Noah Friedman <friedman@prep.ai.mit.edu>
+# Created: 1993-05-16
+# Public domain.
+#
+# This file is maintained in Automake, please report
+# bugs to <bug-automake@gnu.org> or send patches to
+# <automake-patches@gnu.org>.
+
+errstatus=0
+dirmode=""
+
+usage="\
+Usage: mkinstalldirs [-h] [--help] [--version] [-m MODE] DIR ...
+
+Create each directory DIR (with mode MODE, if specified), including all
+leading file name components.
+
+Report bugs to <bug-automake@gnu.org>."
+
+# process command line arguments
+while test $# -gt 0 ; do
+  case $1 in
+    -h | --help | --h*)         # -h for help
+      echo "$usage"
+      exit 0
+      ;;
+    -m)                         # -m PERM arg
+      shift
+      test $# -eq 0 && { echo "$usage" 1>&2; exit 1; }
+      dirmode=$1
+      shift
+      ;;
+    --version)
+      echo "$0 $scriptversion"
+      exit 0
+      ;;
+    --)                         # stop option processing
+      shift
+      break
+      ;;
+    -*)                         # unknown option
+      echo "$usage" 1>&2
+      exit 1
+      ;;
+    *)                          # first non-opt arg
+      break
+      ;;
+  esac
+done
+
+for file
+do
+  if test -d "$file"; then
+    shift
+  else
+    break
+  fi
+done
+
+case $# in
+  0) exit 0 ;;
+esac
+
+# Solaris 8's mkdir -p isn't thread-safe.  If you mkdir -p a/b and
+# mkdir -p a/c at the same time, both will detect that a is missing,
+# one will create a, then the other will try to create a and die with
+# a "File exists" error.  This is a problem when calling mkinstalldirs
+# from a parallel make.  We use --version in the probe to restrict
+# ourselves to GNU mkdir, which is thread-safe.
+case $dirmode in
+  '')
+    if mkdir -p --version . >/dev/null 2>&1 && test ! -d ./--version; then
+      echo "mkdir -p -- $*"
+      exec mkdir -p -- "$@"
+    else
+      # On NextStep and OpenStep, the `mkdir' command does not
+      # recognize any option.  It will interpret all options as
+      # directories to create, and then abort because `.' already
+      # exists.
+      test -d ./-p && rmdir ./-p
+      test -d ./--version && rmdir ./--version
+    fi
+    ;;
+  *)
+    if mkdir -m "$dirmode" -p --version . >/dev/null 2>&1 &&
+       test ! -d ./--version; then
+      echo "mkdir -m $dirmode -p -- $*"
+      exec mkdir -m "$dirmode" -p -- "$@"
+    else
+      # Clean up after NextStep and OpenStep mkdir.
+      for d in ./-m ./-p ./--version "./$dirmode";
+      do
+        test -d $d && rmdir $d
+      done
+    fi
+    ;;
+esac
+
+for file
+do
+  set fnord `echo ":$file" | sed -ne 's/^:\//#/;s/^://;s/\// /g;s/^#/\//;p'`
+  shift
+
+  pathcomp=
+  for d
+  do
+    pathcomp="$pathcomp$d"
+    case $pathcomp in
+      -*) pathcomp=./$pathcomp ;;
+    esac
+
+    if test ! -d "$pathcomp"; then
+      echo "mkdir $pathcomp"
+
+      mkdir "$pathcomp" || lasterr=$?
+
+      if test ! -d "$pathcomp"; then
+       errstatus=$lasterr
+      else
+       if test ! -z "$dirmode"; then
+         echo "chmod $dirmode $pathcomp"
+         lasterr=""
+         chmod "$dirmode" "$pathcomp" || lasterr=$?
+
+         if test ! -z "$lasterr"; then
+           errstatus=$lasterr
+         fi
+       fi
+      fi
+    fi
+
+    pathcomp="$pathcomp/"
+  done
+done
+
+exit $errstatus
+
+# Local Variables:
+# mode: shell-script
+# sh-indentation: 2
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "scriptversion="
+# time-stamp-format: "%:y-%02m-%02d.%02H"
+# time-stamp-end: "$"
+# End:
diff --git a/packaging/sunpinyin.changes b/packaging/sunpinyin.changes
new file mode 100644 (file)
index 0000000..213a143
--- /dev/null
@@ -0,0 +1,6 @@
+* Thu Jan 31 2013 Li Zhang <li2012.zhang@samsung.com> accepted/tizen_2.0/20130123.093018@a110cbf
+- Always show candidate
+- [N_SE-12903][N_SE-12802]flush to commit the first candidate.
+- Modifed to install LICENSE information
+- Initial Release
+
diff --git a/packaging/sunpinyin.spec b/packaging/sunpinyin.spec
new file mode 100755 (executable)
index 0000000..8cfbdd5
--- /dev/null
@@ -0,0 +1,63 @@
+Name:       ise-engine-sunpinyin
+Summary:    Chinese Pinyin ISE
+Version:    0.0.1223
+Release:    1
+Group:      TO_BE/FILLED_IN
+License:    LGPLv2+
+Source0:    %{name}-%{version}.tar.gz
+BuildRequires:  prelink
+BuildRequires:  gettext-tools
+BuildRequires:  pkgconfig(isf)
+BuildRequires:  pkgconfig(glib-2.0)
+BuildRequires:  pkgconfig(sqlite3)
+Requires(post): /sbin/ldconfig
+Requires(postun): /sbin/ldconfig
+
+
+%description
+Chinese Pinyin Engine ISE and it has been supported by Input Service Framework(ISF).
+
+%package devel
+Summary:    ise-engine-sunpinyin header files
+Group:      Development/Libraries
+
+%description devel
+This package contains Chinese Pinyin engine ISE header files and static libraries for Soft ISE development.
+
+%prep
+%setup -q
+
+%build
+./bootstrap
+%configure  --disable-static
+make %{?jobs:-j%jobs}
+
+%install
+rm -rf %{buildroot}
+%make_install
+execstack -c %{buildroot}%{_libdir}/scim-1.0/1.4.0/IMEngine/ise-engine-sunpinyin.so
+mkdir -p %{buildroot}%{_datadir}/license
+install -m0644 %{_builddir}/%{buildsubdir}/LGPL.LICENSE %{buildroot}%{_datadir}/license/%{name}
+cat %{_builddir}/%{buildsubdir}/OPENSOLARIS.LICENSE >> %{buildroot}%{_datadir}/license/%{name}
+
+%define __debug_install_post   \
+    %{_rpmconfigdir}/find-debuginfo.sh %{?_find_debuginfo_opts} "%{_builddir}/%{?buildsubdir}"\
+%{nil}
+
+%post -p /sbin/ldconfig
+
+%postun -p /sbin/ldconfig
+
+%files
+%defattr(-,root,root,-)
+%{_datadir}/scim/icons/sunpinyin_logo.png
+%{_datadir}/locale/*
+%{_datadir}/scim/ise-engine-sunpinyin/*
+%{_libdir}/scim-1.0/1.4.0/IMEngine/ise-engine-sunpinyin.so
+%{_libdir}/libsunpinyin*.so
+%{_datadir}/license/%{name}
+
+%files devel
+%defattr(-,root,root,-)
+%{_includedir}/*
+%{_libdir}/pkgconfig/sunpinyin-2.0.pc
diff --git a/po/ChangeLog b/po/ChangeLog
new file mode 100755 (executable)
index 0000000..5c4094c
--- /dev/null
@@ -0,0 +1,11 @@
+2012-01-12  gettextize  <bug-gnu-gettext@gnu.org>
+
+       * Makefile.in.in: Upgrade to gettext-0.17.
+       * Rules-quot: New file, from gettext-0.17.
+       * boldquot.sed: New file, from gettext-0.17.
+       * en@boldquot.header: New file, from gettext-0.17.
+       * en@quot.header: New file, from gettext-0.17.
+       * insert-header.sin: New file, from gettext-0.17.
+       * quot.sed: New file, from gettext-0.17.
+       * remove-potcdate.sin: New file, from gettext-0.17.
+
diff --git a/po/Makefile.in.in b/po/Makefile.in.in
new file mode 100755 (executable)
index 0000000..5e2dafb
--- /dev/null
@@ -0,0 +1,256 @@
+# Makefile for program source directory in GNU NLS utilities package.
+# Copyright (C) 1995, 1996, 1997 by Ulrich Drepper <drepper@gnu.ai.mit.edu>
+#
+# This file file be copied and used freely without restrictions.  It can
+# be used in projects which are not available under the GNU Public License
+# but which still want to provide support for the GNU gettext functionality.
+# Please note that the actual code is *not* freely available.
+#
+# - Modified by Owen Taylor <otaylor@redhat.com> to use GETTEXT_PACKAGE
+#   instead of PACKAGE and to look for po2tbl in ./ not in intl/
+#
+# - Modified by jacob berkman <jacob@ximian.com> to install
+#   Makefile.in.in and po2tbl.sed.in for use with glib-gettextize
+
+GETTEXT_PACKAGE = @GETTEXT_PACKAGE@
+PACKAGE = @PACKAGE@
+VERSION = @VERSION@
+
+SHELL = /bin/sh
+@SET_MAKE@
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+top_builddir = ..
+VPATH = @srcdir@
+
+prefix = @prefix@
+exec_prefix = @exec_prefix@
+datadir = @datadir@
+libdir = @libdir@
+localedir = $(libdir)/locale
+gnulocaledir = $(datadir)/locale
+gettextsrcdir = $(datadir)/glib-2.0/gettext/po
+subdir = po
+install_sh = @install_sh@
+mkdir_p = @mkdir_p@
+mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
+
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+
+CC = @CC@
+GENCAT = @GENCAT@
+GMSGFMT = @GMSGFMT@
+MSGFMT = @MSGFMT@
+XGETTEXT = @XGETTEXT@
+INTLTOOL_UPDATE = @INTLTOOL_UPDATE@
+INTLTOOL_EXTRACT = @INTLTOOL_EXTRACT@
+MSGMERGE = INTLTOOL_EXTRACT=$(INTLTOOL_EXTRACT) srcdir=$(srcdir) $(INTLTOOL_UPDATE) --gettext-package $(GETTEXT_PACKAGE) --dist
+GENPOT   = INTLTOOL_EXTRACT=$(INTLTOOL_EXTRACT) srcdir=$(srcdir) $(INTLTOOL_UPDATE) --gettext-package $(GETTEXT_PACKAGE) --pot
+
+DEFS = @DEFS@
+CFLAGS = @CFLAGS@
+CPPFLAGS = @CPPFLAGS@
+
+INCLUDES = -I.. -I$(top_srcdir)/intl
+
+COMPILE = $(CC) -c $(DEFS) $(INCLUDES) $(CPPFLAGS) $(CFLAGS) $(XCFLAGS)
+
+SOURCES =
+POFILES = @POFILES@
+GMOFILES = @GMOFILES@
+DISTFILES = Makefile.in.in POTFILES.in \
+$(POFILES) $(GMOFILES) $(SOURCES)
+
+POTFILES = \
+
+CATALOGS = @CATALOGS@
+CATOBJEXT = @CATOBJEXT@
+INSTOBJEXT = @INSTOBJEXT@
+
+.SUFFIXES:
+.SUFFIXES: .c .o .po .pox .gmo .mo .msg .cat
+
+.c.o:
+       $(COMPILE) $<
+
+.po.pox:
+       $(MAKE) $(GETTEXT_PACKAGE).pot
+       $(MSGMERGE) $< $(top_builddir)/po/$(GETTEXT_PACKAGE).pot -o $*pox
+
+.po.mo:
+       $(MSGFMT) -o $@ $<
+
+.po.gmo:
+       file=`echo $* | sed 's,.*/,,'`.gmo \
+         && rm -f $$file && $(GMSGFMT) -o $$file $<
+
+.po.cat:
+       sed -f ../intl/po2msg.sed < $< > $*.msg \
+         && rm -f $@ && $(GENCAT) $@ $*.msg
+
+
+all: all-@USE_NLS@
+
+all-yes: $(CATALOGS)
+all-no:
+
+$(GETTEXT_PACKAGE).pot: $(POTFILES)
+       $(GENPOT)
+
+install: install-exec install-data
+install-exec:
+install-data: install-data-@USE_NLS@
+install-data-no: all
+install-data-yes: all
+       if test -n "$(MKINSTALLDIRS)"; then \
+         $(MKINSTALLDIRS) $(DESTDIR)$(datadir); \
+       else \
+         $(SHELL) $(top_srcdir)/mkinstalldirs $(DESTDIR)$(datadir); \
+       fi
+       @catalogs='$(CATALOGS)'; \
+       for cat in $$catalogs; do \
+         cat=`basename $$cat`; \
+         case "$$cat" in \
+           *.gmo) destdir=$(gnulocaledir);; \
+           *)     destdir=$(localedir);; \
+         esac; \
+         lang=`echo $$cat | sed 's/\$(CATOBJEXT)$$//'`; \
+         dir=$(DESTDIR)$$destdir/$$lang/LC_MESSAGES; \
+         if test -n "$(MKINSTALLDIRS)"; then \
+           $(MKINSTALLDIRS) $$dir; \
+         else \
+           $(SHELL) $(top_srcdir)/mkinstalldirs $$dir; \
+         fi; \
+         if test -r $$cat; then \
+           $(INSTALL_DATA) $$cat $$dir/$(GETTEXT_PACKAGE)$(INSTOBJEXT); \
+           echo "installing $$cat as $$dir/$(GETTEXT_PACKAGE)$(INSTOBJEXT)"; \
+         else \
+           $(INSTALL_DATA) $(srcdir)/$$cat $$dir/$(GETTEXT_PACKAGE)$(INSTOBJEXT); \
+           echo "installing $(srcdir)/$$cat as" \
+                "$$dir/$(GETTEXT_PACKAGE)$(INSTOBJEXT)"; \
+         fi; \
+         if test -r $$cat.m; then \
+           $(INSTALL_DATA) $$cat.m $$dir/$(GETTEXT_PACKAGE)$(INSTOBJEXT).m; \
+           echo "installing $$cat.m as $$dir/$(GETTEXT_PACKAGE)$(INSTOBJEXT).m"; \
+         else \
+           if test -r $(srcdir)/$$cat.m ; then \
+             $(INSTALL_DATA) $(srcdir)/$$cat.m \
+               $$dir/$(GETTEXT_PACKAGE)$(INSTOBJEXT).m; \
+             echo "installing $(srcdir)/$$cat as" \
+                  "$$dir/$(GETTEXT_PACKAGE)$(INSTOBJEXT).m"; \
+           else \
+             true; \
+           fi; \
+         fi; \
+       done
+       if test "$(PACKAGE)" = "glib"; then \
+         if test -n "$(MKINSTALLDIRS)"; then \
+           $(MKINSTALLDIRS) $(DESTDIR)$(gettextsrcdir); \
+         else \
+           $(SHELL) $(top_srcdir)/mkinstalldirs $(DESTDIR)$(gettextsrcdir); \
+         fi; \
+         $(INSTALL_DATA) $(srcdir)/Makefile.in.in \
+                         $(DESTDIR)$(gettextsrcdir)/Makefile.in.in; \
+       else \
+         : ; \
+       fi
+
+# Define this as empty until I found a useful application.
+installcheck:
+
+uninstall:
+       catalogs='$(CATALOGS)'; \
+       for cat in $$catalogs; do \
+         cat=`basename $$cat`; \
+         lang=`echo $$cat | sed 's/\$(CATOBJEXT)$$//'`; \
+         rm -f $(DESTDIR)$(localedir)/$$lang/LC_MESSAGES/$(GETTEXT_PACKAGE)$(INSTOBJEXT); \
+         rm -f $(DESTDIR)$(localedir)/$$lang/LC_MESSAGES/$(GETTEXT_PACKAGE)$(INSTOBJEXT).m; \
+         rm -f $(DESTDIR)$(gnulocaledir)/$$lang/LC_MESSAGES/$(GETTEXT_PACKAGE)$(INSTOBJEXT); \
+         rm -f $(DESTDIR)$(gnulocaledir)/$$lang/LC_MESSAGES/$(GETTEXT_PACKAGE)$(INSTOBJEXT).m; \
+       done
+       if test "$(PACKAGE)" = "glib"; then \
+         rm -f $(DESTDIR)$(gettextsrcdir)/Makefile.in.in; \
+       fi
+
+check: all
+
+dvi info tags TAGS ID:
+
+mostlyclean:
+       rm -f core core.* *.pox $(GETTEXT_PACKAGE).pot *.old.po cat-id-tbl.tmp
+       rm -fr *.o
+       rm -f .intltool-merge-cache
+
+clean: mostlyclean
+
+distclean: clean
+       rm -f Makefile Makefile.in POTFILES *.mo *.msg *.cat *.cat.m
+
+maintainer-clean: distclean
+       @echo "This command is intended for maintainers to use;"
+       @echo "it deletes files that may require special tools to rebuild."
+       rm -f $(GMOFILES)
+
+distdir = ../$(GETTEXT_PACKAGE)-$(VERSION)/$(subdir)
+dist distdir: $(DISTFILES) $(GETTEXT_PACKAGE).pot
+       dists="$(DISTFILES)"; \
+       for file in $$dists; do \
+         ln $(srcdir)/$$file $(distdir) 2> /dev/null \
+           || cp -p $(srcdir)/$$file $(distdir); \
+       done
+
+update-po: Makefile
+       $(MAKE) $(GETTEXT_PACKAGE).pot
+       tmpdir=`pwd`; \
+       catalogs='$(CATALOGS)'; \
+       for cat in $$catalogs; do \
+         cat=`basename $$cat`; \
+         lang=`echo $$cat | sed 's/\$(CATOBJEXT)$$//'`; \
+         echo "$$lang:"; \
+         result="`$(MSGMERGE) -o $$tmpdir/$$lang.new.po $$lang`"; \
+         if $$result; then \
+           if cmp $(srcdir)/$$lang.po $$tmpdir/$$lang.new.po >/dev/null 2>&1; then \
+             rm -f $$tmpdir/$$lang.new.po; \
+            else \
+             if mv -f $$tmpdir/$$lang.new.po $$lang.po; then \
+               :; \
+             else \
+               echo "msgmerge for $$lang.po failed: cannot move $$tmpdir/$$lang.new.po to $$lang.po" 1>&2; \
+               rm -f $$tmpdir/$$lang.new.po; \
+               exit 1; \
+             fi; \
+           fi; \
+         else \
+           echo "msgmerge for $$cat failed!"; \
+           rm -f $$tmpdir/$$lang.new.po; \
+         fi; \
+       done
+
+# POTFILES is created from POTFILES.in by stripping comments, empty lines
+# and Intltool tags (enclosed in square brackets), and appending a full
+# relative path to them
+POTFILES: POTFILES.in
+       ( if test 'x$(srcdir)' != 'x.'; then \
+           posrcprefix='$(top_srcdir)/'; \
+         else \
+           posrcprefix="../"; \
+         fi; \
+         rm -f $@-t $@ \
+           && (sed -e '/^#/d'                                          \
+                   -e "s/^\[.*\] +//"                                  \
+                   -e '/^[     ]*$$/d'                                 \
+                   -e "s@.*@   $$posrcprefix& \\\\@" < $(srcdir)/$@.in \
+               | sed -e '$$s/\\$$//') > $@-t \
+           && chmod a-w $@-t \
+           && mv $@-t $@ )
+
+Makefile: Makefile.in.in ../config.status POTFILES
+       cd .. \
+         && CONFIG_FILES=$(subdir)/$@.in CONFIG_HEADERS= \
+              $(SHELL) ./config.status
+
+# Tell versions [3.59,3.63) of GNU make not to export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/po/POTFILES.in b/po/POTFILES.in
new file mode 100755 (executable)
index 0000000..8b2ed1b
--- /dev/null
@@ -0,0 +1,2 @@
+wrapper/scim/src/sunpinyin_imengine_setup.cpp
+wrapper/scim/src/sunpinyin_imengine.cpp
diff --git a/po/de.po b/po/de.po
new file mode 100755 (executable)
index 0000000..b030ef9
--- /dev/null
+++ b/po/de.po
@@ -0,0 +1,35 @@
+# translation of de.po to German
+# translation of scim-input-pad.po to German
+# Copyright (C) 2005 Free Software Foundation, Inc.
+# This file is distributed under the same license as the PACKAGE package.
+# Mike FABIAN <mfabian@suse.de>, 2005.
+# Jan Hefti <j.hefti@chinaboard.de>, 2005.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: de\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2011-03-14 15:52+0900\n"
+"PO-Revision-Date: 2005-06-25 14:30+0200\n"
+"Last-Translator: Jan Hefti <j.hefti@chinaboard.de>\n"
+"Language-Team: German <scim-devel@lists.sourceforge.net>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: KBabel 1.10.1\n"
+"Plural-Forms:  nplurals=2; plural=(n != 1);\n"
+
+#: ../src/isf_xt9_imengine.h:23
+#, fuzzy
+msgid "Chinese PinYin"
+msgstr ""
+
+#: ../src/isf_xt9_imengine.h:24
+#, fuzzy
+msgid "Chinese CangJie"
+msgstr ""
+
+#: ../src/isf_xt9_imengine.h:25
+#, fuzzy
+msgid "Chinese ZhuYin"
+msgstr ""
diff --git a/po/de_DE.po b/po/de_DE.po
new file mode 100755 (executable)
index 0000000..9d1d8a5
--- /dev/null
@@ -0,0 +1,59 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2012-04-07 05:55+0800\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"Language: \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=CHARSET\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#. Controlbar
+#. Evas_Object *cbar = elm_controlbar_add(_pparent_layout);
+#. elm_controlbar_tool_item_append(cbar, NULL, _("Delete"), _OnButton, (void *)&m_delete);
+#. elm_controlbar_tool_item_append(cbar, NULL, _("Create"), _OnButton, (void *)&m_create);
+#: src/t9options/t9options.cpp:521
+msgid "Delete"
+msgstr ""
+
+#: src/t9options/t9options.cpp:522
+msgid "Create"
+msgstr ""
+
+#: src/t9options/t9options.cpp:663
+msgid "Cancel"
+msgstr ""
+
+#: src/t9options/t9options.cpp:673
+msgid "Save"
+msgstr ""
+
+#: src/t9options/t9options.h:36
+msgid "XT9 options"
+msgstr ""
+
+#. #define T9_OPTIONS_4x4   gettext("Keypad XT9 Options")
+#: src/t9options/t9options.h:38
+msgid "MoHu XT9 Options"
+msgstr ""
+
+#: src/t9options/t9options.h:39
+msgid "XT9 dictionary"
+msgstr ""
+
+#: src/t9options/t9options.h:40
+msgid "About XT9"
+msgstr ""
+
+#: src/t9options/t9options.h:41
+msgid "XT9 help"
+msgstr ""
diff --git a/po/el_GR.po b/po/el_GR.po
new file mode 100755 (executable)
index 0000000..9d1d8a5
--- /dev/null
@@ -0,0 +1,59 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2012-04-07 05:55+0800\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"Language: \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=CHARSET\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#. Controlbar
+#. Evas_Object *cbar = elm_controlbar_add(_pparent_layout);
+#. elm_controlbar_tool_item_append(cbar, NULL, _("Delete"), _OnButton, (void *)&m_delete);
+#. elm_controlbar_tool_item_append(cbar, NULL, _("Create"), _OnButton, (void *)&m_create);
+#: src/t9options/t9options.cpp:521
+msgid "Delete"
+msgstr ""
+
+#: src/t9options/t9options.cpp:522
+msgid "Create"
+msgstr ""
+
+#: src/t9options/t9options.cpp:663
+msgid "Cancel"
+msgstr ""
+
+#: src/t9options/t9options.cpp:673
+msgid "Save"
+msgstr ""
+
+#: src/t9options/t9options.h:36
+msgid "XT9 options"
+msgstr ""
+
+#. #define T9_OPTIONS_4x4   gettext("Keypad XT9 Options")
+#: src/t9options/t9options.h:38
+msgid "MoHu XT9 Options"
+msgstr ""
+
+#: src/t9options/t9options.h:39
+msgid "XT9 dictionary"
+msgstr ""
+
+#: src/t9options/t9options.h:40
+msgid "About XT9"
+msgstr ""
+
+#: src/t9options/t9options.h:41
+msgid "XT9 help"
+msgstr ""
diff --git a/po/en.po b/po/en.po
new file mode 100755 (executable)
index 0000000..9d1d8a5
--- /dev/null
+++ b/po/en.po
@@ -0,0 +1,59 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2012-04-07 05:55+0800\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"Language: \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=CHARSET\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#. Controlbar
+#. Evas_Object *cbar = elm_controlbar_add(_pparent_layout);
+#. elm_controlbar_tool_item_append(cbar, NULL, _("Delete"), _OnButton, (void *)&m_delete);
+#. elm_controlbar_tool_item_append(cbar, NULL, _("Create"), _OnButton, (void *)&m_create);
+#: src/t9options/t9options.cpp:521
+msgid "Delete"
+msgstr ""
+
+#: src/t9options/t9options.cpp:522
+msgid "Create"
+msgstr ""
+
+#: src/t9options/t9options.cpp:663
+msgid "Cancel"
+msgstr ""
+
+#: src/t9options/t9options.cpp:673
+msgid "Save"
+msgstr ""
+
+#: src/t9options/t9options.h:36
+msgid "XT9 options"
+msgstr ""
+
+#. #define T9_OPTIONS_4x4   gettext("Keypad XT9 Options")
+#: src/t9options/t9options.h:38
+msgid "MoHu XT9 Options"
+msgstr ""
+
+#: src/t9options/t9options.h:39
+msgid "XT9 dictionary"
+msgstr ""
+
+#: src/t9options/t9options.h:40
+msgid "About XT9"
+msgstr ""
+
+#: src/t9options/t9options.h:41
+msgid "XT9 help"
+msgstr ""
diff --git a/po/es_ES.po b/po/es_ES.po
new file mode 100755 (executable)
index 0000000..9d1d8a5
--- /dev/null
@@ -0,0 +1,59 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2012-04-07 05:55+0800\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"Language: \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=CHARSET\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#. Controlbar
+#. Evas_Object *cbar = elm_controlbar_add(_pparent_layout);
+#. elm_controlbar_tool_item_append(cbar, NULL, _("Delete"), _OnButton, (void *)&m_delete);
+#. elm_controlbar_tool_item_append(cbar, NULL, _("Create"), _OnButton, (void *)&m_create);
+#: src/t9options/t9options.cpp:521
+msgid "Delete"
+msgstr ""
+
+#: src/t9options/t9options.cpp:522
+msgid "Create"
+msgstr ""
+
+#: src/t9options/t9options.cpp:663
+msgid "Cancel"
+msgstr ""
+
+#: src/t9options/t9options.cpp:673
+msgid "Save"
+msgstr ""
+
+#: src/t9options/t9options.h:36
+msgid "XT9 options"
+msgstr ""
+
+#. #define T9_OPTIONS_4x4   gettext("Keypad XT9 Options")
+#: src/t9options/t9options.h:38
+msgid "MoHu XT9 Options"
+msgstr ""
+
+#: src/t9options/t9options.h:39
+msgid "XT9 dictionary"
+msgstr ""
+
+#: src/t9options/t9options.h:40
+msgid "About XT9"
+msgstr ""
+
+#: src/t9options/t9options.h:41
+msgid "XT9 help"
+msgstr ""
diff --git a/po/fr.po b/po/fr.po
new file mode 100755 (executable)
index 0000000..6d560dc
--- /dev/null
+++ b/po/fr.po
@@ -0,0 +1,34 @@
+# translation of fr.po to French
+# translation of scim-input-pad.po to German
+# Copyright (C) 2005 Free Software Foundation, Inc.
+# This file is distributed under the same license as the PACKAGE package.
+# Damien Menanteau <damien.menanteau@cegetel.net>, 2005.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: fr\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2011-03-14 15:52+0900\n"
+"PO-Revision-Date: 2005-06-04 20:26+0200\n"
+"Last-Translator: Damien Menanteau <damien.menanteau@cegetel.net>\n"
+"Language-Team: French\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: KBabel 1.10.1\n"
+"Plural-Forms:  nplurals=2; plural=(n > 1);\n"
+
+#: ../src/isf_xt9_imengine.h:23
+#, fuzzy
+msgid "Chinese PinYin"
+msgstr ""
+
+#: ../src/isf_xt9_imengine.h:24
+#, fuzzy
+msgid "Chinese CangJie"
+msgstr ""
+
+#: ../src/isf_xt9_imengine.h:25
+#, fuzzy
+msgid "Chinese ZhuYin"
+msgstr ""
diff --git a/po/fr_FR.po b/po/fr_FR.po
new file mode 100755 (executable)
index 0000000..9d1d8a5
--- /dev/null
@@ -0,0 +1,59 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2012-04-07 05:55+0800\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"Language: \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=CHARSET\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#. Controlbar
+#. Evas_Object *cbar = elm_controlbar_add(_pparent_layout);
+#. elm_controlbar_tool_item_append(cbar, NULL, _("Delete"), _OnButton, (void *)&m_delete);
+#. elm_controlbar_tool_item_append(cbar, NULL, _("Create"), _OnButton, (void *)&m_create);
+#: src/t9options/t9options.cpp:521
+msgid "Delete"
+msgstr ""
+
+#: src/t9options/t9options.cpp:522
+msgid "Create"
+msgstr ""
+
+#: src/t9options/t9options.cpp:663
+msgid "Cancel"
+msgstr ""
+
+#: src/t9options/t9options.cpp:673
+msgid "Save"
+msgstr ""
+
+#: src/t9options/t9options.h:36
+msgid "XT9 options"
+msgstr ""
+
+#. #define T9_OPTIONS_4x4   gettext("Keypad XT9 Options")
+#: src/t9options/t9options.h:38
+msgid "MoHu XT9 Options"
+msgstr ""
+
+#: src/t9options/t9options.h:39
+msgid "XT9 dictionary"
+msgstr ""
+
+#: src/t9options/t9options.h:40
+msgid "About XT9"
+msgstr ""
+
+#: src/t9options/t9options.h:41
+msgid "XT9 help"
+msgstr ""
diff --git a/po/it_IT.po b/po/it_IT.po
new file mode 100755 (executable)
index 0000000..9d1d8a5
--- /dev/null
@@ -0,0 +1,59 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2012-04-07 05:55+0800\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"Language: \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=CHARSET\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#. Controlbar
+#. Evas_Object *cbar = elm_controlbar_add(_pparent_layout);
+#. elm_controlbar_tool_item_append(cbar, NULL, _("Delete"), _OnButton, (void *)&m_delete);
+#. elm_controlbar_tool_item_append(cbar, NULL, _("Create"), _OnButton, (void *)&m_create);
+#: src/t9options/t9options.cpp:521
+msgid "Delete"
+msgstr ""
+
+#: src/t9options/t9options.cpp:522
+msgid "Create"
+msgstr ""
+
+#: src/t9options/t9options.cpp:663
+msgid "Cancel"
+msgstr ""
+
+#: src/t9options/t9options.cpp:673
+msgid "Save"
+msgstr ""
+
+#: src/t9options/t9options.h:36
+msgid "XT9 options"
+msgstr ""
+
+#. #define T9_OPTIONS_4x4   gettext("Keypad XT9 Options")
+#: src/t9options/t9options.h:38
+msgid "MoHu XT9 Options"
+msgstr ""
+
+#: src/t9options/t9options.h:39
+msgid "XT9 dictionary"
+msgstr ""
+
+#: src/t9options/t9options.h:40
+msgid "About XT9"
+msgstr ""
+
+#: src/t9options/t9options.h:41
+msgid "XT9 help"
+msgstr ""
diff --git a/po/ja.po b/po/ja.po
new file mode 100755 (executable)
index 0000000..aa7003b
--- /dev/null
+++ b/po/ja.po
@@ -0,0 +1,31 @@
+# translation of scim-input-pad.po to Japanese
+# Copyright (C) 2005 Free Software Foundation, Inc.
+# This file is distributed under the same license as the PACKAGE package.
+# Yukiko BANDO <ybando@k6.dion.ne.jp>, 2005.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: translation of scim-input-pad.po\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2011-03-14 15:52+0900\n"
+"PO-Revision-Date: 2005-03-19 07:00+0900\n"
+"Last-Translator: Yukiko BANDO <ybando@k6.dion.ne.jp>\n"
+"Language-Team: Japanese <ja@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#: ../src/isf_xt9_imengine.h:23
+#, fuzzy
+msgid "Chinese PinYin"
+msgstr ""
+
+#: ../src/isf_xt9_imengine.h:24
+#, fuzzy
+msgid "Chinese CangJie"
+msgstr ""
+
+#: ../src/isf_xt9_imengine.h:25
+#, fuzzy
+msgid "Chinese ZhuYin"
+msgstr ""
diff --git a/po/ja_JP.po b/po/ja_JP.po
new file mode 100755 (executable)
index 0000000..9d1d8a5
--- /dev/null
@@ -0,0 +1,59 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2012-04-07 05:55+0800\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"Language: \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=CHARSET\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#. Controlbar
+#. Evas_Object *cbar = elm_controlbar_add(_pparent_layout);
+#. elm_controlbar_tool_item_append(cbar, NULL, _("Delete"), _OnButton, (void *)&m_delete);
+#. elm_controlbar_tool_item_append(cbar, NULL, _("Create"), _OnButton, (void *)&m_create);
+#: src/t9options/t9options.cpp:521
+msgid "Delete"
+msgstr ""
+
+#: src/t9options/t9options.cpp:522
+msgid "Create"
+msgstr ""
+
+#: src/t9options/t9options.cpp:663
+msgid "Cancel"
+msgstr ""
+
+#: src/t9options/t9options.cpp:673
+msgid "Save"
+msgstr ""
+
+#: src/t9options/t9options.h:36
+msgid "XT9 options"
+msgstr ""
+
+#. #define T9_OPTIONS_4x4   gettext("Keypad XT9 Options")
+#: src/t9options/t9options.h:38
+msgid "MoHu XT9 Options"
+msgstr ""
+
+#: src/t9options/t9options.h:39
+msgid "XT9 dictionary"
+msgstr ""
+
+#: src/t9options/t9options.h:40
+msgid "About XT9"
+msgstr ""
+
+#: src/t9options/t9options.h:41
+msgid "XT9 help"
+msgstr ""
diff --git a/po/ko.po b/po/ko.po
new file mode 100755 (executable)
index 0000000..29defc3
--- /dev/null
+++ b/po/ko.po
@@ -0,0 +1,30 @@
+# Korean translation of scim-hangul.
+# Copyright (C) 2004 James Su <suzhe@tsinghua.org.cn>
+# This file is distributed under the same license as the scim-hangul package.
+# 김기태 <neeum@yahoo.com>, 2004.
+# Choe Hwanjin <choehwanjin@gmail.com>, 2004.
+#
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: scim-hangul 0.0.3\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2011-03-14 15:52+0900\n"
+"PO-Revision-Date: 2005-10-29 18:57+0800\n"
+"Last-Translator: Choe Hwanjin <choe.hwanjin@gmail.com>\n"
+"Language-Team: Korean\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#: ../src/isf_xt9_imengine.h:23
+msgid "Chinese PinYin"
+msgstr ""
+
+#: ../src/isf_xt9_imengine.h:24
+msgid "Chinese CangJie"
+msgstr ""
+
+#: ../src/isf_xt9_imengine.h:25
+msgid "Chinese ZhuYin"
+msgstr ""
diff --git a/po/ko_KR.po b/po/ko_KR.po
new file mode 100755 (executable)
index 0000000..9d1d8a5
--- /dev/null
@@ -0,0 +1,59 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2012-04-07 05:55+0800\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"Language: \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=CHARSET\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#. Controlbar
+#. Evas_Object *cbar = elm_controlbar_add(_pparent_layout);
+#. elm_controlbar_tool_item_append(cbar, NULL, _("Delete"), _OnButton, (void *)&m_delete);
+#. elm_controlbar_tool_item_append(cbar, NULL, _("Create"), _OnButton, (void *)&m_create);
+#: src/t9options/t9options.cpp:521
+msgid "Delete"
+msgstr ""
+
+#: src/t9options/t9options.cpp:522
+msgid "Create"
+msgstr ""
+
+#: src/t9options/t9options.cpp:663
+msgid "Cancel"
+msgstr ""
+
+#: src/t9options/t9options.cpp:673
+msgid "Save"
+msgstr ""
+
+#: src/t9options/t9options.h:36
+msgid "XT9 options"
+msgstr ""
+
+#. #define T9_OPTIONS_4x4   gettext("Keypad XT9 Options")
+#: src/t9options/t9options.h:38
+msgid "MoHu XT9 Options"
+msgstr ""
+
+#: src/t9options/t9options.h:39
+msgid "XT9 dictionary"
+msgstr ""
+
+#: src/t9options/t9options.h:40
+msgid "About XT9"
+msgstr ""
+
+#: src/t9options/t9options.h:41
+msgid "XT9 help"
+msgstr ""
diff --git a/po/nl.po b/po/nl.po
new file mode 100755 (executable)
index 0000000..5aa85be
--- /dev/null
+++ b/po/nl.po
@@ -0,0 +1,31 @@
+# translation of nl.po to Nederlands
+# This file is distributed under the same license as the PACKAGE package.
+# Copyright (C) 2004 James Su <suzhe@tsinghua.org.cn>.
+#
+# Ronald Stroethoff <stroet43@zonnet.nl>, 2007.
+msgid ""
+msgstr ""
+"Project-Id-Version: nl\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2011-03-14 15:52+0900\n"
+"PO-Revision-Date: 2007-05-20 12:49+0200\n"
+"Last-Translator: Ronald Stroethoff <stroet43@zonnet.nl>\n"
+"Language-Team: Nederlands\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms:  nplurals=2; plural=(n != 1);\n"
+"X-Generator: KBabel 1.11.4\n"
+
+#: ../src/isf_xt9_imengine.h:23
+msgid "Chinese PinYin"
+msgstr ""
+
+#: ../src/isf_xt9_imengine.h:24
+msgid "Chinese CangJie"
+msgstr ""
+
+#: ../src/isf_xt9_imengine.h:25
+msgid "Chinese ZhuYin"
+msgstr ""
+
diff --git a/po/nl_NL.po b/po/nl_NL.po
new file mode 100755 (executable)
index 0000000..9d1d8a5
--- /dev/null
@@ -0,0 +1,59 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2012-04-07 05:55+0800\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"Language: \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=CHARSET\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#. Controlbar
+#. Evas_Object *cbar = elm_controlbar_add(_pparent_layout);
+#. elm_controlbar_tool_item_append(cbar, NULL, _("Delete"), _OnButton, (void *)&m_delete);
+#. elm_controlbar_tool_item_append(cbar, NULL, _("Create"), _OnButton, (void *)&m_create);
+#: src/t9options/t9options.cpp:521
+msgid "Delete"
+msgstr ""
+
+#: src/t9options/t9options.cpp:522
+msgid "Create"
+msgstr ""
+
+#: src/t9options/t9options.cpp:663
+msgid "Cancel"
+msgstr ""
+
+#: src/t9options/t9options.cpp:673
+msgid "Save"
+msgstr ""
+
+#: src/t9options/t9options.h:36
+msgid "XT9 options"
+msgstr ""
+
+#. #define T9_OPTIONS_4x4   gettext("Keypad XT9 Options")
+#: src/t9options/t9options.h:38
+msgid "MoHu XT9 Options"
+msgstr ""
+
+#: src/t9options/t9options.h:39
+msgid "XT9 dictionary"
+msgstr ""
+
+#: src/t9options/t9options.h:40
+msgid "About XT9"
+msgstr ""
+
+#: src/t9options/t9options.h:41
+msgid "XT9 help"
+msgstr ""
diff --git a/po/pa.po b/po/pa.po
new file mode 100755 (executable)
index 0000000..197e254
--- /dev/null
+++ b/po/pa.po
@@ -0,0 +1,34 @@
+# translation of scim-input-pad.po to Punjabi
+# This file is distributed under the same license as the PACKAGE package.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER.
+# Amanpreet Singh Alam <amanpreetalam@yahoo.com>, 2005.
+# Amanpreet Singh Brar <amanpreetalam@yahoo.com>, 2005.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: scim-input-pad\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2011-03-14 15:52+0900\n"
+"PO-Revision-Date: 2005-09-07 11:44+0530\n"
+"Last-Translator: Amanpreet Singh Brar <amanpreetalam@yahoo.com>\n"
+"Language-Team: Punjabi <fedora-trans-pa@redhat.com>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: KBabel 1.9.1\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+
+#: ../src/isf_xt9_imengine.h:23
+#, fuzzy
+msgid "Chinese PinYin"
+msgstr ""
+
+#: ../src/isf_xt9_imengine.h:24
+#, fuzzy
+msgid "Chinese CangJie"
+msgstr ""
+
+#: ../src/isf_xt9_imengine.h:25
+#, fuzzy
+msgid "Chinese ZhuYin"
+msgstr ""
diff --git a/po/pt_PT.po b/po/pt_PT.po
new file mode 100755 (executable)
index 0000000..9d1d8a5
--- /dev/null
@@ -0,0 +1,59 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2012-04-07 05:55+0800\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"Language: \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=CHARSET\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#. Controlbar
+#. Evas_Object *cbar = elm_controlbar_add(_pparent_layout);
+#. elm_controlbar_tool_item_append(cbar, NULL, _("Delete"), _OnButton, (void *)&m_delete);
+#. elm_controlbar_tool_item_append(cbar, NULL, _("Create"), _OnButton, (void *)&m_create);
+#: src/t9options/t9options.cpp:521
+msgid "Delete"
+msgstr ""
+
+#: src/t9options/t9options.cpp:522
+msgid "Create"
+msgstr ""
+
+#: src/t9options/t9options.cpp:663
+msgid "Cancel"
+msgstr ""
+
+#: src/t9options/t9options.cpp:673
+msgid "Save"
+msgstr ""
+
+#: src/t9options/t9options.h:36
+msgid "XT9 options"
+msgstr ""
+
+#. #define T9_OPTIONS_4x4   gettext("Keypad XT9 Options")
+#: src/t9options/t9options.h:38
+msgid "MoHu XT9 Options"
+msgstr ""
+
+#: src/t9options/t9options.h:39
+msgid "XT9 dictionary"
+msgstr ""
+
+#: src/t9options/t9options.h:40
+msgid "About XT9"
+msgstr ""
+
+#: src/t9options/t9options.h:41
+msgid "XT9 help"
+msgstr ""
diff --git a/po/ru_RU.po b/po/ru_RU.po
new file mode 100755 (executable)
index 0000000..9d1d8a5
--- /dev/null
@@ -0,0 +1,59 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2012-04-07 05:55+0800\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"Language: \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=CHARSET\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#. Controlbar
+#. Evas_Object *cbar = elm_controlbar_add(_pparent_layout);
+#. elm_controlbar_tool_item_append(cbar, NULL, _("Delete"), _OnButton, (void *)&m_delete);
+#. elm_controlbar_tool_item_append(cbar, NULL, _("Create"), _OnButton, (void *)&m_create);
+#: src/t9options/t9options.cpp:521
+msgid "Delete"
+msgstr ""
+
+#: src/t9options/t9options.cpp:522
+msgid "Create"
+msgstr ""
+
+#: src/t9options/t9options.cpp:663
+msgid "Cancel"
+msgstr ""
+
+#: src/t9options/t9options.cpp:673
+msgid "Save"
+msgstr ""
+
+#: src/t9options/t9options.h:36
+msgid "XT9 options"
+msgstr ""
+
+#. #define T9_OPTIONS_4x4   gettext("Keypad XT9 Options")
+#: src/t9options/t9options.h:38
+msgid "MoHu XT9 Options"
+msgstr ""
+
+#: src/t9options/t9options.h:39
+msgid "XT9 dictionary"
+msgstr ""
+
+#: src/t9options/t9options.h:40
+msgid "About XT9"
+msgstr ""
+
+#: src/t9options/t9options.h:41
+msgid "XT9 help"
+msgstr ""
diff --git a/po/tr_TR.po b/po/tr_TR.po
new file mode 100755 (executable)
index 0000000..9d1d8a5
--- /dev/null
@@ -0,0 +1,59 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2012-04-07 05:55+0800\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"Language: \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=CHARSET\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#. Controlbar
+#. Evas_Object *cbar = elm_controlbar_add(_pparent_layout);
+#. elm_controlbar_tool_item_append(cbar, NULL, _("Delete"), _OnButton, (void *)&m_delete);
+#. elm_controlbar_tool_item_append(cbar, NULL, _("Create"), _OnButton, (void *)&m_create);
+#: src/t9options/t9options.cpp:521
+msgid "Delete"
+msgstr ""
+
+#: src/t9options/t9options.cpp:522
+msgid "Create"
+msgstr ""
+
+#: src/t9options/t9options.cpp:663
+msgid "Cancel"
+msgstr ""
+
+#: src/t9options/t9options.cpp:673
+msgid "Save"
+msgstr ""
+
+#: src/t9options/t9options.h:36
+msgid "XT9 options"
+msgstr ""
+
+#. #define T9_OPTIONS_4x4   gettext("Keypad XT9 Options")
+#: src/t9options/t9options.h:38
+msgid "MoHu XT9 Options"
+msgstr ""
+
+#: src/t9options/t9options.h:39
+msgid "XT9 dictionary"
+msgstr ""
+
+#: src/t9options/t9options.h:40
+msgid "About XT9"
+msgstr ""
+
+#: src/t9options/t9options.h:41
+msgid "XT9 help"
+msgstr ""
diff --git a/po/update-po.sh b/po/update-po.sh
new file mode 100755 (executable)
index 0000000..35fa013
--- /dev/null
@@ -0,0 +1,57 @@
+#!/bin/sh
+
+PACKAGE=ise-engine-xt9
+SRCROOT=..
+POTFILES=POTFILES.in
+
+#ALL_LINGUAS= am az be ca cs da de el en_CA en_GB es et fi fr hr hu it ja ko lv mk ml ms nb ne nl pa pl pt pt_BR ru rw sk sl sr sr@Latn sv ta tr uk vi zh_CN zh_TW
+ALL_LINGUAS="ko_KR en zh_CN zh_HK zh_TW de_DE nl_NL es_ES pt_PT el_GR it_IT fr_FR tr_TR ja_JP ru_RU"
+
+XGETTEXT=/usr/bin/xgettext
+MSGMERGE=/usr/bin/msgmerge
+
+echo -n "Make ${PACKAGE}.pot  "
+if [ ! -e $POTFILES ] ; then
+       echo "$POTFILES not found"
+       exit 1
+fi
+
+$XGETTEXT --default-domain=${PACKAGE} --directory=${SRCROOT} \
+               --add-comments --keyword=_ --keyword=N_ --files-from=$POTFILES \
+&& test ! -f ${PACKAGE}.po \
+       || (rm -f ${PACKAGE}.pot && mv ${PACKAGE}.po ${PACKAGE}.pot)
+
+if [ $? -ne 0 ]; then
+       echo "error"
+       exit 1
+else
+       echo "done"
+fi
+
+for LANG in $ALL_LINGUAS; do 
+       echo "$LANG : "
+
+       if [ ! -e $LANG.po ] ; then
+               cp ${PACKAGE}.pot ${LANG}.po
+               echo "${LANG}.po created"
+       else
+               if $MSGMERGE ${LANG}.po ${PACKAGE}.pot -o ${LANG}.new.po ; then
+                       if cmp ${LANG}.po ${LANG}.new.po > /dev/null 2>&1; then
+                               rm -f ${LANG}.new.po
+                       else
+                               if mv -f ${LANG}.new.po ${LANG}.po; then
+                                       echo "" 
+                               else
+                                       echo "msgmerge for $LANG.po failed: cannot move $LANG.new.po to $LANG.po" 1>&2
+                                       rm -f ${LANG}.new.po
+                                       exit 1
+                               fi
+                       fi
+               else
+                       echo "msgmerge for $LANG failed!"
+                       rm -f ${LANG}.new.po
+               fi
+       fi
+       echo ""
+done
+
diff --git a/po/zh_CN.po b/po/zh_CN.po
new file mode 100755 (executable)
index 0000000..b68d9c5
--- /dev/null
@@ -0,0 +1,70 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: 0.0.1\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2011-03-14 15:52+0900\n"
+"PO-Revision-Date: 2005-03-05 12:16+0800\n"
+"Last-Translator: James Su<suzhe@tsinghua.org.cn>\n"
+"Language-Team: Simplified Chinese <zh@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#: ../src/isf_xt9_imengine.h:23
+msgid "Chinese PinYin"
+msgstr "中文拼音"
+
+#: ../src/isf_xt9_imengine.h:24
+msgid "Chinese CangJie"
+msgstr "中文仓颉"
+
+#: ../src/isf_xt9_imengine.h:25
+msgid "Chinese ZhuYin"
+msgstr "中文注音"
+
+#. Controlbar
+#. Evas_Object *cbar = elm_controlbar_add(_pparent_layout);
+#. elm_controlbar_tool_item_append(cbar, NULL, _("Delete"), _OnButton, (void *)&m_delete);
+#. elm_controlbar_tool_item_append(cbar, NULL, _("Create"), _OnButton, (void *)&m_create);
+#: src/t9options/t9options.cpp:521
+msgid "Delete"
+msgstr ""
+
+#: src/t9options/t9options.cpp:522
+msgid "Create"
+msgstr ""
+
+#: src/t9options/t9options.cpp:663
+msgid "Cancel"
+msgstr ""
+
+#: src/t9options/t9options.cpp:673
+msgid "Save"
+msgstr ""
+
+#: src/t9options/t9options.h:36
+msgid "XT9 options"
+msgstr ""
+
+#. #define T9_OPTIONS_4x4   gettext("Keypad XT9 Options")
+#: src/t9options/t9options.h:38
+msgid "MoHu XT9 Options"
+msgstr ""
+
+#: src/t9options/t9options.h:39
+msgid "XT9 dictionary"
+msgstr ""
+
+#: src/t9options/t9options.h:40
+msgid "About XT9"
+msgstr ""
+
+#: src/t9options/t9options.h:41
+msgid "XT9 help"
+msgstr ""
diff --git a/po/zh_HK.po b/po/zh_HK.po
new file mode 100755 (executable)
index 0000000..3e5261c
--- /dev/null
@@ -0,0 +1,70 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: 0.0.3\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2011-03-14 15:52+0900\n"
+"PO-Revision-Date: 2005-06-05 15:16+0800\n"
+"Last-Translator: Jim Huang <jserv@kaffe.org>\n"
+"Language-Team: Traditional Chinese <zh@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#: ../src/isf_xt9_imengine.h:23
+msgid "Chinese PinYin"
+msgstr "中文拼音"
+
+#: ../src/isf_xt9_imengine.h:24
+msgid "Chinese CangJie"
+msgstr "中文倉頡"
+
+#: ../src/isf_xt9_imengine.h:25
+msgid "Chinese ZhuYin"
+msgstr "中文注音"
+
+#. Controlbar
+#. Evas_Object *cbar = elm_controlbar_add(_pparent_layout);
+#. elm_controlbar_tool_item_append(cbar, NULL, _("Delete"), _OnButton, (void *)&m_delete);
+#. elm_controlbar_tool_item_append(cbar, NULL, _("Create"), _OnButton, (void *)&m_create);
+#: src/t9options/t9options.cpp:521
+msgid "Delete"
+msgstr ""
+
+#: src/t9options/t9options.cpp:522
+msgid "Create"
+msgstr ""
+
+#: src/t9options/t9options.cpp:663
+msgid "Cancel"
+msgstr ""
+
+#: src/t9options/t9options.cpp:673
+msgid "Save"
+msgstr ""
+
+#: src/t9options/t9options.h:36
+msgid "XT9 options"
+msgstr ""
+
+#. #define T9_OPTIONS_4x4   gettext("Keypad XT9 Options")
+#: src/t9options/t9options.h:38
+msgid "MoHu XT9 Options"
+msgstr ""
+
+#: src/t9options/t9options.h:39
+msgid "XT9 dictionary"
+msgstr ""
+
+#: src/t9options/t9options.h:40
+msgid "About XT9"
+msgstr ""
+
+#: src/t9options/t9options.h:41
+msgid "XT9 help"
+msgstr ""
diff --git a/po/zh_TW.po b/po/zh_TW.po
new file mode 100755 (executable)
index 0000000..a1f3a3d
--- /dev/null
@@ -0,0 +1,71 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: 0.0.3\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2011-03-14 15:52+0900\n"
+"PO-Revision-Date: 2005-06-05 15:16+0800\n"
+"Last-Translator: Jim Huang <jserv@kaffe.org>\n"
+"Language-Team: Traditional Chinese <zh@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#: ../src/isf_xt9_imengine.h:23
+msgid "Chinese PinYin"
+msgstr "中文拼音"
+
+#: ../src/isf_xt9_imengine.h:24
+msgid "Chinese CangJie"
+msgstr "中文倉頡"
+
+#: ../src/isf_xt9_imengine.h:25
+msgid "Chinese ZhuYin"
+msgstr "中文注音"
+
+#. Controlbar
+#. Evas_Object *cbar = elm_controlbar_add(_pparent_layout);
+#. elm_controlbar_tool_item_append(cbar, NULL, _("Delete"), _OnButton, (void *)&m_delete);
+#. elm_controlbar_tool_item_append(cbar, NULL, _("Create"), _OnButton, (void *)&m_create);
+#: src/t9options/t9options.cpp:521
+
+msgid "Delete"
+msgstr ""
+
+#: src/t9options/t9options.cpp:522
+msgid "Create"
+msgstr ""
+
+#: src/t9options/t9options.cpp:663
+msgid "Cancel"
+msgstr ""
+
+#: src/t9options/t9options.cpp:673
+msgid "Save"
+msgstr ""
+
+#: src/t9options/t9options.h:36
+msgid "XT9 options"
+msgstr ""
+
+#. #define T9_OPTIONS_4x4   gettext("Keypad XT9 Options")
+#: src/t9options/t9options.h:38
+msgid "MoHu XT9 Options"
+msgstr ""
+
+#: src/t9options/t9options.h:39
+msgid "XT9 dictionary"
+msgstr ""
+
+#: src/t9options/t9options.h:40
+msgid "About XT9"
+msgstr ""
+
+#: src/t9options/t9options.h:41
+msgid "XT9 help"
+msgstr ""
diff --git a/python/imdict.py b/python/imdict.py
new file mode 100755 (executable)
index 0000000..31c5c34
--- /dev/null
@@ -0,0 +1,53 @@
+#!/usr/bin/python 
+
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+# 
+# Copyright (c) 2007 Sun Microsystems, Inc. All Rights Reserved.
+# 
+# The contents of this file are subject to the terms of either the GNU Lesser
+# General Public License Version 2.1 only ("LGPL") or the Common Development and
+# Distribution License ("CDDL")(collectively, the "License"). You may not use this
+# file except in compliance with the License. You can obtain a copy of the CDDL at
+# http://www.opensource.org/licenses/cddl1.php and a copy of the LGPLv2.1 at
+# http://www.opensource.org/licenses/lgpl-license.php. See the License for the 
+# specific language governing permissions and limitations under the License. When
+# distributing the software, include this License Header Notice in each file and
+# include the full text of the License in the License file as well as the
+# following notice:
+# 
+# NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND DISTRIBUTION LICENSE
+# (CDDL)
+# For Covered Software in this distribution, this License shall be governed by the
+# laws of the State of California (excluding conflict-of-law provisions).
+# Any litigation relating to this License shall be subject to the jurisdiction of
+# the Federal Courts of the Northern District of California and the state courts
+# of the State of California, with venue lying in Santa Clara County, California.
+# 
+# Contributor(s):
+# 
+# If you wish your version of this file to be governed by only the CDDL or only
+# the LGPL Version 2.1, indicate your decision by adding "[Contributor]" elects to
+# include this software in this distribution under the [CDDL or LGPL Version 2.1]
+# license." If you don't indicate a single choice of license, a recipient has the
+# option to distribute your version of this file under either the CDDL or the LGPL
+# Version 2.1, or to extend the choice of license to its licensees as provided
+# above. However, if you add LGPL Version 2.1 code and therefore, elected the LGPL
+# Version 2 license, then the option applies only if the new code is made subject
+# to such option by the copyright holder. 
+
+import codecs
+from trie import Trie
+
+class IMDict (Trie):
+    def __init__(self, fname):
+        super (IMDict, self).__init__()
+        self.load(fname)
+
+    def load(self, fname):
+        file = codecs.open(fname, 'r', 'utf-8')
+        for line in file:
+            line = line.strip()
+            if line[0] not in ('#', '<', '\n'):
+                word, id= line.split(' ')[0:2]
+                self.add(word, int(id))
+        file.close()
diff --git a/python/importer/import_fcitx_userdict.py b/python/importer/import_fcitx_userdict.py
new file mode 100755 (executable)
index 0000000..f6a3e5e
--- /dev/null
@@ -0,0 +1,30 @@
+#!/usr/bin/python
+
+import os, sys
+import codecs
+from importer import import_to_sunpinyin_user_dict
+
+def load_fcitx_user_dict (fname):
+    result = []
+    f = codecs.open (fname, "r", "GB18030")
+    for l in f:
+        if l[0] in ('\n'):
+            continue
+
+        pystr, utf8str = l.strip().split(" ")
+        result.append ((pystr, utf8str))
+
+    return result
+
+def main ():
+    if len (sys.argv) != 2:
+        os.system ("/usr/bin/mb2org ~/.fcitx/pyusrphrase.mb > /tmp/fcitx_userdict_gb.txt")
+        fcitx_user_dict = load_fcitx_user_dict("/tmp/fcitx_userdict_gb.txt")
+        os.system ("rm -rf /tmp/fcitx_userdict_gb.txt")
+    else:
+        fcitx_user_dict = load_fcitx_user_dict(sys.argv[1])
+
+    import_to_sunpinyin_user_dict (fcitx_user_dict)
+
+if __name__ == "__main__":
+    main()
diff --git a/python/importer/import_fit_userdict.py b/python/importer/import_fit_userdict.py
new file mode 100755 (executable)
index 0000000..e131f8f
--- /dev/null
@@ -0,0 +1,20 @@
+#!/usr/bin/python
+
+import os
+import sqlite3 as sqlite
+from importer import import_to_sunpinyin_user_dict
+
+def load_fit_user_dict ():
+    homedir = os.environ.get("HOME")
+    db = sqlite.connect (homedir+"/Library/FunInputToy/py.sqlite")
+    sqlstring = "SELECT code, string FROM words WHERE is_new==1"
+    result = list (db.execute (sqlstring).fetchall ())
+    db.close ()
+    return result
+
+def main ():
+    fit_user_dict = load_fit_user_dict()
+    import_to_sunpinyin_user_dict (fit_user_dict)
+
+if __name__ == "__main__":
+    main()
diff --git a/python/importer/import_google_userdict.py b/python/importer/import_google_userdict.py
new file mode 100755 (executable)
index 0000000..b82cace
--- /dev/null
@@ -0,0 +1,33 @@
+#!/usr/bin/python
+
+import os, sys
+import codecs
+from importer import import_to_sunpinyin_user_dict
+
+def load_google_user_dict (fname):
+    result = []
+    f = codecs.open (fname, "r", "GB18030")
+    for l in f:
+        v = l.strip().split()
+        utf8str = v[0]
+
+        try:
+            freq = int(v[1])
+            pystr = '\''.join (v[2:])
+        except:
+            pystr = '\''.join (v[1:])
+
+        result.append ((pystr, utf8str))
+
+    return result
+
+def main ():
+    if len (sys.argv) != 2:
+        print "Please specify the Google Pinyin exported user dict file!"
+        exit (1)
+
+    google_user_dict = load_google_user_dict(sys.argv[1])
+    import_to_sunpinyin_user_dict (google_user_dict)
+
+if __name__ == "__main__":
+    main()
diff --git a/python/importer/import_qim_userdict.py b/python/importer/import_qim_userdict.py
new file mode 100755 (executable)
index 0000000..61f18cf
--- /dev/null
@@ -0,0 +1,28 @@
+#!/usr/bin/python
+
+import os, sys
+import codecs
+from importer import import_to_sunpinyin_user_dict
+
+def load_qim_user_dict (fname):
+    result = []
+    f = codecs.open (fname, "r", "UTF-8")
+    for l in f:
+        pystr, utf8str = l.strip().split(" ")
+        if 'P' in pystr:
+            continue
+
+        result.append ((pystr, utf8str))
+
+    return result
+
+def main ():
+    if len (sys.argv) != 2:
+        print "Please specify the QIM exported user dict file!"
+        exit (1)
+
+    qim_user_dict = load_qim_user_dict(sys.argv[1])
+    import_to_sunpinyin_user_dict (qim_user_dict)
+
+if __name__ == "__main__":
+    main()
diff --git a/python/importer/import_qq_userdict.py b/python/importer/import_qq_userdict.py
new file mode 100755 (executable)
index 0000000..8fae041
--- /dev/null
@@ -0,0 +1,31 @@
+#!/usr/bin/python
+
+import os, sys
+import codecs
+from importer import import_to_sunpinyin_user_dict
+
+def load_qq_user_dict (fname):
+    result = []
+    f = codecs.open (fname, "r", "UTF-16")
+    for l in f:
+        if l[0] in ('\n', '\r'):
+            continue
+
+        try:
+            pystr, utf8str, _ = l.strip().split(",")[0].split(" ")
+            result.append ((pystr[1:], utf8str))
+        except:
+            pass
+
+    return result
+
+def main ():
+    if len (sys.argv) != 2:
+        print "Please specify the QQ PinYin exported user dict file!"
+        exit (1)
+
+    qq_user_dict = load_qq_user_dict(sys.argv[1])
+    import_to_sunpinyin_user_dict (qq_user_dict)
+
+if __name__ == "__main__":
+    main()
diff --git a/python/importer/import_sogou_celldict.py b/python/importer/import_sogou_celldict.py
new file mode 100755 (executable)
index 0000000..5401fc0
--- /dev/null
@@ -0,0 +1,81 @@
+#!/usr/bin/python
+
+# thanks for the reverse engineering efforts of following projects/peoples:
+# http://code.google.com/p/imewlconverter
+# http://code.google.com/p/ibus-cloud-pinyin
+# http://forum.ubuntu.org.cn/viewtopic.php?f=8&t=250136&start=0
+
+from importer import import_to_sunpinyin_user_dict
+import struct
+import os, sys
+
+def read_utf16_str (f, offset=-1, len=2):
+    if offset >= 0:
+        f.seek(offset)
+    str = f.read(len)
+    return str.decode('UTF-16LE')
+
+def read_uint16 (f):
+    return struct.unpack ('<H', f.read(2))[0]
+
+def get_word_from_sogou_cell_dict (fname):
+    f = open (fname, 'rb')
+    file_size = os.path.getsize (fname)
+    
+    hz_offset = 0
+    mask = struct.unpack ('B', f.read(128)[4])[0]
+    if mask == 0x44:
+        hz_offset = 0x2628
+    elif mask == 0x45:
+        hz_offset = 0x26c4
+    else:
+        sys.exit(1)
+    
+    title   = read_utf16_str (f, 0x130, 0x338  - 0x130)
+    type    = read_utf16_str (f, 0x338, 0x540  - 0x338)
+    desc    = read_utf16_str (f, 0x540, 0xd40  - 0x540)
+    samples = read_utf16_str (f, 0xd40, 0x1540 - 0xd40)
+    
+    py_map = {}
+    f.seek(0x1540+4)
+    
+    while 1:
+        py_code = read_uint16 (f)
+        py_len  = read_uint16 (f)
+        py_str  = read_utf16_str (f, -1, py_len)
+    
+        if py_code not in py_map:
+            py_map[py_code] = py_str
+    
+        if py_str == 'zuo':
+            break
+    
+    f.seek(hz_offset)
+    while f.tell() != file_size:
+        word_count   = read_uint16 (f)
+        pinyin_count = read_uint16 (f) / 2
+    
+        py_set = []
+        for i in range(pinyin_count):
+            py_id = read_uint16(f)
+            py_set.append(py_map[py_id])
+        py_str = "'".join (py_set)
+    
+        for i in range(word_count):
+            word_len = read_uint16(f)
+            word_str = read_utf16_str (f, -1, word_len)
+            f.read(12)  # simply ignore word frequence info
+            yield py_str, word_str
+
+    f.close()
+
+def main ():
+    if len (sys.argv) != 2:
+        print "Please specify the Sogou PinYin Cell dict file!"
+        exit (1)
+
+    generator = get_word_from_sogou_cell_dict (sys.argv[1])
+    import_to_sunpinyin_user_dict (generator)
+
+if __name__ == "__main__":
+    main()
diff --git a/python/importer/import_sogou_userdict.py b/python/importer/import_sogou_userdict.py
new file mode 100755 (executable)
index 0000000..28f1676
--- /dev/null
@@ -0,0 +1,29 @@
+#!/usr/bin/python
+
+import os, sys
+import codecs
+from importer import import_to_sunpinyin_user_dict
+
+def load_sogou_user_dict (fname):
+    result = []
+    f = codecs.open (fname, "r", "UTF-16")
+
+    for l in f:
+        if l[0] in (';', '\n', '\r'):
+            continue
+
+        pystr, utf8str = l.strip().split(" ")
+        result.append ((pystr[1:], utf8str))
+
+    return result
+
+def main ():
+    if len (sys.argv) != 2:
+        print "Please specify the Sogou PinYin exported user dict file!"
+        exit (1)
+
+    sogou_user_dict = load_sogou_user_dict(sys.argv[1])
+    import_to_sunpinyin_user_dict (sogou_user_dict)
+
+if __name__ == "__main__":
+    main()
diff --git a/python/importer/import_ziguang_userdict.py b/python/importer/import_ziguang_userdict.py
new file mode 100755 (executable)
index 0000000..b4c9b5f
--- /dev/null
@@ -0,0 +1,31 @@
+#!/usr/bin/python
+
+import os, sys
+import codecs
+from importer import import_to_sunpinyin_user_dict
+
+def load_ziguang_user_dict (fname):
+    result = []
+    f = codecs.open (fname, "r", "UTF-16")
+    for l in f:
+        if l[0] in ('\n', '\r'):
+            continue
+
+        try:
+            utf8str, pystr, _ = l.strip().split("\t")
+            result.append ((pystr, utf8str))
+        except:
+            pass
+
+    return result
+
+def main ():
+    if len (sys.argv) != 2:
+        print "Please specify the ZiGuang PinYin exported user dict file!"
+        exit (1)
+
+    ziguang_user_dict = load_ziguang_user_dict(sys.argv[1])
+    import_to_sunpinyin_user_dict (ziguang_user_dict)
+
+if __name__ == "__main__":
+    main()
diff --git a/python/importer/importer.py b/python/importer/importer.py
new file mode 100644 (file)
index 0000000..bf0dd5f
--- /dev/null
@@ -0,0 +1,136 @@
+#!/usr/bin/python
+import os, sys
+import struct
+import sqlite3 as sqlite
+from pinyin_data import valid_syllables, decode_syllable, initials, finals
+
+def get_userdict_path ():
+    homedir = os.environ.get("HOME")
+
+    if sys.platform == "darwin":
+        return homedir+"/Library/Application Support/SunPinyin/userdict"
+
+    # FIXME: not sure how to get the ibus version or wrapper type (xim or ibus)
+    if os.path.exists (homedir+"/.cache/ibus/sunpinyin"):
+        return homedir+"/.cache/ibus/sunpinyin/userdict"
+        
+    if os.path.exists (homedir+"/.ibus/sunpinyin"):
+        return homedir+"/.ibus/sunpinyin/userdict"
+    
+    if os.path.exists (homedir+"/.sunpinyin"):
+        return homedir+"/.sunpinyin/userdict"
+
+    raise "Can not detect sunpinyin's userdict!"
+
+def get_sysdict_path ():
+    if sys.platform == "darwin":
+        homedir = os.environ.get("HOME")
+        sysdict_path = "/Library/Input Methods/SunPinyin.app/Contents/Resources/pydict_sc.bin"
+        if os.path.exists (homedir + sysdict_path):
+            return homedir + sysdict_path
+        else:
+            return sysdict_path
+
+    return "/usr/lib/sunpinyin/data/pydict_sc.bin"
+
+def load_system_dict ():
+    sysdict_path = get_sysdict_path ()
+    f = open (sysdict_path, "rb")
+    
+    f.seek(8)
+    word_offset = struct.unpack ('I', f.read(4))[0]
+    f.seek (word_offset)
+
+    words = set()
+    str = f.read()
+    
+    for w in str.decode('UTF-32').split('\0'):
+        if w:
+            words.add (w)
+    
+    f.close()
+    return words
+
+def import_to_sunpinyin_user_dict (records, userdict_path=''):
+    userdict_path = userdict_path if userdict_path else get_userdict_path()
+    db = sqlite.connect (userdict_path)
+
+    sysdict = load_system_dict()
+
+    sqlstring = """
+            CREATE TABLE IF NOT EXISTS dict(
+            id INTEGER PRIMARY KEY, len INTEGER,
+            i0 INTEGER, i1 INTEGER, i2 INTEGER, i3 INTEGER, i4 INTEGER, i5 INTEGER,
+            f0 INTEGER, f1 INTEGER, f2 INTEGER, f3 INTEGER, f4 INTEGER, f5 INTEGER,
+            utf8str TEXT, UNIQUE (utf8str));
+            """
+    db.executescript (sqlstring)
+
+    batch_count = 0
+
+    for (pystr, utf8str) in records:
+        try:
+            syllables = [valid_syllables[s] for s in pystr.split("'")]
+        except:
+            print "[%s] has un-recognized syllables, ignoring this record!" % pystr
+            continue
+
+        if len (syllables) < 2 or len (syllables) > 6:
+            print "[%s] is too long or too short for sunpinyin userdict" % utf8str
+            continue
+
+        if utf8str in sysdict:
+            #print "[%s] is already in sunpinyin's sysdict" % utf8str
+            continue
+
+        record = [0]*14
+        record[0] = len (syllables)
+        record[13] = utf8str
+
+        c = 1
+        for s in syllables:
+            i, f = s>>12, (s&0x00ff0)>>4
+            if i and not f:
+                break; 
+            record[c] = i
+            record[c+1] = f
+            c += 2
+        else:
+            sqlstring = """
+                    INSERT INTO dict (len, i0, f0, i1, f1, i2, f2, i3, f3, i4, f4, i5, f5, utf8str)
+                    VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);
+                    """
+            try:
+                db.execute (sqlstring, record)
+                #print "[%s] is imported into sunpinyin's userdict" % utf8str
+
+                batch_count += 1
+                if batch_count == 100:
+                    db.commit ()
+                    batch_count = 0
+
+            except:
+                #print "[%s] is already in sunpinyin's userdict" % utf8str
+                pass
+
+    db.commit()
+    db.close()
+
+def export_sunpinyin_user_dict (userdict_path=''):
+    userdict_path = userdict_path if userdict_path else get_userdict_path()
+    db = sqlite.connect (userdict_path)
+
+    sqlstring = "SELECT * FROM dict"
+    result = list (db.execute (sqlstring).fetchall ())
+
+    for record in result:
+        id   = record[0]
+        l    = record[1]
+        i    = record[2:8]
+        f    = record[8:14]
+        str  = record[-1]
+        syls = [initials[i[x]] + finals[f[x]] for x in range(l)]
+        print str.encode ('UTF-8'), id, "'".join(syls) 
+        
+if __name__ == "__main__":
+    export_sunpinyin_user_dict ()
diff --git a/python/mmseg.py b/python/mmseg.py
new file mode 100755 (executable)
index 0000000..1a58fb1
--- /dev/null
@@ -0,0 +1,144 @@
+#!/usr/bin/python
+
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+# 
+# Copyright (c) 2007 Sun Microsystems, Inc. All Rights Reserved.
+# 
+# The contents of this file are subject to the terms of either the GNU Lesser
+# General Public License Version 2.1 only ("LGPL") or the Common Development and
+# Distribution License ("CDDL")(collectively, the "License"). You may not use this
+# file except in compliance with the License. You can obtain a copy of the CDDL at
+# http://www.opensource.org/licenses/cddl1.php and a copy of the LGPLv2.1 at
+# http://www.opensource.org/licenses/lgpl-license.php. See the License for the 
+# specific language governing permissions and limitations under the License. When
+# distributing the software, include this License Header Notice in each file and
+# include the full text of the License in the License file as well as the
+# following notice:
+# 
+# NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND DISTRIBUTION LICENSE
+# (CDDL)
+# For Covered Software in this distribution, this License shall be governed by the
+# laws of the State of California (excluding conflict-of-law provisions).
+# Any litigation relating to this License shall be subject to the jurisdiction of
+# the Federal Courts of the Northern District of California and the state courts
+# of the State of California, with venue lying in Santa Clara County, California.
+# 
+# Contributor(s):
+# 
+# If you wish your version of this file to be governed by only the CDDL or only
+# the LGPL Version 2.1, indicate your decision by adding "[Contributor]" elects to
+# include this software in this distribution under the [CDDL or LGPL Version 2.1]
+# license." If you don't indicate a single choice of license, a recipient has the
+# option to distribute your version of this file under either the CDDL or the LGPL
+# Version 2.1, or to extend the choice of license to its licensees as provided
+# above. However, if you add LGPL Version 2.1 code and therefore, elected the LGPL
+# Version 2 license, then the option applies only if the new code is made subject
+# to such option by the copyright holder. 
+
+import sys
+import getopt
+import codecs
+import struct
+
+from imdict import IMDict
+from trie import match_longest, get_ambiguious_length
+from utils import read_ch_sentences
+
+def usage():
+    print '''
+Usage:
+mmseg.py -d dict_file [-f (text|bin)] [-i] [-s STOK_ID] [-a AMBI_ID] corpus_file
+
+  -d --dict:
+    The dictionary file (in UTF-8 encoding) to be used.
+  -f --format:
+    Output format, can be 'text' or 'bin'. Default is 'bin'.
+    Normally, in text mode, word text are output, while in binary mode,
+    the integer of the word-ids are writed to stdout.
+  -i --show-id:
+    Show Id info. In text output format, attach id after known words. 
+  -s --stok-id:
+    Sentence token id. Default 10.
+    It will be write to output in binary mode after every sentence.
+  -a --ambi-id:
+    Ambiguious means ABC => A BC or AB C. If specified (AMBI-ID != 0), 
+    The sequence ABC will not be segmented, in binary mode, the AMBI-ID 
+    is written out; in text mode, <ambi>ABC</ambi> will be output. Default 
+    is 9.
+'''
+
+options={'show-id':       False, 
+         'format' :       'bin', 
+         'stok-id':       10,
+         'ambi-id':       9}
+
+def parse_options(args):
+    try:
+        opts, args = getopt.getopt(args, "hid:f:s:a:", ["help", "show-id", "dict=", "format=", "stok-id=", "ambi-id="])
+    except getopt.GetoptError, err:
+        print str(err) 
+        sys.exit(1)
+
+    for opt,val in opts:
+        if opt in ('-h', '--help'):
+            usage()
+            sys.exit()
+        elif opt in ('-d', '--dict'):
+            options['dict'] = val
+        elif opt in ('-i', '--show-id'):
+            options['show-id'] = True
+        elif opt in ('-f', '--format'):
+            if val in ('bin', 'text'):
+                options['format'] = val
+        elif opt in ('-s', '--stok-id'):
+            options['stok-id'] = int(val)
+        elif opt in ('-val', '--ambi-id'):
+            options['ambi-id'] = int(val)
+
+    if 'dict' not in options:
+        usage()
+        sys.exit(1)
+
+    if args:
+        options['corpus'] = args[0]
+
+def output_word(wid, word):
+    if options['format'] == 'text':
+        if wid == options['ambi-id']:
+            word = '<ambi>'+word+'</ambi>'
+        if options['show-id']:
+            word = word+'('+str(wid)+')'
+        sys.stdout.write('%s ' % word.encode('UTF-8'))
+    else:
+        sys.stdout.write(struct.pack('I', wid))
+
+def process_file(file, dict):
+    for line in read_ch_sentences(file):
+        print >> sys.stderr, line.encode('UTF-8')
+        length = len(line)
+        i = 0
+        while (i < length):
+            strbuf = line[i:]
+            wid, l = match_longest(dict, strbuf)
+            if wid == 0:
+                l = 1
+            else:
+                ambi_len = get_ambiguious_length(dict, strbuf, l)
+                if ambi_len > l:
+                    wid, l = options['ambi-id'], ambi_len
+
+            output_word (wid, strbuf[:l])
+            i += l
+
+        output_word (options['stok-id'], '\n')
+
+if __name__ == "__main__":
+    parse_options(sys.argv[1:])
+
+    dict = IMDict(options['dict'])
+    
+    try:    file = codecs.open(options['corpus'], "r", "UTF-8")
+    except: file = codecs.getreader('UTF-8')(sys.stdin)
+
+    process_file (file, dict)
+    file.close()
diff --git a/python/pinyin_data.py b/python/pinyin_data.py
new file mode 100755 (executable)
index 0000000..f984f67
--- /dev/null
@@ -0,0 +1,571 @@
+#!/usr/bin/python 
+
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+# 
+# Copyright (c) 2007 Sun Microsystems, Inc. All Rights Reserved.
+# 
+# The contents of this file are subject to the terms of either the GNU Lesser
+# General Public License Version 2.1 only ("LGPL") or the Common Development and
+# Distribution License ("CDDL")(collectively, the "License"). You may not use this
+# file except in compliance with the License. You can obtain a copy of the CDDL at
+# http://www.opensource.org/licenses/cddl1.php and a copy of the LGPLv2.1 at
+# http://www.opensource.org/licenses/lgpl-license.php. See the License for the 
+# specific language governing permissions and limitations under the License. When
+# distributing the software, include this License Header Notice in each file and
+# include the full text of the License in the License file as well as the
+# following notice:
+# 
+# NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND DISTRIBUTION LICENSE
+# (CDDL)
+# For Covered Software in this distribution, this License shall be governed by the
+# laws of the State of California (excluding conflict-of-law provisions).
+# Any litigation relating to this License shall be subject to the jurisdiction of
+# the Federal Courts of the Northern District of California and the state courts
+# of the State of California, with venue lying in Santa Clara County, California.
+# 
+# Contributor(s):
+# 
+# If you wish your version of this file to be governed by only the CDDL or only
+# the LGPL Version 2.1, indicate your decision by adding "[Contributor]" elects to
+# include this software in this distribution under the [CDDL or LGPL Version 2.1]
+# license." If you don't indicate a single choice of license, a recipient has the
+# option to distribute your version of this file under either the CDDL or the LGPL
+# Version 2.1, or to extend the choice of license to its licensees as provided
+# above. However, if you add LGPL Version 2.1 code and therefore, elected the LGPL
+# Version 2 license, then the option applies only if the new code is made subject
+# to such option by the copyright holder. 
+
+initials = ["", "b", "p", "m", "f", "d", "t", "n", "l", "g", "k", "h", "j", "q", "x", "zh", "ch", "sh", "r", "z", "c", "s", "y", "w", ]
+
+finals = ["", "a", "o", "e", "ai", "ei", "ao", "ou", "an", "en", "ang", "eng", "er", "i", "ia", "ie", "iao", "iu", "ian", "in", "iang", "ing", "u", "ua", "uo", "uai", "ui", "uan", "un", "uang", "ong", "v", "ue", "iong", ]
+
+inner_fuzzy_finals = ['ia', 'iao', 'ian', 'iang', 'ie', 'ua', 'uai', 'uan', 'uang', 'ue']
+
+fuzzy_pairs = [
+    ('z',       'zh'), 
+    ('c',       'ch'), 
+    ('s',       'sh'), 
+    ('an',      'ang'), 
+    ('on',      'ong'), 
+    ('en',      'eng'), 
+    ('in',      'ing'), 
+    ('eng',     'ong'), 
+    ('ian',     'iang'), 
+    ('uan',     'uang'), 
+    ('l',       'n'), 
+    ('f',       'h'), 
+    ('r',       'l'), 
+    ('k',       'g'),
+]
+
+auto_correction_pairs = {
+    'ign':      'ing',
+    'img':      'ing',
+    'uei':      'ui',
+    'uen':      'un',
+    'iou':      'iu',
+}
+
+valid_syllables = {
+    "a":        0x00010,
+    "ai":       0x00040,
+    "an":       0x00080,
+    "ang":      0x000a0,
+    "ao":       0x00060,
+    "b":        0x01000,
+    "ba":       0x01010,
+    "bai":      0x01040,
+    "ban":      0x01080,
+    "bang":     0x010a0,
+    "bao":      0x01060,
+    "bei":      0x01050,
+    "ben":      0x01090,
+    "beng":     0x010b0,
+    "bi":       0x010d0,
+    "bian":     0x01120,
+    "biao":     0x01100,
+    "bie":      0x010f0,
+    "bin":      0x01130,
+    "bing":     0x01150,
+    "bo":       0x01020,
+    "bu":       0x01160,
+    "c":        0x14000,
+    "ca":       0x14010,
+    "cai":      0x14040,
+    "can":      0x14080,
+    "cang":     0x140a0,
+    "cao":      0x14060,
+    "ce":       0x14030,
+    "cei":      0x14050,
+    "cen":      0x14090,
+    "ceng":     0x140b0,
+    "ch":       0x10000,
+    "cha":      0x10010,
+    "chai":     0x10040,
+    "chan":     0x10080,
+    "chang":    0x100a0,
+    "chao":     0x10060,
+    "che":      0x10030,
+    "chen":     0x10090,
+    "cheng":    0x100b0,
+    "chi":      0x100d0,
+    "chong":    0x101e0,
+    "chou":     0x10070,
+    "chu":      0x10160,
+    "chua":     0x10170,
+    "chuai":    0x10190,
+    "chuan":    0x101b0,
+    "chuang":   0x101d0,
+    "chui":     0x101a0,
+    "chun":     0x101c0,
+    "chuo":     0x10180,
+    "ci":       0x140d0,
+    "cong":     0x141e0,
+    "cou":      0x14070,
+    "cu":       0x14160,
+    "cuan":     0x141b0,
+    "cui":      0x141a0,
+    "cun":      0x141c0,
+    "cuo":      0x14180,
+    "d":        0x05000,
+    "da":       0x05010,
+    "dai":      0x05040,
+    "dan":      0x05080,
+    "dang":     0x050a0,
+    "dao":      0x05060,
+    "de":       0x05030,
+    "dei":      0x05050,
+    "den":      0x05090,
+    "deng":     0x050b0,
+    "di":       0x050d0,
+    "dia":      0x050e0,
+    "dian":     0x05120,
+    "diao":     0x05100,
+    "die":      0x050f0,
+    "ding":     0x05150,
+    "diu":      0x05110,
+    "dong":     0x051e0,
+    "dou":      0x05070,
+    "du":       0x05160,
+    "duan":     0x051b0,
+    "dui":      0x051a0,
+    "dun":      0x051c0,
+    "duo":      0x05180,
+    "e":        0x00030,
+    "ei":       0x00050,
+    "en":       0x00090,
+    "eng":      0x000b0,
+    "er":       0x000c0,
+    "f":        0x04000,
+    "fa":       0x04010,
+    "fan":      0x04080,
+    "fang":     0x040a0,
+    "fei":      0x04050,
+    "fen":      0x04090,
+    "feng":     0x040b0,
+    "fiao":     0x04100,
+    "fo":       0x04020,
+    "fou":      0x04070,
+    "fu":       0x04160,
+    "g":        0x09000,
+    "ga":       0x09010,
+    "gai":      0x09040,
+    "gan":      0x09080,
+    "gang":     0x090a0,
+    "gao":      0x09060,
+    "ge":       0x09030,
+    "gei":      0x09050,
+    "gen":      0x09090,
+    "geng":     0x090b0,
+    "gong":     0x091e0,
+    "gou":      0x09070,
+    "gu":       0x09160,
+    "gua":      0x09170,
+    "guai":     0x09190,
+    "guan":     0x091b0,
+    "guang":    0x091d0,
+    "gui":      0x091a0,
+    "gun":      0x091c0,
+    "guo":      0x09180,
+    "h":        0x0b000,
+    "ha":       0x0b010,
+    "hai":      0x0b040,
+    "han":      0x0b080,
+    "hang":     0x0b0a0,
+    "hao":      0x0b060,
+    "he":       0x0b030,
+    "hei":      0x0b050,
+    "hen":      0x0b090,
+    "heng":     0x0b0b0,
+    "hong":     0x0b1e0,
+    "hou":      0x0b070,
+    "hu":       0x0b160,
+    "hua":      0x0b170,
+    "huai":     0x0b190,
+    "huan":     0x0b1b0,
+    "huang":    0x0b1d0,
+    "hui":      0x0b1a0,
+    "hun":      0x0b1c0,
+    "huo":      0x0b180,
+    "j":        0x0c000,
+    "ji":       0x0c0d0,
+    "jia":      0x0c0e0,
+    "jian":     0x0c120,
+    "jiang":    0x0c140,
+    "jiao":     0x0c100,
+    "jie":      0x0c0f0,
+    "jin":      0x0c130,
+    "jing":     0x0c150,
+    "jiong":    0x0c210,
+    "jiu":      0x0c110,
+    "ju":       0x0c160,
+    "juan":     0x0c1b0,
+    "jue":      0x0c200,
+    "jun":      0x0c1c0,
+    "k":        0x0a000,
+    "ka":       0x0a010,
+    "kai":      0x0a040,
+    "kan":      0x0a080,
+    "kang":     0x0a0a0,
+    "kao":      0x0a060,
+    "ke":       0x0a030,
+    "kei":      0x0a050,
+    "ken":      0x0a090,
+    "keng":     0x0a0b0,
+    "kong":     0x0a1e0,
+    "kou":      0x0a070,
+    "ku":       0x0a160,
+    "kua":      0x0a170,
+    "kuai":     0x0a190,
+    "kuan":     0x0a1b0,
+    "kuang":    0x0a1d0,
+    "kui":      0x0a1a0,
+    "kun":      0x0a1c0,
+    "kuo":      0x0a180,
+    "l":        0x08000,
+    "la":       0x08010,
+    "lai":      0x08040,
+    "lan":      0x08080,
+    "lang":     0x080a0,
+    "lao":      0x08060,
+    "le":       0x08030,
+    "lei":      0x08050,
+    "leng":     0x080b0,
+    "li":       0x080d0,
+    "lia":      0x080e0,
+    "lian":     0x08120,
+    "liang":    0x08140,
+    "liao":     0x08100,
+    "lie":      0x080f0,
+    "lin":      0x08130,
+    "ling":     0x08150,
+    "liu":      0x08110,
+    "lo":       0x08020,
+    "long":     0x081e0,
+    "lou":      0x08070,
+    "lu":       0x08160,
+    "luan":     0x081b0,
+    "lue":      0x08200,
+    "lun":      0x081c0,
+    "luo":      0x08180,
+    "lv":       0x081f0,
+    "m":        0x03000,
+    "ma":       0x03010,
+    "mai":      0x03040,
+    "man":      0x03080,
+    "mang":     0x030a0,
+    "mao":      0x03060,
+    "me":       0x03030,
+    "mei":      0x03050,
+    "men":      0x03090,
+    "meng":     0x030b0,
+    "mi":       0x030d0,
+    "mian":     0x03120,
+    "miao":     0x03100,
+    "mie":      0x030f0,
+    "min":      0x03130,
+    "ming":     0x03150,
+    "miu":      0x03110,
+    "mo":       0x03020,
+    "mou":      0x03070,
+    "mu":       0x03160,
+    "n":        0x07000,
+    "na":       0x07010,
+    "nai":      0x07040,
+    "nan":      0x07080,
+    "nang":     0x070a0,
+    "nao":      0x07060,
+    "ne":       0x07030,
+    "nei":      0x07050,
+    "nen":      0x07090,
+    "neng":     0x070b0,
+    "ni":       0x070d0,
+    "nian":     0x07120,
+    "niang":    0x07140,
+    "niao":     0x07100,
+    "nie":      0x070f0,
+    "nin":      0x07130,
+    "ning":     0x07150,
+    "niu":      0x07110,
+    "nong":     0x071e0,
+    "nou":      0x07070,
+    "nu":       0x07160,
+    "nuan":     0x071b0,
+    "nue":      0x07200,
+    "nun":      0x071c0,
+    "nuo":      0x07180,
+    "nv":       0x071f0,
+    "o":        0x00020,
+    "ou":       0x00070,
+    "p":        0x02000,
+    "pa":       0x02010,
+    "pai":      0x02040,
+    "pan":      0x02080,
+    "pang":     0x020a0,
+    "pao":      0x02060,
+    "pei":      0x02050,
+    "pen":      0x02090,
+    "peng":     0x020b0,
+    "pi":       0x020d0,
+    "pian":     0x02120,
+    "piao":     0x02100,
+    "pie":      0x020f0,
+    "pin":      0x02130,
+    "ping":     0x02150,
+    "po":       0x02020,
+    "pou":      0x02070,
+    "pu":       0x02160,
+    "q":        0x0d000,
+    "qi":       0x0d0d0,
+    "qia":      0x0d0e0,
+    "qian":     0x0d120,
+    "qiang":    0x0d140,
+    "qiao":     0x0d100,
+    "qie":      0x0d0f0,
+    "qin":      0x0d130,
+    "qing":     0x0d150,
+    "qiong":    0x0d210,
+    "qiu":      0x0d110,
+    "qu":       0x0d160,
+    "quan":     0x0d1b0,
+    "que":      0x0d200,
+    "qun":      0x0d1c0,
+    "r":        0x12000,
+    "ran":      0x12080,
+    "rang":     0x120a0,
+    "rao":      0x12060,
+    "re":       0x12030,
+    "ren":      0x12090,
+    "reng":     0x120b0,
+    "ri":       0x120d0,
+    "rong":     0x121e0,
+    "rou":      0x12070,
+    "ru":       0x12160,
+    "ruan":     0x121b0,
+    "rui":      0x121a0,
+    "run":      0x121c0,
+    "ruo":      0x12180,
+    "s":        0x15000,
+    "sa":       0x15010,
+    "sai":      0x15040,
+    "san":      0x15080,
+    "sang":     0x150a0,
+    "sao":      0x15060,
+    "se":       0x15030,
+    "sen":      0x15090,
+    "seng":     0x150b0,
+    "sh":       0x11000,
+    "sha":      0x11010,
+    "shai":     0x11040,
+    "shan":     0x11080,
+    "shang":    0x110a0,
+    "shao":     0x11060,
+    "she":      0x11030,
+    "shei":     0x11050,
+    "shen":     0x11090,
+    "sheng":    0x110b0,
+    "shi":      0x110d0,
+    "shou":     0x11070,
+    "shu":      0x11160,
+    "shua":     0x11170,
+    "shuai":    0x11190,
+    "shuan":    0x111b0,
+    "shuang":   0x111d0,
+    "shui":     0x111a0,
+    "shun":     0x111c0,
+    "shuo":     0x11180,
+    "si":       0x150d0,
+    "song":     0x151e0,
+    "sou":      0x15070,
+    "su":       0x15160,
+    "suan":     0x151b0,
+    "sui":      0x151a0,
+    "sun":      0x151c0,
+    "suo":      0x15180,
+    "t":        0x06000,
+    "ta":       0x06010,
+    "tai":      0x06040,
+    "tan":      0x06080,
+    "tang":     0x060a0,
+    "tao":      0x06060,
+    "te":       0x06030,
+    "tei":      0x06050,
+    "teng":     0x060b0,
+    "ti":       0x060d0,
+    "tian":     0x06120,
+    "tiao":     0x06100,
+    "tie":      0x060f0,
+    "ting":     0x06150,
+    "tong":     0x061e0,
+    "tou":      0x06070,
+    "tu":       0x06160,
+    "tuan":     0x061b0,
+    "tui":      0x061a0,
+    "tun":      0x061c0,
+    "tuo":      0x06180,
+    "w":        0x17000,
+    "wa":       0x17010,
+    "wai":      0x17040,
+    "wan":      0x17080,
+    "wang":     0x170a0,
+    "wei":      0x17050,
+    "wen":      0x17090,
+    "weng":     0x170b0,
+    "wo":       0x17020,
+    "wu":       0x17160,
+    "x":        0x0e000,
+    "xi":       0x0e0d0,
+    "xia":      0x0e0e0,
+    "xian":     0x0e120,
+    "xiang":    0x0e140,
+    "xiao":     0x0e100,
+    "xie":      0x0e0f0,
+    "xin":      0x0e130,
+    "xing":     0x0e150,
+    "xiong":    0x0e210,
+    "xiu":      0x0e110,
+    "xu":       0x0e160,
+    "xuan":     0x0e1b0,
+    "xue":      0x0e200,
+    "xun":      0x0e1c0,
+    "y":        0x16000,
+    "ya":       0x16010,
+    "yan":      0x16080,
+    "yang":     0x160a0,
+    "yao":      0x16060,
+    "ye":       0x16030,
+    "yi":       0x160d0,
+    "yin":      0x16130,
+    "ying":     0x16150,
+    "yo":       0x16020,
+    "yong":     0x161e0,
+    "you":      0x16070,
+    "yu":       0x16160,
+    "yuan":     0x161b0,
+    "yue":      0x16200,
+    "yun":      0x161c0,
+    "z":        0x13000,
+    "za":       0x13010,
+    "zai":      0x13040,
+    "zan":      0x13080,
+    "zang":     0x130a0,
+    "zao":      0x13060,
+    "ze":       0x13030,
+    "zei":      0x13050,
+    "zen":      0x13090,
+    "zeng":     0x130b0,
+    "zh":       0x0f000,
+    "zha":      0x0f010,
+    "zhai":     0x0f040,
+    "zhan":     0x0f080,
+    "zhang":    0x0f0a0,
+    "zhao":     0x0f060,
+    "zhe":      0x0f030,
+    "zhei":     0x0f050,
+    "zhen":     0x0f090,
+    "zheng":    0x0f0b0,
+    "zhi":      0x0f0d0,
+    "zhong":    0x0f1e0,
+    "zhou":     0x0f070,
+    "zhu":      0x0f160,
+    "zhua":     0x0f170,
+    "zhuai":    0x0f190,
+    "zhuan":    0x0f1b0,
+    "zhuang":   0x0f1d0,
+    "zhui":     0x0f1a0,
+    "zhun":     0x0f1c0,
+    "zhuo":     0x0f180,
+    "zi":       0x130d0,
+    "zong":     0x131e0,
+    "zou":      0x13070,
+    "zu":       0x13160,
+    "zuan":     0x131b0,
+    "zui":      0x131a0,
+    "zun":      0x131c0,
+    "zuo":      0x13180,
+}
+
+def decode_syllable (s):
+    return initials[(s>>12)], finals[(s&0x00ff0)>>4]
+
+def init_fuzzy_map (fuzzy_pairs):
+    fuzzy_map = {}
+    for i, j in fuzzy_pairs:
+        fuzzy_map.setdefault (i, []).append (j)
+        fuzzy_map.setdefault (j, []).append (i)
+
+    return fuzzy_map
+
+fuzzy_map = init_fuzzy_map (fuzzy_pairs)
+
+def get_fuzzy_syllables (syllable):
+    i, f = decode_syllable (syllable)
+    iset = fuzzy_map.setdefault(i, []) + [i]
+    fset = fuzzy_map.setdefault(f, []) + [f]
+    sset = [valid_syllables[i+f] for i in iset for f in fset if i+f in valid_syllables]
+    sset.remove (syllable)
+    return sset
+
+def gen_suffix_trie (fname):
+    from trie import Trie, DATrie
+    
+    trie = Trie ()
+    pytrie = DATrie ()
+
+    for s in valid_syllables:
+        trie.add (s[::-1], valid_syllables[s])
+    
+    pytrie.construct_from_trie (trie)
+    pytrie.output_static_c_arrays (fname)
+
+def gen_fuzzy_syllable_pairs_tables ():
+    fuzzy_pro_syllables = [s for s in valid_syllables if s[1:] in valid_syllables and s[0] in initials and s not in initials]
+    fuzzy_pre_syllables = [s for s in valid_syllables if s[:-1] in valid_syllables and s[-1] in initials and s not in initials]
+
+    initial_sets = set([s[0] for s in fuzzy_pro_syllables]) & set([s[-1] for s in fuzzy_pre_syllables])
+
+    fuzzy_pro_syllables  = [s for s in fuzzy_pro_syllables if s[0] in initial_sets]
+    fuzzy_pre_syllables  = [s for s in fuzzy_pre_syllables if s[-1] in initial_sets]
+
+    print "static const unsigned fuzzy_pre_syllables [] = {"
+    for s in fuzzy_pre_syllables:
+        print "    %-12s %-12s %-12s /* %s */" % ("0x%05x," % valid_syllables[s[:-1]], "'%s'," % s[-1], "0x%05x," % valid_syllables[s], s)
+    print "    0x0,"
+    print "};\n"
+
+    print "static const unsigned fuzzy_pro_syllables [] = {"
+    for s in fuzzy_pro_syllables:
+        print "    %-12s %-12s %-12s /* %s */" % ("0x%05x," % valid_syllables[s], "'%s'," % s[0], "0x%05x," % valid_syllables[s[1:]], s)
+    print "    0x0,"
+    print "};\n"
+
+def gen_inner_fuzzy_syllable_tables ():
+    print "static const unsigned fuzzy_finals_map[] = {"
+    for s in inner_fuzzy_finals:
+        print "    %-12s %-12s %-12s /* %-4s -> %-4s len %d */" % ("0x%02x," % finals.index(s), "0x%02x," % valid_syllables[s[1:]], "%d," % (len(s)-1,),  s, s[1:], len(s)-1)
+    print "};\n"
+
+if __name__ == "__main__":
+    gen_suffix_trie ("../src/pinyin/quanpin_trie.h")
+    gen_inner_fuzzy_syllable_tables ()
+    gen_fuzzy_syllable_pairs_tables ()
diff --git a/python/pyslm.pyx b/python/pyslm.pyx
new file mode 100644 (file)
index 0000000..2a49ed2
--- /dev/null
@@ -0,0 +1,125 @@
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+# 
+# Copyright (c) 2007 Sun Microsystems, Inc. All Rights Reserved.
+# 
+# The contents of this file are subject to the terms of either the GNU Lesser
+# General Public License Version 2.1 only ("LGPL") or the Common Development and
+# Distribution License ("CDDL")(collectively, the "License"). You may not use this
+# file except in compliance with the License. You can obtain a copy of the CDDL at
+# http://www.opensource.org/licenses/cddl1.php and a copy of the LGPLv2.1 at
+# http://www.opensource.org/licenses/lgpl-license.php. See the License for the 
+# specific language governing permissions and limitations under the License. When
+# distributing the software, include this License Header Notice in each file and
+# include the full text of the License in the License file as well as the
+# following notice:
+# 
+# NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND DISTRIBUTION LICENSE
+# (CDDL)
+# For Covered Software in this distribution, this License shall be governed by the
+# laws of the State of California (excluding conflict-of-law provisions).
+# Any litigation relating to this License shall be subject to the jurisdiction of
+# the Federal Courts of the Northern District of California and the state courts
+# of the State of California, with venue lying in Santa Clara County, California.
+# 
+# Contributor(s):
+# 
+# If you wish your version of this file to be governed by only the CDDL or only
+# the LGPL Version 2.1, indicate your decision by adding "[Contributor]" elects to
+# include this software in this distribution under the [CDDL or LGPL Version 2.1]
+# license." If you don't indicate a single choice of license, a recipient has the
+# option to distribute your version of this file under either the CDDL or the LGPL
+# Version 2.1, or to extend the choice of license to its licensees as provided
+# above. However, if you add LGPL Version 2.1 code and therefore, elected the LGPL
+# Version 2 license, then the option applies only if the new code is made subject
+# to such option by the copyright holder. 
+
+cdef extern from "slm.h":
+
+    ctypedef union CThreadSlm_TState "CThreadSlm::TState":
+        void setIdx (unsigned int idx)
+        void setLevel (unsigned int level)
+        unsigned int getLevel()
+        unsigned int getIdx()
+
+    ctypedef struct CThreadSlm "CThreadSlm":
+        bint load(char *filename, bint MMap)
+        bint isUseLogPr()
+        void free()
+        double transferNegLog (CThreadSlm_TState history, unsigned int wid, CThreadSlm_TState result)
+        double transfer (CThreadSlm_TState history, unsigned int wid, CThreadSlm_TState result)
+        CThreadSlm_TState history_state_of(CThreadSlm_TState st)
+        CThreadSlm_TState historify(CThreadSlm_TState st)
+        unsigned int lastWordId(CThreadSlm_TState st)
+
+    CThreadSlm *new_CThreadSlm "new CThreadSlm" ()
+    void del_CThreadSlm "delete" (CThreadSlm *slm)
+
+cdef class SlmState:
+    cdef public int level, idx
+    def __cinit__(self, level=0, idx=0):
+        self.level = level
+        self.idx = idx
+
+    def __richcmp__ (self, other, op):
+        equal = self.level == other.level and self.idx == other.idx
+        if   op == 2:   return equal
+        elif op == 3:   return not equal
+        else:           return NotImplemented
+
+    def __hash__ (self):
+        return ((self.level, self.idx)).__hash__()
+
+    def __str__(self):
+        return "[level=%d, idx=%d]" % (self.level, self.idx)
+
+cdef inline pystate_to_cstate (state, CThreadSlm_TState *st):
+    st.setLevel (state.level)
+    st.setIdx (state.idx)
+
+cdef class Slm:
+    cdef CThreadSlm *thisptr
+
+    def __cinit__(self):
+        self.thisptr = new_CThreadSlm()
+
+    def __dealloc__(self):
+        del_CThreadSlm (self.thisptr)
+
+    def load (self, fname):
+        return self.thisptr.load(fname, True)
+
+    def is_using_log_pr(self):
+        return self.thisptr.isUseLogPr()
+
+    def free(self):
+        self.thisptr.free()
+
+    def transfer_neglog(self, history, wid):
+        cdef CThreadSlm_TState his, ret
+        pystate_to_cstate (history, &his)
+        pr = self.thisptr.transferNegLog(his, wid, ret)
+        return pr, SlmState(ret.getLevel(), ret.getIdx())
+
+    def transfer(self, history, wid):
+        cdef CThreadSlm_TState his, ret
+        pystate_to_cstate (history, &his)
+        pr = self.thisptr.transfer(his, wid, ret)
+        return pr, SlmState(ret.getLevel(), ret.getIdx())
+    
+    def history_state_of(self, state):
+        cdef CThreadSlm_TState st, ret
+        pystate_to_cstate (state, &st)
+        ret = self.thisptr.history_state_of(st)
+        return SlmState(ret.getLevel(), ret.getIdx())
+
+    def historify (self, state):
+        cdef CThreadSlm_TState st
+        pystate_to_cstate (state, &st)
+        self.thisptr.historify(st)
+        state.level = int(st.getLevel())
+        state.idx = int(st.getIdx())
+
+    def last_word_id (self, state):
+        cdef CThreadSlm_TState st
+        pystate_to_cstate (state, &st)
+        return self.thisptr.lastWordId(st)
diff --git a/python/pytrie.pyx b/python/pytrie.pyx
new file mode 100644 (file)
index 0000000..d80af52
--- /dev/null
@@ -0,0 +1,146 @@
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+# 
+# Copyright (c) 2007 Sun Microsystems, Inc. All Rights Reserved.
+# 
+# The contents of this file are subject to the terms of either the GNU Lesser
+# General Public License Version 2.1 only ("LGPL") or the Common Development and
+# Distribution License ("CDDL")(collectively, the "License"). You may not use this
+# file except in compliance with the License. You can obtain a copy of the CDDL at
+# http://www.opensource.org/licenses/cddl1.php and a copy of the LGPLv2.1 at
+# http://www.opensource.org/licenses/lgpl-license.php. See the License for the 
+# specific language governing permissions and limitations under the License. When
+# distributing the software, include this License Header Notice in each file and
+# include the full text of the License in the License file as well as the
+# following notice:
+# 
+# NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND DISTRIBUTION LICENSE
+# (CDDL)
+# For Covered Software in this distribution, this License shall be governed by the
+# laws of the State of California (excluding conflict-of-law provisions).
+# Any litigation relating to this License shall be subject to the jurisdiction of
+# the Federal Courts of the Northern District of California and the state courts
+# of the State of California, with venue lying in Santa Clara County, California.
+# 
+# Contributor(s):
+# 
+# If you wish your version of this file to be governed by only the CDDL or only
+# the LGPL Version 2.1, indicate your decision by adding "[Contributor]" elects to
+# include this software in this distribution under the [CDDL or LGPL Version 2.1]
+# license." If you don't indicate a single choice of license, a recipient has the
+# option to distribute your version of this file under either the CDDL or the LGPL
+# Version 2.1, or to extend the choice of license to its licensees as provided
+# above. However, if you add LGPL Version 2.1 code and therefore, elected the LGPL
+# Version 2 license, then the option applies only if the new code is made subject
+# to such option by the copyright holder. 
+
+cdef extern from "Python.h":
+    ctypedef struct PyUnicodeObject:
+        pass
+    ctypedef unsigned wchar_t
+    ctypedef wchar_t * const_wchar_t_ptr "const wchar_t *"
+    object PyUnicode_FromWideChar (wchar_t *, Py_ssize_t)
+    Py_ssize_t PyUnicode_AsWideChar (PyUnicodeObject *, wchar_t *, Py_ssize_t)
+
+cdef extern from "portability.h":
+    ctypedef unsigned TWCHAR
+    ctypedef TWCHAR * const_TWCHAR_ptr "const TWCHAR *"
+    unsigned WCSLEN (const_TWCHAR_ptr ws)
+
+cdef extern from "pytrie.h":
+    ctypedef struct CPinyinTrie_TWord "CPinyinTrie::TWordIdInfo":
+        bint     m_bSeen
+        unsigned m_cost
+        unsigned m_csLevel
+        unsigned m_id
+        unsigned m_len
+
+    ctypedef struct CPinyinTrie_TNode "CPinyinTrie::TNode":
+        unsigned m_nWordId
+        CPinyinTrie_TWord * getWordIdPtr ()
+
+    ctypedef struct CPinyinTrie "CPinyinTrie":
+        bint load(char *filename)
+        void free()
+        int getWordCount ()
+        CPinyinTrie_TNode * getRootNode ()
+        CPinyinTrie_TNode * transfer (CPinyinTrie_TNode *, unsigned)
+        const_TWCHAR_ptr getitem "operator []" (unsigned)
+        int getSymbolId (const_TWCHAR_ptr)
+        bint isValid (CPinyinTrie_TNode*, bint, unsigned)
+
+    CPinyinTrie *new_CPinyinTrie "new CPinyinTrie" ()
+    void del_CPinyinTrie "delete" (CPinyinTrie *pytrie)
+
+cdef class WordInfo:
+    cdef public bint seen
+    cdef public int wid, cost, length, charset_level
+
+    def __cinit__ (self, wid, seen=True, cost=0, length=0, charset_level=0):
+        self.wid = wid
+        self.seen = seen
+        self.cost = cost
+        self.length = length
+        self.charset_level = charset_level
+
+    def __str__ (self):
+        return "wid=%d, seen=%d, cost=%d, length=%d, charset_level=%d" % \
+               (self.wid, self.seen, self.cost, self.length, self.charset_level)
+
+cdef class PinyinTrieNode:
+    cdef CPinyinTrie_TNode *pnode
+
+    def get_words (self):
+        words = []
+        cdef CPinyinTrie_TWord *p= <CPinyinTrie_TWord*> self.pnode.getWordIdPtr ()
+        for i in xrange (self.pnode.m_nWordId):
+            words.append (WordInfo(p[i].m_id, p[i].m_bSeen, p[i].m_cost, p[i].m_len, p[i].m_csLevel))
+        return words 
+
+cdef class PinyinTrie:
+    cdef CPinyinTrie *thisptr
+
+    def __cinit__ (self):
+        self.thisptr = new_CPinyinTrie ()
+
+    def __dealloc__ (self):
+        del_CPinyinTrie (self.thisptr)
+
+    def load (self, fname):
+        return self.thisptr.load (fname)
+
+    def free (self):
+        self.thisptr.free ()
+
+    def get_word_count (self):
+        return self.thisptr.getWordCount()
+
+    def get_root_node (self):
+        cdef CPinyinTrie_TNode * pnode = <CPinyinTrie_TNode*> self.thisptr.getRootNode ()
+        node = PinyinTrieNode ()
+        (<PinyinTrieNode>node).pnode = pnode
+        return node
+
+    def transfer (self, node, syllable):
+        cdef CPinyinTrie_TNode *pnode = (<PinyinTrieNode>node).pnode
+        pnode = <CPinyinTrie_TNode*> self.thisptr.transfer (pnode, <int>syllable)
+        if not pnode:
+            return None
+
+        node = PinyinTrieNode ()
+        (<PinyinTrieNode>node).pnode = pnode
+        return node
+
+    def __getitem__ (self, idx):
+        if idx<0 or idx>=self.thisptr.getWordCount(): return ''
+        cdef const_TWCHAR_ptr cwstr = self.thisptr.getitem (idx)
+        return PyUnicode_FromWideChar (<const_wchar_t_ptr>cwstr, WCSLEN(cwstr))
+
+    def get_symbol_id (self, symbol):
+        cdef wchar_t buf[2]
+        if len (symbol) != 1: return 0
+        PyUnicode_AsWideChar (<PyUnicodeObject*> symbol, buf, sizeof(buf))
+        return self.thisptr.getSymbolId (<const_TWCHAR_ptr> buf)
+
+    def is_valid (self, node, allowNonComplete=True, csLevel=0):
+        cdef CPinyinTrie_TNode *pnode = (<PinyinTrieNode>node).pnode
+        return self.thisptr.isValid (pnode, allowNonComplete, csLevel)
diff --git a/python/setup.py b/python/setup.py
new file mode 100644 (file)
index 0000000..e43c590
--- /dev/null
@@ -0,0 +1,34 @@
+from distutils.core import setup
+from distutils.extension import Extension
+from Cython.Distutils import build_ext
+
+setup(
+    name='sunpinyin-python',
+    version='0.1',
+    author = "Yong Sun",
+    author_email = "Yong.Sun@Sun.COM",
+    url = "http://www.opensolaris.org/os/project/input-method",
+    description = "A Python binding of the SunPinyin ngram model",
+    long_description = "A Python binding of the SunPinyin ngram model",
+    license = "CDDL/LGPLv2.1",
+
+    ext_modules=[
+        Extension(
+            "pyslm", ["pyslm.pyx", 
+                      "../src/slm/slm.cpp"], 
+            language="c++", 
+            include_dirs=["../src/slm", ".."], 
+            define_macros=[("HAVE_CONFIG_H", None)]
+        ),
+        Extension(
+            "pytrie", ["pytrie.pyx", 
+                       "../src/portability.cpp", 
+                       "../src/lexicon/pytrie.cpp", 
+                       "../src/lexicon/pinyin_data.cpp"], 
+            language="c++", 
+            include_dirs=["../src", "../src/lexicon", ".."], 
+            define_macros=[("HAVE_CONFIG_H", None)]
+        ),
+    ],
+    cmdclass = {'build_ext': build_ext}
+)
diff --git a/python/test.py b/python/test.py
new file mode 100644 (file)
index 0000000..51e7ee8
--- /dev/null
@@ -0,0 +1,48 @@
+#!/usr/bin/python
+# -*- coding: UTF-8 -*-
+
+from pyslm import Slm, SlmState
+from pytrie import PinyinTrie, PinyinTrieNode, WordInfo
+
+def test_pyslm ():
+    slm = Slm ()
+    if not slm.load ("../data/lm_sc.t3g"):
+        return
+
+    pr, result = slm.transfer (SlmState(0,0), 58614)
+    print "pr =", pr, "\tresult = %s" % result
+    
+    pr, result = slm.transfer (result, 75956)
+    print "pr =", pr, "\tresult = %s" % result
+    
+    pr, result = slm.transfer (result, 84582)
+    print "pr =", pr, "\tresult = %s" % result
+    
+    his = slm.history_state_of (result)
+    print "his = %s" % his
+    
+    slm.historify (result)
+    print "result = %s" % result
+
+    print 'last_word_id =', slm.last_word_id (result)
+
+    slm.free ()
+
+def test_pytrie ():
+    trie = PinyinTrie()
+    if not trie.load ("../data/pydict_sc.bin"):
+        return
+
+    root = trie.get_root_node ()
+    node = trie.transfer (root, 0x1000)
+    for w in node.get_words ():
+        print w
+
+    print trie.is_valid (node, False, 0)
+    print trie[10000]
+
+    print trie.get_symbol_id (u'。')
+    trie.free ()
+
+test_pyslm()
+test_pytrie()
diff --git a/python/trie.py b/python/trie.py
new file mode 100755 (executable)
index 0000000..2262a73
--- /dev/null
@@ -0,0 +1,279 @@
+#!/usr/bin/python
+
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+# 
+# Copyright (c) 2007 Sun Microsystems, Inc. All Rights Reserved.
+# 
+# The contents of this file are subject to the terms of either the GNU Lesser
+# General Public License Version 2.1 only ("LGPL") or the Common Development and
+# Distribution License ("CDDL")(collectively, the "License"). You may not use this
+# file except in compliance with the License. You can obtain a copy of the CDDL at
+# http://www.opensource.org/licenses/cddl1.php and a copy of the LGPLv2.1 at
+# http://www.opensource.org/licenses/lgpl-license.php. See the License for the 
+# specific language governing permissions and limitations under the License. When
+# distributing the software, include this License Header Notice in each file and
+# include the full text of the License in the License file as well as the
+# following notice:
+# 
+# NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND DISTRIBUTION LICENSE
+# (CDDL)
+# For Covered Software in this distribution, this License shall be governed by the
+# laws of the State of California (excluding conflict-of-law provisions).
+# Any litigation relating to this License shall be subject to the jurisdiction of
+# the Federal Courts of the Northern District of California and the state courts
+# of the State of California, with venue lying in Santa Clara County, California.
+# 
+# Contributor(s):
+# 
+# If you wish your version of this file to be governed by only the CDDL or only
+# the LGPL Version 2.1, indicate your decision by adding "[Contributor]" elects to
+# include this software in this distribution under the [CDDL or LGPL Version 2.1]
+# license." If you don't indicate a single choice of license, a recipient has the
+# option to distribute your version of this file under either the CDDL or the LGPL
+# Version 2.1, or to extend the choice of license to its licensees as provided
+# above. However, if you add LGPL Version 2.1 code and therefore, elected the LGPL
+# Version 2 license, then the option applies only if the new code is made subject
+# to such option by the copyright holder. 
+
+__all__ = ['Trie', 'DATrie', 'match_longest', 'get_ambiguious_length']
+
+from math import log
+import struct
+
+class Trie (object):
+    class TrieNode:
+        def __init__ (self):
+            self.val = 0
+            self.trans = {}
+
+    def __init__(self):
+        self.root = Trie.TrieNode()
+
+    def add(self, word, value=1):
+        curr_node = self.root
+        for ch in word:
+            try: 
+                curr_node = curr_node.trans[ch]
+            except:
+                curr_node.trans[ch] = Trie.TrieNode()
+                curr_node = curr_node.trans[ch]
+
+        curr_node.val = value
+
+    def walk (self, trienode, ch):
+        if ch in trienode.trans:
+            trienode = trienode.trans[ch]
+            return trienode, trienode.val
+        else:
+            return None, 0
+
+class FlexibleList (list):
+    def __check_size (self, index):
+        if index >= len(self):
+            self.extend ([0] * (index-len(self)+1))
+
+    def __getitem__ (self, index):
+        self.__check_size (index)
+        return list.__getitem__(self, index)
+
+    def __setitem__ (self, index, value):
+        self.__check_size (index)
+        return list.__setitem__(self, index, value)
+
+def character_based_encoder (ch, range=('a', 'z')):
+    ret = ord(ch) - ord(range[0]) + 1
+    if ret <= 0: ret = ord(range[1]) + 1
+    return ret
+
+class DATrie (object):
+    def __init__(self, chr_encoder=character_based_encoder):
+        self.root = 0
+        self.chr_encoder = chr_encoder
+        self.clear()
+
+    def clear (self):
+        self.base  = FlexibleList ()
+        self.check = FlexibleList ()
+        self.value = FlexibleList ()
+
+    def walk (self, s, ch):
+        c = self.chr_encoder (ch)
+        t = abs(self.base[s]) + c
+
+        if t<len(self.check) and self.check[t] == s and self.base[t]:
+            if self.value: 
+                v = self.value[t]
+            else: 
+                v = -1 if self.base[t] < 0 else 0
+            return t, v
+        else:
+            return 0, 0
+
+    def find_base (self, s, children, i=1):
+        if s == 0 or not children:
+            return s
+
+        i = max (i, 1)
+        loop_times = 0
+        while True:
+            for ch in children:
+                k = i + self.chr_encoder (ch)
+                if self.base[k] or self.check[k] or k == s:
+                    loop_times += 1
+                    i += int (log (loop_times, 2)) + 1
+                    break
+            else:
+                break
+
+        return i
+
+    def build (self, words, values=None):
+        assert (not values or (len(words) == len(values)))
+        itval = iter(values) if values else None
+
+        trie = Trie()
+        for w in words:
+            trie.add (w, itval.next() if itval else -1)
+
+        self.construct_from_trie (trie, values!=None)
+
+    def construct_from_trie (self, trie, with_value=True, progress_cb=None, progress_cb_thr=100):
+        nodes = [(trie.root, 0)]
+        find_from = 1
+        loop_times = 0
+
+        while nodes:
+            trienode, s = nodes.pop(0)
+            find_from = b = self.find_base (s, trienode.trans, find_from)
+            self.base[s] = -b if trienode.val else b
+            if with_value: self.value[s] = trienode.val
+
+            for ch in trienode.trans:
+                c = self.chr_encoder (ch)
+                t = abs(self.base[s]) + c
+                self.check[t] = s if s else -1
+
+                nodes.append ((trienode.trans[ch], t))
+
+            loop_times += 1
+            if loop_times == progress_cb_thr:
+                loop_times = 0
+                if progress_cb:
+                    progress_cb ()
+
+        for i in xrange (self.chr_encoder (max(trie.root.trans))+1):
+            if self.check[i] == -1:
+                self.check[i] = 0
+
+    def save (self, fname):
+        f = open (fname, 'w+')
+        l = len (self.base)
+
+        using_32bits = l > 2**15
+        elm_size = 4 if using_32bits else 2
+        fmt_str = '%di'%l if using_32bits else '%dh'%l
+
+        # the data types here should be aligned with those in datrie.h
+        f.write (struct.pack ('I', l))
+        f.write (struct.pack ('H', elm_size))
+        f.write (struct.pack ('H', 1 if self.value else 0))
+
+        f.write (struct.pack (fmt_str, *self.base))
+        f.write (struct.pack (fmt_str, *self.check))
+
+        if self.value:
+            if len(self.value) < l: self.value[l-1] = 0
+            f.write (struct.pack ('%di'%l, *self.value))
+
+        f.close()
+
+    def output_static_c_arrays (self, fname):
+        f = open(fname, 'w+')
+        l = len (self.base)
+
+        type = "int" if l > 2**15 else "short"
+
+        f.write (self.__to_c_array (self.base,  type,  "base"))
+        f.write (self.__to_c_array (self.check, type,  "check"))
+        f.write (self.__to_c_array (self.value, "int", "value"))
+
+        f.close()
+
+    def __to_c_array (self, array, type, name):
+        return "static %s %s[] = {%s};\n\n" % (type, name, ', '.join (str(i) for i in array))
+
+    def load (self, fname):
+        f = open (fname, 'r')
+
+        l = struct.unpack ('I', f.read(4))[0]
+        elm_size = struct.unpack ('H', f.read(2))[0]
+        has_value = struct.unpack ('H', f.read(2))[0]
+
+        fmt_str = '%di'%l if elm_size == 4 else '%dh'%l
+        self.base  = struct.unpack (fmt_str, f.read(l*elm_size))
+        self.check = struct.unpack (fmt_str, f.read(l*elm_size))
+        self.value = struct.unpack ('%di'%l, f.read(l*4)) if has_value else []
+
+        f.close()
+
+def search (trie, word):
+    curr_node = trie.root
+
+    for ch in word:
+        curr_node, val = trie.walk (curr_node, ch)
+        if not curr_node: 
+            break
+    else:
+        return val
+
+    return 0
+
+def match_longest (trie, word):
+    l = ret_l = ret_v = 0
+    curr_node = trie.root
+
+    for ch in word:
+        curr_node, val = trie.walk (curr_node, ch)
+        if not curr_node: 
+            break
+
+        l += 1
+        if val: 
+            ret_l, ret_v = l, val
+
+    return ret_v, ret_l
+
+def get_ambiguious_length (trie, str, word_len):
+    i = 1
+    while i < word_len and i < len(str):
+        wid, l = match_longest(trie, str[i:])
+        if word_len < i + l:
+            word_len = i + l
+        i += 1
+    return i
+
+def test ():
+    from pinyin_data import valid_syllables
+
+    trie = Trie()
+    for s in valid_syllables:
+        trie.add (s, valid_syllables[s])
+
+    for s in valid_syllables:
+        v, l = match_longest (trie, s+'b')
+        assert (len(s) == l and valid_syllables[s] == v)
+
+    datrie = DATrie()
+    datrie.construct_from_trie (trie)
+
+    datrie.save ('/tmp/trie_test')
+    datrie.load ('/tmp/trie_test')
+
+    for s in valid_syllables:
+        v, l = match_longest (datrie, s+'b')
+        assert (len(s) == l and valid_syllables[s] == v)
+
+    print 'test executed successfully'
+
+if __name__ == "__main__":
+    test ()
diff --git a/python/trie.pyc b/python/trie.pyc
new file mode 100644 (file)
index 0000000..fd7791e
Binary files /dev/null and b/python/trie.pyc differ
diff --git a/python/utils.py b/python/utils.py
new file mode 100644 (file)
index 0000000..1fa2cc5
--- /dev/null
@@ -0,0 +1,210 @@
+#!/usr/bin/python 
+# -*- coding: UTF-8 -*-
+
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+# 
+# Copyright (c) 2007 Sun Microsystems, Inc. All Rights Reserved.
+# 
+# The contents of this file are subject to the terms of either the GNU Lesser
+# General Public License Version 2.1 only ("LGPL") or the Common Development and
+# Distribution License ("CDDL")(collectively, the "License"). You may not use this
+# file except in compliance with the License. You can obtain a copy of the CDDL at
+# http://www.opensource.org/licenses/cddl1.php and a copy of the LGPLv2.1 at
+# http://www.opensource.org/licenses/lgpl-license.php. See the License for the 
+# specific language governing permissions and limitations under the License. When
+# distributing the software, include this License Header Notice in each file and
+# include the full text of the License in the License file as well as the
+# following notice:
+# 
+# NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND DISTRIBUTION LICENSE
+# (CDDL)
+# For Covered Software in this distribution, this License shall be governed by the
+# laws of the State of California (excluding conflict-of-law provisions).
+# Any litigation relating to this License shall be subject to the jurisdiction of
+# the Federal Courts of the Northern District of California and the state courts
+# of the State of California, with venue lying in Santa Clara County, California.
+# 
+# Contributor(s):
+# 
+# If you wish your version of this file to be governed by only the CDDL or only
+# the LGPL Version 2.1, indicate your decision by adding "[Contributor]" elects to
+# include this software in this distribution under the [CDDL or LGPL Version 2.1]
+# license." If you don't indicate a single choice of license, a recipient has the
+# option to distribute your version of this file under either the CDDL or the LGPL
+# Version 2.1, or to extend the choice of license to its licensees as provided
+# above. However, if you add LGPL Version 2.1 code and therefore, elected the LGPL
+# Version 2 license, then the option applies only if the new code is made subject
+# to such option by the copyright holder. 
+
+import os
+import mmap
+import struct
+import heapq
+import tempfile
+
+class NGram:
+    key = ()
+    freq = 0
+
+    def __init__(self, key, freq):
+        self.key = key
+        self.freq = freq
+
+    def __cmp__(self,other):
+        return cmp(self.key, other.key)
+
+    def __str__(self):
+        return "ngram: " + self.key.__str__() + " freq: " + str(self.freq)
+
+def read_ch_sentences(file):
+    buf = []
+    for line in file:
+        if buf and (line[0].isspace() or len(buf) <= 40):
+            yield ''.join(buf)
+            buf = []
+
+        for ch in line:
+            if ch.isspace() or ch == u'—':
+                continue
+
+            if ch in u";。!?…—":
+                if buf:
+                    buf.append(ch)
+                    yield ''.join (buf)
+                    buf = []
+            else:
+                buf.append (ch)
+    if buf:
+        yield ''.join (buf)
+
+def mergesort (iters):
+        heap=[]
+
+        for it in iters:
+            try:
+                heap.append((it.next(), it))
+            except StopIteration:
+                pass
+
+        heapq.heapify(heap)
+
+        while heap:
+            val, it = heap[0]
+            yield val
+
+            try:
+                heapq.heapreplace(heap, (it.next(),it))
+            except StopIteration:
+                heapq.heappop(heap)
+
+def read_ngrams (fname, n):
+    file = open(fname, "r")
+    fsize = os.path.getsize(fname)
+    mem = mmap.mmap(file.fileno(), fsize, mmap.MAP_SHARED, mmap.PROT_READ)
+
+    while True:
+        ngram = mem.read((n+1)*4)
+        if ngram:
+            data = struct.unpack('%dl' % (n+1), ngram)
+            yield NGram(data[:n], data[n])
+        else:
+            break
+
+    mem.close()
+    file.close()
+
+class MMArray:
+    __file = __mem = None
+    __realsize = __capsize = 0
+
+    def __init__(self, elmsize=1, fname=None, capsize=1024*1024):
+        self.__elmsize = elmsize
+
+        if not fname:
+            fno, self.__fname = tempfile.mkstemp("-mmarray", "pyslm-")
+            self.__file = os.fdopen (fno, "w+")
+            self.__enlarge(capsize)
+        else:
+            self.fromfile(fname)
+
+    def fromfile(self, fname):
+        if not os.path.exists(fname):
+            raise "The file '%s' does not exist!"
+
+        fsize = os.path.getsize(fname)
+        if fsize == 0:
+            raise "The size of file '%s' is zero!" % fname
+
+        if self.__mem: self.__mem.close()
+        if self.__file: self.__file.close()
+
+        self.__file = open (fname, "r+")
+        self.__mem = mmap.mmap(self.__file.fileno(), fsize)
+        self.__realsize = self.__capsize = fsize/self.__elmsize
+
+    def tofile(self, fname):
+        if fname == self.__file.name:
+            raise "Can not dump the array to currently mapping file!"
+        tf = open(fname, "w+")
+        bsize = self.__realsize * self.__elmsize
+        tf.write (self.__mem[:bsize])
+        tf.close()
+
+    def __enlarge(self, capsize):
+        if self.__capsize >= capsize:
+            return
+        
+        self.__capsize = capsize
+        self.__file.seek(self.__elmsize * self.__capsize - 1)
+        self.__file.write('\0')
+        self.__file.flush()
+
+        if (self.__mem): self.__mem.close()
+        self.__mem = mmap.mmap(self.__file.fileno(), self.__file.tell())
+
+    def __del__ (self):
+        bsize = self.__realsize * self.__elmsize
+        self.__file.truncate (bsize)
+        self.__file.close()
+        if self.__mem: self.__mem.close()
+        os.remove(self.__fname)
+
+    def __getitem__(self, idx):
+        if idx < -self.__realsize or idx >= self.__realsize:
+            raise IndexError
+        return self.__access(idx)
+
+    def __setitem__(self, idx, buf):
+        if idx < -self.__realsize or idx >= self.__realsize:
+            raise IndexError
+        if type(buf) != type("") or len(buf) != self.__elmsize:
+            raise "Not a string, or the buffer size is incorrect!"
+        self.__access(idx, buf)
+
+    def __access (self, idx, buf=None):
+        if idx < 0: idx = self.__realsize + idx
+        start = idx * self.__elmsize
+        end = start + self.__elmsize
+        if not buf: return self.__mem[start:end]
+        self.__mem[start:end] = buf
+
+    def size(self):
+        return self.__realsize
+
+    def append(self, buf):
+        if type(buf) != type("") or len(buf) != self.__elmsize:
+            raise "Not a string, or the buffer size is incorrect!"
+
+        if self.__realsize >= self.__capsize:
+            self.__enlarge(self.__capsize*2)
+
+        self.__access(self.__realsize, buf)
+        self.__realsize += 1
+
+    def __iter__(self):
+        for i in xrange(0, self.__realsize):
+            yield self.__access(i)
+
+    def truncate(self, tsize):
+        if self.__realsize >= tsize:
+            self.__realsize = tsize
diff --git a/raw/Makefile.am b/raw/Makefile.am
new file mode 100755 (executable)
index 0000000..c7283fd
--- /dev/null
@@ -0,0 +1,12 @@
+## Makefile.am -- Process this file with automake to produce Makefile.in
+## Copyright (C) 2009 SAMSUNG
+##
+
+MAINTAINERCLEANFILES  = Makefile.in
+CLEANFILES      = *.bak
+
+dictdir                        = $(SUNPINYIN_DATA_DIR)
+dict_DATA              = pydict_sc.bin lm_sc.t3g
+
+EXTRA_DIST            = $(dict_DATA)
+
diff --git a/raw/lm_sc.t3g b/raw/lm_sc.t3g
new file mode 100755 (executable)
index 0000000..d72d428
Binary files /dev/null and b/raw/lm_sc.t3g differ
diff --git a/raw/pydict_sc.bin b/raw/pydict_sc.bin
new file mode 100644 (file)
index 0000000..9d9c004
Binary files /dev/null and b/raw/pydict_sc.bin differ
diff --git a/src/Makefile.am b/src/Makefile.am
new file mode 100755 (executable)
index 0000000..ee2fd7e
--- /dev/null
@@ -0,0 +1,57 @@
+## Makefile.am -- Process this file with automake to produce Makefile.in
+## Copyright (C) 2002 James Su
+##
+## This program is free software; you can redistribute it and/or modify
+## it under the terms of the GNU General Public License as published by
+## the Free Software Foundation; either version 2, or (at your option)
+## any later version.
+##
+## This program is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+## GNU General Public License for more details.
+##
+## You should have received a copy of the GNU General Public License
+## along with this program; if not, write to the Free Software
+## Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+
+SUBDIRS                = ime-core lexicon pinyin slm
+MAINTAINERCLEANFILES   = Makefile.in
+
+#####################portability##########################
+noinst_LTLIBRARIES = libportability.la
+libportability_la_SOURCES              = portability.cpp
+
+libsunpinyinincludedir       = $(includedir)/sunpinyin-2.0
+libsunpinyininclude_HEADERS    = portability.h\
+                                    sunpinyin.h\
+                                    ime-core/imi_option_event.h\
+                                    ime-core/imi_view.h\
+                                    ime-core/imi_options.h\
+                                    ime-core/imi_keys.h\
+                                    ime-core/imi_option_keys.h\
+                                   ime-core/imi_winHandler.h\
+                                   ime-core/imi_uiobjects.h
+#####################sunpinyin##########################
+SUNPINYIN_DEFINES=-DSUNPINYIN_DATA_DIR=\"@SUNPINYIN_DATA_DIR@\"
+moduledir = /usr/lib
+module_LTLIBRARIES = libsunpinyin.la
+
+libsunpinyin_la_SOURCES = 
+
+libsunpinyin_la_CXXFLAGS = @ISF_CXXFLAGS@ @SQLITE_CXXFLAGS@ @GLIB_CXXFLAGS@ $(SUNPINYIN_DEFINES)
+
+libsunpinyin_la_LDFLAGS = -avoid-version  @LTLIBINTL@\
+                                       -module \
+                                       -export-dynamic\
+                                       @ISF_LIBS@ \
+                                       @SQLITE_LIBS@\
+                                       @GLIB_LIBS@\
+                                       -lstdc++ 
+
+libsunpinyin_la_LIBADD = libportability.la\
+                        $(top_srcdir)/src/ime-core/libime-core.la\
+                        $(top_srcdir)/src/lexicon/liblexicon.la\
+                        $(top_srcdir)/src/pinyin/libpinyin.la\
+                        $(top_srcdir)/src/slm/libslm.la
diff --git a/src/ime-core/Makefile.am b/src/ime-core/Makefile.am
new file mode 100755 (executable)
index 0000000..dbc8d68
--- /dev/null
@@ -0,0 +1,61 @@
+## Makefile.am -- Process this file with automake to produce Makefile.in
+## Copyright (C) 2002 James Su
+##
+## This program is free software; you can redistribute it and/or modify
+## it under the terms of the GNU General Public License as published by
+## the Free Software Foundation; either version 2, or (at your option)
+## any later version.
+##
+## This program is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+## GNU General Public License for more details.
+##
+## You should have received a copy of the GNU General Public License
+## along with this program; if not, write to the Free Software
+## Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+
+MAINTAINERCLEANFILES   = Makefile.in
+CLEANFILES                    =        *.bak
+INCLUDES=-I$(top_srcdir)\
+         -I$(top_srcdir)/src\
+         -I$(top_srcdir)/src/ime-core\
+         -I$(top_srcdir)/src/lexicon\
+         -I$(top_srcdir)/src/pinyin\
+         -I$(top_srcdir)/src/slm
+         
+noinst_HEADERS = ic_history.h\
+                     imi_context.h\
+                     imi_data.h\
+                     imi_defines.h\
+                     imi_funcobjs.h\
+                     imi_glibHandler.h\
+                     imi_keys.h\
+                     imi_option_event.h\
+                     imi_option_keys.h\
+                     imi_options.h\
+                     imi_plugin.h\
+                     imi_uiobjects.h\
+                     imi_view_classic.h\
+                     imi_view.h\
+                     imi_winHandler.h\
+                     lattice_states.h\
+                     userdict.h\
+                     utils.h
+
+noinst_LTLIBRARIES = libime-core.la
+libime_core_la_SOURCES                 =  imi_context.cpp\
+           imi_data.cpp\
+           lattice_states.cpp\
+           imi_view.cpp\
+           imi_uiobjects.cpp\
+           imi_view_classic.cpp\
+           imi_winHandler.cpp\
+           ic_history.cpp\
+           imi_funcobjs.cpp\
+           imi_options.cpp\
+           imi_option_event.cpp\
+           userdict.cpp
+libime_core_la_CXXFLAGS = -DSUNPINYIN_DATA_DIR=\"@SUNPINYIN_DATA_DIR@\"\
+                         @SQLITE_CFLAGS@ @GLIB_CFLAGS@
diff --git a/src/ime-core/ic_history.cpp b/src/ime-core/ic_history.cpp
new file mode 100644 (file)
index 0000000..693c0b0
--- /dev/null
@@ -0,0 +1,420 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright (c) 2007 Sun Microsystems, Inc. All Rights Reserved.
+ *
+ * The contents of this file are subject to the terms of either the GNU Lesser
+ * General Public License Version 2.1 only ("LGPL") or the Common Development and
+ * Distribution License ("CDDL")(collectively, the "License"). You may not use this
+ * file except in compliance with the License. You can obtain a copy of the CDDL at
+ * http://www.opensource.org/licenses/cddl1.php and a copy of the LGPLv2.1 at
+ * http://www.opensource.org/licenses/lgpl-license.php. See the License for the
+ * specific language governing permissions and limitations under the License. When
+ * distributing the software, include this License Header Notice in each file and
+ * include the full text of the License in the License file as well as the
+ * following notice:
+ *
+ * NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND DISTRIBUTION LICENSE
+ * (CDDL)
+ * For Covered Software in this distribution, this License shall be governed by the
+ * laws of the State of California (excluding conflict-of-law provisions).
+ * Any litigation relating to this License shall be subject to the jurisdiction of
+ * the Federal Courts of the Northern District of California and the state courts
+ * of the State of California, with venue lying in Santa Clara County, California.
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by only the CDDL or only
+ * the LGPL Version 2.1, indicate your decision by adding "[Contributor]" elects to
+ * include this software in this distribution under the [CDDL or LGPL Version 2.1]
+ * license." If you don't indicate a single choice of license, a recipient has the
+ * option to distribute your version of this file under either the CDDL or the LGPL
+ * Version 2.1, or to extend the choice of license to its licensees as provided
+ * above. However, if you add LGPL Version 2.1 code and therefore, elected the LGPL
+ * Version 2 license, then the option applies only if the new code is made subject
+ * to such option by the copyright holder.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <unistd.h>
+#include <cassert>
+#include <arpa/inet.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <algorithm>
+#include "ic_history.h"
+
+const uint32_t CICHistory::DCWID = (uint32_t)-1;
+
+CICHistory::~CICHistory()
+{
+}
+
+const size_t CBigramHistory::contxt_memory_size = 8192;
+const double CBigramHistory::focus_memory_ratio = 0.05;
+
+//FIXME: CBigramHistory need to be thread safe
+CBigramHistory::CBigramHistory() : m_memory(), m_unifreq(), m_bifreq()
+{
+    initStopWords();
+}
+
+CBigramHistory::~CBigramHistory()
+{
+}
+
+bool
+CBigramHistory::memorize(uint32_t* its_wid, uint32_t* ite_wid)
+{
+    TBigram bigram(DCWID, DCWID);
+
+    // First , we insert an DC word id before the context history
+    // to seperated from previous stream.
+    if (m_memory.size() == contxt_memory_size) {
+        TBigram hb;
+        hb.first = m_memory.front();
+        m_memory.pop_front();
+        hb.second = m_memory.front();
+
+        decUniFreq(hb.first);
+        decBiFreq(hb);
+    }
+    m_memory.push_back(DCWID);
+
+    //Now trying to memorize new stream and forget oldest
+    for (; its_wid != ite_wid; ++its_wid) {
+        if (m_memory.size() == contxt_memory_size) {
+            TBigram hb;
+            hb.first = m_memory.front();
+            m_memory.pop_front();
+            hb.second = m_memory.front();
+
+            decUniFreq(hb.first);
+            decBiFreq(hb);
+        }
+        bigram.first = bigram.second;
+        bigram.second = *its_wid;
+        m_memory.push_back(*its_wid);
+        incUniFreq(bigram.second);
+        incBiFreq(bigram);
+    }
+    return true;
+}
+
+void
+CBigramHistory::clear()
+{
+    m_memory.clear();
+    m_unifreq.clear();
+    m_bifreq.clear();
+}
+
+double
+CBigramHistory::pr(uint32_t* its_wid, uint32_t* ite_wid)
+{
+    TBigram bigram(DCWID, DCWID);
+    if (its_wid != ite_wid) {
+        --ite_wid;
+        bigram.second = *ite_wid;
+        if (its_wid != ite_wid)
+            bigram.first = *(ite_wid - 1);
+    }
+    return pr(bigram);
+}
+
+double
+CBigramHistory::pr(uint32_t* its_wid, uint32_t* ite_wid, uint32_t wid)
+{
+    TBigram bigram(DCWID, DCWID);
+    if (its_wid != ite_wid)
+        bigram.first = *(ite_wid - 1);
+    bigram.second = wid;
+    return pr(bigram);
+}
+
+// htonl could be a macro, so wrap it in a func.
+inline uint32_t
+swap32(uint32_t x)
+{
+    return htonl(x);
+}
+
+bool
+CBigramHistory::bufferize(void** buf_ptr, size_t* sz)
+{
+    *buf_ptr = NULL;
+    *sz = 0;
+    try {
+        *sz = sizeof(uint32_t) * m_memory.size();
+        if (*sz > 0) {
+            *buf_ptr = malloc(*sz); // malloc for C compatible
+#ifdef WORDS_BIGENDIAN
+            std::copy(m_memory.begin(), m_memory.end(), (uint32_t*)*buf_ptr);
+#else
+            std::transform(m_memory.begin(),
+                           m_memory.end(), (uint32_t*)*buf_ptr, swap32);
+#endif
+        }
+        return true;
+    } catch (...) {
+        if (*buf_ptr)
+            free(*buf_ptr);
+        *buf_ptr = NULL;
+        *sz = 0;
+    }
+    return false;
+}
+
+bool
+CBigramHistory::loadFromFile(const char *fname)
+{
+    m_history_path = fname;
+
+    bool suc = false;
+    int fd = open(fname, O_CREAT, 0600);
+    if (fd == -1) {
+        suc = loadFromBuffer(NULL, 0);
+        return suc;
+    }
+
+    struct stat info;
+    fstat(fd, &info);
+    void* buf = malloc(info.st_size);
+
+    if (buf) {
+        read(fd, buf, info.st_size);
+        suc = loadFromBuffer(buf, info.st_size);
+        free(buf);
+    }
+    close(fd);
+    return suc;
+}
+
+bool
+CBigramHistory::saveToFile(const char *fname)
+{
+    if (!fname)
+        fname = m_history_path.c_str();
+
+    bool suc = false;
+    size_t sz = 0;
+    void* buf = NULL;
+    if (bufferize(&buf, &sz) && buf) {
+        FILE* fp = fopen(fname, "wb");
+        if (fp) {
+            suc = (fwrite(buf, 1, sz, fp) == sz);
+            fclose(fp);
+        }
+        free(buf);
+    }
+    return suc;
+}
+
+bool
+CBigramHistory::loadFromBuffer(void* buf_ptr, size_t sz)
+{
+    clear();
+
+    sz /= sizeof(uint32_t);
+    uint32_t *pw = (uint32_t*)buf_ptr;
+
+    if (pw && sz > 0) {
+#ifndef WORDS_BIGENDIAN
+        std::transform(pw, pw + sz, pw, swap32);
+#endif
+        TBigram bigram(DCWID, DCWID);
+        for (size_t i = 0; i < sz; ++i) {
+            bigram.first = bigram.second;
+            bigram.second = *pw++;
+            m_memory.push_back(bigram.second);
+            incUniFreq(bigram.second);
+            incBiFreq(bigram);
+        }
+    }
+    return true;
+}
+
+double
+CBigramHistory::pr(TBigram& bigram)
+{
+    int uf0 = uniFreq(bigram.first);
+    int bf = biFreq(bigram);
+    int uf1 = uniFreq(bigram.second);
+
+    double pr = 0.0;
+    pr += 0.68 * double(bf) / double(uf0 + 0.5);
+    pr += 0.32 * double(uf1) /
+          double(m_memory.size() + (contxt_memory_size - m_memory.size()) / 10);
+
+#ifdef DEBUG
+    if (pr != 0)
+        fprintf(stderr, "uf0:%d bf:%d uf1:%d pr(%d|%d):%lf\n", uf0, bf, uf1,
+                bigram.second, bigram.first, pr);
+#endif
+
+    return pr;
+}
+
+int
+CBigramHistory::uniFreq(TUnigram& ug)
+{
+    int freq = 0;
+    if (m_stopWords.find(ug) == m_stopWords.end()) {
+        TUnigramPool::iterator it = m_unifreq.find(ug);
+        if (it != m_unifreq.end()) {
+            freq = it->second;
+            TContextMemory::reverse_iterator rit = m_memory.rbegin();
+            for (int i =
+                     0;
+                 rit != m_memory.rend() && i < contxt_memory_size *
+                 focus_memory_ratio;
+                 i++) {
+                if (*rit == ug)
+                    freq += 1.0 / focus_memory_ratio;
+                *rit++;
+            }
+        }
+    }
+    //if (freq != 0) printf("uniFreq[%d]-->%d\n", ug, freq);
+    return freq / 2;
+}
+
+int
+CBigramHistory::biFreq(TBigram& bg)
+{
+    int freq = 0;
+    //std::set<unsigned>::const_iterator ite = m_stopWords.end();
+    if (m_stopWords.find(bg.first) == m_stopWords.end()
+        && m_stopWords.find(bg.second) == m_stopWords.end()) {
+        TBigramPool::const_iterator it = m_bifreq.find(bg);
+        if (it != m_bifreq.end()) {
+            freq = it->second;
+            TContextMemory::reverse_iterator re = m_memory.rbegin();
+            TContextMemory::reverse_iterator rs = re + 1;
+            for (int i = 0;
+                 rs != m_memory.rend() && i < contxt_memory_size *
+                 focus_memory_ratio;
+                 i++) {
+                if (*rs == bg.first && *re == bg.second)
+                    freq += 1.0 / focus_memory_ratio;
+                ++rs; ++re;
+            }
+        }
+    }
+
+    //if (freq != 0) printf("biFreq[%d,%d]-->%d\n", bg.first, bg.second, freq);
+    return freq;
+}
+
+void
+CBigramHistory::decUniFreq(TUnigram& ug)
+{
+    TUnigramPool::iterator it = m_unifreq.find(ug);
+    if (it != m_unifreq.end()) {
+        if (it->second > 1)
+            --(it->second);
+        else
+            m_unifreq.erase(it);
+    }
+}
+
+bool
+CBigramHistory::seenBefore(uint32_t wid)
+{
+    return(wid != DCWID && m_stopWords.find(wid) == m_stopWords.end() &&
+           m_unifreq.find(wid) != m_unifreq.end());
+}
+
+void
+CBigramHistory::decBiFreq(TBigram& bg)
+{
+    TBigramPool::iterator it = m_bifreq.find(bg);
+    if (it != m_bifreq.end()) {
+        if (it->second > 1)
+            --(it->second);
+        else
+            m_bifreq.erase(it);
+    }
+}
+
+void
+CBigramHistory::incUniFreq(TUnigram& ug)
+{
+    ++m_unifreq[ug];
+    //printf("Remebering uniFreq[%d]-->%d\n", ug, m_unifreq[ug]);
+}
+
+void
+CBigramHistory::incBiFreq(TBigram& bg)
+{
+    ++m_bifreq[bg];
+    //printf("Remebering biFreq[%d,%d]-->%d\n", bg.first, bg.second, m_bifreq[bg]);
+}
+
+// so far, it's very expensive to erase a word from bigram pairs, need to design
+// a better data structure for this.
+//
+// And Even though, we may also need to remove the individual characters in this
+// word (identified by wid), which is current infeasible,
+//
+// Here are what we need to do:
+//   1. get the wstring by word id from userdict
+//   2. iterate the character in this wstring
+//   3. get the word id from each character from system lexicon (not supported yet)
+//   4. remove the unigrams and bigrams of each character, and the entire word
+//
+void
+CBigramHistory::forget(uint32_t wid)
+{
+    TUnigramPool::iterator uni_it = m_unifreq.find(wid);
+    if (uni_it != m_unifreq.end())
+        m_unifreq.erase(uni_it);
+
+    TBigramPool::iterator it = m_bifreq.begin();
+    TBigramPool::iterator ite = m_bifreq.end();
+
+    while (it != ite) {
+        TBigram bigram = it->first;
+
+        if (bigram.first == wid || bigram.second == wid)
+            m_bifreq.erase(it++);
+        else
+            ++it;
+    }
+}
+
+void
+CBigramHistory::forget(uint32_t *its_wid, uint32_t *ite_wid)
+{
+    for (; its_wid < ite_wid; ++its_wid) {
+        TBigram bigram(*its_wid, DCWID);
+
+        if (its_wid + 1 != ite_wid)
+            bigram.second = *(its_wid + 1);
+
+        TBigramPool::iterator it = m_bifreq.find(bigram);
+        if (it != m_bifreq.end())
+            m_bifreq.erase(it);
+    }
+}
+
+void
+CBigramHistory::addStopWords(const std::set<uint32_t>& stopWords)
+{
+    m_stopWords.insert(stopWords.begin(), stopWords.end());
+}
+
+void
+CBigramHistory::initStopWords()
+{
+    m_stopWords.clear();
+
+    m_stopWords.insert(0);     //unknown world
+    m_stopWords.insert(DCWID); //seperator word id used by history memory interanlly
+}
diff --git a/src/ime-core/ic_history.h b/src/ime-core/ic_history.h
new file mode 100644 (file)
index 0000000..ba5a929
--- /dev/null
@@ -0,0 +1,186 @@
+// -*- mode: c++ -*-
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright (c) 2007 Sun Microsystems, Inc. All Rights Reserved.
+ *
+ * The contents of this file are subject to the terms of either the GNU Lesser
+ * General Public License Version 2.1 only ("LGPL") or the Common Development and
+ * Distribution License ("CDDL")(collectively, the "License"). You may not use this
+ * file except in compliance with the License. You can obtain a copy of the CDDL at
+ * http://www.opensource.org/licenses/cddl1.php and a copy of the LGPLv2.1 at
+ * http://www.opensource.org/licenses/lgpl-license.php. See the License for the
+ * specific language governing permissions and limitations under the License. When
+ * distributing the software, include this License Header Notice in each file and
+ * include the full text of the License in the License file as well as the
+ * following notice:
+ *
+ * NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND DISTRIBUTION LICENSE
+ * (CDDL)
+ * For Covered Software in this distribution, this License shall be governed by the
+ * laws of the State of California (excluding conflict-of-law provisions).
+ * Any litigation relating to this License shall be subject to the jurisdiction of
+ * the Federal Courts of the Northern District of California and the state courts
+ * of the State of California, with venue lying in Santa Clara County, California.
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by only the CDDL or only
+ * the LGPL Version 2.1, indicate your decision by adding "[Contributor]" elects to
+ * include this software in this distribution under the [CDDL or LGPL Version 2.1]
+ * license." If you don't indicate a single choice of license, a recipient has the
+ * option to distribute your version of this file under either the CDDL or the LGPL
+ * Version 2.1, or to extend the choice of license to its licensees as provided
+ * above. However, if you add LGPL Version 2.1 code and therefore, elected the LGPL
+ * Version 2 license, then the option applies only if the new code is made subject
+ * to such option by the copyright holder.
+ */
+
+#ifndef _SUNPINYIN_CONTEXT_HISTORY_H
+#define _SUNPINYIN_CONTEXT_HISTORY_H
+
+#include "portability.h"
+
+#include <map>
+#include <deque>
+#include <set>
+
+/**
+ * A forget all history memory
+ */
+class CICHistory {
+public:
+    /** don't care word id, or seperator word id */
+    static const uint32_t DCWID;
+
+    virtual ~CICHistory();
+
+    virtual bool seenBefore(uint32_t wid) = 0;
+
+    /**
+     * memorize the context stream pointed by [its_wid, ite_wid)
+     */
+    virtual bool memorize(uint32_t* its_wid, uint32_t* ite_wid) = 0;
+    virtual void clear() = 0;
+
+    /**
+     * remove a word id from history cache
+     */
+    virtual void forget(uint32_t wid) = 0;
+    virtual void forget(uint32_t* its_wid, uint32_t* ite_wid) = 0;
+
+    /**
+     * @param its_wid is the first word pointer of the context stream
+     * @param ite_wid is the last (exclusive) word pointer of the context stream
+     * @return pr(*(ite_wid-1) | *its_wid, ..., *(ite_wid-2))
+     * The return value could be zero, i.e. no need to smooth the probabilities
+     */
+    virtual double pr(uint32_t* its_wid, uint32_t* ite_wid) = 0;
+
+    /**
+     * @param its_wid is the first word pointer of the history stream
+     * @param ite_wid is the last (exclusive) word pointer of the history stream
+     * @return pr(*wid | *its_wid, ..., *(ite_wid-1))
+     * The return value could be zero, i.e. no need to smooth the probabilities
+     */
+    virtual double pr(uint32_t* its_wid,
+                      uint32_t* ite_wid,
+                      uint32_t wid) = 0;
+
+    /**
+     * allocate a buffer, and put the context memory's contect into it
+     * @param buf_ptr would be stored the buffer pointer
+     * @param sz would be the size in byte of the buffer allocated
+     * @return false on error
+     * Note: the buf_ptr should be used free(*buf_ptr) to free after usage
+     */
+    virtual bool
+    bufferize(void** buf_ptr, size_t* sz) = 0;
+
+    /**
+     * Load context memory according to the buf
+     * @param buf_ptr uffer pointer
+     * @param sz is the size in byte of the buffer
+     * @return false on error
+     * call with buf_ptr with NULL value would clear the context memory
+     */
+    virtual bool loadFromBuffer(void* buf_ptr, size_t sz) = 0;
+    virtual bool loadFromFile(const char *fname) = 0;
+    virtual bool saveToFile(const char *fname = NULL) = 0;
+
+    virtual void addStopWords(const std::set<uint32_t>& stopWords) = 0;
+
+    virtual void initStopWords() = 0;
+};
+
+class CBigramHistory : public CICHistory {
+public:
+    static void initClass();
+
+    CBigramHistory();
+
+    virtual ~CBigramHistory();
+
+    virtual bool seenBefore(uint32_t wid);
+
+    virtual bool memorize(uint32_t* its_wid, uint32_t* ite_wid);
+    virtual void clear();
+
+    virtual void forget(uint32_t wid);
+    virtual void forget(uint32_t* its_wid, uint32_t* ite_wid);
+
+    /**
+     * @param its_wid is the first word pointer of the context stream
+     * @param ite_wid is the last (exclusive) word pointer of the context stream
+     * @return pr(*(ite_wid-1) | *(ite_wid-2))
+     */
+    virtual double pr(uint32_t* its_wid, uint32_t* ite_wid);
+
+    /**
+     * @param its_wid is the first word pointer of the history stream
+     * @param ite_wid is the last (exclusive) word pointer of the history stream
+     * @return pr(*wid | *(ite_wid-1))
+     */
+    virtual double pr(uint32_t* its_wid,
+                      uint32_t* ite_wid,
+                      uint32_t wid);
+
+    virtual bool bufferize(void** buf_ptr, size_t* sz);
+
+    virtual bool loadFromBuffer(void* buf_ptr, size_t sz);
+    virtual bool loadFromFile(const char *fname);
+    virtual bool saveToFile(const char *fname = NULL);
+
+    virtual void addStopWords(const std::set<uint32_t>& stopWords);
+    virtual void initStopWords();
+
+protected:
+    typedef uint32_t TWordId;
+    typedef std::pair<TWordId, TWordId>           TBigram;
+    typedef TWordId TUnigram;
+    typedef std::map<TBigram, int>                TBigramPool;
+    typedef std::map<TUnigram, int>               TUnigramPool;
+    typedef std::deque<TWordId>                   TContextMemory;
+
+    static const size_t contxt_memory_size;
+    static const double focus_memory_ratio;
+
+    TContextMemory m_memory;
+    TUnigramPool m_unifreq;
+    TBigramPool m_bifreq;
+
+    std::string m_history_path;
+    std::set<uint32_t>  m_stopWords;
+
+protected:
+    double pr(TBigram& bg);
+    int  uniFreq(TUnigram& ug);
+    int  biFreq(TBigram& bg);
+
+    void decUniFreq(TUnigram& ug);
+    void decBiFreq(TBigram& bg);
+    void incUniFreq(TUnigram& ug);
+    void incBiFreq(TBigram& bg);
+};
+
+#endif
diff --git a/src/ime-core/imi_context.cpp b/src/ime-core/imi_context.cpp
new file mode 100644 (file)
index 0000000..fb387ea
--- /dev/null
@@ -0,0 +1,1061 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright (c) 2007 Sun Microsystems, Inc. All Rights Reserved.
+ *
+ * The contents of this file are subject to the terms of either the GNU Lesser
+ * General Public License Version 2.1 only ("LGPL") or the Common Development and
+ * Distribution License ("CDDL")(collectively, the "License"). You may not use this
+ * file except in compliance with the License. You can obtain a copy of the CDDL at
+ * http://www.opensource.org/licenses/cddl1.php and a copy of the LGPLv2.1 at
+ * http://www.opensource.org/licenses/lgpl-license.php. See the License for the
+ * specific language governing permissions and limitations under the License. When
+ * distributing the software, include this License Header Notice in each file and
+ * include the full text of the License in the License file as well as the
+ * following notice:
+ *
+ * NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND DISTRIBUTION LICENSE
+ * (CDDL)
+ * For Covered Software in this distribution, this License shall be governed by the
+ * laws of the State of California (excluding conflict-of-law provisions).
+ * Any litigation relating to this License shall be subject to the jurisdiction of
+ * the Federal Courts of the Northern District of California and the state courts
+ * of the State of California, with venue lying in Santa Clara County, California.
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by only the CDDL or only
+ * the LGPL Version 2.1, indicate your decision by adding "[Contributor]" elects to
+ * include this software in this distribution under the [CDDL or LGPL Version 2.1]
+ * license." If you don't indicate a single choice of license, a recipient has the
+ * option to distribute your version of this file under either the CDDL or the LGPL
+ * Version 2.1, or to extend the choice of license to its licensees as provided
+ * above. However, if you add LGPL Version 2.1 code and therefore, elected the LGPL
+ * Version 2 license, then the option applies only if the new code is made subject
+ * to such option by the copyright holder.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <assert.h>
+#include <algorithm>
+#include "imi_defines.h"
+#include "imi_context.h"
+
+TCandiRank::TCandiRank(bool user, bool best, unsigned len,
+                       bool fromLattice, TSentenceScore score)
+{
+    anony.m_user = (user) ? 0 : 1;
+    anony.m_best = (best) ? 0 : 1;
+    anony.m_len = (len > 31) ? (0) : (31 - len);
+    anony.m_lattice = (fromLattice) ? 0 : 1;
+
+    double ds = -score.log2();
+
+    //make it 24-bit
+    if (ds > 32767.0)
+        ds = 32767.0;
+    else if (ds < -32768.0)
+        ds = -32768.0;
+    unsigned cost = unsigned((ds + 32768.0) * 256.0);
+    anony.m_cost = cost;
+}
+
+TCandiRank::TCandiRank(bool user, bool best, unsigned len,
+                       bool fromLattice, unsigned rank)
+{
+    anony.m_user = (user) ? 0 : 1;
+    anony.m_best = (best) ? 0 : 1;
+    anony.m_len = (len > 31) ? (0) : (31 - len);
+    anony.m_lattice = (fromLattice) ? 0 : 1;
+    anony.m_cost = rank;
+}
+
+void
+CLatticeFrame::print(std::string prefix)
+{
+    if (m_bwType & BESTWORD) printf("B");
+    if (m_bwType & USER_SELECTED) printf("U");
+    printf("\n");
+
+    prefix += "    ";
+    printf("  Lexicon States:\n");
+    for_each(m_lexiconStates.begin(), m_lexiconStates.end(),
+             bind2nd(mem_fun_ref(&TLexiconState::print), prefix));
+
+    printf("  Lattice States:\n");
+    for_each(m_latticeStates.begin(), m_latticeStates.end(),
+             bind2nd(mem_fun_ref(&TLatticeState::print), prefix));
+    printf("\n");
+}
+
+void
+CIMIContext::printLattice()
+{
+    std::string prefix;
+
+    for (size_t i = 0; i <= m_tailIdx; ++i) {
+        if (m_lattice[i].m_type == CLatticeFrame::UNUSED)
+            continue;
+
+        printf("Lattice Frame [%lu]:", i);
+        m_lattice[i].print(prefix);
+    }
+}
+
+CIMIContext::CIMIContext()
+    : m_tailIdx(1), m_nBest(0), m_maxBest(1), m_maxTailCandidateNum(0),
+      m_pModel(NULL), m_pPinyinTrie(NULL), m_pUserDict(NULL), m_pHistory(NULL),
+      m_historyPower(5), m_csLevel(0), m_bFullSymbolForwarding(false),
+      m_bOmitPunct(false), m_pGetFullSymbolOp(NULL),
+      m_bFullPunctForwarding(true), m_pGetFullPunctOp(NULL),
+      m_pPySegmentor(NULL), m_bNonCompleteSyllable(true),
+      m_bDynaCandiOrder(true), m_candiStarts(0), m_candiEnds(0)
+{
+    m_lattice.resize(MAX_LATTICE_LENGTH);
+    m_lattice[0].m_latticeStates.add(TLatticeState(-1.0, 0));
+    setMaxBest(m_maxBest);
+}
+
+void
+CIMIContext::setCoreData(CIMIData *pCoreData)
+{
+    m_pModel = pCoreData->getSlm();
+    m_pPinyinTrie = pCoreData->getPinyinTrie();
+}
+
+void
+CIMIContext::clear()
+{
+    _clearFrom(1);
+    _clearPaths();
+    m_tailIdx = 1;
+    m_candiStarts = m_candiEnds = 0;
+}
+
+void
+CIMIContext::_clearFrom(unsigned idx)
+{
+    for (size_t i = idx; i < m_tailIdx + 1; i++)
+        m_lattice[i].clear();
+}
+
+bool
+CIMIContext::buildLattice(IPySegmentor *segmentor, bool doSearch)
+{
+    m_pPySegmentor = segmentor;
+    return _buildLattice(segmentor->getSegments(),
+                         segmentor->updatedFrom() + 1, doSearch);
+}
+
+bool
+CIMIContext::_buildLattice(IPySegmentor::TSegmentVec &segments,
+                           unsigned rebuildFrom,
+                           bool doSearch)
+{
+    _clearFrom(rebuildFrom);
+
+    IPySegmentor::TSegmentVec::const_iterator it = segments.begin();
+    IPySegmentor::TSegmentVec::const_iterator ite = segments.end();
+
+    unsigned i, j = 0;
+    for (; it != ite; ++it) {
+        i = it->m_start;
+        j = i + it->m_len;
+
+        if (i < rebuildFrom - 1)
+            continue;
+
+        if (j >= m_lattice.capacity() - 1)
+            break;
+
+        if (it->m_type == IPySegmentor::SYLLABLE)
+            _forwardSyllables(i, j, *it);
+        else if (it->m_type == IPySegmentor::SYLLABLE_SEP)
+            _forwardSyllableSep(i, j);
+        else
+            _forwardString(i, j, it->m_syllables);
+        m_bOmitPunct = false;
+    }
+
+    _forwardTail(j, j + 1);
+    m_tailIdx = j + 1;
+
+    return doSearch && searchFrom(rebuildFrom);
+}
+
+void
+CIMIContext::_forwardSyllables(unsigned i,
+                               unsigned j,
+                               const IPySegmentor::TSegment& seg)
+{
+    std::vector<unsigned>::const_iterator it = seg.m_syllables.begin();
+    std::vector<unsigned>::const_iterator ite = seg.m_syllables.end();
+
+    for (; it != ite; ++it)
+        _forwardSingleSyllable(i, j, *it, seg);
+
+    it = seg.m_fuzzy_syllables.begin();
+    ite = seg.m_fuzzy_syllables.end();
+
+    for (; it != ite; ++it)
+        _forwardSingleSyllable(i, j, *it, seg, true);
+}
+
+
+void
+CIMIContext::_forwardString(unsigned i,
+                            unsigned j,
+                            const std::vector<unsigned>& strbuf)
+{
+    if (strbuf.size() == 1) {
+        unsigned ch = strbuf[0];
+        if (ispunct(ch)) {
+            _forwardPunctChar(i, j, ch);
+        } else {
+            _forwardOrdinaryChar(i, j, ch);
+        }
+    } else{
+        CLatticeFrame &fr = m_lattice[j];
+        fr.m_wstr.assign(strbuf.begin(), strbuf.end());
+        fr.m_lexiconStates.push_back(TLexiconState(i, 0));
+    }
+}
+
+void
+CIMIContext::_forwardSingleSyllable(unsigned i,
+                                    unsigned j,
+                                    TSyllable syllable,
+                                    const IPySegmentor::TSegment& seg,
+                                    bool fuzzy)
+{
+    const CPinyinTrie::TNode * pn = NULL;
+
+    CLatticeFrame &fr = m_lattice[j];
+    fr.m_type = CLatticeFrame::SYLLABLE;
+
+    CLexiconStates::iterator it = m_lattice[i].m_lexiconStates.begin();
+    CLexiconStates::iterator ite = m_lattice[i].m_lexiconStates.end();
+    for (; it != ite; ++it) {
+        TLexiconState &lxst = *it;
+        bool added_from_sysdict = false;
+
+        if (lxst.m_pPYNode) {
+            // try to match a word from lattice i to lattice j
+            // and if match, we'll count it as a new lexicon on lattice j
+            pn = m_pPinyinTrie->transfer(lxst.m_pPYNode, syllable);
+            if (pn) {
+                added_from_sysdict = true;
+                TLexiconState new_lxst = TLexiconState(lxst.m_start,
+                                                       pn,
+                                                       lxst.m_syls,
+                                                       lxst.m_seg_path,
+                                                       fuzzy);
+                new_lxst.m_syls.push_back(syllable);
+                new_lxst.m_num_of_inner_fuzzies = lxst.m_num_of_inner_fuzzies +
+                                                  (seg.m_inner_fuzzy ? 1 : 0);
+                new_lxst.m_seg_path.push_back(seg.m_start + seg.m_len);
+                fr.m_lexiconStates.push_back(new_lxst);
+            }
+        }
+
+        if (m_pUserDict && lxst.m_syls.size() < MAX_USRDEF_WORD_LEN) {
+            // try to match a word from user dict
+            CSyllables syls = lxst.m_syls;
+            syls.push_back(syllable);
+            std::vector<CPinyinTrie::TWordIdInfo> words;
+            m_pUserDict->getWords(syls, words);
+            if (!words.empty() || !added_from_sysdict) {
+                // even if the words is empty we'll add a fake lexicon
+                // here. This helps _saveUserDict detect new words.
+                TLexiconState new_lxst = TLexiconState(lxst.m_start,
+                                                       words,
+                                                       lxst.m_syls,
+                                                       lxst.m_seg_path,
+                                                       fuzzy);
+                new_lxst.m_syls.push_back(syllable);
+                new_lxst.m_num_of_inner_fuzzies = lxst.m_num_of_inner_fuzzies +
+                                                  (seg.m_inner_fuzzy ? 1 : 0);
+                new_lxst.m_seg_path.push_back(seg.m_start + seg.m_len);
+                fr.m_lexiconStates.push_back(new_lxst);
+            }
+        }
+    }
+
+    // last, create a lexicon for single character with only one syllable
+    pn = m_pPinyinTrie->transfer(syllable);
+    if (pn) {
+        CSyllables syls;
+        syls.push_back(syllable);
+        std::vector<unsigned> seg_path;
+        seg_path.push_back(seg.m_start);
+        seg_path.push_back(seg.m_start + seg.m_len);
+        TLexiconState new_lxst = TLexiconState(i, pn, syls, seg_path, fuzzy);
+        new_lxst.m_num_of_inner_fuzzies = seg.m_inner_fuzzy ? 1 : 0;
+        fr.m_lexiconStates.push_back(new_lxst);
+    }
+}
+
+void
+CIMIContext::_forwardSyllableSep(unsigned i, unsigned j)
+{
+    CLatticeFrame &fr = m_lattice[j];
+    fr.m_type = CLatticeFrame::SYLLABLE | CLatticeFrame::SYLLABLE_SEP;
+    fr.m_lexiconStates = m_lattice[i].m_lexiconStates;
+
+    CLexiconStates::iterator it = fr.m_lexiconStates.begin();
+    CLexiconStates::iterator ite = fr.m_lexiconStates.end();
+    for (; it != ite; ++it) {
+        it->m_seg_path.back() = j;
+    }
+}
+
+void
+CIMIContext::_forwardPunctChar(unsigned i, unsigned j, unsigned ch)
+{
+    CLatticeFrame &fr = m_lattice[j];
+
+    wstring wstr;
+    unsigned wid = 0;
+
+    if (m_pGetFullPunctOp) {
+        if (m_bFullPunctForwarding && !m_bOmitPunct) {
+            wstr = (*m_pGetFullPunctOp)(ch);
+            wid = m_pPinyinTrie->getSymbolId(wstr);
+        }
+    }
+
+    fr.m_type = CLatticeFrame::PUNC;
+
+    if (!wstr.empty())
+        fr.m_wstr = wstr;
+    else
+        fr.m_wstr.push_back(ch);
+
+    fr.m_lexiconStates.push_back(TLexiconState(i, wid));
+}
+
+void
+CIMIContext::_forwardOrdinaryChar(unsigned i, unsigned j, unsigned ch)
+{
+    CLatticeFrame &fr = m_lattice[j];
+
+    wstring wstr;
+    unsigned wid = 0;
+
+    if (m_pGetFullSymbolOp) {
+        wstr = (*m_pGetFullSymbolOp)(ch);
+        wid = m_pPinyinTrie->getSymbolId(wstr);
+
+        if (!m_bFullSymbolForwarding)
+            wstr.clear();
+    }
+
+    fr.m_type = wid ? CLatticeFrame::SYMBOL : CLatticeFrame::ASCII;
+
+    if (!wstr.empty())
+        fr.m_wstr = wstr;
+    else
+        fr.m_wstr.push_back(ch);
+
+    fr.m_lexiconStates.push_back(TLexiconState(i, wid));
+}
+
+void
+CIMIContext::_forwardTail(unsigned i, unsigned j)
+{
+    CLatticeFrame &fr = m_lattice[j];
+    fr.m_type = CLatticeFrame::TAIL;
+
+    fr.m_lexiconStates.push_back(TLexiconState(i, ENDING_WORD_ID));
+}
+
+static double exp2_tbl[32] = {
+    exp2(-0), exp2(-1), exp2(-2), exp2(-3), exp2(-4), exp2(-5), exp2(-6), exp2(-7),
+    exp2(-8), exp2(-9), exp2(-10), exp2(-11), exp2(-12), exp2(-13), exp2(-14),
+    exp2(-15), exp2(-16), exp2(-17), exp2(-18), exp2(-19), exp2(-20), exp2(-21),
+    exp2(-22), exp2(-23), exp2(-24), exp2(-25), exp2(-26), exp2(-27), exp2(-28),
+    exp2(-29), exp2(-30), exp2(-31)
+};
+
+bool
+CIMIContext::searchFrom(unsigned idx)
+{
+    bool affectCandidates = (idx <= m_candiEnds);
+
+    for (; idx <= m_tailIdx; ++idx) {
+        CLatticeFrame &fr = m_lattice[idx];
+
+        if (fr.m_type == CLatticeFrame::UNUSED)
+            continue;
+
+        fr.m_latticeStates.clear();
+
+        /* user selected word might be cut in next step */
+        if (fr.m_bwType & CLatticeFrame::USER_SELECTED) {
+            _transferBetween(fr.m_selWord.m_start, idx,
+                             fr.m_selWord.m_pLexiconState,
+                             fr.m_selWord.m_wordId);
+        }
+
+        CLexiconStates::iterator it = fr.m_lexiconStates.begin();
+        CLexiconStates::iterator ite = fr.m_lexiconStates.end();
+        for (; it != ite; ++it) {
+            unsigned word_num = 0;
+            TLexiconState &lxst = *it;
+            const CPinyinTrie::TWordIdInfo *words = lxst.getWords(word_num);
+
+            if (!word_num)
+                continue;
+
+            if (lxst.m_start == m_candiStarts && idx > m_candiEnds)
+                affectCandidates = true;
+
+            // only selected the word with higher unigram probablities, and
+            // narrow the search deepth and lower the initial score for fuzzy
+            // syllables
+            int maxsz = it->m_bFuzzy ? MAX_LEXICON_TRIES /
+                        2 : MAX_LEXICON_TRIES;
+
+            double ic = it->m_bFuzzy ? 0.5 : 1.0;
+
+            int sz = (int) word_num < maxsz ? (int) word_num : maxsz;
+            int i = 0, count = 0;
+
+            while (count < sz && i < sz && (words[i].m_bSeen || count < 2)) {
+                if (m_csLevel >= words[i].m_csLevel) {
+                    // printf("cost %d\n", words[i].m_cost);
+                    _transferBetween(lxst.m_start, idx, &lxst, words[i].m_id,
+                                     ic * exp2_tbl[words[i].m_cost]);
+                    ++count;
+                }
+                i++;
+            }
+
+            /* try extra words in history cache */
+            if (m_pHistory) {
+                while (i < (int) word_num) {
+                    if (m_csLevel >= words[i].m_csLevel
+                        && m_pHistory->seenBefore(words[i].m_id)) {
+                        // printf("history cost %d\n", words[i].m_cost);
+                        _transferBetween(lxst.m_start, idx, &lxst,
+                                         words[i].m_id,
+                                         ic * exp2_tbl[words[i].m_cost]);
+                    }
+                    i++;
+                }
+            }
+        }
+    }
+
+    _clearPaths();
+    m_path.clear();
+    m_segPath.clear();
+    m_nBest = 0;
+
+    std::vector<TLatticeState> tail_states =
+        m_lattice[m_tailIdx].m_latticeStates.getFilteredResult();
+
+#ifdef DEBUG
+    for (int i = 0; i < tail_states.size(); i++) {
+        std::string score;
+        tail_states[i].m_score.toString(score);
+        printf("score[%d]: %s\n", i, score.c_str());
+    }
+#endif
+
+    for (size_t i = 0; i < m_maxBest; i++) {
+        TPath path, segpath;
+        if (_backTracePaths(tail_states, m_nBest, path, segpath)) {
+            m_path.push_back(path);
+            m_segPath.push_back(segpath);
+            m_nBest++;
+        }
+    }
+
+    if (m_pPySegmentor && m_nBest > 0 && !m_segPath[0].empty())
+        m_pPySegmentor->notify_best_segpath(m_segPath[0]);
+
+    return affectCandidates;
+}
+
+void
+CIMIContext::_transferBetween(unsigned start, unsigned end,
+                              TLexiconState* plxst, unsigned wid,
+                              double ic)
+{
+    CLatticeFrame &start_fr = m_lattice[start];
+    CLatticeFrame &end_fr = m_lattice[end];
+
+    TLatticeState node(-1.0, end, plxst);
+    TSentenceScore efic(ic);
+
+    if ((end_fr.m_bwType & CLatticeFrame::USER_SELECTED)
+        && end_fr.m_selWord.m_wordId == wid)
+        efic = TSentenceScore(30000, 1.0);
+
+    static double s_history_distribution[] = {
+        0.0, 0.05, 0.10, 0.15, 0.20, 0.25, 0.30, 0.35, 0.40, 0.45, 0.50
+    };
+
+    double weight_h = s_history_distribution[m_historyPower];
+    double weight_s = 1.0 - weight_h;
+
+    CLatticeStates::iterator it = start_fr.m_latticeStates.begin();
+    CLatticeStates::iterator ite = start_fr.m_latticeStates.end();
+
+    for (; it != ite; ++it) {
+        // for 1-length lattice states, replace ending_word_id (comma)
+        // with none_word_id (recognized by CThreadSlm)
+       unsigned _wid = wid;
+        if (wid == ENDING_WORD_ID && it->m_pBackTraceNode && it->m_pBackTraceNode->m_frIdx == 0)
+            _wid = NONE_WORD_ID;
+
+        node.m_pBackTraceNode = &(*it);
+        node.m_backTraceWordId = wid;
+
+        double ts = m_pModel->transfer(it->m_slmState, _wid, node.m_slmState);
+        m_pModel->historify(node.m_slmState);
+
+        // backward to psuedo root, so wid is probably a user word,
+        // save the wid in idx field, so that later we could get it via
+        // CThreadSlm::lastWordId, to calculate p_{cache} correctly.
+        if (node.m_slmState.getLevel() == 0
+            && m_pHistory && m_pHistory->seenBefore(wid))
+            node.m_slmState.setIdx(wid);  // an psuedo unigram node state
+
+        if (m_pHistory) {
+            unsigned history[2] = { m_pModel->lastWordId(it->m_slmState), _wid };
+            double hpr = m_pHistory->pr(history, history + 2);
+            ts = weight_s * ts + weight_h * hpr;
+        }
+
+        node.m_score = it->m_score * efic * TSentenceScore(ts);
+        // std::string buf;
+        // node.m_score.toString(buf);
+        // printf("node score %s ts=%lf ", buf.c_str(), ts);
+        // it->m_score.toString(buf);
+        // printf("%s ic=%lf\n", buf.c_str(), ic);
+        end_fr.m_latticeStates.add(node);
+    }
+}
+
+bool
+CIMIContext::_backTracePaths(const std::vector<TLatticeState>& tail_states,
+                             int rank, TPath& path, TPath& segmentPath)
+{
+    path.clear();
+    segmentPath.clear();
+
+    if (rank >= (int) tail_states.size()) {
+        // rank out of bounds, only return the segment path
+        return false;
+    }
+
+    const TLatticeState *bs = &(tail_states[rank]);
+
+    while (bs->m_pBackTraceNode) {
+        unsigned start = bs->m_pBackTraceNode->m_frIdx;
+        unsigned end = bs->m_frIdx;
+        CLatticeFrame & end_fr = m_lattice[end];
+
+        if (!(end_fr.m_bwType & CLatticeFrame::USER_SELECTED)) {
+            const TWCHAR* cwstr = NULL;
+            if (end_fr.m_wstr.empty()) {
+                cwstr = _getWstr(bs->m_backTraceWordId);
+            } else {
+                cwstr = end_fr.m_wstr.c_str();
+            }
+
+            CCandidate candi(start, end, bs->m_pLexiconState, cwstr,
+                             bs->m_backTraceWordId);
+
+            end_fr.m_bwType |= CLatticeFrame::BESTWORD;
+            end_fr.m_bestWords[rank] = candi;
+            if (rank == 0) {
+                end_fr.m_selWord = candi; // select the first by default.
+            }
+        }
+
+        if (bs->m_pBackTraceNode->m_pLexiconState) {
+            std::vector<unsigned> seg_path =
+                bs->m_pBackTraceNode->m_pLexiconState->m_seg_path;
+            std::vector<unsigned>::reverse_iterator it = seg_path.rbegin();
+
+            for (; it != seg_path.rend(); ++it) {
+                if (segmentPath.empty() || segmentPath.back() != *it)
+                    segmentPath.push_back(*it);
+            }
+        }
+
+        path.push_back(end);
+        bs = bs->m_pBackTraceNode;
+    }
+
+    std::reverse(path.begin(), path.end());
+    std::reverse(segmentPath.begin(), segmentPath.end());
+
+#ifdef DEBUG
+    std::vector<unsigned>::iterator it;
+
+    printf("trace lattice path[%d]: ", rank);
+    for (it = path.begin(); it != path.end(); ++it)
+        printf("%d ", *it);
+    printf("\n");
+
+    printf("trace segments path[%d]: ", rank);
+    for (it = segmentPath.begin(); it != segmentPath.end(); ++it)
+        printf("%d ", *it);
+    printf("\n");
+#endif
+
+    return true;
+}
+
+void
+CIMIContext::_clearPaths()
+{
+    m_path.clear();
+    m_segPath.clear();
+}
+
+std::vector<CCandidates>
+CIMIContext::getBestSentenceTails(int rank, unsigned start, unsigned end)
+{
+    std::vector<CCandidates> result;
+    if (rank < 0) {
+        return result;
+    }
+
+    CCandidates sentence;
+    unsigned word_num = getBestSentence(sentence, rank, start, end);
+    unsigned tail_word_num = word_num;
+
+    while (tail_word_num > 1) {
+        unsigned dec = tail_word_num / (m_maxTailCandidateNum + 1) + 1;
+        tail_word_num -= std::min(dec, tail_word_num);
+        if (tail_word_num <= 1) {
+            break;
+        }
+        CCandidates tail(sentence.begin(), sentence.begin() + tail_word_num);
+        result.push_back(tail);
+    }
+    return result;
+}
+
+unsigned
+CIMIContext::getBestSentence(CCandidates& result, int rank,
+                             unsigned start, unsigned end)
+{
+    // -1 means selected sentence
+    if (rank < -1 || rank >= (int) m_nBest)
+        return 0;
+
+    result.clear();
+
+    if (end == UINT_MAX)
+        end = m_tailIdx - 1;
+
+    while (end > start && m_lattice[end].m_bwType == CLatticeFrame::NO_BESTWORD)
+        end--;
+
+    unsigned i = end, nWordConverted = 0;
+    while (i > start) {
+        CLatticeFrame& fr = m_lattice[i];
+        if (rank < 0) {
+            result.insert(result.begin(), fr.m_selWord);
+            i = fr.m_selWord.m_start;
+        } else {
+            result.insert(result.begin(), fr.m_bestWords[rank]);
+            i = fr.m_bestWords[rank].m_start;
+        }
+        nWordConverted++;
+    }
+    return nWordConverted;
+}
+
+unsigned
+CIMIContext::getBestSentence(wstring& result, int rank,
+                             unsigned start, unsigned end)
+{
+    CCandidates sentence;
+    unsigned nWordConverted = getBestSentence(sentence, rank, start, end);
+    result.clear();
+    for (size_t i = 0; i < sentence.size(); i++) {
+        result += sentence[i].m_cwstr;
+    }
+    return nWordConverted;
+}
+
+unsigned
+CIMIContext::getBestSentence(std::vector<unsigned>& result, int rank,
+                             unsigned start, unsigned end)
+{
+    CCandidates sentence;
+    unsigned nWordConverted = getBestSentence(sentence, rank, start, end);
+    result.clear();
+    for (size_t i = 0; i < sentence.size(); i++) {
+        result.push_back(sentence[i].m_wordId);
+    }
+    return nWordConverted;
+}
+
+
+unsigned
+CIMIContext::getSelectedSentence(wstring& result,
+                                 unsigned start, unsigned end)
+{
+    return getBestSentence(result, -1, start, end);
+}
+
+
+unsigned
+CIMIContext::getSelectedSentence(std::vector<unsigned>& result,
+                                 unsigned start, unsigned end)
+{
+    return getBestSentence(result, -1, start, end);
+}
+
+struct TCandiPair {
+    CCandidate m_candi;
+    TCandiRank m_Rank;
+
+    TCandiPair() : m_candi(), m_Rank()
+    {
+    }
+};
+
+struct TCandiPairPtr {
+    TCandiPair*                     m_Ptr;
+
+    TCandiPairPtr(TCandiPair* p = NULL) : m_Ptr(p)
+    {
+    }
+
+    bool
+    operator<(const TCandiPairPtr& b) const
+    {
+        return m_Ptr->m_Rank < b.m_Ptr->m_Rank;
+    }
+};
+
+const TWCHAR *
+CIMIContext::_getWstr(unsigned wid)
+{
+    if (wid < m_pPinyinTrie->getWordCount())
+        return (*m_pPinyinTrie)[wid];
+    else if (m_pUserDict)
+        return (*m_pUserDict)[wid];
+    else
+        return NULL;
+}
+
+void
+CIMIContext::getCandidates(unsigned frIdx, CCandidates& result)
+{
+    TCandiPair cp;
+    static std::map<wstring, TCandiPair> candidates_map;
+    std::map<wstring, TCandiPair>::iterator candidates_it;
+
+    candidates_map.clear();
+    result.clear();
+
+    std::vector<unsigned> st;
+    getSelectedSentence(st, frIdx);
+
+    cp.m_candi.m_start = m_candiStarts = frIdx++;
+
+    for (; frIdx < m_tailIdx; ++frIdx) {
+        if (m_lattice[frIdx + 1].isSyllableSepFrame())
+            continue;
+
+        CLatticeFrame &fr = m_lattice[frIdx];
+        if (!fr.isSyllableFrame())
+            continue;
+
+        cp.m_candi.m_end = frIdx;
+        if (fr.m_bwType != CLatticeFrame::NO_BESTWORD) {
+            for (size_t i = 0; i < m_nBest; i++) {
+                if (fr.m_bestWords.find(i) == fr.m_bestWords.end())
+                    continue;
+                CCandidate candi = fr.m_bestWords[i];
+                if (candi.m_start != m_candiStarts)
+                    continue;
+                if (candi.m_pLexiconState == NULL)
+                    continue;
+
+                TLexiconState & lxst = *(candi.m_pLexiconState);
+                int len = lxst.m_syls.size() - lxst.m_num_of_inner_fuzzies;
+                if (len == 0) len = 1;
+
+                cp.m_candi = candi;
+                cp.m_Rank =
+                    TCandiRank(fr.m_bwType & CLatticeFrame::USER_SELECTED,
+                               fr.m_bwType & CLatticeFrame::BESTWORD,
+                               len, false, 0);
+                candidates_map[candi.m_cwstr] = cp;
+            }
+        }
+
+        bool found = false;
+        CLexiconStates::iterator it = fr.m_lexiconStates.begin();
+        CLexiconStates::iterator ite = fr.m_lexiconStates.end();
+        for (; it != ite; ++it) {
+            TLexiconState & lxst = *it;
+
+            if (lxst.m_start != m_candiStarts)
+                continue;
+
+            int len = lxst.m_syls.size() - lxst.m_num_of_inner_fuzzies;
+            if (0 == len) len = 1;
+
+            found = true;
+            unsigned word_num;
+            const CPinyinTrie::TWordIdInfo *words = lxst.getWords(word_num);
+
+            for (unsigned i = 0; i < word_num; ++i) {
+                if (m_csLevel < words[i].m_csLevel)
+                    continue;
+
+                cp.m_candi.m_wordId = words[i].m_id;
+                cp.m_candi.m_cwstr = _getWstr(cp.m_candi.m_wordId);
+                cp.m_candi.m_pLexiconState = &lxst;
+                if (!cp.m_candi.m_cwstr)
+                    continue;
+
+                //sorting according to the order in PinYinTire
+                cp.m_Rank =
+                    TCandiRank(false,
+                               !st.empty() && st.front() == cp.m_candi.m_wordId,
+                               len, false, i);
+                candidates_it = candidates_map.find(cp.m_candi.m_cwstr);
+                if (candidates_it == candidates_map.end()
+                    || cp.m_Rank < candidates_it->second.m_Rank
+                    || cp.m_candi.m_wordId > INI_USRDEF_WID) {
+                    candidates_map[cp.m_candi.m_cwstr] = cp;
+                    // print_wide(cp.m_candi.m_cwstr);
+                    // printf(" ");
+                }
+            }
+            // puts("");
+        }
+
+        if (!found) continue;  // FIXME: need better solution later
+
+        if (m_bDynaCandiOrder) {
+            CLatticeStates::iterator it = fr.m_latticeStates.begin();
+            CLatticeStates::iterator ite = fr.m_latticeStates.end();
+            // printf("adjusting ");
+            for (; it != ite; ++it) {
+                TLatticeState & ltst = *it;
+
+                if (ltst.m_pBackTraceNode->m_frIdx != m_candiStarts)
+                    continue;
+
+                cp.m_candi.m_wordId = ltst.m_backTraceWordId;
+                cp.m_candi.m_cwstr = _getWstr(cp.m_candi.m_wordId);
+                cp.m_candi.m_pLexiconState = ltst.m_pLexiconState;
+                if (!cp.m_candi.m_cwstr)
+                    continue;
+
+                int len = cp.m_candi.m_pLexiconState->m_syls.size() -
+                          cp.m_candi.m_pLexiconState->m_num_of_inner_fuzzies;
+                if (0 == len) len = 1;
+                cp.m_Rank = TCandiRank(false,
+                                       !st.empty() && st.front() ==
+                                       cp.m_candi.m_wordId,
+                                       len, true, ltst.m_score /
+                                       ltst.m_pBackTraceNode->m_score);
+                candidates_it = candidates_map.find(cp.m_candi.m_cwstr);
+                if (candidates_it == candidates_map.end()
+                    || cp.m_Rank < candidates_it->second.m_Rank
+                    || cp.m_candi.m_wordId > INI_USRDEF_WID) {
+                    // print_wide(cp.m_candi.m_cwstr);
+                    // std::string buf;
+                    // ltst.m_score.toString(buf);
+                    // printf("len:%d %s", len, buf.c_str());
+                    // ltst.m_pBackTraceNode->m_score.toString(buf);
+                    // printf("%s ", buf.c_str());
+                    candidates_map[cp.m_candi.m_cwstr] = cp;
+                }
+            }
+            // puts("");
+        }
+
+        m_candiEnds = frIdx;
+    }
+
+    std::vector<TCandiPairPtr> vec;
+
+    vec.reserve(candidates_map.size());
+    for (candidates_it = candidates_map.begin();
+         candidates_it != candidates_map.end(); ++candidates_it) {
+        vec.push_back(TCandiPairPtr(&(candidates_it->second)));
+    }
+
+    std::sort(vec.begin(), vec.end());
+    for (size_t i = 0; i < vec.size(); i++) {
+        // print_wide(vec[i].m_Ptr->m_candi.m_cwstr);
+        // printf(" ");
+        result.push_back(vec[i].m_Ptr->m_candi);
+    }
+    // puts("");
+}
+
+unsigned
+CIMIContext::cancelSelection(unsigned frIdx, bool doSearch)
+{
+    unsigned ret = frIdx;
+
+    CLatticeFrame &fr = m_lattice[frIdx];
+    while (fr.m_bwType & CLatticeFrame::IGNORED) {
+        --frIdx;
+        fr = m_lattice[frIdx];
+    }
+
+    if (fr.m_bwType &
+        (CLatticeFrame::USER_SELECTED | CLatticeFrame::BESTWORD)) {
+        ret = fr.m_selWord.m_start;
+        fr.m_bwType = CLatticeFrame::NO_BESTWORD;
+        if (doSearch) searchFrom(frIdx);
+    }
+
+    return ret;
+}
+
+void
+CIMIContext::makeSelection(CCandidate &candi, bool doSearch)
+{
+    CLatticeFrame &fr = m_lattice[candi.m_end];
+    fr.m_bwType = fr.m_bwType | CLatticeFrame::USER_SELECTED;
+    fr.m_selWord = candi;
+    // make best sentence word consistent as well
+    for (size_t i = 0; i < m_nBest; i++) {
+        fr.m_bestWords[i] = candi;
+    }
+
+    if (doSearch) searchFrom(candi.m_end);
+}
+
+void
+CIMIContext::selectSentence(int idx)
+{
+    unsigned i = m_tailIdx - 1;
+    while (i > 0 && m_lattice[i].m_bwType == CLatticeFrame::NO_BESTWORD)
+        i--;
+
+    while (i > 0) {
+        CLatticeFrame &fr = m_lattice[i];
+        fr.m_selWord = fr.m_bestWords[idx];
+        i = fr.m_selWord.m_start;
+    }
+}
+
+void
+CIMIContext::memorize()
+{
+    _saveUserDict();
+    _saveHistoryCache();
+}
+
+void
+CIMIContext::_saveUserDict()
+{
+    if (!m_pUserDict)
+        return;
+
+    CSyllables syls;
+    bool has_user_selected = false;
+    unsigned i = m_tailIdx - 1;
+    unsigned e_pos = 0;
+
+    while (i > 0 && m_lattice[i].m_bwType == CLatticeFrame::NO_BESTWORD)
+        i--;
+
+    while (i > 0) {
+        CLatticeFrame &fr = m_lattice[i];
+        if (!fr.isSyllableFrame()) {
+            i = fr.m_selWord.m_start;
+            break;
+        }
+
+        TLexiconState* state = fr.m_selWord.m_pLexiconState;
+        if (!state) {
+            i = fr.m_selWord.m_start;
+            continue;
+        }
+
+        if (syls.size() + state->m_syls.size() > MAX_USRDEF_WORD_LEN) {
+            i = fr.m_selWord.m_start;
+            break;
+        }
+
+       if (!e_pos) e_pos = i;
+
+        has_user_selected |= (fr.m_bwType & CLatticeFrame::USER_SELECTED);
+        std::copy(state->m_syls.begin(), state->m_syls.end(), inserter(syls, syls.begin()));
+        i = fr.m_selWord.m_start;
+    }
+
+    if (has_user_selected && syls.size() > 1) {
+        wstring phrase;
+        getSelectedSentence (phrase, 0, e_pos);
+        m_pUserDict->addWord (syls, phrase);
+    }
+}
+
+void
+CIMIContext::_saveHistoryCache()
+{
+    if (!m_pHistory)
+        return;
+
+    std::vector<unsigned> result;
+    unsigned i = m_tailIdx - 1;
+    while (i > 0 && m_lattice[i].m_bwType == CLatticeFrame::NO_BESTWORD)
+        i--;
+
+    while (i > 0) {
+        CLatticeFrame &fr = m_lattice[i];
+        if (fr.isSyllableFrame()) {
+            result.insert(result.begin(), fr.m_selWord.m_wordId);
+        } else {
+            result.insert(result.begin(), 0);
+        }
+        i = fr.m_selWord.m_start;
+    }
+
+    if (!result.empty()) {
+        m_pHistory->memorize(&(result[0]), &(result[0]) + result.size());
+        m_pHistory->saveToFile();
+    }
+}
+
+void
+CIMIContext::deleteCandidate(CCandidate &candi)
+{
+    unsigned wid = candi.m_wordId;
+    deleteCandidateByWID(wid);
+}
+
+void
+CIMIContext::deleteCandidateByWID(unsigned wid)
+{
+    if (wid > INI_USRDEF_WID) {
+        m_pHistory->forget(wid);
+        m_pUserDict->removeWord(wid);
+        _buildLattice(m_pPySegmentor->getSegments());
+    }
+}
+
+void
+CIMIContext::removeFromHistoryCache(std::vector<unsigned>& wids)
+{
+    if (!m_pHistory)
+        return;
+
+    m_pHistory->forget(&(wids[0]), &(wids[0]) + wids.size());
+    buildLattice(m_pPySegmentor);
+}
diff --git a/src/ime-core/imi_context.h b/src/ime-core/imi_context.h
new file mode 100644 (file)
index 0000000..0860844
--- /dev/null
@@ -0,0 +1,390 @@
+// -*- mode: c++ -*-
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright (c) 2007 Sun Microsystems, Inc. All Rights Reserved.
+ *
+ * The contents of this file are subject to the terms of either the GNU Lesser
+ * General Public License Version 2.1 only ("LGPL") or the Common Development and
+ * Distribution License ("CDDL")(collectively, the "License"). You may not use this
+ * file except in compliance with the License. You can obtain a copy of the CDDL at
+ * http://www.opensource.org/licenses/cddl1.php and a copy of the LGPLv2.1 at
+ * http://www.opensource.org/licenses/lgpl-license.php. See the License for the
+ * specific language governing permissions and limitations under the License. When
+ * distributing the software, include this License Header Notice in each file and
+ * include the full text of the License in the License file as well as the
+ * following notice:
+ *
+ * NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND DISTRIBUTION LICENSE
+ * (CDDL)
+ * For Covered Software in this distribution, this License shall be governed by the
+ * laws of the State of California (excluding conflict-of-law provisions).
+ * Any litigation relating to this License shall be subject to the jurisdiction of
+ * the Federal Courts of the Northern District of California and the state courts
+ * of the State of California, with venue lying in Santa Clara County, California.
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by only the CDDL or only
+ * the LGPL Version 2.1, indicate your decision by adding "[Contributor]" elects to
+ * include this software in this distribution under the [CDDL or LGPL Version 2.1]
+ * license." If you don't indicate a single choice of license, a recipient has the
+ * option to distribute your version of this file under either the CDDL or the LGPL
+ * Version 2.1, or to extend the choice of license to its licensees as provided
+ * above. However, if you add LGPL Version 2.1 code and therefore, elected the LGPL
+ * Version 2 license, then the option applies only if the new code is made subject
+ * to such option by the copyright holder.
+ */
+
+#ifndef SUNPY_IMI_CONTEXT_H
+#define SUNPY_IMI_CONTEXT_H
+
+#include "portability.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#if defined(DEBUG) && defined (HAVE_ASSET_H)
+#include <assert.h>
+#endif
+
+#include <climits>
+#include <map>
+#include <vector>
+
+#include "pinyin/pinyin_seg.h"
+#include "imi_data.h"
+#include "ic_history.h"
+#include "userdict.h"
+#include "lattice_states.h"
+#include "imi_funcobjs.h"
+
+/**
+ * TSentenceScore is only used for whole sentence score,
+ * the score from language model still using double.
+ */
+typedef TLongExpFloat TSentenceScore;
+
+class CLatticeFrame;
+class CCandidate;
+class CIMIContext;
+
+typedef std::vector<CLatticeFrame>  CLattice;
+typedef std::vector<CCandidate>     CCandidates;
+typedef CCandidates::iterator CCandidatesIter;
+
+union TCandiRank {
+public:
+    bool operator<(const TCandiRank& b) const
+    { return m_all < b.m_all; };
+
+    TCandiRank() : m_all(0) {
+    }
+
+    TCandiRank(bool user, bool best, unsigned int len,
+               bool fromLattice, TSentenceScore score);
+
+    TCandiRank(bool user, bool best, unsigned int len,
+               bool fromLattice, unsigned score);
+
+protected:
+    unsigned int m_all;
+#if !defined(WORDS_BIGENDIAN)
+    struct TAnony {
+        unsigned m_cost   : 24;
+        unsigned m_lattice : 1;
+        unsigned m_best   : 1;
+        unsigned m_len    : 5;
+        unsigned m_user   : 1;
+    } anony;
+#else
+    struct TAnony {
+        unsigned m_user   : 1;
+        unsigned m_len    : 5;
+        unsigned m_best   : 1;
+        unsigned m_lattice : 1;
+        unsigned m_cost   : 24;
+    } anony;
+#endif
+}; // TCandiRank
+
+/**
+ * CCandidate represent basic information about a single candidate.
+ * Its start bone and finishing bone. It's content string. and its
+ * word id.
+ */
+class CCandidate {
+    friend class CIMIContext;
+public:
+    unsigned m_start;
+    unsigned m_end;
+    const TWCHAR       *m_cwstr;
+
+public:
+    /** Give out the constructor for convinience */
+    CCandidate(unsigned start = 0,
+               unsigned end = 0,
+               TLexiconState* pLxst = NULL,
+               const TWCHAR* s = NULL,
+               unsigned int wid = 0)
+        : m_start(start), m_end(end), m_cwstr(s), m_wordId(wid),
+          m_pLexiconState(pLxst) {}
+
+protected:
+    unsigned int m_wordId;
+    TLexiconState* m_pLexiconState;
+}; // of CCandidate
+
+class CLatticeFrame {
+    friend class CIMIContext;
+public:
+    enum TYPE {
+        UNUSED                  = 0x0000,      // unused frame
+        TAIL                    = 0x0001,      // tail frame
+
+        CATE_SYLLABLE           = 0x0100,
+        SYLLABLE                = 0x0101,      // pinyin
+        SYLLABLE_SEP            = 0x0102,      // pinyin
+        INCOMPLETE_SYLLABLE     = 0x0104,      // incomplete syllable string
+
+        CATE_OTHER              = 0x0200,
+        ASCII                   = 0x0201,      // english string
+        PUNC                    = 0x0202,      // punctuation
+        SYMBOL                  = 0x0204,      // other symbol
+        DIGITAL                 = 0x0208,      // not implemeted here
+    }; // TYPE
+
+    enum BESTWORD_TYPE {
+        NO_BESTWORD             = 1 << 0,
+        BESTWORD                = 1 << 1,
+        USER_SELECTED           = 1 << 2,
+        IGNORED                 = 1 << 3,
+    }; // BESTWORD_TYPE
+
+    unsigned m_type;
+    unsigned m_bwType;
+    wstring m_wstr;
+
+    CLatticeFrame () : m_type(UNUSED), m_bwType(NO_BESTWORD) {}
+
+    bool isUnusedFrame() const
+    { return m_type == 0; }
+
+    bool isSyllableFrame() const
+    { return(m_type & CATE_SYLLABLE); }
+
+    bool isSyllableSepFrame() const
+    { return((m_type & SYLLABLE_SEP) > CATE_SYLLABLE); }
+
+    bool isTailFrame() const
+    { return(m_type == TAIL); }
+
+    void clear(){
+        m_type = UNUSED;
+        m_bwType = NO_BESTWORD;
+        m_lexiconStates.clear();
+        m_latticeStates.clear();
+        m_wstr.clear();
+        m_bestWords.clear();
+    }
+
+    void print(std::string prefix);
+
+protected:
+    std::map<int, CCandidate>   m_bestWords;
+    CCandidate m_selWord;
+    CLexiconStates m_lexiconStates;
+    CLatticeStates m_latticeStates;
+}; // CLatticeFrame
+
+typedef std::vector<unsigned> TPath;
+
+class CIMIContext
+{
+public:
+    CIMIContext ();
+    ~CIMIContext () { clear(); }
+
+    void clear();
+
+    void setCoreData(CIMIData *pCoreData);
+    void setUserDict(CUserDict *pUserDict) { m_pUserDict = pUserDict; }
+
+    void setHistoryMemory(CICHistory *phm) { m_pHistory = phm; }
+    CICHistory * getHistoryMemory() { return m_pHistory; }
+
+    void setHistoryPower(unsigned power)
+    { m_historyPower = power <= 10 ? power : 3; }
+
+    int getHistoryPower()
+    { return m_historyPower; }
+
+    void setFullSymbolForwarding(bool value = true) {
+        m_bFullSymbolForwarding = value;
+    }
+    bool getFullSymbolForwarding() { return m_bFullSymbolForwarding; }
+    void setGetFullSymbolOp(CGetFullSymbolOp *op) { m_pGetFullSymbolOp = op; }
+    CGetFullSymbolOp& fullSymbolOp() const { return *m_pGetFullSymbolOp; }
+
+    void setFullPunctForwarding(bool value = true) {
+        m_bFullPunctForwarding = value;
+    }
+    bool getFullPunctForwarding() { return m_bFullPunctForwarding; }
+    void setGetFullPunctOp(CGetFullPunctOp *op) { m_pGetFullPunctOp = op; }
+    CGetFullPunctOp& fullPuncOp() const { return *m_pGetFullPunctOp; }
+
+    void setNonCompleteSyllable(bool value = true) {
+        m_bNonCompleteSyllable = value;
+    }
+    bool getNonCompleteSyllable() { return m_bNonCompleteSyllable; }
+
+    void setCharsetLevel(unsigned l) { m_csLevel = l; }
+    unsigned getCharsetLevel() { return m_csLevel; }
+
+    void setDynamicCandidateOrder(bool value = true) {
+        m_bDynaCandiOrder = value;
+    }
+    bool getDynaCandiOrder() { return m_bDynaCandiOrder; }
+
+    CLattice& getLattice() { return m_lattice; }
+    bool buildLattice(IPySegmentor *segmentor, bool doSearch = true);
+    bool isEmpty() { return m_tailIdx <= 1; }
+    unsigned getLastFrIdx() { return m_tailIdx - 1; }
+
+    // omit next punctuation if the very next symbol is an punctuation
+    void omitNextPunct() { m_bOmitPunct = true; }
+
+    bool searchFrom(unsigned from = 1);
+
+    size_t getMaxBest() const { return m_maxBest; }
+    void setMaxBest(size_t maxBest) {
+        m_maxBest = maxBest;
+        for (int i = 0; i < MAX_LATTICE_LENGTH; i++) {
+            m_lattice[i].m_latticeStates.setMaxBest(m_maxBest);
+        }
+    }
+
+    size_t getMaxTailCandidateNum() const { return m_maxTailCandidateNum; }
+    void setMaxTailCandidateNum(size_t maxTailCandidateNum) {
+        m_maxTailCandidateNum = maxTailCandidateNum;
+    }
+
+    size_t getNBest() { return m_nBest; }
+    std::vector<TPath>& getPath(int rank) { return m_path; }
+    std::vector<TPath>& getSegPath(int rank) { return m_segPath; }
+
+    TPath& getBestPath() { return m_path[0]; }
+    TPath& getBestSegPath() {
+        if (m_segPath.empty()) {
+            static TPath emptyPath;
+            return emptyPath;
+        }
+        // CIMIContext would fail to backTrace the bestPathes when there are
+        // no latticeStates on frame e.g., 'yiden' in Quanpin mode, in this
+        // case, return the original segs
+        if (m_segPath[0].empty() && m_pPySegmentor) {
+            // only require the primary segments without the auxiliary ones
+            IPySegmentor::TSegmentVec& segments =
+                m_pPySegmentor->getSegments(false);
+            IPySegmentor::TSegmentVec::const_iterator it = segments.begin();
+            IPySegmentor::TSegmentVec::const_iterator ite = segments.end();
+            m_segPath[0].push_back(0);
+            for (; it != ite; ++it)
+                m_segPath[0].push_back(it->m_start + it->m_len);
+        }
+        return m_segPath[0];
+    }
+
+    std::vector<CCandidates> getBestSentenceTails(int rank, unsigned start,
+                                                  unsigned end = UINT_MAX);
+
+    unsigned getBestSentence(CCandidates& result, int rank,
+                             unsigned start = 0, unsigned end = UINT_MAX);
+    unsigned getBestSentence(wstring& result, int rank,
+                             unsigned start = 0, unsigned end = UINT_MAX);
+    unsigned getBestSentence(std::vector<unsigned>& result, int rank,
+                             unsigned start = 0, unsigned end = UINT_MAX);
+
+    unsigned getSelectedSentence(wstring& result,
+                                 unsigned start = 0, unsigned end = UINT_MAX);
+    unsigned getSelectedSentence(std::vector<unsigned>& result,
+                                 unsigned start = 0, unsigned end = UINT_MAX);
+
+    void getCandidates(unsigned frIdx, CCandidates& result);
+    unsigned cancelSelection(unsigned frIdx, bool doSearch = true);
+    void makeSelection(CCandidate &candi, bool doSearch = true);
+    void deleteCandidate(CCandidate &candi);
+    void deleteCandidateByWID(unsigned wid);
+    void selectSentence(int idx);
+
+    void memorize();
+    void removeFromHistoryCache(std::vector<unsigned>& wids);
+    void printLattice();
+
+    CUserDict* getUserDict() { return m_pUserDict; }
+
+protected:
+    void _clearFrom(unsigned from);
+
+    bool _buildLattice(IPySegmentor::TSegmentVec &segments,
+                       unsigned rebuildFrom = 1, bool doSearch = true);
+    void _forwardSyllables(unsigned i, unsigned j,
+                           const IPySegmentor::TSegment& seg);
+    void _forwardSingleSyllable(unsigned i, unsigned j, TSyllable syllable,
+                                const IPySegmentor::TSegment& seg,
+                                bool fuzzy = false);
+    void _forwardSyllableSep(unsigned i, unsigned j);
+    void _forwardString(unsigned i, unsigned j,
+                        const std::vector<unsigned>& strbuf);
+    void _forwardPunctChar(unsigned i, unsigned j, unsigned ch);
+    void _forwardOrdinaryChar(unsigned i, unsigned j, unsigned ch);
+    void _forwardTail(unsigned i, unsigned j);
+
+    void _transferBetween(unsigned start, unsigned end, TLexiconState* plxst,
+                          unsigned wid, double ic = 1.0);
+    bool _backTracePaths(const std::vector<TLatticeState>& tail_states,
+                         int rank, TPath& path, TPath& segPath);
+    void _clearPaths();
+
+    const TWCHAR *_getWstr(unsigned wid);
+
+    void _saveUserDict();
+    void _saveHistoryCache();
+
+protected:
+    CLattice m_lattice;
+    unsigned m_tailIdx;
+
+    size_t m_nBest;
+    size_t m_maxBest;
+    size_t m_maxTailCandidateNum;
+
+    std::vector<TPath> m_path;
+    std::vector<TPath> m_segPath;
+
+    CThreadSlm* m_pModel;
+    CPinyinTrie* m_pPinyinTrie;
+    CUserDict* m_pUserDict;
+    CICHistory* m_pHistory;
+    unsigned m_historyPower;
+
+    unsigned m_csLevel;
+
+    bool m_bFullSymbolForwarding;
+    bool m_bOmitPunct;
+    CGetFullSymbolOp  *m_pGetFullSymbolOp;
+
+    bool m_bFullPunctForwarding;
+    CGetFullPunctOp *m_pGetFullPunctOp;
+
+    IPySegmentor *m_pPySegmentor;
+
+    bool m_bNonCompleteSyllable;
+    bool m_bDynaCandiOrder;
+
+    unsigned m_candiStarts;
+    unsigned m_candiEnds;
+}; // CIMIContext
+
+#endif
diff --git a/src/ime-core/imi_data.cpp b/src/ime-core/imi_data.cpp
new file mode 100644 (file)
index 0000000..6c12c1d
--- /dev/null
@@ -0,0 +1,112 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright (c) 2007 Sun Microsystems, Inc. All Rights Reserved.
+ *
+ * The contents of this file are subject to the terms of either the GNU Lesser
+ * General Public License Version 2.1 only ("LGPL") or the Common Development and
+ * Distribution License ("CDDL")(collectively, the "License"). You may not use this
+ * file except in compliance with the License. You can obtain a copy of the CDDL at
+ * http://www.opensource.org/licenses/cddl1.php and a copy of the LGPLv2.1 at
+ * http://www.opensource.org/licenses/lgpl-license.php. See the License for the
+ * specific language governing permissions and limitations under the License. When
+ * distributing the software, include this License Header Notice in each file and
+ * include the full text of the License in the License file as well as the
+ * following notice:
+ *
+ * NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND DISTRIBUTION LICENSE
+ * (CDDL)
+ * For Covered Software in this distribution, this License shall be governed by the
+ * laws of the State of California (excluding conflict-of-law provisions).
+ * Any litigation relating to this License shall be subject to the jurisdiction of
+ * the Federal Courts of the Northern District of California and the state courts
+ * of the State of California, with venue lying in Santa Clara County, California.
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by only the CDDL or only
+ * the LGPL Version 2.1, indicate your decision by adding "[Contributor]" elects to
+ * include this software in this distribution under the [CDDL or LGPL Version 2.1]
+ * license." If you don't indicate a single choice of license, a recipient has the
+ * option to distribute your version of this file under either the CDDL or the LGPL
+ * Version 2.1, or to extend the choice of license to its licensees as provided
+ * above. However, if you add LGPL Version 2.1 code and therefore, elected the LGPL
+ * Version 2 license, then the option applies only if the new code is made subject
+ * to such option by the copyright holder.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifdef HAVE_ICONV_H
+#include <iconv.h>
+#else
+#include "portability.h"
+#endif // HAVE_ICONV_H
+
+#include "imi_data.h"
+
+void
+print_wide(const TWCHAR* wstr)
+{
+    char buf[512];
+
+#ifdef HAVE_ICONV_H
+    iconv_t icv = iconv_open("UTF-8", TWCHAR_ICONV_NAME);
+    TIConvSrcPtr src = (TIConvSrcPtr)wstr;
+    size_t srclen = (WCSLEN(wstr) + 1) * sizeof(TWCHAR);
+    char *dst = buf;
+    size_t dstlen = 1024;
+    iconv(icv, &src, &srclen, &dst, &dstlen);
+    iconv_close(icv);
+#else // !HAVE_ICONV_H
+    memset(&buf[0], 0, sizeof(buf));
+    WCSTOMBS(&buf[0], wstr, sizeof(buf) - 1);
+#endif // HAVE_ICONV_H
+
+    printf("%s", buf);
+}
+
+bool
+CIMIData::loadResource(const char* lm_file_path, const char* pytrie_file_path)
+{
+    clear();
+
+    #ifdef DEBUG
+    printf("\n    openning lm file %s, pytrie file %s...",
+           lm_file_path,
+           pytrie_file_path);
+    #endif
+
+    if ((m_pLM = new CThreadSlm()) != NULL &&
+        m_pLM->load(lm_file_path, true) &&
+        (m_pPinyinTrie = new CPinyinTrie()) != NULL &&
+        m_pPinyinTrie->load(pytrie_file_path)) {
+        #ifdef DEBUG
+        printf("done! LM @%p, Trie @%p\n", m_pLM, m_pPinyinTrie);
+        fflush(stdout);
+        #endif
+
+        return true;
+    }
+
+    clear();
+
+    #ifdef DEBUG
+    printf("fail!\n");
+    fflush(stdout);
+    #endif
+
+    return false;
+}
+
+void
+CIMIData::clear()
+{
+    delete m_pLM;
+    delete m_pPinyinTrie;
+
+    m_pPinyinTrie = NULL;
+    m_pLM = NULL;
+}
diff --git a/src/ime-core/imi_data.h b/src/ime-core/imi_data.h
new file mode 100644 (file)
index 0000000..7e808b0
--- /dev/null
@@ -0,0 +1,79 @@
+// -*- mode: c++ -*-
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright (c) 2007 Sun Microsystems, Inc. All Rights Reserved.
+ *
+ * The contents of this file are subject to the terms of either the GNU Lesser
+ * General Public License Version 2.1 only ("LGPL") or the Common Development and
+ * Distribution License ("CDDL")(collectively, the "License"). You may not use this
+ * file except in compliance with the License. You can obtain a copy of the CDDL at
+ * http://www.opensource.org/licenses/cddl1.php and a copy of the LGPLv2.1 at
+ * http://www.opensource.org/licenses/lgpl-license.php. See the License for the
+ * specific language governing permissions and limitations under the License. When
+ * distributing the software, include this License Header Notice in each file and
+ * include the full text of the License in the License file as well as the
+ * following notice:
+ *
+ * NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND DISTRIBUTION LICENSE
+ * (CDDL)
+ * For Covered Software in this distribution, this License shall be governed by the
+ * laws of the State of California (excluding conflict-of-law provisions).
+ * Any litigation relating to this License shall be subject to the jurisdiction of
+ * the Federal Courts of the Northern District of California and the state courts
+ * of the State of California, with venue lying in Santa Clara County, California.
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by only the CDDL or only
+ * the LGPL Version 2.1, indicate your decision by adding "[Contributor]" elects to
+ * include this software in this distribution under the [CDDL or LGPL Version 2.1]
+ * license." If you don't indicate a single choice of license, a recipient has the
+ * option to distribute your version of this file under either the CDDL or the LGPL
+ * Version 2.1, or to extend the choice of license to its licensees as provided
+ * above. However, if you add LGPL Version 2.1 code and therefore, elected the LGPL
+ * Version 2 license, then the option applies only if the new code is made subject
+ * to such option by the copyright holder.
+ */
+
+#ifndef SUNPY_IMI_DATA_H
+#define SUNPY_IMI_DATA_H
+
+#include "portability.h"
+
+#include <stdarg.h>
+
+#include "slm/slm.h"
+#include "lexicon/pytrie.h"
+
+void print_wide(const TWCHAR* wstr);
+
+/**
+ * Data of the IM implementation shared by all Desktop/Session(IC)
+ */
+class CIMIData {
+public:
+    CIMIData()
+        : m_pPinyinTrie(NULL), m_pLM(NULL) { }
+
+    ~CIMIData()
+    { clear(); }
+
+    CThreadSlm*getSlm()
+    { return m_pLM; }
+
+    CPinyinTrie*getPinyinTrie()
+    { return m_pPinyinTrie; }
+
+    bool
+    loadResource(const char* lm_file_path, const char* pytrie_file_path);
+
+    void
+    clear();
+
+public:
+    CPinyinTrie     *m_pPinyinTrie;
+    CThreadSlm      *m_pLM;
+};
+
+#endif
diff --git a/src/ime-core/imi_defines.h b/src/ime-core/imi_defines.h
new file mode 100644 (file)
index 0000000..168c6f1
--- /dev/null
@@ -0,0 +1,53 @@
+// -*- mode: c++ -*-
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright (c) 2007 Sun Microsystems, Inc. All Rights Reserved.
+ *
+ * The contents of this file are subject to the terms of either the GNU Lesser
+ * General Public License Version 2.1 only ("LGPL") or the Common Development and
+ * Distribution License ("CDDL")(collectively, the "License"). You may not use this
+ * file except in compliance with the License. You can obtain a copy of the CDDL at
+ * http://www.opensource.org/licenses/cddl1.php and a copy of the LGPLv2.1 at
+ * http://www.opensource.org/licenses/lgpl-license.php. See the License for the
+ * specific language governing permissions and limitations under the License. When
+ * distributing the software, include this License Header Notice in each file and
+ * include the full text of the License in the License file as well as the
+ * following notice:
+ *
+ * NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND DISTRIBUTION LICENSE
+ * (CDDL)
+ * For Covered Software in this distribution, this License shall be governed by the
+ * laws of the State of California (excluding conflict-of-law provisions).
+ * Any litigation relating to this License shall be subject to the jurisdiction of
+ * the Federal Courts of the Northern District of California and the state courts
+ * of the State of California, with venue lying in Santa Clara County, California.
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by only the CDDL or only
+ * the LGPL Version 2.1, indicate your decision by adding "[Contributor]" elects to
+ * include this software in this distribution under the [CDDL or LGPL Version 2.1]
+ * license." If you don't indicate a single choice of license, a recipient has the
+ * option to distribute your version of this file under either the CDDL or the LGPL
+ * Version 2.1, or to extend the choice of license to its licensees as provided
+ * above. However, if you add LGPL Version 2.1 code and therefore, elected the LGPL
+ * Version 2 license, then the option applies only if the new code is made subject
+ * to such option by the copyright holder.
+ */
+
+#ifndef SUNPY_IMI_CONFIG_H
+#define SUNPY_IMI_CONFIG_H
+
+#define MAX_LATTICE_LENGTH      512
+#define MAX_LEXICON_TRIES       32
+#define UNKNOWN_WORD_ID         0
+#define NONE_WORD_ID            69
+#define ENDING_WORD_ID          70         /* use comma as the ending character */
+
+#define MAX_USRDEF_WORD_LEN     6
+#define INI_USRDEF_WID          0x00040000 /* 2^18     */
+#define MAX_USRDEF_WID          0x00ffffff /* 2^24 - 1 */
+
+
+#endif /* SUNPY_IMI_CONFIG_H */
diff --git a/src/ime-core/imi_funcobjs.cpp b/src/ime-core/imi_funcobjs.cpp
new file mode 100644 (file)
index 0000000..0370f9c
--- /dev/null
@@ -0,0 +1,126 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright (c) 2007 Sun Microsystems, Inc. All Rights Reserved.
+ *
+ * The contents of this file are subject to the terms of either the GNU Lesser
+ * General Public License Version 2.1 only ("LGPL") or the Common Development and
+ * Distribution License ("CDDL")(collectively, the "License"). You may not use this
+ * file except in compliance with the License. You can obtain a copy of the CDDL at
+ * http://www.opensource.org/licenses/cddl1.php and a copy of the LGPLv2.1 at
+ * http://www.opensource.org/licenses/lgpl-license.php. See the License for the
+ * specific language governing permissions and limitations under the License. When
+ * distributing the software, include this License Header Notice in each file and
+ * include the full text of the License in the License file as well as the
+ * following notice:
+ *
+ * NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND DISTRIBUTION LICENSE
+ * (CDDL)
+ * For Covered Software in this distribution, this License shall be governed by the
+ * laws of the State of California (excluding conflict-of-law provisions).
+ * Any litigation relating to this License shall be subject to the jurisdiction of
+ * the Federal Courts of the Northern District of California and the state courts
+ * of the State of California, with venue lying in Santa Clara County, California.
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by only the CDDL or only
+ * the LGPL Version 2.1, indicate your decision by adding "[Contributor]" elects to
+ * include this software in this distribution under the [CDDL or LGPL Version 2.1]
+ * license." If you don't indicate a single choice of license, a recipient has the
+ * option to distribute your version of this file under either the CDDL or the LGPL
+ * Version 2.1, or to extend the choice of license to its licensees as provided
+ * above. However, if you add LGPL Version 2.1 code and therefore, elected the LGPL
+ * Version 2 license, then the option applies only if the new code is made subject
+ * to such option by the copyright holder.
+ */
+
+#include "imi_funcobjs.h"
+
+void
+CGetFullSymbolOp::initSymbolMap()
+{
+    m_symbolMap.clear();
+
+    TWCHAR cwstr[256];
+    static const char half_symbol[] = "azAZ";
+    static const char full_symbol[] = "azAZ";
+
+    char * src = (char*)full_symbol;
+    memset(&cwstr[0], 0, sizeof(cwstr));
+    MBSTOWCS(&cwstr[0], src, (sizeof(cwstr) / sizeof(TWCHAR)) - 1);
+
+    TWCHAR wch = cwstr[0];
+    for (char h = half_symbol[0], t = half_symbol[1]; h <= t; ++h, ++wch)
+        m_symbolMap[h] = wch;
+
+    wch = cwstr[2];
+    for (char h = half_symbol[2], t = half_symbol[3]; h <= t; ++h, ++wch)
+        m_symbolMap[h] = wch;
+}
+
+const wstring&
+CGetFullSymbolOp::operator ()(unsigned ch)
+{
+    static wstring ret;
+
+    if (m_symbolMap.empty())
+        initSymbolMap();
+
+    CSymbolMap::iterator it1 = m_symbolMap.find(ch);
+    if (it1 != m_symbolMap.end())
+        return it1->second;
+
+    return ret;
+}
+
+CGetFullPunctOp::CGetFullPunctOp()
+{
+}
+
+void
+CGetFullPunctOp::initPunctMap(const string_pairs& punc_map)
+{
+    TWCHAR cwstr[256];
+
+    m_punctMap.clear();
+    m_punctClosingSts.clear();
+
+    string_pairs::const_iterator it = punc_map.begin();
+    string_pairs::const_iterator ite = punc_map.end();
+
+    for (; it != ite; ++it) {
+        const char *k = it->first.c_str();
+        const char *v = it->second.c_str();
+
+        if (!v) continue;
+
+        memset(cwstr, 0, sizeof(cwstr));
+        MBSTOWCS(&cwstr[0], v, (sizeof(cwstr) / sizeof(TWCHAR)) - 1);
+
+        unsigned key = *k;
+        if (m_punctMap.find(*k) != m_punctMap.end()) {
+            m_punctClosingSts.insert(std::make_pair(key, false));
+            key |= 0x80000000;
+        }
+
+        m_punctMap[key] = wstring(cwstr);
+    }
+}
+
+const wstring&
+CGetFullPunctOp::operator ()(unsigned ch)
+{
+    static wstring ret;
+    CPunctClosingStates::iterator it = m_punctClosingSts.find(ch);
+    if (it != m_punctClosingSts.end()) {
+        if (it->second) ch |= 0x80000000;
+        it->second = !it->second;
+    }
+
+    CPunctMap::iterator it1 = m_punctMap.find(ch);
+    if (it1 != m_punctMap.end())
+        return it1->second;
+
+    return ret;
+}
diff --git a/src/ime-core/imi_funcobjs.h b/src/ime-core/imi_funcobjs.h
new file mode 100644 (file)
index 0000000..80e990f
--- /dev/null
@@ -0,0 +1,76 @@
+// -*- mode: c++ -*-
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright (c) 2007 Sun Microsystems, Inc. All Rights Reserved.
+ *
+ * The contents of this file are subject to the terms of either the GNU Lesser
+ * General Public License Version 2.1 only ("LGPL") or the Common Development and
+ * Distribution License ("CDDL")(collectively, the "License"). You may not use this
+ * file except in compliance with the License. You can obtain a copy of the CDDL at
+ * http://www.opensource.org/licenses/cddl1.php and a copy of the LGPLv2.1 at
+ * http://www.opensource.org/licenses/lgpl-license.php. See the License for the
+ * specific language governing permissions and limitations under the License. When
+ * distributing the software, include this License Header Notice in each file and
+ * include the full text of the License in the License file as well as the
+ * following notice:
+ *
+ * NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND DISTRIBUTION LICENSE
+ * (CDDL)
+ * For Covered Software in this distribution, this License shall be governed by the
+ * laws of the State of California (excluding conflict-of-law provisions).
+ * Any litigation relating to this License shall be subject to the jurisdiction of
+ * the Federal Courts of the Northern District of California and the state courts
+ * of the State of California, with venue lying in Santa Clara County, California.
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by only the CDDL or only
+ * the LGPL Version 2.1, indicate your decision by adding "[Contributor]" elects to
+ * include this software in this distribution under the [CDDL or LGPL Version 2.1]
+ * license." If you don't indicate a single choice of license, a recipient has the
+ * option to distribute your version of this file under either the CDDL or the LGPL
+ * Version 2.1, or to extend the choice of license to its licensees as provided
+ * above. However, if you add LGPL Version 2.1 code and therefore, elected the LGPL
+ * Version 2 license, then the option applies only if the new code is made subject
+ * to such option by the copyright holder.
+ */
+
+#ifndef SUNPY_IMI_FUNCS_H
+#define SUNPY_IMI_FUNCS_H
+
+#include "portability.h"
+#include "utils.h"
+#include <map>
+
+class CGetFullSymbolOp : private CNonCopyable
+{
+public:
+    typedef std::map<unsigned, wstring> CSymbolMap;
+
+    CGetFullSymbolOp () {}
+    void initSymbolMap();
+    const wstring& operator ()(unsigned ch);
+
+private:
+    CSymbolMap m_symbolMap;
+};
+
+class CGetFullPunctOp : private CNonCopyable
+{
+public:
+    typedef std::map<unsigned, wstring> CPunctMap;
+    typedef std::map<unsigned, bool> CPunctClosingStates;
+
+    CGetFullPunctOp ();
+
+    void initPunctMap(const std::vector<string_pair>& punc_map);
+    const wstring& operator ()(unsigned ch);
+
+private:
+
+    CPunctMap m_punctMap;
+    CPunctClosingStates m_punctClosingSts;
+};
+
+#endif
diff --git a/src/ime-core/imi_glibHandler.h b/src/ime-core/imi_glibHandler.h
new file mode 100644 (file)
index 0000000..8a9a3a1
--- /dev/null
@@ -0,0 +1,81 @@
+// -*- mode: c++ -*-
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright (c) 2007 Sun Microsystems, Inc. All Rights Reserved.
+ *
+ * The contents of this file are subject to the terms of either the GNU Lesser
+ * General Public License Version 2.1 only ("LGPL") or the Common Development and
+ * Distribution License ("CDDL")(collectively, the "License"). You may not use this
+ * file except in compliance with the License. You can obtain a copy of the CDDL at
+ * http://www.opensource.org/licenses/cddl1.php and a copy of the LGPLv2.1 at
+ * http://www.opensource.org/licenses/lgpl-license.php. See the License for the
+ * specific language governing permissions and limitations under the License. When
+ * distributing the software, include this License Header Notice in each file and
+ * include the full text of the License in the License file as well as the
+ * following notice:
+ *
+ * NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND DISTRIBUTION LICENSE
+ * (CDDL)
+ * For Covered Software in this distribution, this License shall be governed by the
+ * laws of the State of California (excluding conflict-of-law provisions).
+ * Any litigation relating to this License shall be subject to the jurisdiction of
+ * the Federal Courts of the Northern District of California and the state courts
+ * of the State of California, with venue lying in Santa Clara County, California.
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by only the CDDL or only
+ * the LGPL Version 2.1, indicate your decision by adding "[Contributor]" elects to
+ * include this software in this distribution under the [CDDL or LGPL Version 2.1]
+ * license." If you don't indicate a single choice of license, a recipient has the
+ * option to distribute your version of this file under either the CDDL or the LGPL
+ * Version 2.1, or to extend the choice of license to its licensees as provided
+ * above. However, if you add LGPL Version 2.1 code and therefore, elected the LGPL
+ * Version 2 license, then the option applies only if the new code is made subject
+ * to such option by the copyright holder.
+ */
+
+#include <glib.h>
+#include "imi_winHandler.h"
+#include "imi_view.h"
+
+static inline gboolean
+UpdateCallback(gpointer ptr)
+{
+    CIMIView* view = (CIMIView*) ptr;
+    view->getWinHandler()->doneDeferedUpdate();
+    view->updateWindows();
+    return FALSE;
+}
+
+// implement gtk loop mechanism
+class CIMIGlibHandler : public CIMIWinHandler
+{
+public:
+    CIMIGlibHandler() : m_sourceId(0) {}
+
+    virtual ~CIMIGlibHandler() {
+        disableDeferedUpdate();
+    }
+
+    virtual void enableDeferedUpdate(CIMIView* view, int waitTime) {
+        if (m_sourceId == 0 && waitTime > 0) {
+            m_sourceId = g_timeout_add_seconds(waitTime, UpdateCallback, view);
+        }
+    }
+
+    virtual void disableDeferedUpdate() {
+        if (m_sourceId != 0) {
+            g_source_remove(m_sourceId);
+            m_sourceId = 0;
+        }
+    }
+
+    virtual void doneDeferedUpdate() {
+        m_sourceId = 0;
+    }
+
+private:
+    guint m_sourceId;
+};
diff --git a/src/ime-core/imi_keys.h b/src/ime-core/imi_keys.h
new file mode 100644 (file)
index 0000000..adce7c7
--- /dev/null
@@ -0,0 +1,116 @@
+// -*- mode: c++ -*-
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright (c) 2007 Sun Microsystems, Inc. All Rights Reserved.
+ *
+ * The contents of this file are subject to the terms of either the GNU Lesser
+ * General Public License Version 2.1 only ("LGPL") or the Common Development and
+ * Distribution License ("CDDL")(collectively, the "License"). You may not use this
+ * file except in compliance with the License. You can obtain a copy of the CDDL at
+ * http://www.opensource.org/licenses/cddl1.php and a copy of the LGPLv2.1 at
+ * http://www.opensource.org/licenses/lgpl-license.php. See the License for the
+ * specific language governing permissions and limitations under the License. When
+ * distributing the software, include this License Header Notice in each file and
+ * include the full text of the License in the License file as well as the
+ * following notice:
+ *
+ * NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND DISTRIBUTION LICENSE
+ * (CDDL)
+ * For Covered Software in this distribution, this License shall be governed by the
+ * laws of the State of California (excluding conflict-of-law provisions).
+ * Any litigation relating to this License shall be subject to the jurisdiction of
+ * the Federal Courts of the Northern District of California and the state courts
+ * of the State of California, with venue lying in Santa Clara County, California.
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by only the CDDL or only
+ * the LGPL Version 2.1, indicate your decision by adding "[Contributor]" elects to
+ * include this software in this distribution under the [CDDL or LGPL Version 2.1]
+ * license." If you don't indicate a single choice of license, a recipient has the
+ * option to distribute your version of this file under either the CDDL or the LGPL
+ * Version 2.1, or to extend the choice of license to its licensees as provided
+ * above. However, if you add LGPL Version 2.1 code and therefore, elected the LGPL
+ * Version 2 license, then the option applies only if the new code is made subject
+ * to such option by the copyright holder.
+ */
+
+#ifndef SUNPINYIN_KEYSDEFINE_H
+#define SUNPINYIN_KEYSDEFINE_H
+
+#include "portability.h"
+
+#define IM_SHIFT_MASK        (1 << 0)
+#define IM_CTRL_MASK         (1 << 2)
+#define IM_ALT_MASK          (1 << 3)
+#define IM_SUPER_MASK        (1 << 26)
+#define IM_RELEASE_MASK      (1 << 30)
+
+#define IM_VK_SPACE          ' '
+#define IM_VK_MINUS          '-'
+#define IM_VK_EQUALS         '='
+#define IM_VK_COMMA          ','
+#define IM_VK_PERIOD         '.'
+#define IM_VK_OPEN_BRACKET   '['
+#define IM_VK_CLOSE_BRACKET  ']'
+#define IM_VK_BACK_QUOTE     '`'
+
+#define IM_VK_HOME           0xff50
+#define IM_VK_LEFT           0xff51
+#define IM_VK_UP             0xff52
+#define IM_VK_RIGHT          0xff53
+#define IM_VK_DOWN           0xff54
+#define IM_VK_PAGE_UP        0xff55
+#define IM_VK_PAGE_DOWN      0xff56
+#define IM_VK_END            0xff57
+
+#define IM_VK_DELETE         0xffff
+#define IM_VK_BACK_SPACE     0xff08
+
+#define IM_VK_ENTER          0xff0d
+#define IM_VK_ESCAPE         0xff1b
+
+#define IM_VK_SHIFT_L        0xffe1
+#define IM_VK_SHIFT_R        0xffe2
+#define IM_VK_CONTROL_L      0xffe3
+#define IM_VK_CONTROL_R      0xffe4
+#define IM_VK_ALT            0xffe9
+
+struct CKeyEvent {
+    unsigned code;
+    unsigned value;
+    unsigned modifiers;
+
+    CKeyEvent (unsigned kc, unsigned kv = 0, unsigned m = 0)
+        : code(kc), value(kv), modifiers(m){
+        // clear other mask bit we do not care
+        modifiers &=
+            (IM_SHIFT_MASK | IM_CTRL_MASK | IM_ALT_MASK | IM_SUPER_MASK |
+        IM_RELEASE_MASK);
+    }
+
+    bool operator <(const CKeyEvent& b) const {
+        return((code < b.code) ||
+               ((code == b.code) &&
+                (modifiers < b.modifiers)));
+    }
+
+    bool operator ==(const CKeyEvent& rhs) const {
+        return(code == rhs.code &&
+               modifiers == rhs.modifiers);
+    }
+
+    bool operator !=(const CKeyEvent& rhs) const {
+        return(code != rhs.code ||
+               modifiers != rhs.modifiers);
+    }
+
+    void reset(){
+        code = (unsigned) ~0;
+        value = (unsigned) ~0;
+        modifiers = 0;
+    }
+};
+
+#endif
diff --git a/src/ime-core/imi_option_event.cpp b/src/ime-core/imi_option_event.cpp
new file mode 100644 (file)
index 0000000..d575898
--- /dev/null
@@ -0,0 +1,108 @@
+#include <cassert>
+#include <algorithm>
+#include "imi_option_event.h"
+
+COptionEvent::variant_::variant_(int v)
+    : type(VAL_INTEGER)
+{
+    data.d_int = v;
+}
+
+COptionEvent::variant_::variant_(const std::string& v)
+    : type(VAL_STRING)
+{
+    data.d_string = v;
+}
+
+COptionEvent::variant_::variant_(const std::vector<std::string>& v)
+    : type(VAL_STRING_LIST)
+{
+    data.d_strings = v;
+}
+
+COptionEvent::variant_::variant_(const std::vector<string_pair>& v)
+    : type(VAL_STRING_PAIR_LIST)
+{
+    data.d_string_pair_list = v;
+}
+
+COptionEvent::variant_::variant_(bool v)
+    : type(VAL_BOOL)
+{
+    data.d_bool = v;
+}
+
+int
+COptionEvent::get_int() const
+{
+    return value.data.d_int;
+}
+
+bool
+COptionEvent::get_bool() const
+{
+    return value.data.d_bool;
+}
+
+std::string
+COptionEvent::get_string() const
+{
+    return value.data.d_string;
+}
+
+std::vector<std::string>
+COptionEvent::get_string_list() const
+{
+    return value.data.d_strings;
+}
+
+std::vector<string_pair>
+COptionEvent::get_string_pair_list() const
+{
+    return value.data.d_string_pair_list;
+}
+
+IConfigurable::IConfigurable()
+{
+    AOptionEventBus::instance().registerAsListener(this);
+}
+
+IConfigurable::~IConfigurable()
+{
+    AOptionEventBus::instance().unregisterAsListener(this);
+}
+
+void
+COptionEventBus::registerAsListener(IConfigurable* listener)
+{
+    Subscribers::iterator found = find(m_listeners.begin(),
+                                       m_listeners.end(),
+                                       listener);
+    if (found == m_listeners.end())
+        m_listeners.push_back(listener);
+    else
+        assert(false && "already subscribed");
+}
+
+void
+COptionEventBus::unregisterAsListener(IConfigurable* listener)
+{
+    Subscribers::iterator found = find(m_listeners.begin(),
+                                       m_listeners.end(),
+                                       listener);
+    if (found != m_listeners.end())
+        m_listeners.erase(found);
+    else
+        assert(false && "not yet subscribed");
+}
+
+void
+COptionEventBus::publishEvent(const COptionEvent& event)
+{
+    Subscribers::iterator end = m_listeners.end();
+    for (Subscribers::iterator it = m_listeners.begin();
+         it != end; ++it) {
+        if ((*it)->onConfigChanged(event))
+            break;
+    }
+}
diff --git a/src/ime-core/imi_option_event.h b/src/ime-core/imi_option_event.h
new file mode 100644 (file)
index 0000000..25e2539
--- /dev/null
@@ -0,0 +1,105 @@
+// -*- mode: c++ -*-
+#ifndef _IMI_SESSION_H
+#define _IMI_SESSION_H
+
+#include <list>
+#include <string>
+#include <vector>
+
+#include "utils.h"
+
+class COptionEventBus;
+
+struct COptionEvent {
+    template<typename ValueType>COptionEvent(const std::string& k,
+                                             const ValueType& v)
+        : name(k), value(v)
+    {}
+
+    int get_int() const;
+    bool get_bool() const;
+    std::string get_string() const;
+    std::vector<std::string> get_string_list() const;
+    std::vector<string_pair> get_string_pair_list() const;
+
+    /* TODO:
+     * string_pair get_string_pair() const;
+     * std::vector<bool> get_bool_list() const;
+     * std::vector<int> get_int_list() const;
+     */
+
+    int type;
+    std::string name;
+
+    struct variant_ {
+        variant_(int);
+        variant_(const std::string&);
+        variant_(bool);
+        variant_(const std::vector<std::string>&);
+        variant_(const std::vector<string_pair>&);
+        struct val_ {
+            int d_int;
+            std::string d_string;
+            bool d_bool;
+            std::vector<std::string> d_strings;
+            std::vector<string_pair> d_string_pair_list;
+        } data;
+        enum {
+            VAL_INTEGER,
+            VAL_INTEGER_LIST,
+            VAL_STRING,
+            VAL_STRING_LIST,
+            VAL_STRING_PAIR,
+            VAL_STRING_PAIR_LIST,
+            VAL_BOOL,
+            VAL_BOOL_LIST,
+        } type;
+    } value;
+};
+
+class IConfigurable
+{
+public:
+    IConfigurable();
+    ~IConfigurable();
+    /**
+     * onConfigChanged will be called whenever an option is changed
+     * @param event presents the changed option
+     * @return true if the event is consumed, and not intented to be
+     *         sent to another event listener, false otherwise.
+     */
+    virtual bool onConfigChanged(const COptionEvent&) { return false; }
+};
+
+class COptionEventBus
+{
+public:
+    /**
+     * listener will receive a message whenever an option is changed
+     * @param listener who is interested in a change of options
+     */
+    void registerAsListener(IConfigurable* listener);
+
+    /**
+     * remove listener from the subscriber list
+     * @param listener who is no more interested in a change of options
+     */
+    void unregisterAsListener(IConfigurable* listener);
+
+    /**
+     * publish an event to all listeners of this event bus
+     * @param event the event which presents an option change
+     */
+    void publishEvent(const COptionEvent& event);
+    template<class> friend class SingletonHolder;
+
+private:
+    COptionEventBus() {}
+
+    typedef std::list<IConfigurable*> Subscribers;
+    Subscribers m_listeners;
+};
+
+typedef SingletonHolder<COptionEventBus> AOptionEventBus;
+
+#endif // _IMI_SESSION_H
diff --git a/src/ime-core/imi_option_keys.h b/src/ime-core/imi_option_keys.h
new file mode 100644 (file)
index 0000000..d0be98b
--- /dev/null
@@ -0,0 +1,20 @@
+// -*- mode: c++ -*-
+#ifndef _IMI_OPTION_KEYS_H
+#define _IMI_OPTION_KEYS_H
+
+/**
+ * these strings are used as names of instances of COptionEvent
+ */
+#define SYSTEM_DATA_DIR                 "General/DataDir"
+#define USER_DATA_DIR                   "General/UserDataDir"
+#define PINYIN_SCHEME                   "Pinyin/Scheme"
+#define PINYIN_PUNCTMAPPING_ENABLED     "General/PunctMapping/Enabled"
+#define PINYIN_PUNCTMAPPING_MAPPINGS    "General/PunctMapping/Mappings"
+#define CONFIG_GENERAL_CHARSET_LEVEL    "General/Charset"
+#define QUANPIN_FUZZY_ENABLED           "QuanPin/Fuzzy/Enabled"
+#define QUANPIN_FUZZY_PINYINS           "QuanPin/Fuzzy/Pinyins"
+#define QUANPIN_AUTOCORRECTION_ENABLED  "QuanPin/AutoCorrection/Enabled"
+#define QUANPIN_AUTOCORRECTION_PINYINS  "QuanPin/AutoCorrection/Pinyins"
+#define SHUANGPIN_TYPE                  "Pinyin/ShuangPinType"
+
+#endif // _IMI_OPTION_KEYS_H
diff --git a/src/ime-core/imi_options.cpp b/src/ime-core/imi_options.cpp
new file mode 100644 (file)
index 0000000..5cb5549
--- /dev/null
@@ -0,0 +1,267 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright (c) 2007 Sun Microsystems, Inc. All Rights Reserved.
+ *
+ * The contents of this file are subject to the terms of either the GNU Lesser
+ * General Public License Version 2.1 only ("LGPL") or the Common Development and
+ * Distribution License ("CDDL")(collectively, the "License"). You may not use this
+ * file except in compliance with the License. You can obtain a copy of the CDDL at
+ * http://www.opensource.org/licenses/cddl1.php and a copy of the LGPLv2.1 at
+ * http://www.opensource.org/licenses/lgpl-license.php. See the License for the
+ * specific language governing permissions and limitations under the License. When
+ * distributing the software, include this License Header Notice in each file and
+ * include the full text of the License in the License file as well as the
+ * following notice:
+ *
+ * NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND DISTRIBUTION LICENSE
+ * (CDDL)
+ * For Covered Software in this distribution, this License shall be governed by the
+ * laws of the State of California (excluding conflict-of-law provisions).
+ * Any litigation relating to this License shall be subject to the jurisdiction of
+ * the Federal Courts of the Northern District of California and the state courts
+ * of the State of California, with venue lying in Santa Clara County, California.
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by only the CDDL or only
+ * the LGPL Version 2.1, indicate your decision by adding "[Contributor]" elects to
+ * include this software in this distribution under the [CDDL or LGPL Version 2.1]
+ * license." If you don't indicate a single choice of license, a recipient has the
+ * option to distribute your version of this file under either the CDDL or the LGPL
+ * Version 2.1, or to extend the choice of license to its licensees as provided
+ * above. However, if you add LGPL Version 2.1 code and therefore, elected the LGPL
+ * Version 2 license, then the option applies only if the new code is made subject
+ * to such option by the copyright holder.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <algorithm>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <cassert>
+#include <errno.h>
+
+#include "imi_option_keys.h"
+#include "imi_keys.h"
+#include "imi_options.h"
+#include "imi_view_classic.h"
+
+CSimplifiedChinesePolicy::CSimplifiedChinesePolicy()
+    : m_bLoaded(false), m_bTried(false), m_csLevel(3),
+      m_bEnableFullSymbol(false), m_bEnableFullPunct(true)
+{
+    m_getFullPunctOp.initPunctMap(getDefaultPunctMapping());
+}
+
+bool
+CSimplifiedChinesePolicy::loadResources()
+{
+    if (m_bLoaded || m_bTried)
+        return m_bLoaded;
+
+    bool suc = true;
+    std::string data_dir = m_data_dir.size() ? m_data_dir : SUNPINYIN_DATA_DIR;
+    std::string lm_path = data_dir + "/lm_sc.t3g";
+    std::string dict_path = data_dir + "/pydict_sc.bin";
+
+    suc &= m_coreData.loadResource(lm_path.c_str(), dict_path.c_str());
+
+    if (!m_user_data_dir.size()) {
+        char path[256];
+        const char *home = getenv("HOME");
+        snprintf(path,
+                 sizeof(path),
+                 "%s/%s",
+                 home,
+                 SUNPINYIN_USERDATA_DIR_PREFIX);
+        m_user_data_dir = path;
+    }
+
+    char * tmp = strdup(m_user_data_dir.c_str());
+    createDirectory(tmp);
+    free(tmp);
+
+    std::string history_path = m_user_data_dir + "/history";
+    suc &= m_historyCache.loadFromFile(history_path.c_str());
+
+    std::string user_dict_path = m_user_data_dir + "/userdict";
+    suc &= m_userDict.load(user_dict_path.c_str());
+
+    m_bTried = true;
+    return m_bLoaded = suc;
+}
+
+CIMIContext *
+CSimplifiedChinesePolicy::createContext()
+{
+    CIMIContext* pic = new CIMIContext();
+    pic->setCoreData(&m_coreData);
+    pic->setHistoryMemory(&m_historyCache);
+    pic->setUserDict(&m_userDict);
+
+    pic->setCharsetLevel(m_csLevel);
+
+    pic->setFullSymbolForwarding(m_bEnableFullSymbol);
+    pic->setGetFullSymbolOp(&m_getFullSymbolOp);
+
+    pic->setFullPunctForwarding(m_bEnableFullPunct);
+    pic->setGetFullPunctOp(&m_getFullPunctOp);
+    return pic;
+}
+
+void
+CSimplifiedChinesePolicy::destroyContext(CIMIContext *context)
+{
+    assert(context != NULL);
+    saveUserHistory();
+    delete context;
+}
+
+string_pairs
+CSimplifiedChinesePolicy::getDefaultPunctMapping() const
+{
+    static const char* punc_map [] = {
+        " ", " ",
+        ",", ",",
+        ";", ";",
+        "!", "!",
+        "?", "?",
+        ".", "。",
+        ":", ":",
+        "^", "……",
+        "\\", "、",
+        "\"", "“",
+        "\"", "”",
+        "'", "‘",
+        "'", "’",
+        "_", "——",
+        "<", "《",
+        ">", "》",
+        "(", "(",
+        ")", ")",
+        "[", "【",
+        "]", "】",
+        "{", "『",
+        "}", "』",
+        "$", "¥",
+        NULL,
+    };
+
+    string_pairs default_punc_map;
+
+    const char *const *p = punc_map;
+    while (*p) {
+        std::string k = *p++;
+        std::string v = *p++;
+        default_punc_map.push_back(std::make_pair(k, v));
+    }
+    return default_punc_map;
+}
+
+bool
+CSimplifiedChinesePolicy::onConfigChanged(const COptionEvent& event)
+{
+    if (event.name == SYSTEM_DATA_DIR) {
+        setDataDir(event.get_string());
+    } else if (event.name == USER_DATA_DIR) {
+        setUserDataDir(event.get_string());
+    } else if (event.name == CONFIG_GENERAL_CHARSET_LEVEL) {
+        m_csLevel = event.get_int() & 3;
+    }
+
+    return false;
+}
+
+bool
+CSimplifiedChinesePolicy::saveUserHistory()
+{
+    return m_historyCache.saveToFile();
+}
+
+bool
+CSimplifiedChinesePolicy::createDirectory(char *path)
+{
+    char *p = path;
+    while ((p = strchr(p + 1, '/'))) {
+        *p = 0;
+        if (access(path, F_OK) != 0 && mkdir(path, S_IRWXU) != 0) {
+            fprintf(stderr, "mkdir %s: %s\n", path, strerror(errno));
+            return false;
+        }
+        *p = '/';
+    }
+    return !(access(path, F_OK) != 0 && mkdir(path, S_IRWXU) != 0);
+}
+
+CShuangpinSchemePolicy::CShuangpinSchemePolicy()
+    : m_shuangpinType(MS2003)
+{
+}
+
+bool
+CQuanpinSchemePolicy::onConfigChanged(const COptionEvent& event)
+{
+    if (event.name == QUANPIN_FUZZY_ENABLED) {
+        setFuzzyForwarding(event.get_bool());
+        return true;
+    } else if (event.name == QUANPIN_FUZZY_PINYINS) {
+        setFuzzyPinyinPairs(event.get_string_pair_list());
+        return true;
+    } else if (event.name == QUANPIN_AUTOCORRECTION_ENABLED) {
+        setAutoCorrecting(event.get_bool());
+        return true;
+    } else if (event.name == QUANPIN_AUTOCORRECTION_PINYINS) {
+        setAutoCorrectionPairs(event.get_string_pair_list());
+        return true;
+    }
+
+    return false;
+}
+
+bool
+CShuangpinSchemePolicy::onConfigChanged(const COptionEvent& event)
+{
+    if (event.name == SHUANGPIN_TYPE) {
+        setShuangpinType((EShuangpinType)event.get_int());
+        return true;
+    } else if (event.name == QUANPIN_FUZZY_ENABLED) {
+        setFuzzyForwarding(event.get_bool());
+        return true;
+    } else if (event.name == QUANPIN_FUZZY_PINYINS) {
+        setFuzzyPinyinPairs(event.get_string_pair_list());
+        return true;
+    }
+
+    return false;
+}
+
+bool
+CHunpinSchemePolicy::onConfigChanged(const COptionEvent& event)
+{
+    if (event.name == SHUANGPIN_TYPE) {
+        setShuangpinType((EShuangpinType)event.get_int());
+        //刷新segmentor狀態
+        COptionEventBus& event_bus = AOptionEventBus::instance();
+        event_bus.publishEvent(COptionEvent(PINYIN_SCHEME, -1));        //第二個參數沒有用
+        return true;
+    } else if (event.name == QUANPIN_FUZZY_ENABLED) {
+        setFuzzyForwarding(event.get_bool());
+        return true;
+    } else if (event.name == QUANPIN_FUZZY_PINYINS) {
+        setFuzzyPinyinPairs(event.get_string_pair_list());
+        return true;
+    }
+
+    return false;
+}
+
+
+CHunpinSchemePolicy::CHunpinSchemePolicy()
+    : m_shuangpinType(MS2003)
+{
+}
diff --git a/src/ime-core/imi_options.h b/src/ime-core/imi_options.h
new file mode 100644 (file)
index 0000000..7043960
--- /dev/null
@@ -0,0 +1,382 @@
+// -*- mode: c++ -*-
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright (c) 2007 Sun Microsystems, Inc. All Rights Reserved.
+ *
+ * The contents of this file are subject to the terms of either the GNU Lesser
+ * General Public License Version 2.1 only ("LGPL") or the Common Development and
+ * Distribution License ("CDDL")(collectively, the "License"). You may not use this
+ * file except in compliance with the License. You can obtain a copy of the CDDL at
+ * http://www.opensource.org/licenses/cddl1.php and a copy of the LGPLv2.1 at
+ * http://www.opensource.org/licenses/lgpl-license.php. See the License for the
+ * specific language governing permissions and limitations under the License. When
+ * distributing the software, include this License Header Notice in each file and
+ * include the full text of the License in the License file as well as the
+ * following notice:
+ *
+ * NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND DISTRIBUTION LICENSE
+ * (CDDL)
+ * For Covered Software in this distribution, this License shall be governed by the
+ * laws of the State of California (excluding conflict-of-law provisions).
+ * Any litigation relating to this License shall be subject to the jurisdiction of
+ * the Federal Courts of the Northern District of California and the state courts
+ * of the State of California, with venue lying in Santa Clara County, California.
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by only the CDDL or only
+ * the LGPL Version 2.1, indicate your decision by adding "[Contributor]" elects to
+ * include this software in this distribution under the [CDDL or LGPL Version 2.1]
+ * license." If you don't indicate a single choice of license, a recipient has the
+ * option to distribute your version of this file under either the CDDL or the LGPL
+ * Version 2.1, or to extend the choice of license to its licensees as provided
+ * above. However, if you add LGPL Version 2.1 code and therefore, elected the LGPL
+ * Version 2 license, then the option applies only if the new code is made subject
+ * to such option by the copyright holder.
+ */
+
+#ifndef _IMI_OPTIONS_H
+#define _IMI_OPTIONS_H
+
+#include "utils.h"
+#include "portability.h"
+#include "imi_view.h"
+#include "imi_view_classic.h"
+#include "imi_funcobjs.h"
+#include "imi_data.h"
+#include "imi_option_event.h"
+#include "userdict.h"
+#include "ic_history.h"
+#include "pinyin/shuangpin_seg.h"
+#include "pinyin/hunpin_seg.h"
+
+#ifndef SUNPINYIN_USERDATA_DIR_PREFIX
+#define SUNPINYIN_USERDATA_DIR_PREFIX ".sunpinyin"
+#endif
+
+struct CSimplifiedChinesePolicy : public IConfigurable {
+    CSimplifiedChinesePolicy ();
+
+    bool loadResources();
+
+    CIMIContext* createContext();
+    void destroyContext(CIMIContext *context);
+
+    void setPunctMapping(string_pairs punc_map)
+    { m_getFullPunctOp.initPunctMap(punc_map); }
+
+    string_pairs getDefaultPunctMapping() const;
+
+    void enableFullSymbol(bool v = true) { m_bEnableFullSymbol = v; }
+    void enableFullPunct(bool v = true) { m_bEnableFullPunct = v; }
+
+    void setDataDir(const std::string& data_dir)
+    { m_data_dir = data_dir; }
+
+    void setUserDataDir(const std::string& user_data_dir)
+    { m_user_data_dir = user_data_dir; }
+
+    virtual bool onConfigChanged(const COptionEvent& event);
+
+    template<class> friend class SingletonHolder;
+
+protected: ~CSimplifiedChinesePolicy () {}
+
+    bool createDirectory(char *path);
+    bool saveUserHistory();
+
+    CIMIData m_coreData;
+    CBigramHistory m_historyCache;
+    bool m_bLoaded;
+    bool m_bTried;
+    unsigned m_csLevel;
+    bool m_bEnableFullSymbol;
+    CGetFullSymbolOp m_getFullSymbolOp;
+    bool m_bEnableFullPunct;
+    CGetFullPunctOp m_getFullPunctOp;
+    std::string m_data_dir;
+    std::string m_user_data_dir;
+public:
+    CUserDict m_userDict;
+};
+
+typedef SingletonHolder<CSimplifiedChinesePolicy> ASimplifiedChinesePolicy;
+
+struct CQuanpinSchemePolicy : IConfigurable {
+public:
+
+    IPySegmentor* createPySegmentor(){
+        CQuanpinSegmentor *pseg = new CQuanpinSegmentor();
+        pseg->setGetFuzzySyllablesOp(&m_getFuzzySyllablesOp);
+        pseg->setGetCorrectionPairOp(&m_getCorrectionPairOp);
+        pseg->setGetFuzzySegmentsOp(&m_getFuzzySegmentsOp);
+        return pseg;
+    }
+
+    void setFuzzyForwarding(bool enable_fuzzies = true,
+                            bool enable_simpler_initials = true){
+        m_getFuzzySyllablesOp.setEnableFuzzies(enable_fuzzies);
+        m_getFuzzySyllablesOp.setEnableSimplerInitials(enable_simpler_initials);
+    }
+
+    void clearFuzzyPinyinPairs()
+    { m_getFuzzySyllablesOp.clearFuzzyMap(); }
+
+    void setFuzzyPinyinPairs(const string_pairs& pairs, bool duplex = true)
+    { m_getFuzzySyllablesOp.initFuzzyMap(pairs, duplex); }
+
+    void setAutoCorrecting(bool v = true)
+    { m_getCorrectionPairOp.setEnable(v); }
+
+    void setAutoCorrectionPairs(const string_pairs& pairs)
+    { m_getCorrectionPairOp.setCorrectionPairs(pairs); }
+
+    void setFuzzySegmentation(bool v = true)
+    { m_getFuzzySegmentsOp.setEnable(v); }
+
+    void setInnerFuzzySegmentation(bool v = true)
+    { m_getFuzzySegmentsOp.setInnerFuzzyEnable(v); }
+
+    virtual bool onConfigChanged(const COptionEvent& event);
+
+    template<class> friend class SingletonHolder;
+
+protected: ~CQuanpinSchemePolicy () {}
+
+    CGetFuzzySyllablesOp<CPinyinData>   m_getFuzzySyllablesOp;
+    CGetCorrectionPairOp m_getCorrectionPairOp;
+    CGetFuzzySegmentsOp m_getFuzzySegmentsOp;
+};
+
+typedef SingletonHolder<CQuanpinSchemePolicy> AQuanpinSchemePolicy;
+
+struct CShuangpinSchemePolicy : public IConfigurable {
+public:
+    CShuangpinSchemePolicy();
+
+    IPySegmentor* createPySegmentor(){
+        CShuangpinSegmentor *pseg = new CShuangpinSegmentor(m_shuangpinType);
+        pseg->setGetFuzzySyllablesOp(&m_getFuzzySyllablesOp);
+        return pseg;
+    }
+
+    void setShuangpinType(EShuangpinType t) { m_shuangpinType = t; }
+
+    void setFuzzyForwarding(bool enable_fuzzies = true,
+                            bool enable_simpler_initials = true){
+        m_getFuzzySyllablesOp.setEnableFuzzies(enable_fuzzies);
+        m_getFuzzySyllablesOp.setEnableSimplerInitials(enable_simpler_initials);
+    }
+
+    void clearFuzzyPinyinPairs()
+    { m_getFuzzySyllablesOp.clearFuzzyMap(); }
+
+    void setFuzzyPinyinPairs(const string_pairs& pairs, bool duplex = true)
+    { m_getFuzzySyllablesOp.initFuzzyMap(pairs, duplex); }
+
+    virtual bool onConfigChanged(const COptionEvent& event);
+
+    template<class> friend class SingletonHolder;
+protected: ~CShuangpinSchemePolicy () {}
+
+    EShuangpinType m_shuangpinType;
+    CGetFuzzySyllablesOp<CPinyinData>   m_getFuzzySyllablesOp;
+};
+
+typedef SingletonHolder<CShuangpinSchemePolicy> AShuangpinSchemePolicy;
+
+struct  CHunpinSchemePolicy : public IConfigurable {
+public:
+    CHunpinSchemePolicy();
+
+    IPySegmentor* createPySegmentor(){
+        CHunpinSegmentor *pseg = new CHunpinSegmentor(m_shuangpinType);
+        pseg->setGetFuzzySyllablesOp(&m_getFuzzySyllablesOp);
+        return pseg;
+    }
+
+    void setShuangpinType(EShuangpinType t) { m_shuangpinType = t; }
+
+    void setFuzzyForwarding(bool enable_fuzzies = true,
+                            bool enable_simpler_initials = true){
+        m_getFuzzySyllablesOp.setEnableFuzzies(enable_fuzzies);
+        m_getFuzzySyllablesOp.setEnableSimplerInitials(enable_simpler_initials);
+    }
+
+    void clearFuzzyPinyinPairs()
+    { m_getFuzzySyllablesOp.clearFuzzyMap(); }
+
+    void setFuzzyPinyinPairs(const string_pairs& pairs, bool duplex = true)
+    { m_getFuzzySyllablesOp.initFuzzyMap(pairs, duplex); }
+
+    virtual bool onConfigChanged(const COptionEvent& event);
+
+    template<class> friend class SingletonHolder;
+protected: ~CHunpinSchemePolicy () {}
+
+    EShuangpinType m_shuangpinType;
+    CGetFuzzySyllablesOp<CPinyinData>   m_getFuzzySyllablesOp;
+};
+
+typedef SingletonHolder<CHunpinSchemePolicy> AHunpinSchemePolicy;
+
+struct CClassicStylePolicy : public IConfigurable {
+    CIMIView* createView() { return new CIMIClassicView(); }
+
+    template<class> friend class SingletonHolder;
+protected: ~CClassicStylePolicy () {}
+};
+
+typedef SingletonHolder<CClassicStylePolicy> AClassicStylePolicy;
+
+struct ISunpinyinProfile {
+    virtual CIMIView* createProfile() = 0;
+    virtual void destroyProfile(CIMIView *) = 0;
+    virtual ~ISunpinyinProfile () {};
+};
+
+template <class LanguagePolicy, class PinyinSchemePolicy,
+          class InputStylePolicy>
+class CSunpinyinProfile : public ISunpinyinProfile
+{
+public:
+    CSunpinyinProfile () : m_langPolicy(LanguagePolicy::instance()),
+                           m_pySchemePolicy(PinyinSchemePolicy::instance()),
+                           m_inputStylePolicy(InputStylePolicy::instance())
+    {}
+
+    /* profile by itself is a profile, so we are creating a session here? */
+    virtual CIMIView* createProfile(){
+        if (!m_langPolicy.loadResources())
+            return NULL;
+
+        IPySegmentor* pseg = m_pySchemePolicy.createPySegmentor();
+        if (pseg == NULL)
+            return NULL;
+
+        CIMIContext *pic = m_langPolicy.createContext();
+        CIMIView* pview = m_inputStylePolicy.createView();
+        pview->attachIC(pic);
+        pview->setPySegmentor(pseg);
+
+        return pview;
+    }
+
+    virtual void destroyProfile(CIMIView* pview){
+        if (pview) {
+            LanguagePolicy::instance().destroyContext(pview->getIC());
+            delete pview->getPySegmentor();
+            delete pview;
+        }
+    }
+private:
+    typename LanguagePolicy::Type & m_langPolicy;
+    typename PinyinSchemePolicy::Type & m_pySchemePolicy;
+    typename InputStylePolicy::Type & m_inputStylePolicy;
+};
+
+class CSunpinyinSessionFactory : private CNonCopyable
+{
+public:
+    typedef enum {
+        QUANPIN,
+        SHUANGPIN,
+        YUEPIN,
+        ZHUYIN,
+        HUNPIN,
+    } EPyScheme;
+
+    typedef enum {
+        MSPY_STYLE,
+        CLASSIC_STYLE,
+    } EInputStyle;
+
+    typedef enum {
+        SIMPLIFIED_CHINESE,
+        TRADITIONAL_CHINESE,
+    } ELanguage;
+
+public:
+    static CSunpinyinSessionFactory& getFactory(){
+        static CSunpinyinSessionFactory inst;
+        return inst;
+    }
+
+    void setLanguage(ELanguage lang) { m_lang = lang; }
+    void setInputStyle(EInputStyle inputStyle) { m_inputStyle = inputStyle; }
+    void setPinyinScheme(EPyScheme pyScheme) { m_pyScheme = pyScheme; }
+    void setCandiWindowSize(unsigned size) { m_candiWindowSize = size; }
+
+    CIMIView* createSession(){
+        unsigned key = _policiesToKey(m_lang, m_pyScheme, m_inputStyle);
+        ISunpinyinProfile *profile = _getProfile(key);
+        if (!profile)
+            return NULL;
+
+        CIMIView *pview = profile->createProfile();
+        if (!pview)
+            return NULL;
+
+        pview->setHotkeyProfile(&m_hotkeyProfile);
+        pview->setCandiWindowSize(m_candiWindowSize);
+        return pview;
+    }
+
+    void destroySession(CIMIView* pview){
+        unsigned key = _policiesToKey(m_lang, m_pyScheme, m_inputStyle);
+        ISunpinyinProfile *profile = _getProfile(key);
+        if (!profile)
+            return;
+        profile->destroyProfile(pview);
+    }
+
+private:
+    CSunpinyinSessionFactory ()
+        : m_pyScheme(QUANPIN), m_inputStyle(CLASSIC_STYLE),
+          m_lang(SIMPLIFIED_CHINESE),
+          m_candiWindowSize(10){
+        m_profiles [_policiesToKey(SIMPLIFIED_CHINESE, QUANPIN,
+                                   CLASSIC_STYLE)] =
+            new CSunpinyinProfile <ASimplifiedChinesePolicy,
+                                   AQuanpinSchemePolicy, AClassicStylePolicy> ();
+
+        m_profiles [_policiesToKey(SIMPLIFIED_CHINESE, SHUANGPIN,
+                                   CLASSIC_STYLE)] =
+            new CSunpinyinProfile <ASimplifiedChinesePolicy,
+                                   AShuangpinSchemePolicy, AClassicStylePolicy> ();
+    }
+
+    ~CSunpinyinSessionFactory (){
+        std::map <unsigned, ISunpinyinProfile*>::iterator it = m_profiles.begin();
+        std::map <unsigned, ISunpinyinProfile*>::iterator ite = m_profiles.end();
+
+        for (; it != ite; ++it)
+            delete it->second;
+    }
+
+    ISunpinyinProfile* _getProfile(unsigned key){
+        std::map <unsigned, ISunpinyinProfile*>::iterator it = m_profiles.find(
+            key);
+        if (it != m_profiles.end()) {
+            return it->second;
+        } else {
+            return NULL;
+        }
+    }
+
+    unsigned _policiesToKey(ELanguage lang,
+                            EPyScheme pyScheme,
+                            EInputStyle inputStyle)
+    { return (lang << 16) + (pyScheme << 8) + inputStyle; }
+
+    std::map <unsigned, ISunpinyinProfile*> m_profiles;
+
+    EPyScheme m_pyScheme;
+    EInputStyle m_inputStyle;
+    ELanguage m_lang;
+    unsigned m_candiWindowSize;
+    CHotkeyProfile m_hotkeyProfile;
+};
+
+#endif
diff --git a/src/ime-core/imi_plugin.cpp b/src/ime-core/imi_plugin.cpp
new file mode 100644 (file)
index 0000000..505b056
--- /dev/null
@@ -0,0 +1,379 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright (c) 2007 Sun Microsystems, Inc. All Rights Reserved.
+ *
+ * The contents of this file are subject to the terms of either the GNU Lesser
+ * General Public License Version 2.1 only ("LGPL") or the Common Development and
+ * Distribution License ("CDDL")(collectively, the "License"). You may not use this
+ * file except in compliance with the License. You can obtain a copy of the CDDL at
+ * http://www.opensource.org/licenses/cddl1.php and a copy of the LGPLv2.1 at
+ * http://www.opensource.org/licenses/lgpl-license.php. See the License for the
+ * specific language governing permissions and limitations under the License. When
+ * distributing the software, include this License Header Notice in each file and
+ * include the full text of the License in the License file as well as the
+ * following notice:
+ *
+ * NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND DISTRIBUTION LICENSE
+ * (CDDL)
+ * For Covered Software in this distribution, this License shall be governed by the
+ * laws of the State of California (excluding conflict-of-law provisions).
+ * Any litigation relating to this License shall be subject to the jurisdiction of
+ * the Federal Courts of the Northern District of California and the state courts
+ * of the State of California, with venue lying in Santa Clara County, California.
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by only the CDDL or only
+ * the LGPL Version 2.1, indicate your decision by adding "[Contributor]" elects to
+ * include this software in this distribution under the [CDDL or LGPL Version 2.1]
+ * license." If you don't indicate a single choice of license, a recipient has the
+ * option to distribute your version of this file under either the CDDL or the LGPL
+ * Version 2.1, or to extend the choice of license to its licensees as provided
+ * above. However, if you add LGPL Version 2.1 code and therefore, elected the LGPL
+ * Version 2 license, then the option applies only if the new code is made subject
+ * to such option by the copyright holder.
+ */
+
+#include <Python.h>
+#include <signal.h>
+#include <sstream>
+
+#include "portability.h"
+#include "imi_plugin.h"
+
+CIMIPlugin::CIMIPlugin(TPluginTypeEnum pluginType)
+    : m_pluginType(pluginType)
+{}
+
+CIMIPlugin::~CIMIPlugin()
+{}
+
+class CIMIPythonPlugin : public CIMIPlugin
+{
+public:
+    CIMIPythonPlugin(std::string filename);
+    virtual ~CIMIPythonPlugin();
+
+    virtual std::string getName() { return m_name; }
+    virtual std::string getAuthor() { return m_author; }
+    virtual std::string getDescription() { return m_description; }
+
+    virtual TPluginCandidates provide_candidates(const TPluginPreedit& str,
+                                                 int* waitTime);
+    virtual TPluginCandidate  translate_candidate(const TPluginCandidate& candi,
+                                                  int* waitTime);
+private:
+    PyObject* m_module;
+    PyObject* m_provide_method;
+    PyObject* m_trans_method;
+
+    std::string m_name;
+    std::string m_author;
+    std::string m_description;
+};
+
+CIMIPythonPlugin::CIMIPythonPlugin(std::string filename)
+    : CIMIPlugin(CIMI_PLUGIN_PYTHON), m_module(NULL), m_provide_method(NULL),
+      m_trans_method(NULL)
+{
+    // filename always ends with .py
+    std::string module_name = filename.substr(0, filename.length() - 3);
+    CIMIPluginManager& manager = AIMIPluginManager::instance();
+    PyObject* dict = NULL;
+    PyObject* name = NULL;
+    PyObject* author = NULL;
+    PyObject* description = NULL;
+
+    m_module = PyImport_ImportModule(module_name.c_str());
+    if (m_module == NULL) {
+        goto error;
+    }
+    dict = PyModule_GetDict(m_module);
+    if (dict == NULL) {
+        goto error;
+    }
+    m_provide_method = PyDict_GetItemString(dict, "provide_candidates");
+    m_trans_method = PyDict_GetItemString(dict, "translate_candidate");
+    name = PyDict_GetItemString(dict, "__NAME__");
+    author = PyDict_GetItemString(dict, "__AUTHOR__");
+    description = PyDict_GetItemString(dict, "__DESCRIPTION__");
+
+    if (name != NULL && PyString_Check(name)) {
+        m_name = PyString_AsString(name);
+    }
+    if (author != NULL && PyString_Check(author)) {
+        m_author = PyString_AsString(author);
+    }
+    if (description != NULL && PyString_Check(description)) {
+        m_description = PyString_AsString(description);
+    }
+    return;
+error:
+    manager.setLastError("Error when loading Python module");
+    return;
+}
+
+CIMIPythonPlugin::~CIMIPythonPlugin()
+{
+    Py_XDECREF(m_module);
+}
+
+static PyObject*
+Py_Call1(PyObject* method, PyObject* obj)
+{
+    PyObject* args = PyTuple_Pack(1, obj);
+    PyObject* ret = PyObject_CallObject(method, args);
+    Py_XDECREF(args);
+    if (ret == NULL) {
+        PyErr_PrintEx(2);
+    }
+    return ret;
+}
+
+static const size_t TWCharBufferSize = 2048;
+
+static wstring
+PyUnicode_AsWString(PyObject* obj)
+{
+    TWCHAR* wide_str_buf = new TWCHAR[TWCharBufferSize];
+    wstring res;
+    memset(wide_str_buf, 0, sizeof(TWCHAR) * TWCharBufferSize);
+
+    Py_ssize_t size = PyUnicode_AsWideChar((PyUnicodeObject*) obj,
+                                           (wchar_t*) wide_str_buf,
+                                           TWCharBufferSize);
+    if (size > 0) {
+        res = wstring(wide_str_buf);
+    }
+    delete [] wide_str_buf;
+    return res;
+}
+
+static void
+ExtractSequence(TPluginCandidates& result, PyObject* py_seq)
+{
+    Py_ssize_t len = PySequence_Length(py_seq);
+    for (Py_ssize_t i = 0; i < len; i++) {
+        PyObject* tuple_item_obj = PySequence_GetItem(py_seq, i);
+        if (!PyTuple_Check(tuple_item_obj)) {
+            continue;
+        }
+        PyObject* rank_obj = PyTuple_GetItem(tuple_item_obj, 0);
+        PyObject* candi_obj = PyTuple_GetItem(tuple_item_obj, 1);
+        if (rank_obj == NULL || !PyInt_Check(rank_obj) || candi_obj == NULL
+            || !PyUnicode_Check(candi_obj)) {
+            continue;
+        }
+
+        result.push_back(TPluginCandidateItem((int) PyInt_AsLong(rank_obj),
+                                              PyUnicode_AsWString(candi_obj)));
+    }
+}
+
+TPluginCandidates
+CIMIPythonPlugin::provide_candidates(const TPluginPreedit& str,
+                                     int* waitTime)
+{
+    TPluginCandidates res;
+    *waitTime = 0;
+
+    if (m_provide_method == NULL) {
+        *waitTime = -1;
+        return res;
+    }
+
+    PyObject* str_obj = PyUnicode_FromWideChar((wchar_t*) str.c_str(),
+                                               str.size());
+    PyObject* ret_obj = Py_Call1(m_provide_method, str_obj);
+
+    if (ret_obj == NULL) {
+        *waitTime = -1;
+    } else if (PyInt_Check(ret_obj)) {
+        *waitTime = (int) PyInt_AsLong(ret_obj);
+    } else if (PyTuple_Check(ret_obj) && PyTuple_Size(ret_obj) == 2) {
+        PyObject* time_obj = PyTuple_GetItem(ret_obj, 0);
+        PyObject* seq_obj = PyTuple_GetItem(ret_obj, 1);
+        if (PyInt_Check(time_obj) && PyList_Check(seq_obj)) {
+            *waitTime = (int) PyInt_AsLong(time_obj);
+            ExtractSequence(res, seq_obj);
+        }
+    } else if (PyList_Check(ret_obj)) {
+        // extract all items inside this sequence.
+        ExtractSequence(res, ret_obj);
+    }
+    Py_XDECREF(str_obj);
+    Py_XDECREF(ret_obj);
+    return res;
+}
+
+TPluginCandidate
+CIMIPythonPlugin::translate_candidate(const TPluginCandidate& candi,
+                                      int* waitTime)
+{
+    TPluginCandidate res;
+    *waitTime = 0;
+
+    if (m_trans_method == NULL) {
+        *waitTime = -1;
+        return res;
+    }
+
+    PyObject* str_obj = PyUnicode_FromWideChar((wchar_t*) candi.c_str(),
+                                               candi.size());
+    PyObject* ret_obj = Py_Call1(m_trans_method, str_obj);
+    if (ret_obj == NULL) {
+        *waitTime = -1;
+    } else if (PyInt_Check(ret_obj)) {
+        *waitTime = (int) PyInt_AsLong(ret_obj);
+    } else if (PyUnicode_Check(ret_obj)) {
+        res = TPluginCandidate(PyUnicode_AsWString(ret_obj));
+    }
+    Py_XDECREF(str_obj);
+    Py_XDECREF(ret_obj);
+    return res;
+}
+
+static void
+InitializePython()
+{
+    if (Py_IsInitialized())
+        return;
+    std::stringstream eval_str;
+
+    // append plugin module path to default load path
+    Py_Initialize();
+    signal(SIGINT, SIG_DFL);
+
+    PyRun_SimpleString("import sys");
+    eval_str << "sys.path.append(r'" << getenv("HOME")
+             << "/.sunpinyin/plugins/" << "')";
+    PyRun_SimpleString(eval_str.str().c_str());
+}
+
+#define PLUGIN_LIST_FILE "/.sunpinyin/plugins.list";
+#define PLUGIN_NAME_LEN 128
+
+CIMIPluginManager::CIMIPluginManager()
+    : m_hasError(false), m_waitTime(0)
+{
+    InitializePython();
+}
+
+CIMIPluginManager::~CIMIPluginManager()
+{
+    for (size_t i = 0;  i < m_plugins.size(); i++) {
+        delete m_plugins[i];
+    }
+}
+
+void
+CIMIPluginManager::initializePlugins()
+{
+    // load configuration file which list all needed plugins
+    std::string plugin_list_path = getenv("HOME");
+    plugin_list_path += PLUGIN_LIST_FILE;
+    FILE* fp = fopen(plugin_list_path.c_str(), "r");
+    if (!fp) {
+        return;
+    }
+    while (true) {
+        char plugin_name[PLUGIN_NAME_LEN];
+        memset(plugin_name, 0, PLUGIN_NAME_LEN);
+        fgets(plugin_name, PLUGIN_NAME_LEN, fp);
+        if (strlen(plugin_name) == 0) {
+            break;
+        }
+        if (strlen(plugin_name) == 1) {
+            continue;
+        }
+        plugin_name[strlen(plugin_name) - 1] = 0; // remove the \n at the end
+        if (loadPlugin(plugin_name) == NULL) {
+            fprintf(stderr, "Error! Cannot load plugin %s\n", plugin_name);
+        }
+    }
+    fclose(fp);
+}
+
+TPluginTypeEnum
+CIMIPluginManager::detectPluginType(std::string filename)
+{
+    if (filename.length() >= 3
+        && filename.substr(filename.length() - 3) == ".py") {
+        return CIMI_PLUGIN_PYTHON;
+    } else {
+        return CIMI_PLUGIN_UNKNOWN;
+    }
+}
+
+CIMIPlugin*
+CIMIPluginManager::loadPlugin(std::string filename)
+{
+    TPluginTypeEnum type = detectPluginType(filename);
+    CIMIPlugin* plugin = createPlugin(filename, type);
+    std::stringstream error;
+
+    if (plugin == NULL) {
+        return NULL;
+    }
+    if (hasLastError()) {
+        delete plugin;
+        return NULL;
+    }
+
+    for (size_t i = 0; i < m_plugins.size(); i++) {
+        if (m_plugins[i]->getName() == plugin->getName()) {
+            error << "Plugin " << plugin->getName() << " has already loaded!";
+            setLastError(error.str());
+            delete plugin; // Reject duplicate plugins
+            return NULL;
+        }
+    }
+    m_plugins.push_back(plugin);
+    return plugin;
+}
+
+CIMIPlugin*
+CIMIPluginManager::createPlugin(std::string filename,
+                                TPluginTypeEnum pluginType)
+{
+    std::stringstream error;
+    clearLastError();
+
+    switch (pluginType) {
+    case CIMI_PLUGIN_PYTHON:
+        return new CIMIPythonPlugin(filename);
+    case CIMI_PLUGIN_UNKNOWN:
+    default:
+        error << "Cannot detect type for " << filename;
+        setLastError(error.str());
+        return NULL;
+    }
+}
+
+void
+CIMIPluginManager::setLastError(std::string desc)
+{
+    m_hasError = true;
+    m_lastError = desc;
+}
+
+void
+CIMIPluginManager::clearLastError()
+{
+    m_hasError = false;
+    m_lastError = "";
+}
+
+void
+CIMIPluginManager::markWaitTime(int waitTime)
+{
+    if (waitTime <= 0)
+        return;
+
+    if (m_waitTime == 0) {
+        m_waitTime = waitTime;
+    } else if (waitTime < m_waitTime) {
+        m_waitTime = waitTime;
+    }
+}
diff --git a/src/ime-core/imi_plugin.h b/src/ime-core/imi_plugin.h
new file mode 100644 (file)
index 0000000..e5f1855
--- /dev/null
@@ -0,0 +1,115 @@
+// -*- mode: c++ -*-
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright (c) 2007 Sun Microsystems, Inc. All Rights Reserved.
+ *
+ * The contents of this file are subject to the terms of either the GNU Lesser
+ * General Public License Version 2.1 only ("LGPL") or the Common Development and
+ * Distribution License ("CDDL")(collectively, the "License"). You may not use this
+ * file except in compliance with the License. You can obtain a copy of the CDDL at
+ * http://www.opensource.org/licenses/cddl1.php and a copy of the LGPLv2.1 at
+ * http://www.opensource.org/licenses/lgpl-license.php. See the License for the
+ * specific language governing permissions and limitations under the License. When
+ * distributing the software, include this License Header Notice in each file and
+ * include the full text of the License in the License file as well as the
+ * following notice:
+ *
+ * NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND DISTRIBUTION LICENSE
+ * (CDDL)
+ * For Covered Software in this distribution, this License shall be governed by the
+ * laws of the State of California (excluding conflict-of-law provisions).
+ * Any litigation relating to this License shall be subject to the jurisdiction of
+ * the Federal Courts of the Northern District of California and the state courts
+ * of the State of California, with venue lying in Santa Clara County, California.
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by only the CDDL or only
+ * the LGPL Version 2.1, indicate your decision by adding "[Contributor]" elects to
+ * include this software in this distribution under the [CDDL or LGPL Version 2.1]
+ * license." If you don't indicate a single choice of license, a recipient has the
+ * option to distribute your version of this file under either the CDDL or the LGPL
+ * Version 2.1, or to extend the choice of license to its licensees as provided
+ * above. However, if you add LGPL Version 2.1 code and therefore, elected the LGPL
+ * Version 2 license, then the option applies only if the new code is made subject
+ * to such option by the copyright holder.
+ */
+
+#include <string>
+#include <vector>
+
+#include "portability.h"
+#include "utils.h"
+
+typedef wstring TPluginPreedit;
+typedef wstring TPluginCandidate;
+
+struct TPluginCandidateItem
+{
+    size_t m_rank;
+    TPluginCandidate m_candidate;
+    TPluginCandidateItem(size_t rank, TPluginCandidate candidate)
+        : m_rank(rank), m_candidate(candidate) {}
+};
+
+typedef std::vector<TPluginCandidateItem> TPluginCandidates;
+
+enum TPluginTypeEnum
+{
+    CIMI_PLUGIN_PYTHON,
+    CIMI_PLUGIN_UNKNOWN
+};
+
+class CIMIPlugin
+{
+private:
+    TPluginTypeEnum m_pluginType;
+protected:
+    CIMIPlugin(TPluginTypeEnum pluginType);
+public:
+    virtual ~CIMIPlugin();
+    virtual TPluginCandidates provide_candidates(const TPluginPreedit& str,
+                                                 int* waitTime) = 0;
+    virtual TPluginCandidate  translate_candidate(const TPluginCandidate& candi,
+                                                  int* waitTime) = 0;
+
+    virtual std::string getName() = 0;
+    virtual std::string getAuthor() = 0;
+    virtual std::string getDescription() = 0;
+
+    TPluginTypeEnum getPluginType() const { return m_pluginType; }
+};
+
+class CIMIPluginManager
+{
+public:
+    CIMIPluginManager();
+    virtual ~CIMIPluginManager();
+
+    void            initializePlugins();
+
+    TPluginTypeEnum detectPluginType(std::string filename);
+    CIMIPlugin*     loadPlugin(std::string filename);
+    CIMIPlugin*     createPlugin(std::string filename,
+                                 TPluginTypeEnum pluginType);
+    size_t          getPluginSize() const { return m_plugins.size(); }
+    CIMIPlugin*     getPlugin(size_t i) { return m_plugins[i]; }
+
+    bool        hasLastError() const { return m_hasError; }
+    std::string getLastError() const { return m_lastError; }
+    void        setLastError(std::string desc);
+    void        clearLastError();
+
+    void        markWaitTime(int waitTime);
+    int         getWaitTime() const { return m_waitTime; }
+    void        resetWaitTime() { m_waitTime = 0; }
+private:
+    std::vector<CIMIPlugin*> m_plugins;
+
+    bool        m_hasError;
+    std::string m_lastError;
+    int         m_waitTime;
+};
+
+typedef SingletonHolder<CIMIPluginManager> AIMIPluginManager;
diff --git a/src/ime-core/imi_uiobjects.cpp b/src/ime-core/imi_uiobjects.cpp
new file mode 100644 (file)
index 0000000..8eef775
--- /dev/null
@@ -0,0 +1,314 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright (c) 2007 Sun Microsystems, Inc. All Rights Reserved.
+ *
+ * The contents of this file are subject to the terms of either the GNU Lesser
+ * General Public License Version 2.1 only ("LGPL") or the Common Development and
+ * Distribution License ("CDDL")(collectively, the "License"). You may not use this
+ * file except in compliance with the License. You can obtain a copy of the CDDL at
+ * http://www.opensource.org/licenses/cddl1.php and a copy of the LGPLv2.1 at
+ * http://www.opensource.org/licenses/lgpl-license.php. See the License for the
+ * specific language governing permissions and limitations under the License. When
+ * distributing the software, include this License Header Notice in each file and
+ * include the full text of the License in the License file as well as the
+ * following notice:
+ *
+ * NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND DISTRIBUTION LICENSE
+ * (CDDL)
+ * For Covered Software in this distribution, this License shall be governed by the
+ * laws of the State of California (excluding conflict-of-law provisions).
+ * Any litigation relating to this License shall be subject to the jurisdiction of
+ * the Federal Courts of the Northern District of California and the state courts
+ * of the State of California, with venue lying in Santa Clara County, California.
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by only the CDDL or only
+ * the LGPL Version 2.1, indicate your decision by adding "[Contributor]" elects to
+ * include this software in this distribution under the [CDDL or LGPL Version 2.1]
+ * license." If you don't indicate a single choice of license, a recipient has the
+ * option to distribute your version of this file under either the CDDL or the LGPL
+ * Version 2.1, or to extend the choice of license to its licensees as provided
+ * above. However, if you add LGPL Version 2.1 code and therefore, elected the LGPL
+ * Version 2 license, then the option applies only if the new code is made subject
+ * to such option by the copyright holder.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "imi_uiobjects.h"
+
+#include <algorithm>
+
+#define MAX_CANDI_COUNT_PER_WINDOW      16
+#define MAX_STRING_LEN_CANDI_PREEDIT    256
+
+IPreeditString::~IPreeditString()
+{
+}
+
+CPreEditString::CPreEditString()
+    : m_caret(0), m_candi_start(0), m_charTypes()
+{
+    m_charTypes.reserve(MAX_STRING_LEN_CANDI_PREEDIT);
+}
+
+CPreEditString::~CPreEditString()
+{
+}
+
+int
+CPreEditString::size() const
+{
+    return m_wstr.size();
+}
+
+const TWCHAR*
+CPreEditString::string() const
+{
+    return m_wstr.c_str();
+}
+
+int
+CPreEditString::charTypeSize() const
+{
+    return std::min(m_charTypes.size(), m_wstr.size());
+}
+
+int
+CPreEditString::charTypeAt(int idx) const
+{
+    if (idx < 0 || idx >= (int) m_charTypes.size()) {
+        return DONTCARE_CHAR;
+    }
+    return m_charTypes[idx];
+}
+
+int
+CPreEditString::caret() const
+{
+    return m_caret;
+}
+
+int
+CPreEditString::candi_start() const
+{
+    return m_candi_start;
+}
+
+void
+CPreEditString::clear()
+{
+    m_caret = 0;
+    m_wstr.clear();
+    m_charTypes.clear();
+}
+
+wstring&
+CPreEditString::getString()
+{
+    return m_wstr;
+}
+
+IPreeditString::CCharTypeVec &
+CPreEditString::getCharTypeVec()
+{
+    return m_charTypes;
+}
+
+void
+CPreEditString::setCaret(int caret)
+{
+    m_caret = caret;
+}
+
+void
+CPreEditString::setCandiStart(int candi_start)
+{
+    m_candi_start = candi_start;
+}
+
+ICandidateList::~ICandidateList()
+{
+}
+
+CCandidateList::CCandidateList()
+    : m_total(0), m_first(0), m_size(0)
+{
+}
+
+CCandidateList::~CCandidateList()
+{
+}
+
+int
+CCandidateList::size() const
+{
+    return m_candiStrings.size();
+}
+
+int
+CCandidateList::total() const
+{
+    return m_total;
+}
+
+int
+CCandidateList::first() const
+{
+    return m_first;
+}
+
+void
+CCandidateList::setTotal(int total)
+{
+    m_total = total;
+}
+
+void
+CCandidateList::setFirst(int first)
+{
+    m_first = first;
+}
+
+int
+CCandidateList::candiType(unsigned item) const
+{
+    return (item >= m_candiTypes.size()) ? (NORMAL_WORD) : (m_candiTypes[item]);
+}
+
+int
+CCandidateList::candiSize(unsigned item) const
+{
+    return (item >= m_candiStrings.size()) ? (0) : (m_candiStrings[item].size());
+}
+
+const TWCHAR*
+CCandidateList::candiString(unsigned item) const
+{
+    return (item >=
+            m_candiStrings.size()) ? (NULL) : (m_candiStrings[item].c_str());
+}
+
+int
+CCandidateList::candiCharTypeSizeAt(unsigned item) const
+{
+    if (item >= m_candiCharTypeVecs.size())
+        return 0;
+    const CCharTypeVec & ctv = m_candiCharTypeVecs[item];
+    return std::min((int)ctv.size(), candiSize(item));
+}
+
+int
+CCandidateList::candiCharTypeAt(unsigned item, unsigned idx) const
+{
+    int sz = candiCharTypeSizeAt(item);
+    if ((int) idx >= sz) {
+        return DONTCARE_CHAR;
+    }
+    return m_candiCharTypeVecs[item][idx];
+}
+
+void
+CCandidateList::clear()
+{
+    m_size = m_first = m_total = 0;
+    m_candiStrings.clear();
+    m_candiTypes.clear();
+    m_candiCharTypeVecs.clear();
+    m_candiUserIndex.clear();
+    m_candiStringsIndex.clear();
+}
+
+void
+CCandidateList::setSize(int count)
+{
+    m_size = count;
+}
+
+ICandidateList::CCandiStrings &
+CCandidateList::getCandiStrings()
+{
+    return m_candiStrings;
+}
+
+ICandidateList::CCandiTypeVec &
+CCandidateList::getCandiTypeVec()
+{
+    return m_candiTypes;
+}
+
+ICandidateList::CCharTypeVecs &
+CCandidateList::getCharTypeVecs()
+{
+    return m_candiCharTypeVecs;
+}
+
+void
+CCandidateList::pushBackCandidate(wstring wstr, int type, int userIdx)
+{
+    if (m_candiStringsIndex.find(wstr) == m_candiStringsIndex.end()) {
+        m_candiStringsIndex.insert(std::make_pair(wstr, m_candiStrings.size()));
+        m_candiStrings.push_back(wstr);
+        m_candiTypes.push_back(type);
+        m_candiUserIndex.push_back(userIdx);
+    }
+}
+
+void
+CCandidateList::insertCandidate(wstring wstr, int type, int rank, int userIdx)
+{
+    if (rank > (int) m_candiStrings.size()) {
+        rank = m_candiStrings.size();
+    }
+    if (m_candiStringsIndex.find(wstr) == m_candiStringsIndex.end()) {
+        m_candiStringsIndex.insert(std::make_pair(wstr, m_candiStrings.size()));
+        insertCandidateNoDedup(wstr, type, rank, userIdx);
+    } else {
+        int idx = m_candiStringsIndex[wstr];
+        if (rank >= idx) {
+            return;
+        }
+        m_candiStringsIndex[wstr] = rank;
+        m_candiStrings.erase(m_candiStrings.begin() + idx);
+        m_candiTypes.erase(m_candiTypes.begin() + idx);
+        m_candiUserIndex.erase(m_candiUserIndex.begin() + idx);
+        m_candiStrings.insert(m_candiStrings.begin() + rank, wstr);
+        m_candiTypes.insert(m_candiTypes.begin() + rank, type);
+        m_candiUserIndex.insert(m_candiUserIndex.begin() + rank, userIdx);
+    }
+}
+
+void
+CCandidateList::insertCandidateNoDedup(wstring wstr, int type, int rank,
+                                       int userIdx)
+{
+    m_candiStrings.insert(m_candiStrings.begin() + rank, wstr);
+    m_candiTypes.insert(m_candiTypes.begin() + rank, type);
+    m_candiUserIndex.insert(m_candiUserIndex.begin() + rank, userIdx);
+}
+
+void
+CCandidateList::shrinkList()
+{
+    if ((int) m_candiStrings.size() > m_first) {
+        m_candiStrings.erase(m_candiStrings.begin(),
+                             m_candiStrings.begin() + m_first);
+        m_candiTypes.erase(m_candiTypes.begin(),
+                           m_candiTypes.begin() + m_first);
+        m_candiUserIndex.erase(m_candiUserIndex.begin(),
+                               m_candiUserIndex.begin() + m_first);
+    }
+
+    if ((int) m_candiStrings.size() > m_size) {
+        m_candiStrings.erase(m_candiStrings.begin() + m_size,
+                             m_candiStrings.end());
+        m_candiTypes.erase(m_candiTypes.begin() + m_size,
+                           m_candiTypes.end());
+        m_candiUserIndex.erase(m_candiUserIndex.begin() + m_size,
+                               m_candiUserIndex.end());
+    }
+}
diff --git a/src/ime-core/imi_uiobjects.h b/src/ime-core/imi_uiobjects.h
new file mode 100644 (file)
index 0000000..ad953c7
--- /dev/null
@@ -0,0 +1,248 @@
+// -*- mode: c++ -*-
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright (c) 2007 Sun Microsystems, Inc. All Rights Reserved.
+ *
+ * The contents of this file are subject to the terms of either the GNU Lesser
+ * General Public License Version 2.1 only ("LGPL") or the Common Development and
+ * Distribution License ("CDDL")(collectively, the "License"). You may not use this
+ * file except in compliance with the License. You can obtain a copy of the CDDL at
+ * http://www.opensource.org/licenses/cddl1.php and a copy of the LGPLv2.1 at
+ * http://www.opensource.org/licenses/lgpl-license.php. See the License for the
+ * specific language governing permissions and limitations under the License. When
+ * distributing the software, include this License Header Notice in each file and
+ * include the full text of the License in the License file as well as the
+ * following notice:
+ *
+ * NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND DISTRIBUTION LICENSE
+ * (CDDL)
+ * For Covered Software in this distribution, this License shall be governed by the
+ * laws of the State of California (excluding conflict-of-law provisions).
+ * Any litigation relating to this License shall be subject to the jurisdiction of
+ * the Federal Courts of the Northern District of California and the state courts
+ * of the State of California, with venue lying in Santa Clara County, California.
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by only the CDDL or only
+ * the LGPL Version 2.1, indicate your decision by adding "[Contributor]" elects to
+ * include this software in this distribution under the [CDDL or LGPL Version 2.1]
+ * license." If you don't indicate a single choice of license, a recipient has the
+ * option to distribute your version of this file under either the CDDL or the LGPL
+ * Version 2.1, or to extend the choice of license to its licensees as provided
+ * above. However, if you add LGPL Version 2.1 code and therefore, elected the LGPL
+ * Version 2 license, then the option applies only if the new code is made subject
+ * to such option by the copyright holder.
+ */
+
+#ifndef SUNPINYIN_UI_OBJECTS_H
+#define SUNPINYIN_UI_OBJECTS_H
+
+#include "portability.h"
+
+#include <vector>
+#include <string>
+#include <map>
+
+#include "imi_context.h"
+
+class IECharType {
+public:
+    enum ECharType {
+        DONTCARE_CHAR   = 0,
+
+        NORMAL_CHAR     = 1,
+        PINYIN_CHAR     = 2 + NORMAL_CHAR,
+        ASCII_CHAR      = ((PINYIN_CHAR - NORMAL_CHAR) << 1) + NORMAL_CHAR,
+        SYMBOL_CHAR     = ((ASCII_CHAR - NORMAL_CHAR) << 1) + NORMAL_CHAR,
+        PUNC_CHAR       = ((SYMBOL_CHAR - NORMAL_CHAR) << 1) + NORMAL_CHAR,
+        HANZI_CHAR      = ((PUNC_CHAR - NORMAL_CHAR) << 1) + NORMAL_CHAR,
+
+        BOUNDARY        = 256,
+
+        CONVERTED       = 0x10000,
+        USER_CHOICE     = (CONVERTED << 1),
+        ILLEGAL         = (USER_CHOICE << 1),
+        SELECTION       = (ILLEGAL << 1)
+    };
+};
+
+/** The interface for retrieve Preedit data*/
+class IPreeditString : public virtual IECharType {
+public:
+    typedef std::vector<int>    CCharTypeVec;
+
+public:
+    virtual ~IPreeditString() = 0;
+
+    /*@{*/
+    /** Following functions are used for CIMIWinHandler to retrieve Preedit data. */
+    virtual int                 size() const = 0;
+    virtual const TWCHAR*       string() const = 0;
+    virtual int                 charTypeSize() const = 0;
+    virtual int                 charTypeAt(int idx) const = 0;
+    virtual int                 caret() const = 0;
+    virtual int                 candi_start() const = 0;
+    /*@}*/
+
+public:
+    /*@{*/
+    /**
+     * Following functions are used for CIMIView to set Preedit data, should not
+     * be used by CIMIWinHandler.
+     */
+    virtual void                clear() = 0;
+    virtual wstring&            getString() = 0;
+    virtual CCharTypeVec&       getCharTypeVec() = 0;
+    virtual void                setCaret(int caret) = 0;
+    virtual void                setCandiStart(int s) = 0;
+    /*@}*/
+};
+
+class CPreEditString : virtual public IPreeditString {
+public:
+    CPreEditString();
+
+    virtual ~CPreEditString();
+
+    /*@{*/
+    virtual int                 size() const;
+    virtual const TWCHAR*       string() const;
+    virtual int                 charTypeSize() const;
+    virtual int                 charTypeAt(int idx) const;
+    virtual int                 caret() const;
+    virtual int                 candi_start() const;
+    /*@}*/
+
+    /*@{*/
+    virtual void                clear();
+    virtual wstring&            getString();
+    virtual CCharTypeVec&       getCharTypeVec();
+    virtual void                setCaret(int caret);
+    virtual void                setCandiStart(int s);
+    /*@}*/
+
+protected:
+    wstring m_wstr;
+    int m_caret;
+    int m_candi_start;
+    CCharTypeVec m_charTypes;
+};
+
+
+/** The interface for retrieve Preedit candidate data*/
+class ICandidateList : public virtual IECharType {
+public:
+    enum ECandidateType {
+        NORMAL_WORD = 0,
+        AS_INPUT,
+        BEST_WORD,
+        USER_SELECTED_WORD,
+        BEST_TAIL,
+        PLUGIN_TAIL,
+        OTHER_BEST_TAIL
+    };
+
+    typedef IPreeditString::CCharTypeVec CCharTypeVec;
+    typedef std::vector< CCharTypeVec >         CCharTypeVecs;
+    typedef std::vector< wstring >              CCandiStrings;
+    typedef std::vector<int>                    CCandiTypeVec;
+
+public:
+    virtual ~ICandidateList() = 0;
+
+    /*@{*/
+    /** Following functions are used for CIMIWinHandler to retrieve Candidate data. */
+    virtual int                 size() const = 0;
+    virtual int                 total() const = 0;
+    virtual int                 first() const = 0;
+
+    virtual int                 candiType(unsigned int item) const = 0;
+    virtual int                 candiSize(unsigned int item) const = 0;
+    virtual const TWCHAR*       candiString(unsigned int item) const = 0;
+
+    virtual int                 candiCharTypeSizeAt(unsigned int item) const =
+        0;
+    virtual int                 candiCharTypeAt(unsigned int item,
+                                                unsigned int idx) const = 0;
+    /*@}*/
+
+public:
+    /*@{*/
+    /**
+     * Following functions are used for CIMIView to set Candidate List data, should not
+     * be used by CIMIWinHandler.
+     */
+    virtual void                clear() = 0;
+    virtual void                setTotal(int total) = 0;
+    virtual void                setFirst(int first) = 0;
+    virtual void                setSize(int count) = 0;
+
+    virtual void shrinkList() = 0;
+    virtual void pushBackCandidate(wstring wstr, int type,
+                                   int userIdx = -1) = 0;
+    virtual void insertCandidate(wstring wstr, int type, int rank,
+                                 int userIdx = -1) = 0;
+    virtual void insertCandidateNoDedup(wstring wstr, int type, int rank,
+                                        int userIdx = -1) = 0;
+
+    virtual CCandiStrings &     getCandiStrings() = 0;
+    virtual CCandiTypeVec &     getCandiTypeVec() = 0;
+    virtual CCharTypeVecs &     getCharTypeVecs() = 0;
+    /*@}*/
+};
+
+class CCandidateList : virtual public ICandidateList {
+public:
+    CCandidateList();
+
+    virtual ~CCandidateList();
+
+    /*@{*/
+    virtual int                 size() const;
+    virtual int                 total() const;
+    virtual int                 first() const;
+
+    virtual int                 candiType(unsigned int item) const;
+    virtual int                 candiSize(unsigned int item) const;
+    virtual const TWCHAR*       candiString(unsigned int item) const;
+
+    virtual int                 candiCharTypeSizeAt(unsigned int item) const;
+    virtual int                 candiCharTypeAt(unsigned int item,
+                                                unsigned int idx) const;
+    /*@}*/
+
+    /*@{*/
+    virtual void                clear();
+    virtual void                setTotal(int total);
+    virtual void                setFirst(int first);
+    virtual void                setSize(int size);
+
+    virtual void shrinkList();
+    virtual void pushBackCandidate(wstring wstr, int type, int userIdx = -1);
+    virtual void insertCandidate(wstring wstr, int type, int rank,
+                                 int userIdx = -1);
+    virtual void insertCandidateNoDedup(wstring wstr, int type, int rank,
+                                        int userIdx = -1);
+
+    virtual CCandiStrings &     getCandiStrings();
+    virtual CCandiTypeVec &     getCandiTypeVec();
+    virtual CCharTypeVecs &     getCharTypeVecs();
+    /*@}*/
+
+    int getUserIndex(int idx) { return m_candiUserIndex[idx]; }
+
+protected:
+    int m_total;
+    int m_first;
+    int m_size;
+    CCandiStrings m_candiStrings;
+    CCandiTypeVec m_candiTypes;
+    std::vector<int> m_candiUserIndex;
+    CCharTypeVecs m_candiCharTypeVecs;
+
+    std::map<wstring, int> m_candiStringsIndex;
+};
+
+#endif
diff --git a/src/ime-core/imi_view.cpp b/src/ime-core/imi_view.cpp
new file mode 100644 (file)
index 0000000..e66f4f4
--- /dev/null
@@ -0,0 +1,223 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright (c) 2007 Sun Microsystems, Inc. All Rights Reserved.
+ *
+ * The contents of this file are subject to the terms of either the GNU Lesser
+ * General Public License Version 2.1 only ("LGPL") or the Common Development and
+ * Distribution License ("CDDL")(collectively, the "License"). You may not use this
+ * file except in compliance with the License. You can obtain a copy of the CDDL at
+ * http://www.opensource.org/licenses/cddl1.php and a copy of the LGPLv2.1 at
+ * http://www.opensource.org/licenses/lgpl-license.php. See the License for the
+ * specific language governing permissions and limitations under the License. When
+ * distributing the software, include this License Header Notice in each file and
+ * include the full text of the License in the License file as well as the
+ * following notice:
+ *
+ * NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND DISTRIBUTION LICENSE
+ * (CDDL)
+ * For Covered Software in this distribution, this License shall be governed by the
+ * laws of the State of California (excluding conflict-of-law provisions).
+ * Any litigation relating to this License shall be subject to the jurisdiction of
+ * the Federal Courts of the Northern District of California and the state courts
+ * of the State of California, with venue lying in Santa Clara County, California.
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by only the CDDL or only
+ * the LGPL Version 2.1, indicate your decision by adding "[Contributor]" elects to
+ * include this software in this distribution under the [CDDL or LGPL Version 2.1]
+ * license." If you don't indicate a single choice of license, a recipient has the
+ * option to distribute your version of this file under either the CDDL or the LGPL
+ * Version 2.1, or to extend the choice of license to its licensees as provided
+ * above. However, if you add LGPL Version 2.1 code and therefore, elected the LGPL
+ * Version 2 license, then the option applies only if the new code is made subject
+ * to such option by the copyright holder.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "imi_view.h"
+#include "imi_view_classic.h"
+
+#ifdef ENABLE_PLUGINS
+#include "imi_plugin.h"
+#endif
+
+// #pragma setlocale("zh_CN.UTF-8")
+
+CHotkeyProfile::CHotkeyProfile()
+    : m_punctSwitchKey(IM_VK_PERIOD, 0, IM_CTRL_MASK),
+      m_symbolSwitchKey(IM_VK_SPACE, 0, IM_SHIFT_MASK),
+      m_candiDeleteKey(0, 0, IM_CTRL_MASK),
+      m_prevKey(0)
+{
+    addModeSwitchKey(CKeyEvent(IM_VK_SHIFT_L, 0, IM_ALT_MASK));
+}
+
+
+CIMIView::CIMIView()
+    : m_pIC(NULL), m_pWinHandler(NULL), m_pPySegmentor(NULL),
+      m_pHotkeyProfile(NULL),
+      m_candiWindowSize(10), m_bCN(true), m_bFullPunct(true),
+      m_bFullSymbol(false), m_backspaceCancel(true), m_smartPunct(true)
+{
+#ifdef ENABLE_PLUGINS
+    // load all needed plugins
+    AIMIPluginManager::instance().initializePlugins();
+#endif
+}
+
+void
+CIMIView::setStatusAttrValue(int key, int value)
+{
+    switch (key) {
+    case CIMIWinHandler::STATUS_ID_CN:
+        m_bCN = (value != 0);
+        if (m_pWinHandler)
+            m_pWinHandler->updateStatus(key, value);
+        break;
+    case CIMIWinHandler::STATUS_ID_FULLPUNC:
+        m_bFullPunct = (value != 0);
+        if (m_pWinHandler)
+            m_pWinHandler->updateStatus(key, value);
+        if (m_pIC)
+            m_pIC->setFullPunctForwarding(m_bFullPunct);
+        break;
+    case CIMIWinHandler::STATUS_ID_FULLSYMBOL:
+        m_bFullSymbol = (value != 0);
+        if (m_pWinHandler)
+            m_pWinHandler->updateStatus(key, value);
+        if (m_pIC)
+            m_pIC->setFullSymbolForwarding(m_bFullSymbol);
+        break;
+    }
+}
+
+int
+CIMIView::getStatusAttrValue(int key)
+{
+    switch (key) {
+    case CIMIWinHandler::STATUS_ID_CN:
+        return (m_bCN) ? 1 : 0;
+    case CIMIWinHandler::STATUS_ID_FULLPUNC:
+        return (m_bFullPunct) ? 1 : 0;
+    case CIMIWinHandler::STATUS_ID_FULLSYMBOL:
+        return (m_bFullSymbol) ? 1 : 0;
+    }
+    return 0;
+}
+
+void
+CIMIView::handlerUpdatePreedit(const IPreeditString* ppd)
+{
+    if (m_pWinHandler == NULL || ppd == NULL) {
+        return;
+    }
+    // nothing to do here for plugins
+    m_pWinHandler->updatePreedit(ppd);
+}
+
+// only build these with plugins support
+#ifdef ENABLE_PLUGINS
+
+void
+CIMIView::_pluginProvideCandidates(wstring preedit, ICandidateList* pcl)
+{
+    CIMIPluginManager& manager = AIMIPluginManager::instance();
+    if (preedit.size() == 0) {
+        return;
+    }
+
+    for (size_t i = 0; i < manager.getPluginSize(); i++) {
+        CIMIPlugin* plugin = manager.getPlugin(i);
+        int wait_time = -1;
+        TPluginCandidates candidates = plugin->provide_candidates(preedit,
+                                                                  &wait_time);
+        if (wait_time != 0) {
+            manager.markWaitTime(wait_time);
+        }
+
+        for (size_t j = 0; j < candidates.size(); j++) {
+            const TPluginCandidateItem& item = candidates[j];
+            pcl->insertCandidateNoDedup(item.m_candidate,
+                                        ICandidateList::PLUGIN_TAIL,
+                                        item.m_rank);
+        }
+    }
+}
+
+void
+CIMIView::_pluginTranslateCandidate(ICandidateList* pcl)
+{
+    CIMIPluginManager& manager = AIMIPluginManager::instance();
+    ICandidateList::CCandiStrings& css = pcl->getCandiStrings();
+    if (css.size() == 0) {
+        return;
+    }
+
+    for (size_t i = 0; i < css.size(); i++) {
+        for (size_t j = 0; j < manager.getPluginSize(); j++) {
+            CIMIPlugin* plugin = manager.getPlugin(j);
+            int wait_time = -1;
+            wstring result = plugin->translate_candidate(css[i], &wait_time);
+            if (wait_time != 0) {
+                manager.markWaitTime(wait_time);
+            } else {
+                css[i] = result;
+            }
+        }
+    }
+}
+
+#endif // ENABLE_PLUGINS
+
+void
+CIMIView::handlerUpdateCandidates(IPreeditString* ppd,
+                                  ICandidateList* pcl)
+{
+    if (m_pWinHandler == NULL || pcl == NULL) {
+        return;
+    }
+#ifdef ENABLE_PLUGINS
+    _pluginProvideCandidates(ppd->getString(), pcl);
+    pcl->shrinkList();
+    _pluginTranslateCandidate(pcl);
+
+    m_pWinHandler->updateCandidates(pcl);
+    CIMIPluginManager& manager = AIMIPluginManager::instance();
+    m_pWinHandler->enableDeferedUpdate(this, manager.getWaitTime());
+    manager.resetWaitTime();
+#else
+    pcl->shrinkList();
+    m_pWinHandler->updateCandidates(pcl);
+#endif
+}
+
+void
+CIMIView::handlerCommit(const wstring& wstr)
+{
+    if (m_pWinHandler == NULL) {
+        return;
+    }
+#ifdef ENABLE_PLUGINS
+    wstring commit_result = wstr;
+    CIMIPluginManager& manager = AIMIPluginManager::instance();
+    // re-run filter again
+    for (size_t i = 0; i < manager.getPluginSize(); i++) {
+        CIMIPlugin* plugin = manager.getPlugin(i);
+        int wait_time = -1;
+        wstring result = plugin->translate_candidate(commit_result, &wait_time);
+        if (wait_time != 0) {
+            continue;
+        }
+        commit_result = result;
+    }
+    m_pWinHandler->commit(commit_result.c_str());
+    m_pWinHandler->disableDeferedUpdate();
+#else
+    m_pWinHandler->commit(wstr.c_str());
+#endif
+}
diff --git a/src/ime-core/imi_view.h b/src/ime-core/imi_view.h
new file mode 100644 (file)
index 0000000..fdbaaa3
--- /dev/null
@@ -0,0 +1,227 @@
+// -*- mode: c++ -*-
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright (c) 2007 Sun Microsystems, Inc. All Rights Reserved.
+ *
+ * The contents of this file are subject to the terms of either the GNU Lesser
+ * General Public License Version 2.1 only ("LGPL") or the Common Development and
+ * Distribution License ("CDDL")(collectively, the "License"). You may not use this
+ * file except in compliance with the License. You can obtain a copy of the CDDL at
+ * http://www.opensource.org/licenses/cddl1.php and a copy of the LGPLv2.1 at
+ * http://www.opensource.org/licenses/lgpl-license.php. See the License for the
+ * specific language governing permissions and limitations under the License. When
+ * distributing the software, include this License Header Notice in each file and
+ * include the full text of the License in the License file as well as the
+ * following notice:
+ *
+ * NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND DISTRIBUTION LICENSE
+ * (CDDL)
+ * For Covered Software in this distribution, this License shall be governed by the
+ * laws of the State of California (excluding conflict-of-law provisions).
+ * Any litigation relating to this License shall be subject to the jurisdiction of
+ * the Federal Courts of the Northern District of California and the state courts
+ * of the State of California, with venue lying in Santa Clara County, California.
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by only the CDDL or only
+ * the LGPL Version 2.1, indicate your decision by adding "[Contributor]" elects to
+ * include this software in this distribution under the [CDDL or LGPL Version 2.1]
+ * license." If you don't indicate a single choice of license, a recipient has the
+ * option to distribute your version of this file under either the CDDL or the LGPL
+ * Version 2.1, or to extend the choice of license to its licensees as provided
+ * above. However, if you add LGPL Version 2.1 code and therefore, elected the LGPL
+ * Version 2 license, then the option applies only if the new code is made subject
+ * to such option by the copyright holder.
+ */
+
+#ifndef SUNPY_IMI_SESSION_VIEW_H
+#define SUNPY_IMI_SESSION_VIEW_H
+
+#include "portability.h"
+
+#include "imi_context.h"
+#include "imi_winHandler.h"
+#include "imi_uiobjects.h"
+#include "imi_keys.h"
+#include "utils.h"
+#include <set>
+
+class CHotkeyProfile : private CNonCopyable
+{
+public:
+    CHotkeyProfile();
+
+    void clear(){
+        m_pageUpKeys.clear();
+        m_pageDownKeys.clear();
+        m_modeSwitchKeys.clear();
+    }
+
+    void addPageUpKey(const CKeyEvent& key){
+        m_pageUpKeys.insert(key);
+    }
+
+    void removePageUpKey(const CKeyEvent& key){
+        m_pageUpKeys.erase(key);
+    }
+
+    bool isPageUpKey(const CKeyEvent& key) const {
+        return(m_pageUpKeys.find(key) != m_pageUpKeys.end());
+    }
+
+    void addPageDownKey(const CKeyEvent& key){
+        m_pageDownKeys.insert(key);
+    }
+
+    void removePageDownKey(const CKeyEvent& key){
+        m_pageDownKeys.erase(key);
+    }
+
+    bool isPageDownKey(const CKeyEvent& key) const {
+        return(m_pageDownKeys.find(key) != m_pageDownKeys.end());
+    }
+
+    void addModeSwitchKey(const CKeyEvent& key){
+        m_modeSwitchKeys.insert(key);
+    }
+
+    void removeModeSwitchKey(const CKeyEvent& key){
+        m_modeSwitchKeys.erase(key);
+    }
+
+    bool isModeSwitchKey(const CKeyEvent& key) const {
+        std::set<CKeyEvent>::const_iterator end(m_modeSwitchKeys.end());
+        for (std::set<CKeyEvent>::const_iterator it = m_modeSwitchKeys.begin();
+             it != end; ++it) {
+            if (matches(*it, key))
+                return true;
+        }
+        return false;
+    }
+
+    void setPunctSwitchKey(const CKeyEvent& key){
+        m_punctSwitchKey = key;
+    }
+
+    bool isPunctSwitchKey(const CKeyEvent& key) const {
+        return matches(m_punctSwitchKey, key);
+    }
+
+    void setSymbolSwitchKey(const CKeyEvent& key){
+        m_symbolSwitchKey = key;
+    }
+
+    bool isSymbolSwitchKey(const CKeyEvent& key) const {
+        return matches(m_symbolSwitchKey, key);
+    }
+
+    void rememberLastKey(const CKeyEvent& key){
+        m_prevKey = key;
+    }
+
+    void setCandiDeleteKey(const CKeyEvent& key){
+        m_candiDeleteKey = key;
+    }
+
+    bool isCandiDeleteKey(const CKeyEvent& key, unsigned candiWndSize){
+        return (key.modifiers == m_candiDeleteKey.modifiers) &&
+               (key.value >= '0' && key.value <= '9') &&
+               (candiWndSize >= 10 || key.value < ('1' + candiWndSize));
+    }
+
+private:
+    bool matches(const CKeyEvent& lhs, const CKeyEvent& rhs) const {
+        if (lhs == rhs)
+            return(!(lhs.modifiers & IM_RELEASE_MASK) ||
+                   m_prevKey.code == rhs.code);
+        return false;
+    }
+
+protected:
+    std::set<CKeyEvent> m_pageUpKeys;
+    std::set<CKeyEvent> m_pageDownKeys;
+    std::set<CKeyEvent> m_modeSwitchKeys;
+    CKeyEvent m_punctSwitchKey;
+    CKeyEvent m_symbolSwitchKey;
+    CKeyEvent m_candiDeleteKey;
+    CKeyEvent m_prevKey;
+};
+
+class CIMIView {
+public:
+    enum {
+        KEYEVENT_USED  = (1),
+        PREEDIT_MASK   = (1 << 2),
+        CANDIDATE_MASK = (1 << 3)
+    };
+
+public:
+    CIMIView();
+    virtual ~CIMIView() {}
+
+    void attachIC(CIMIContext* pIC) { m_pIC = pIC; }
+    CIMIContext* getIC(void) const { return m_pIC; }
+
+    void setPySegmentor(IPySegmentor *p) { m_pPySegmentor = p; }
+    IPySegmentor* getPySegmentor() const { return m_pPySegmentor; }
+
+    void attachWinHandler(CIMIWinHandler* wh) { m_pWinHandler = wh; }
+    CIMIWinHandler* getWinHandler(void) const { return m_pWinHandler; }
+
+    void setHotkeyProfile(CHotkeyProfile *prof) { m_pHotkeyProfile = prof; }
+    void setCandiWindowSize(unsigned size) {
+        m_candiWindowSize = size;
+    }
+
+    CHotkeyProfile* getHotkeyProfile() { return m_pHotkeyProfile; }
+    unsigned getCandiWindowSize() const { return m_candiWindowSize; }
+
+    void setCancelOnBackspace(bool backspaceCancel)
+    { m_backspaceCancel = backspaceCancel; }
+    bool getCancelOnBackspace() const { return m_backspaceCancel; }
+
+    void setSmartPunct(bool smart) { m_smartPunct = smart; }
+    bool getSmartPunct() const { return m_smartPunct; }
+
+    virtual unsigned clearIC(void) { m_pIC->clear(); return 0; }
+    virtual bool onKeyEvent(const CKeyEvent&) { return false; }
+
+    virtual void setStatusAttrValue(int key, int value);
+    virtual int  getStatusAttrValue(int key);
+    virtual void updateWindows(unsigned mask = CANDIDATE_MASK) = 0;
+
+    virtual void getPreeditString(IPreeditString& ps) = 0;
+    virtual void getCandidateList(ICandidateList& cl, int start, int size) = 0;
+
+    virtual int  onCandidatePageRequest(int pgno, bool relative) = 0; //pgno == -1, relative == false means last page
+    virtual int  onCandidateSelectRequest(int index) = 0;
+
+    virtual void handlerUpdatePreedit(const IPreeditString* ppd);
+    virtual void handlerUpdateCandidates(IPreeditString* ppd,
+                                         ICandidateList* pcl);
+    virtual void handlerCommit(const wstring& wstr);
+
+#ifdef ENABLE_PLUGINS
+private:
+    void _pluginProvideCandidates(wstring preedit, ICandidateList* pcl);
+    void _pluginTranslateCandidate(ICandidateList* pcl);
+#endif // ENABLE_PLUGINS
+
+protected:
+    CIMIContext        *m_pIC;
+    CIMIWinHandler     *m_pWinHandler;
+    IPySegmentor       *m_pPySegmentor;
+    CHotkeyProfile     *m_pHotkeyProfile;
+
+    unsigned m_candiWindowSize;
+
+    bool m_bCN;
+    bool m_bFullPunct;
+    bool m_bFullSymbol;
+    bool m_backspaceCancel;
+    bool m_smartPunct;
+};
+
+#endif
diff --git a/src/ime-core/imi_view_classic.cpp b/src/ime-core/imi_view_classic.cpp
new file mode 100644 (file)
index 0000000..b4d374f
--- /dev/null
@@ -0,0 +1,749 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright (c) 2007 Sun Microsystems, Inc. All Rights Reserved.
+ *
+ * The contents of this file are subject to the terms of either the GNU Lesser
+ * General Public License Version 2.1 only ("LGPL") or the Common Development and
+ * Distribution License ("CDDL")(collectively, the "License"). You may not use this
+ * file except in compliance with the License. You can obtain a copy of the CDDL at
+ * http://www.opensource.org/licenses/cddl1.php and a copy of the LGPLv2.1 at
+ * http://www.opensource.org/licenses/lgpl-license.php. See the License for the
+ * specific language governing permissions and limitations under the License. When
+ * distributing the software, include this License Header Notice in each file and
+ * include the full text of the License in the License file as well as the
+ * following notice:
+ *
+ * NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND DISTRIBUTION LICENSE
+ * (CDDL)
+ * For Covered Software in this distribution, this License shall be governed by the
+ * laws of the State of California (excluding conflict-of-law provisions).
+ * Any litigation relating to this License shall be subject to the jurisdiction of
+ * the Federal Courts of the Northern District of California and the state courts
+ * of the State of California, with venue lying in Santa Clara County, California.
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by only the CDDL or only
+ * the LGPL Version 2.1, indicate your decision by adding "[Contributor]" elects to
+ * include this software in this distribution under the [CDDL or LGPL Version 2.1]
+ * license." If you don't indicate a single choice of license, a recipient has the
+ * option to distribute your version of this file under either the CDDL or the LGPL
+ * Version 2.1, or to extend the choice of license to its licensees as provided
+ * above. However, if you add LGPL Version 2.1 code and therefore, elected the LGPL
+ * Version 2 license, then the option applies only if the new code is made subject
+ * to such option by the copyright holder.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "imi_view_classic.h"
+#include "imi_uiobjects.h"
+
+#include "imi_keys.h"
+
+CIMIClassicView::CIMIClassicView()
+    : CIMIView(), m_cursorFrIdx(0), m_candiFrIdx(0),
+      m_candiPageFirst(0)
+{
+}
+
+CIMIClassicView::~CIMIClassicView()
+{
+}
+
+size_t CIMIClassicView::top_candidate_threshold = 5;
+
+void
+CIMIClassicView::attachIC(CIMIContext* pIC)
+{
+    CIMIView::attachIC(pIC);
+    clearIC();
+}
+
+unsigned
+CIMIClassicView::clearIC(void)
+{
+    if (!m_pIC->isEmpty()) {
+        m_cursorFrIdx = m_candiFrIdx = m_candiPageFirst = 0;
+
+        m_pIC->clear();
+        m_pPySegmentor->clear();
+        m_candiList.clear();
+        //m_tailSentence.clear ();
+        m_sentences.clear();
+        m_tails.clear();
+        return PREEDIT_MASK | CANDIDATE_MASK;
+    }
+    return 0;
+}
+
+void
+CIMIClassicView::updateWindows(unsigned mask)
+{
+    if (!m_pWinHandler)
+        return;
+
+    if (mask & PREEDIT_MASK) {
+        m_uiPreeditString.clear();
+        getPreeditString(m_uiPreeditString);
+        // m_pWinHandler->updatePreedit(&ps);
+        handlerUpdatePreedit(&m_uiPreeditString);
+    }
+
+    if ((mask & PREEDIT_MASK) || (mask & CANDIDATE_MASK)) {
+        // calculate all possible best sentences
+        m_sentences.clear();
+        int best_rank = -1;
+        for (size_t i = 0; i < m_pIC->getNBest(); i++) {
+            wstring sentence;
+            unsigned word_num = m_pIC->getBestSentence(sentence, i,
+                                                       m_candiFrIdx);
+            if (word_num == 0) goto pass;  // when sentence is not worthy of
+
+#ifdef DEBUG
+            printf("%d ", i);
+            print_wide(sentence.c_str());
+            printf("\n");
+#endif
+
+            for (size_t j = 0; j < m_sentences.size(); j++) {
+                if (sentence == m_sentences[j].second) goto pass;
+            }
+
+            if (best_rank < 0 && word_num > 1) {
+                best_rank = i;
+            }
+            m_sentences.push_back(std::make_pair(i, sentence));
+        pass:
+            continue;
+        }
+        // build all possible tails with best_rank
+        std::vector<CCandidates> tails =
+            m_pIC->getBestSentenceTails(best_rank, m_candiFrIdx);
+        m_tails.clear();
+        for (size_t i = 0; i < tails.size(); i++) {
+            CCandidates& tail = tails[i];
+            wstring tail_text;
+            // translate this tail into text
+            for (size_t j = 0; j < tail.size(); j++) {
+                tail_text += tail[j].m_cwstr;
+            }
+            m_tails.push_back(std::make_pair(tail_text, tail));
+        }
+    }
+
+    if (mask & CANDIDATE_MASK) {
+        m_uiCandidateList.clear();
+        getCandidateList(m_uiCandidateList, m_candiPageFirst,
+                         m_candiWindowSize);
+        // m_pWinHandler->updateCandidates(&cl);
+        handlerUpdateCandidates(&m_uiPreeditString, &m_uiCandidateList);
+    }
+}
+
+bool
+CIMIClassicView::onKeyEvent(const CKeyEvent& key)
+{
+    unsigned changeMasks = 0;
+
+    unsigned keycode = key.code;
+    unsigned keyvalue = key.value;
+    unsigned modifiers = key.modifiers;
+
+#ifdef DEBUG
+    printf("Classic View got a key (0x%x-0x%x-0x%x)...",
+           keycode, keyvalue, modifiers);
+    if (((modifiers & IM_CTRL_MASK) != 0) &&
+        (keyvalue == 'P' || keyvalue == 'p'))
+        m_pIC->printLattice();
+#endif
+
+    if (m_pHotkeyProfile && m_pHotkeyProfile->isModeSwitchKey(key)) {
+        setStatusAttrValue(CIMIWinHandler::STATUS_ID_CN, (!m_bCN) ? 1 : 0);
+        if (!m_pIC->isEmpty()) {
+            changeMasks |= CANDIDATE_MASK | PREEDIT_MASK;
+            clearIC();
+        }
+    } else if (m_pHotkeyProfile && m_pHotkeyProfile->isPunctSwitchKey(key)) {
+        // On CTRL+. switch Full/Half punc
+        changeMasks |= KEYEVENT_USED;
+        setStatusAttrValue(CIMIWinHandler::STATUS_ID_FULLPUNC,
+                           (!m_bFullPunct) ? 1 : 0);
+    } else if (m_pHotkeyProfile && m_pHotkeyProfile->isSymbolSwitchKey(key)) {
+        // On SHIFT+SPACE switch Full/Half symbol
+        changeMasks |= KEYEVENT_USED;
+        setStatusAttrValue(CIMIWinHandler::STATUS_ID_FULLSYMBOL,
+                           (!m_bFullSymbol) ? 1 : 0);
+    } else if (modifiers == IM_CTRL_MASK && keycode == IM_VK_LEFT) {
+        // move left
+        if (!m_pIC->isEmpty()) {
+            changeMasks |= KEYEVENT_USED;
+            _moveLeft(changeMasks);
+        }
+    } else if (modifiers == IM_CTRL_MASK && keycode == IM_VK_RIGHT) {
+        // move right
+        if (!m_pIC->isEmpty()) {
+            changeMasks |= KEYEVENT_USED;
+            _moveRight(changeMasks);
+        }
+    } else if (((modifiers == 0 && keycode == IM_VK_PAGE_UP)
+                || (m_pHotkeyProfile && m_pHotkeyProfile->isPageUpKey(key)))
+               && !m_pIC->isEmpty()) {
+        changeMasks |= KEYEVENT_USED;
+        if (m_candiPageFirst > 0) {
+            m_candiPageFirst -= m_candiWindowSize;
+            if (m_candiPageFirst < 0) m_candiPageFirst = 0;
+            changeMasks |= CANDIDATE_MASK;
+        }
+    } else if (((modifiers == 0 && keycode == IM_VK_PAGE_DOWN)
+                || (m_pHotkeyProfile && m_pHotkeyProfile->isPageDownKey(key)))
+               && !m_pIC->isEmpty()) {
+        changeMasks |= KEYEVENT_USED;
+        if (m_candiPageFirst + m_candiWindowSize < candidateListSize()) {
+            m_candiPageFirst += m_candiWindowSize;
+            changeMasks |= CANDIDATE_MASK;
+        }
+    } else if (m_pHotkeyProfile
+              && m_pHotkeyProfile->isCandiDeleteKey(key, m_candiWindowSize)
+              && !m_pIC->isEmpty()) {
+        changeMasks |= KEYEVENT_USED;
+        unsigned sel = (keyvalue == '0' ? 9 : keyvalue - '1');
+        deleteCandidate(sel, changeMasks);
+        goto PROCESSED;
+    } else if ((modifiers &
+                (IM_CTRL_MASK | IM_ALT_MASK | IM_SUPER_MASK |
+                 IM_RELEASE_MASK)) == 0) {
+        if ((keyvalue >= '0' && keyvalue <= '9')
+            && (m_candiWindowSize >= 10
+                || keyvalue < ('1' + m_candiWindowSize))) {
+            // try to make selection
+            if (!m_pIC->isEmpty()) {
+                changeMasks |= KEYEVENT_USED;
+                unsigned sel = (keyvalue == '0' ? 9 : keyvalue - '1');
+                makeSelection(sel, changeMasks);
+            } else if (m_smartPunct) {
+                m_pIC->omitNextPunct();
+            }
+            goto PROCESSED;
+        }
+
+        if (keyvalue > 0x60 && keyvalue < 0x7b) {
+            /* islower(keyvalue) */
+            changeMasks |= KEYEVENT_USED;
+            _insert(keyvalue, changeMasks);
+        } else if (keyvalue > 0x20 && keyvalue < 0x7f) {
+            /* isprint(keyvalue) && !isspace(keyvalue) */
+            changeMasks |= KEYEVENT_USED;
+            if (m_pIC->isEmpty()) {
+                _insert(keyvalue, changeMasks);
+                _doCommit();
+                clearIC();
+            } else {
+                _insert(keyvalue, changeMasks);
+            }
+        } else if (keycode == IM_VK_BACK_SPACE || keycode == IM_VK_DELETE) {
+            if (!m_pIC->isEmpty()) {
+                changeMasks |= KEYEVENT_USED;
+                _erase(keycode == IM_VK_BACK_SPACE, changeMasks);
+            }
+        } else if (keycode == IM_VK_SPACE) {
+            if (!m_pIC->isEmpty()) {
+                changeMasks |= KEYEVENT_USED;
+                makeSelection(0, changeMasks);
+            } else {
+                wstring wstr = (m_pIC->fullPuncOp())(keyvalue);
+                if (wstr.size()) {
+                    _commitString(wstr);
+                    changeMasks |= KEYEVENT_USED;
+                }
+            }
+        } else if (keycode == IM_VK_ENTER) {
+            if (!m_pIC->isEmpty()) {
+                changeMasks |= KEYEVENT_USED | CANDIDATE_MASK | PREEDIT_MASK;
+                _doCommit(false);
+                clearIC();
+            }
+        } else if (keycode == IM_VK_ESCAPE) {
+            if (!m_pIC->isEmpty()) {
+                changeMasks |= KEYEVENT_USED | CANDIDATE_MASK | PREEDIT_MASK;
+                clearIC();
+            }
+        } else if (keycode == IM_VK_LEFT) { // move left syllable
+            if (!m_pIC->isEmpty()) {
+                changeMasks |= KEYEVENT_USED;
+                _moveLeftSyllable(changeMasks);
+            }
+        } else if (keycode == IM_VK_RIGHT) { // move right syllable
+            if (!m_pIC->isEmpty()) {
+                changeMasks |= KEYEVENT_USED;
+                _moveRightSyllable(changeMasks);
+            }
+        } else if (keycode == IM_VK_HOME) { // move home
+            if (!m_pIC->isEmpty()) {
+                changeMasks |= KEYEVENT_USED;
+                _moveHome(changeMasks);
+            }
+        } else if (keycode == IM_VK_END) { // move end
+            if (!m_pIC->isEmpty()) {
+                changeMasks |= KEYEVENT_USED;
+                _moveEnd(changeMasks);
+            }
+        }
+    } else {
+        goto RETURN;
+    }
+
+PROCESSED:;
+    m_pHotkeyProfile->rememberLastKey(key);
+
+RETURN:;
+
+#ifdef DEBUG
+    printf("   |-->(Mask=0x%x)\n", changeMasks);
+#endif
+
+    updateWindows(changeMasks);
+    return changeMasks & KEYEVENT_USED;
+}
+
+int
+CIMIClassicView::onCandidatePageRequest(int pgno, bool relative)
+{
+    unsigned changeMasks = 0;
+    int ncandi, lastpgidx;
+
+    if (!m_pIC->isEmpty()) {
+        changeMasks |= KEYEVENT_USED;
+        size_t sz = candidateListSize();
+        lastpgidx = (sz - 1) / m_candiWindowSize * m_candiWindowSize;
+        if (relative == true) {
+            ncandi = m_candiPageFirst + pgno * m_candiWindowSize;
+            if (ncandi >= (int) sz)
+                ncandi = lastpgidx;
+            if (ncandi < 0)
+                ncandi = 0;
+            if (ncandi != (int) m_candiPageFirst) {
+                m_candiPageFirst = ncandi;
+                changeMasks |= CANDIDATE_MASK;
+            }
+        } else {
+            if (pgno == -1) { //last page
+                ncandi = lastpgidx;
+            } else {
+                ncandi = pgno * m_candiWindowSize;
+                if (ncandi > lastpgidx)
+                    ncandi = lastpgidx;
+            }
+            if (ncandi != (int) m_candiPageFirst) {
+                m_candiPageFirst = ncandi;
+                changeMasks |= CANDIDATE_MASK;
+            }
+        }
+    }
+
+    updateWindows(changeMasks);
+    return 0;
+}
+
+int
+CIMIClassicView::onCandidateSelectRequest(int index)
+{
+    unsigned changeMasks = 0;
+
+    if (!m_pIC->isEmpty())
+        makeSelection(index, changeMasks);
+
+    updateWindows(changeMasks);
+    return 0;
+}
+
+void
+CIMIClassicView::getPreeditString(IPreeditString& ps)
+{
+    ps.clear();
+
+    wstring &wstr = ps.getString();
+    IPreeditString::CCharTypeVec& charTypes = ps.getCharTypeVec();
+
+    m_pIC->getSelectedSentence(wstr, 0, m_candiFrIdx);
+
+    int caret = wstr.size();
+    charTypes.reserve(caret);
+    for (int i = 0; i < caret; ++i)
+        charTypes.push_back(
+            IPreeditString::HANZI_CHAR | IPreeditString::USER_CHOICE);
+
+    const wstring& pystr = m_pPySegmentor->getInputBuffer();
+    std::vector<unsigned>& seg_path = m_pIC->getBestSegPath();
+
+    if (pystr.empty())
+        return;
+
+    CLattice& lattice = m_pIC->getLattice();
+    unsigned last = 0, len = 0;
+    for (std::vector<unsigned>::iterator it = seg_path.begin();
+         it != seg_path.end(); ++it) {
+        len = *it - last;
+        if (*it <= m_candiFrIdx) {
+            last = *it;
+            continue;
+        }
+        if (last < m_cursorFrIdx && m_cursorFrIdx <= last + len)
+            caret = wstr.size() + (m_cursorFrIdx - last);
+
+        CLatticeFrame &fr = lattice[last + len];
+        int ct = IPreeditString::PINYIN_CHAR;
+        if (fr.isSyllableSepFrame()) {
+            ct = IPreeditString::BOUNDARY | IPreeditString::USER_CHOICE;
+        } else if (fr.m_type == CLatticeFrame::ASCII) {
+            ct = IPreeditString::ASCII_CHAR;
+        } else if (fr.m_type == CLatticeFrame::SYMBOL) {
+            ct = IPreeditString::SYMBOL_CHAR;
+        }
+
+        wstr.insert(wstr.end(), pystr.begin() + last,
+                    pystr.begin() + last + len);
+        for (size_t c = 0; c < len; ++c)
+            charTypes.push_back(ct);
+
+        if (fr.isSyllableFrame() && !fr.isSyllableSepFrame()) {
+            if (it != seg_path.end() - 1
+                && !lattice[last + len + 1].isSyllableSepFrame()) {
+                wstr.push_back(' ');
+                charTypes.push_back(IPreeditString::BOUNDARY);
+            }
+        }
+        last = *it;
+    }
+    // segment path might be missing or incomplete, therefore append the input
+    // buffer left to wstr
+    wstr.insert(wstr.end(), pystr.begin() + last, pystr.end());
+
+    ps.setCaret(caret);
+}
+
+void
+CIMIClassicView::getCandidateList(ICandidateList& cl, int start, int size)
+{
+    cl.clear();
+    cl.setSize(size);
+
+    cl.setFirst(start);
+    cl.setTotal(candidateListSize());
+
+    // sentences
+    for (size_t i = 0; i < m_sentences.size(); i++) {
+        cl.pushBackCandidate(m_sentences[i].second,
+                             ICandidateList::BEST_TAIL, i);
+    }
+    // possible tails
+    for (size_t i = 0; i < m_tails.size(); i++) {
+        cl.pushBackCandidate(m_tails[i].first,
+                             ICandidateList::OTHER_BEST_TAIL, i);
+    }
+    // word candidates
+    for (size_t i = 0; i < m_candiList.size(); i++) {
+        if (i == 0) {
+            cl.pushBackCandidate(m_candiList[i].m_cwstr,
+                                 ICandidateList::BEST_WORD, i);
+        } else {
+            cl.pushBackCandidate(m_candiList[i].m_cwstr,
+                                 ICandidateList::NORMAL_WORD, i);
+        }
+    }
+}
+
+void
+CIMIClassicView::_insert(unsigned keyvalue, unsigned &changeMasks)
+{
+    changeMasks |= KEYEVENT_USED;
+
+    if (m_pPySegmentor->getInputBuffer().size() >= MAX_LATTICE_LENGTH - 1)
+        return;
+
+    if (m_cursorFrIdx == m_pIC->getLastFrIdx())
+        m_pPySegmentor->push(keyvalue);
+    else
+        m_pPySegmentor->insertAt(m_cursorFrIdx, keyvalue);
+
+    m_cursorFrIdx++;
+
+    if (m_pIC->buildLattice(m_pPySegmentor))
+        _getCandidates();
+
+    changeMasks |= PREEDIT_MASK | CANDIDATE_MASK;
+}
+
+void
+CIMIClassicView::_erase(bool backward, unsigned &changeMasks)
+{
+    if (backward) {
+        // if possible to cancel the last selection
+        if (m_backspaceCancel) {
+            if (m_candiFrIdx > 0) {
+                m_candiFrIdx = m_pIC->cancelSelection(m_candiFrIdx, true);
+                goto done;
+            }
+        }
+        if (m_cursorFrIdx == m_pIC->getLastFrIdx()) {
+            m_pPySegmentor->pop();
+        } else if (m_cursorFrIdx > 0) {
+            m_pPySegmentor->deleteAt(m_cursorFrIdx - 1, backward);
+        } else {
+            return;
+        }
+        _moveLeft(changeMasks, true);
+    } else {
+        if (m_cursorFrIdx == m_pIC->getLastFrIdx() - 1) {
+            m_pPySegmentor->pop();
+        } else if (m_cursorFrIdx < m_pIC->getLastFrIdx() - 1) {
+            m_pPySegmentor->deleteAt(m_cursorFrIdx - 1, backward);
+        } else {
+            return;
+        }
+    }
+done:
+    if (m_pIC->buildLattice(m_pPySegmentor))
+        _getCandidates();
+
+    changeMasks |= PREEDIT_MASK | CANDIDATE_MASK | KEYEVENT_USED;
+}
+
+void
+CIMIClassicView::_getCandidates()
+{
+    m_candiPageFirst = 0;
+    m_pIC->getCandidates(m_candiFrIdx, m_candiList);
+}
+
+void
+CIMIClassicView::_commitChar(TWCHAR ch)
+{
+    TWCHAR wa[2] = { ch, 0 };
+    m_pWinHandler->commit(wa);
+}
+
+void
+CIMIClassicView::_commitString(const wstring& wstr)
+{
+    m_pWinHandler->commit(wstr.c_str());
+}
+
+void
+CIMIClassicView::_doCommit(bool bConvert)
+{
+    wstring bs;
+
+    if (bConvert) {
+        m_pIC->memorize();
+        m_pIC->getSelectedSentence(bs);
+        handlerCommit(bs.c_str());
+    } else {
+        bs += m_pPySegmentor->getInputBuffer();
+        handlerCommit(bs.c_str());
+    }
+}
+
+unsigned
+CIMIClassicView::_moveLeft(unsigned& mask, bool searchAgain)
+{
+    if (m_cursorFrIdx == 0)
+        return _moveEnd(mask);
+
+    mask |= PREEDIT_MASK;
+    if (m_cursorFrIdx == m_candiFrIdx) {
+        mask |= CANDIDATE_MASK;
+        m_candiFrIdx = m_pIC->cancelSelection(m_candiFrIdx, searchAgain);
+        _getCandidates();
+    }
+
+    return --m_cursorFrIdx;
+}
+
+unsigned
+CIMIClassicView::_moveLeftSyllable(unsigned& mask, bool searchAgain)
+{
+    if (m_cursorFrIdx == 0)
+        return _moveEnd(mask);
+
+    mask |= PREEDIT_MASK;
+
+    if (m_cursorFrIdx == m_candiFrIdx) {
+        mask |= CANDIDATE_MASK;
+        m_candiFrIdx = m_pIC->cancelSelection(m_candiFrIdx, searchAgain);
+        _getCandidates();
+    }
+
+    std::vector<unsigned>& seg_path = m_pIC->getBestSegPath();
+    std::vector<unsigned>::iterator it =
+        std::upper_bound(seg_path.begin(), seg_path.end(), m_cursorFrIdx - 1);
+    return m_cursorFrIdx = *(--it);
+}
+
+unsigned
+CIMIClassicView::_moveHome(unsigned& mask, bool searchAgain)
+{
+    if (m_cursorFrIdx == 0)
+        return 0;
+
+    mask |= PREEDIT_MASK;
+
+    if (m_candiFrIdx != 0) {
+        std::vector<unsigned>& best_path = m_pIC->getBestPath();
+        std::vector<unsigned>::iterator it = best_path.begin();
+        std::vector<unsigned>::iterator ite = best_path.end();
+        CLattice& lattice = m_pIC->getLattice();
+
+        for (; it != ite; ++it) {
+            if (lattice[*it].m_bwType & CLatticeFrame::USER_SELECTED)
+                m_pIC->cancelSelection(*it, false);
+        }
+
+        mask |= CANDIDATE_MASK;
+        m_candiFrIdx = 0;
+        _getCandidates();
+
+        if (searchAgain) m_pIC->searchFrom();
+    }
+
+    m_cursorFrIdx = 0;
+    return 0;
+}
+
+unsigned
+CIMIClassicView::_moveRight(unsigned& mask)
+{
+    if (m_cursorFrIdx < m_pIC->getLastFrIdx()) {
+        mask |= PREEDIT_MASK;
+        ++m_cursorFrIdx;
+        return m_cursorFrIdx;
+    }
+
+    return _moveHome(mask);
+}
+
+unsigned
+CIMIClassicView::_moveRightSyllable(unsigned& mask)
+{
+    if (m_cursorFrIdx < m_pIC->getLastFrIdx()) {
+        mask |= PREEDIT_MASK;
+
+        std::vector<unsigned>& seg_path = m_pIC->getBestSegPath();
+        std::vector<unsigned>::iterator it = std::upper_bound(
+            seg_path.begin(), seg_path.end(), m_cursorFrIdx);
+        m_cursorFrIdx = *it;
+        return m_cursorFrIdx;
+    }
+
+    return _moveHome(mask);
+}
+
+unsigned
+CIMIClassicView::_moveEnd(unsigned& mask)
+{
+    if (m_cursorFrIdx < m_pIC->getLastFrIdx()) {
+        mask |= PREEDIT_MASK;
+        m_cursorFrIdx = m_pIC->getLastFrIdx();
+    }
+
+    return m_cursorFrIdx;
+}
+
+void
+CIMIClassicView::makeSelection(int candiIdx, unsigned& mask)
+{
+    if (m_candiList.size() == 0 || m_sentences.size() == 0) {
+        // user might delete all the left over pinyin characters, this will
+        // make m_candiList empty
+        // 0 or space choices should commit previous selected candidates
+        mask |= PREEDIT_MASK | CANDIDATE_MASK;
+        _doCommit();
+        clearIC();
+        return;
+    }
+
+    // candiIdx += m_candiPageFirst;
+    if (candiIdx >= m_uiCandidateList.size()) {
+        return;
+    }
+    int idx = m_uiCandidateList.getUserIndex(candiIdx);
+    int type = m_uiCandidateList.getCandiTypeVec()[candiIdx];
+    bool selected = false;
+
+    mask |= PREEDIT_MASK | CANDIDATE_MASK;
+    if (type == ICandidateList::BEST_TAIL) {
+        // get the rank of that sentence and select it
+        m_pIC->selectSentence(m_sentences[idx].first);
+        _doCommit();
+        clearIC();
+    } else if (type == ICandidateList::OTHER_BEST_TAIL) {
+        CCandidates& tail = m_tails[idx].second;
+        for (size_t i = 0; i < tail.size(); i++) {
+            m_pIC->makeSelection(tail[i]);
+        }
+        m_candiFrIdx = tail.back().m_end;
+        selected = true;
+    } else if (type == ICandidateList::BEST_WORD
+               || type == ICandidateList::NORMAL_WORD) {
+        CCandidate& candi = m_candiList[idx];
+        m_pIC->makeSelection(candi);
+        m_candiFrIdx = candi.m_end;
+        selected = true;
+    } else if (type == ICandidateList::PLUGIN_TAIL) {
+        handlerCommit(m_uiCandidateList.getCandiStrings()[candiIdx]);
+        clearIC();
+    }
+
+    if (selected) {
+        if (m_cursorFrIdx < m_candiFrIdx)
+            m_cursorFrIdx = m_candiFrIdx;
+
+        CLattice& lattice = m_pIC->getLattice();
+        while (m_candiFrIdx < m_pIC->getLastFrIdx() &&
+               !lattice[m_candiFrIdx + 1].isUnusedFrame() &&
+               !lattice[m_candiFrIdx + 1].isSyllableFrame()) {
+            ++m_candiFrIdx;
+            lattice[m_candiFrIdx].m_bwType |= CLatticeFrame::IGNORED;
+        }
+
+        if (m_candiFrIdx == m_pIC->getLastFrIdx()) {
+            _doCommit();
+            clearIC();
+        } else {
+            m_candiPageFirst = 0;
+            _getCandidates();
+        }
+    }
+}
+
+void
+CIMIClassicView::deleteCandidate(int candiIdx, unsigned& mask)
+{
+    // candiIdx += m_candiPageFirst;
+    int idx = m_uiCandidateList.getUserIndex(candiIdx);
+    int type = m_uiCandidateList.getCandiTypeVec()[candiIdx];
+
+    if (type == ICandidateList::BEST_TAIL) {
+        // try to remove candidate 0 which is a calculated sentence
+        std::vector<unsigned> wids;
+        m_pIC->getSelectedSentence(wids, m_candiFrIdx);
+        m_pIC->removeFromHistoryCache(wids);
+
+        /* if the sentence wid length is 1, also delete this word */
+        if (wids.size() == 1) {
+            unsigned wid = wids[0];
+            m_pIC->deleteCandidateByWID(wid);
+        }
+    } else if (type == ICandidateList::BEST_WORD
+               || type == ICandidateList::NORMAL_WORD) {
+        // remove an ordinary candidate
+        CCandidate& candi = m_candiList[idx];
+        m_pIC->deleteCandidate(candi);
+    }
+
+    _getCandidates();
+    mask |= PREEDIT_MASK | CANDIDATE_MASK;
+}
diff --git a/src/ime-core/imi_view_classic.h b/src/ime-core/imi_view_classic.h
new file mode 100644 (file)
index 0000000..135a932
--- /dev/null
@@ -0,0 +1,103 @@
+// -*- mode: c++ -*-
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright (c) 2007 Sun Microsystems, Inc. All Rights Reserved.
+ *
+ * The contents of this file are subject to the terms of either the GNU Lesser
+ * General Public License Version 2.1 only ("LGPL") or the Common Development and
+ * Distribution License ("CDDL")(collectively, the "License"). You may not use this
+ * file except in compliance with the License. You can obtain a copy of the CDDL at
+ * http://www.opensource.org/licenses/cddl1.php and a copy of the LGPLv2.1 at
+ * http://www.opensource.org/licenses/lgpl-license.php. See the License for the
+ * specific language governing permissions and limitations under the License. When
+ * distributing the software, include this License Header Notice in each file and
+ * include the full text of the License in the License file as well as the
+ * following notice:
+ *
+ * NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND DISTRIBUTION LICENSE
+ * (CDDL)
+ * For Covered Software in this distribution, this License shall be governed by the
+ * laws of the State of California (excluding conflict-of-law provisions).
+ * Any litigation relating to this License shall be subject to the jurisdiction of
+ * the Federal Courts of the Northern District of California and the state courts
+ * of the State of California, with venue lying in Santa Clara County, California.
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by only the CDDL or only
+ * the LGPL Version 2.1, indicate your decision by adding "[Contributor]" elects to
+ * include this software in this distribution under the [CDDL or LGPL Version 2.1]
+ * license." If you don't indicate a single choice of license, a recipient has the
+ * option to distribute your version of this file under either the CDDL or the LGPL
+ * Version 2.1, or to extend the choice of license to its licensees as provided
+ * above. However, if you add LGPL Version 2.1 code and therefore, elected the LGPL
+ * Version 2 license, then the option applies only if the new code is made subject
+ * to such option by the copyright holder.
+ */
+
+#ifndef SUNPY_IMI_CLASSIC_VIEW_H
+#define SUNPY_IMI_CLASSIC_VIEW_H
+
+#include "portability.h"
+
+#include "imi_view.h"
+
+class CIMIClassicView : public CIMIView
+{
+public:
+    CIMIClassicView();
+    virtual ~CIMIClassicView();
+
+    virtual void attachIC(CIMIContext* pIC);
+    virtual unsigned clearIC(void);
+
+    virtual bool onKeyEvent(const CKeyEvent&);
+
+    virtual void updateWindows(unsigned mask);
+
+    virtual void getPreeditString(IPreeditString& ps);
+    virtual void getCandidateList(ICandidateList& cl, int start, int size);
+
+    virtual int  onCandidatePageRequest(int pgno, bool relative);
+    virtual int  onCandidateSelectRequest(int index);
+
+    size_t candidateListSize() const
+    { return m_candiList.size() + m_sentences.size() + m_tails.size(); }
+
+    void makeSelection(int candiIdx, unsigned& mask);
+    void deleteCandidate(int candiIdx, unsigned& mask);
+
+private:
+    static size_t top_candidate_threshold;
+
+    unsigned m_cursorFrIdx;
+    unsigned m_candiFrIdx;
+    unsigned m_candiPageFirst;
+
+    CCandidateList m_uiCandidateList;
+    CPreEditString m_uiPreeditString;
+
+    CCandidates m_candiList;
+    std::vector<std::pair<int, wstring> > m_sentences;
+    std::vector<std::pair<wstring, CCandidates> > m_tails;
+
+    void _insert(unsigned keyvalue, unsigned& mask);
+    void _erase(bool backward, unsigned& mask);
+
+    void _getCandidates();
+
+    void _commitChar(TWCHAR ch);
+    void _commitString(const wstring& wstr);
+    void _doCommit(bool bConvert = true);
+
+    unsigned _moveLeft(unsigned& mask, bool searchAgain = true);
+    unsigned _moveLeftSyllable(unsigned& mask, bool searchAgain = true);
+    unsigned _moveHome(unsigned& mask, bool searchAgain = true);
+
+    unsigned _moveRight(unsigned& mask);
+    unsigned _moveRightSyllable(unsigned& mask);
+    unsigned _moveEnd(unsigned& mask);
+};
+
+#endif
diff --git a/src/ime-core/imi_winHandler.cpp b/src/ime-core/imi_winHandler.cpp
new file mode 100644 (file)
index 0000000..b9f41c2
--- /dev/null
@@ -0,0 +1,104 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright (c) 2007 Sun Microsystems, Inc. All Rights Reserved.
+ *
+ * The contents of this file are subject to the terms of either the GNU Lesser
+ * General Public License Version 2.1 only ("LGPL") or the Common Development and
+ * Distribution License ("CDDL")(collectively, the "License"). You may not use this
+ * file except in compliance with the License. You can obtain a copy of the CDDL at
+ * http://www.opensource.org/licenses/cddl1.php and a copy of the LGPLv2.1 at
+ * http://www.opensource.org/licenses/lgpl-license.php. See the License for the
+ * specific language governing permissions and limitations under the License. When
+ * distributing the software, include this License Header Notice in each file and
+ * include the full text of the License in the License file as well as the
+ * following notice:
+ *
+ * NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND DISTRIBUTION LICENSE
+ * (CDDL)
+ * For Covered Software in this distribution, this License shall be governed by the
+ * laws of the State of California (excluding conflict-of-law provisions).
+ * Any litigation relating to this License shall be subject to the jurisdiction of
+ * the Federal Courts of the Northern District of California and the state courts
+ * of the State of California, with venue lying in Santa Clara County, California.
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by only the CDDL or only
+ * the LGPL Version 2.1, indicate your decision by adding "[Contributor]" elects to
+ * include this software in this distribution under the [CDDL or LGPL Version 2.1]
+ * license." If you don't indicate a single choice of license, a recipient has the
+ * option to distribute your version of this file under either the CDDL or the LGPL
+ * Version 2.1, or to extend the choice of license to its licensees as provided
+ * above. However, if you add LGPL Version 2.1 code and therefore, elected the LGPL
+ * Version 2 license, then the option applies only if the new code is made subject
+ * to such option by the copyright holder.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "imi_winHandler.h"
+#include "imi_view.h"
+
+void
+CIMIWinHandler::commit(const TWCHAR* wstr)
+{
+    if (wstr) print_wide(wstr);
+    fflush(stdout);
+}
+
+void
+CIMIWinHandler::updatePreedit(const IPreeditString* ppd)
+{
+    if (ppd) {
+        print_wide(ppd->string());
+        printf("\n");
+        fflush(stdout);
+    }
+}
+
+void
+CIMIWinHandler::updateCandidates(const ICandidateList* pcl)
+{
+    for (int i = 0, sz = pcl->size(); i < sz; ++i) {
+        const TWCHAR* pcand = pcl->candiString(i);
+        if (pcand != NULL) {
+            printf("%c. ", '1' + i);
+            print_wide(pcand);
+            printf("\n");
+        }
+    }
+    fflush(stdout);
+}
+
+void
+CIMIWinHandler::throwBackKey(unsigned keycode,
+                             unsigned keyvalue,
+                             unsigned modifier)
+{
+    if (keyvalue > 0x0 && keyvalue < 0x7f) {
+        printf("%c", keyvalue);
+        fflush(stdout);
+    }
+}
+
+void
+CIMIWinHandler::updateStatus(int key, int value)
+{
+    switch (key) {
+    case STATUS_ID_CN:
+        printf("CN status is "); break;
+    case STATUS_ID_FULLPUNC:
+        printf("Full Punc is "); break;
+    case STATUS_ID_FULLSYMBOL:
+        printf("Full Simbol is "); break;
+    default:
+        printf("Unknow Status id %d is ", key);
+        break;
+    }
+
+    printf("%d\n", value);
+    fflush(stdout);
+}
diff --git a/src/ime-core/imi_winHandler.h b/src/ime-core/imi_winHandler.h
new file mode 100644 (file)
index 0000000..f0182ed
--- /dev/null
@@ -0,0 +1,93 @@
+// -*- mode: c++ -*-
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright (c) 2007 Sun Microsystems, Inc. All Rights Reserved.
+ *
+ * The contents of this file are subject to the terms of either the GNU Lesser
+ * General Public License Version 2.1 only ("LGPL") or the Common Development and
+ * Distribution License ("CDDL")(collectively, the "License"). You may not use this
+ * file except in compliance with the License. You can obtain a copy of the CDDL at
+ * http://www.opensource.org/licenses/cddl1.php and a copy of the LGPLv2.1 at
+ * http://www.opensource.org/licenses/lgpl-license.php. See the License for the
+ * specific language governing permissions and limitations under the License. When
+ * distributing the software, include this License Header Notice in each file and
+ * include the full text of the License in the License file as well as the
+ * following notice:
+ *
+ * NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND DISTRIBUTION LICENSE
+ * (CDDL)
+ * For Covered Software in this distribution, this License shall be governed by the
+ * laws of the State of California (excluding conflict-of-law provisions).
+ * Any litigation relating to this License shall be subject to the jurisdiction of
+ * the Federal Courts of the Northern District of California and the state courts
+ * of the State of California, with venue lying in Santa Clara County, California.
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by only the CDDL or only
+ * the LGPL Version 2.1, indicate your decision by adding "[Contributor]" elects to
+ * include this software in this distribution under the [CDDL or LGPL Version 2.1]
+ * license." If you don't indicate a single choice of license, a recipient has the
+ * option to distribute your version of this file under either the CDDL or the LGPL
+ * Version 2.1, or to extend the choice of license to its licensees as provided
+ * above. However, if you add LGPL Version 2.1 code and therefore, elected the LGPL
+ * Version 2 license, then the option applies only if the new code is made subject
+ * to such option by the copyright holder.
+ */
+
+#ifndef SUNPINYIN_IMI_WINHANDLER_H
+#define SUNPINYIN_IMI_WINHANDLER_H
+
+#include "portability.h"
+
+#include "imi_uiobjects.h"
+
+#ifdef HAVE_ICONV_H
+#include <iconv.h>
+#endif // HAVE_ICONV_H
+
+class CIMIView;
+
+/*@}*/
+
+class CIMIWinHandler
+{
+public:
+    enum {
+        STATUS_ID_CN,
+        STATUS_ID_FULLPUNC,
+        STATUS_ID_FULLSYMBOL
+    };
+
+public:
+    CIMIWinHandler() {}
+
+    /*@{*/
+    virtual ~CIMIWinHandler() {}
+
+    virtual void enableDeferedUpdate(CIMIView* view, int waitTime) {}
+    virtual void disableDeferedUpdate() {}
+    virtual void doneDeferedUpdate() {}
+
+    /** commit a string, normally the converted result */
+    virtual void commit(const TWCHAR* wstr);
+
+    /** when a key is not processed */
+    virtual void throwBackKey(unsigned keycode,
+                              unsigned keyvalue,
+                              unsigned modifier);
+
+    /** Update window's preedit area. */
+    virtual void updatePreedit(const IPreeditString* ppd);
+
+    /** Update window's candidates area. */
+    virtual void updateCandidates(const ICandidateList* pcl);
+
+    /** Update status area. */
+    virtual void updateStatus(int key, int value);
+
+    /*@}*/
+};
+
+#endif
diff --git a/src/ime-core/lattice_states.cpp b/src/ime-core/lattice_states.cpp
new file mode 100644 (file)
index 0000000..4da071d
--- /dev/null
@@ -0,0 +1,322 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright (c) 2007 Sun Microsystems, Inc. All Rights Reserved.
+ *
+ * The contents of this file are subject to the terms of either the GNU Lesser
+ * General Public License Version 2.1 only ("LGPL") or the Common Development and
+ * Distribution License ("CDDL")(collectively, the "License"). You may not use this
+ * file except in compliance with the License. You can obtain a copy of the CDDL at
+ * http://www.opensource.org/licenses/cddl1.php and a copy of the LGPLv2.1 at
+ * http://www.opensource.org/licenses/lgpl-license.php. See the License for the
+ * specific language governing permissions and limitations under the License. When
+ * distributing the software, include this License Header Notice in each file and
+ * include the full text of the License in the License file as well as the
+ * following notice:
+ *
+ * NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND DISTRIBUTION LICENSE
+ * (CDDL)
+ * For Covered Software in this distribution, this License shall be governed by the
+ * laws of the State of California (excluding conflict-of-law provisions).
+ * Any litigation relating to this License shall be subject to the jurisdiction of
+ * the Federal Courts of the Northern District of California and the state courts
+ * of the State of California, with venue lying in Santa Clara County, California.
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by only the CDDL or only
+ * the LGPL Version 2.1, indicate your decision by adding "[Contributor]" elects to
+ * include this software in this distribution under the [CDDL or LGPL Version 2.1]
+ * license." If you don't indicate a single choice of license, a recipient has the
+ * option to distribute your version of this file under either the CDDL or the LGPL
+ * Version 2.1, or to extend the choice of license to its licensees as provided
+ * above. However, if you add LGPL Version 2.1 code and therefore, elected the LGPL
+ * Version 2 license, then the option applies only if the new code is made subject
+ * to such option by the copyright holder.
+ */
+
+#include "pinyin_data.h"
+#include "lattice_states.h"
+#include <algorithm>
+
+const CPinyinTrie::TWordIdInfo*
+TLexiconState::getWords(unsigned &num)
+{
+    num = 0;
+
+    if (!m_words.empty()) {
+        num = m_words.size();
+        return &m_words[0];
+    }
+
+    if (m_bPinyin && m_pPYNode) {
+        num = m_pPYNode->m_nWordId;
+        return m_pPYNode->getWordIdPtr();
+    }
+
+    return NULL;
+}
+
+void
+TLexiconState::print(std::string prefix) const
+{
+    printf("%s", prefix.c_str());
+    printf("from frame[%d] ", m_start);
+
+    if (m_bPinyin) {
+        printf("%sdict ", m_pPYNode ? "sys" : "usr");
+        if (!m_syls.empty()) {
+            printf("pinyin: ");
+            CSyllables::const_iterator it = m_syls.begin();
+            for (; it != m_syls.end(); ++it)
+                printf("%x:%x:%x ", it->initial, it->final, it->tone);
+        }
+
+        printf("seg_ranges: (");
+        for (std::vector<unsigned>::const_iterator it = m_seg_path.begin();
+             it != m_seg_path.end();
+             ++it)
+            printf("%d ", *it);
+        printf(")");
+    } else {
+        printf("word id ");
+        printf("%d", m_words.front().m_id);
+    }
+
+    printf("\n");
+}
+
+void
+TLatticeState::print(std::string prefix) const
+{
+    printf("%s", prefix.c_str());
+    char valbuf[256];
+    m_score.toString(valbuf);
+    printf("<State(%d:%d), from word %d, score %s>\n", m_slmState.getLevel(),
+           m_slmState.getIdx(), m_backTraceWordId, valbuf);
+}
+
+const unsigned CLatticeStates::beam_width = 48;
+const TSentenceScore CLatticeStates::filter_ratio_l1 = TSentenceScore(0.12);
+const TSentenceScore CLatticeStates::filter_ratio_l2 = TSentenceScore(0.02);
+const TSentenceScore CLatticeStates::filter_threshold_exp =
+    TSentenceScore(-40, -1.0);
+
+bool
+CTopLatticeStates::push(const TLatticeState& state)
+{
+    bool ret = true;
+    if (size() >= m_threshold) {
+        if (m_heap[0] < state) return false;
+        std::pop_heap(m_heap.begin(), m_heap.end());
+        m_heap.pop_back();
+        ret = false;
+    }
+    m_heap.push_back(state);
+    std::push_heap(m_heap.begin(), m_heap.end());
+    return ret;
+}
+
+void
+CTopLatticeStates::pop()
+{
+    std::pop_heap(m_heap.begin(), m_heap.end());
+    m_heap.pop_back();
+}
+
+void
+CLatticeStates::clear()
+{
+    m_heapIdx.clear();
+    m_scoreHeap.clear();
+    m_stateMap.clear();
+    m_size = 0;
+}
+
+std::vector<TLatticeState>
+CLatticeStates::getSortedResult()
+{
+    std::vector<TLatticeState> res;
+    for (CLatticeStates::iterator it = begin(); it != end(); ++it) {
+        res.push_back(*it);
+    }
+    std::sort(res.begin(), res.end());
+    return res;
+}
+
+std::vector<TLatticeState>
+CLatticeStates::getFilteredResult()
+{
+    std::vector<TLatticeState> sorted = getSortedResult();
+    std::vector<TLatticeState> res;
+    if (sorted.size() == 0) {
+        return sorted;
+    }
+    res.push_back(sorted[0]);
+    TSentenceScore max_score = sorted[0].m_score;
+    for (size_t i = 1; i < sorted.size(); i++) {
+        TSentenceScore current_score = sorted[i].m_score;
+        if (filter_threshold_exp < current_score
+            && current_score / max_score < filter_ratio_l1) {
+            break;
+        }
+        if (current_score / max_score < filter_ratio_l2) {
+            break;
+        }
+        res.push_back(sorted[i]);
+    }
+    return res;
+}
+
+void
+CLatticeStates::add(const TLatticeState& state)
+{
+    CSlmState slmState = state.m_slmState;
+    state_map::iterator it = m_stateMap.find(slmState);
+    bool inserted = false;
+
+    if (it == m_stateMap.end()) {
+        CTopLatticeStates topstates(m_maxBest);
+        inserted = topstates.push(state);
+        m_stateMap.insert(std::make_pair(slmState, topstates));
+        _pushScoreHeap(state.m_score, slmState);
+    } else {
+        inserted = it->second.push(state);
+        slmState = it->second.top().m_slmState;
+        _adjustDown(m_heapIdx[slmState]);
+    }
+    if (inserted) m_size++;
+
+    if (m_size > beam_width) {
+        slmState = m_scoreHeap[0].second;
+        it = m_stateMap.find(slmState);
+
+        // pop one node from it, and if it's empty, remove it from map and heap
+        it->second.pop();
+        if (it->second.size() == 0) {
+            m_stateMap.erase(it);
+            _popScoreHeap();
+        } else {
+            m_scoreHeap[0].first = it->second.top().m_score;
+            _adjustDown(0);
+        }
+        m_size--;
+    }
+}
+
+void
+CLatticeStates::_pushScoreHeap(TSentenceScore score, CSlmState slmState)
+{
+    m_scoreHeap.push_back(std::make_pair(score, slmState));
+    _adjustUp(m_scoreHeap.size() - 1);
+}
+
+void
+CLatticeStates::_popScoreHeap()
+{
+    m_heapIdx.erase(m_scoreHeap[0].second);
+    m_scoreHeap[0] = m_scoreHeap[m_scoreHeap.size() - 1];
+    m_scoreHeap.pop_back();
+    if (m_scoreHeap.size() > 0) {
+        _refreshHeapIdx(0);
+        _adjustDown(0);
+    }
+}
+
+void
+CLatticeStates::_refreshHeapIdx(int heapIdx)
+{
+    m_heapIdx[m_scoreHeap[heapIdx].second] = heapIdx;
+}
+
+void
+CLatticeStates::_adjustUp(int node)
+{
+    int parent = (node - 1) / 2;
+    while (parent >= 0) {
+        if (m_scoreHeap[parent].first < m_scoreHeap[node].first) {
+            std::swap(m_scoreHeap[parent], m_scoreHeap[node]);
+            _refreshHeapIdx(parent);
+            node = parent;
+            parent = (node - 1) / 2;
+        } else {
+            _refreshHeapIdx(node);
+            return;
+        }
+    }
+}
+
+void
+CLatticeStates::_adjustDown(int node)
+{
+    int left = node * 2 + 1;
+    int right = node * 2 + 2;
+    while (left < (int) m_scoreHeap.size()) {
+        int child = -1;
+        if (m_scoreHeap[node].first < m_scoreHeap[left].first) {
+            child = left;
+        } else if (right < (int) m_scoreHeap.size()
+                   && m_scoreHeap[node].first < m_scoreHeap[right].first) {
+            child = right;
+        } else {
+            _refreshHeapIdx(node);
+            return;
+        }
+        std::swap(m_scoreHeap[node], m_scoreHeap[child]);
+        _refreshHeapIdx(child);
+        node = child;
+        left = node * 2 + 1;
+        right = node * 2 + 2;
+    }
+}
+
+CLatticeStates::iterator
+CLatticeStates::begin()
+{
+    CLatticeStates::iterator it;
+    it.m_mainIt = m_stateMap.begin();
+    it.m_mainEnd = m_stateMap.end();
+    it.m_childIt = it.m_mainIt->second.begin();
+    return it;
+}
+
+CLatticeStates::iterator
+CLatticeStates::end()
+{
+    CLatticeStates::iterator it;
+    it.m_mainEnd = it.m_mainIt = m_stateMap.end();
+    return it;
+}
+
+void
+CLatticeStates::iterator::operator++()
+{
+    ++m_childIt;
+    if (m_childIt == m_mainIt->second.end()) {
+        ++m_mainIt;
+        if (m_mainIt != m_mainEnd)
+            m_childIt = m_mainIt->second.begin();
+    }
+}
+
+bool
+CLatticeStates::iterator::operator!=(const CLatticeStates::iterator& rhs)
+{
+    if (m_mainIt == m_mainEnd || rhs.m_mainIt == rhs.m_mainEnd) {
+        return m_mainIt != rhs.m_mainIt;
+    } else {
+        return m_mainIt != rhs.m_mainIt && m_childIt != rhs.m_childIt;
+    }
+}
+
+TLatticeState&
+CLatticeStates::iterator::operator*()
+{
+    return m_childIt.operator*();
+}
+
+TLatticeState*
+CLatticeStates::iterator::operator->()
+{
+    return m_childIt.operator->();
+}
diff --git a/src/ime-core/lattice_states.h b/src/ime-core/lattice_states.h
new file mode 100644 (file)
index 0000000..b7f3ef5
--- /dev/null
@@ -0,0 +1,246 @@
+// -*- mode: c++ -*-
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright (c) 2007 Sun Microsystems, Inc. All Rights Reserved.
+ *
+ * The contents of this file are subject to the terms of either the GNU Lesser
+ * General Public License Version 2.1 only ("LGPL") or the Common Development and
+ * Distribution License ("CDDL")(collectively, the "License"). You may not use this
+ * file except in compliance with the License. You can obtain a copy of the CDDL at
+ * http://www.opensource.org/licenses/cddl1.php and a copy of the LGPLv2.1 at
+ * http://www.opensource.org/licenses/lgpl-license.php. See the License for the
+ * specific language governing permissions and limitations under the License. When
+ * distributing the software, include this License Header Notice in each file and
+ * include the full text of the License in the License file as well as the
+ * following notice:
+ *
+ * NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND DISTRIBUTION LICENSE
+ * (CDDL)
+ * For Covered Software in this distribution, this License shall be governed by the
+ * laws of the State of California (excluding conflict-of-law provisions).
+ * Any litigation relating to this License shall be subject to the jurisdiction of
+ * the Federal Courts of the Northern District of California and the state courts
+ * of the State of California, with venue lying in Santa Clara County, California.
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by only the CDDL or only
+ * the LGPL Version 2.1, indicate your decision by adding "[Contributor]" elects to
+ * include this software in this distribution under the [CDDL or LGPL Version 2.1]
+ * license." If you don't indicate a single choice of license, a recipient has the
+ * option to distribute your version of this file under either the CDDL or the LGPL
+ * Version 2.1, or to extend the choice of license to its licensees as provided
+ * above. However, if you add LGPL Version 2.1 code and therefore, elected the LGPL
+ * Version 2 license, then the option applies only if the new code is made subject
+ * to such option by the copyright holder.
+ */
+
+#ifndef SUNPY_LATTICE_STATES_H
+#define SUNPY_LATTICE_STATES_H
+
+#include <vector>
+#include <map>
+#include "portability.h"
+#include "imi_data.h"
+#include "pinyin/pinyin_seg.h"
+
+typedef TLongExpFloat TSentenceScore;
+
+/**
+ * CSlmState represent the history. In real implementation, it's a
+ * node pointer to a state in the language model. But to save the
+ * language model size, the state node in language model do not
+ * thread the back-off pointer. Now, we just use the Word Id for
+ * the node in the language model. Later we should abstract the
+ * StateNode from language model implemetation to replace this
+ * definition.
+ */
+typedef CThreadSlm::TState CSlmState;
+
+/**
+ * A WordKey could represent a word. Define this use the unsigned int
+ * directly. Because in the future, we may adopt word class, such as
+ * Digital Word Class.
+ */
+typedef unsigned CWordId;
+
+/**
+ * This class is used to record lexicon state (pinyin trie nodes)
+ * just before a bone. From the bone, it could see when arriving
+ * it, how many valid Pinyin Trie Node still could be used to search
+ * more words further, and what bone is its starting bone.
+ */
+struct TLexiconState {
+    typedef std::vector<CPinyinTrie::TWordIdInfo> TWordIdInfoVec;
+
+    const CPinyinTrie::TNode   *m_pPYNode;
+    TWordIdInfoVec m_words;
+    // accumulated syllables, may contain fuzzy syllables
+    CSyllables m_syls;
+    // accumulated segments,  may contain fuzzy segments
+    std::vector<unsigned> m_seg_path;
+
+    unsigned m_start                 : 16;
+    unsigned m_num_of_inner_fuzzies  : 14;
+    bool m_bFuzzy                : 1;
+    bool m_bPinyin               : 1;
+
+    TLexiconState (unsigned start,
+                   const CPinyinTrie::TNode *pnode,
+                   CSyllables& syls,
+                   std::vector<unsigned>& seg_path,
+                   bool fuzzy = false)
+    : m_pPYNode(pnode), m_syls(syls), m_seg_path(seg_path), m_start(start),
+        m_num_of_inner_fuzzies(0), m_bFuzzy(fuzzy), m_bPinyin(true) {}
+
+    TLexiconState (unsigned start,
+                   TWordIdInfoVec &words,
+                   CSyllables &syls,
+                   std::vector<unsigned>& seg_path,
+                   bool fuzzy = false)
+    : m_pPYNode(NULL), m_words(words), m_syls(syls), m_seg_path(seg_path),
+        m_start(start), m_num_of_inner_fuzzies(0), m_bFuzzy(fuzzy),
+        m_bPinyin(true) {}
+
+    TLexiconState (unsigned start, unsigned wid)
+    : m_pPYNode(NULL), m_start(start), m_bPinyin(false) {
+        m_words.push_back(wid);
+        m_seg_path.push_back(start);
+        m_seg_path.push_back(start + 1);
+    }
+
+    const CPinyinTrie::TWordIdInfo *getWords(unsigned &num);
+    void print(std::string prefix) const;
+};
+
+/**
+ * A list of Lexicon State. Every state may from different
+ * starting position. Later, when Fuzzy PinYin are added,
+ * more than one state may comes from one starting bone.
+ */
+typedef std::vector<TLexiconState>    CLexiconStates;
+
+
+/**
+ * The basic static unit used in the lattice searching
+ */
+struct TLatticeState {
+    TSentenceScore m_score;
+    unsigned m_frIdx;
+    TLexiconState* m_pLexiconState;
+    TLatticeState* m_pBackTraceNode;
+    CSlmState m_slmState;
+    CWordId m_backTraceWordId;
+
+    TLatticeState(double score = -1.0,
+                  unsigned frIdx = 0,
+                  TLexiconState* lxstPtr = NULL,
+                  TLatticeState* btNodePtr = NULL,
+                  CSlmState sk = CSlmState(),
+                  CWordId wk = CWordId())
+    : m_score(score), m_frIdx(frIdx), m_pLexiconState(lxstPtr),
+        m_pBackTraceNode(btNodePtr), m_slmState(sk), m_backTraceWordId(wk) {}
+
+    /** for debug printing... */
+    void print(std::string prefix) const;
+
+    bool operator<(const TLatticeState& rhs) const {
+        return m_score < rhs.m_score;
+    }
+
+    bool operator==(const TLatticeState& rhs) const {
+        return m_score == rhs.m_score;
+    }
+
+    bool operator>(const TLatticeState& rhs) const {
+        return !((*this) < rhs || (*this) == rhs);
+    }
+};
+
+typedef std::vector<TLatticeState>  CLatticeStateVec;
+
+/**
+ * A container that keeps the top K elements.
+ */
+class CTopLatticeStates {
+    std::vector<TLatticeState> m_heap;
+    size_t m_threshold;
+public:
+    CTopLatticeStates(size_t threshold) : m_threshold(threshold) {}
+
+    bool push(const TLatticeState& state);
+    void pop();
+
+    const TLatticeState& top() const { return m_heap[0]; }
+
+    size_t size() const { return m_heap.size(); }
+
+    typedef std::vector<TLatticeState>::iterator iterator;
+
+    iterator begin() { return m_heap.begin(); }
+    iterator end() { return m_heap.end(); }
+};
+
+/**
+ * All lattice node on a lattice frame. This class provide beam pruning
+ * while push_back, which means at most the best MAX states are reserved,
+ * ie, weak state will may be discard while new better state are inserted,
+ * and the number MAX is arrived.
+ */
+class CLatticeStates {
+private:
+    static const unsigned beam_width;
+    static const TSentenceScore filter_ratio_l1;
+    static const TSentenceScore filter_ratio_l2;
+    static const TSentenceScore filter_threshold_exp;
+
+public:
+    CLatticeStates() : m_size(0), m_maxBest(2) {}
+
+    void setMaxBest(size_t maxBest) { m_maxBest = maxBest; }
+
+    void clear();
+    void add(const TLatticeState& state);
+
+    std::vector<TLatticeState> getSortedResult();
+    std::vector<TLatticeState> getFilteredResult();
+
+    typedef std::map<CSlmState, CTopLatticeStates> state_map;
+    class iterator {
+        friend class CLatticeStates;
+        state_map::iterator m_mainIt;
+        state_map::iterator m_mainEnd;
+        CTopLatticeStates::iterator m_childIt;
+public:
+        iterator(state_map::iterator mit, state_map::iterator mend,
+                 CTopLatticeStates::iterator cit)
+            : m_mainIt(mit), m_mainEnd(mend), m_childIt(cit) {}
+
+        iterator() {}
+
+        void operator++();
+        bool operator!=(const CLatticeStates::iterator& rhs);
+        TLatticeState& operator*();
+        TLatticeState* operator->();
+    };
+
+    iterator begin();
+    iterator end();
+private:
+    void _pushScoreHeap(TSentenceScore score, CSlmState slmState);
+    void _popScoreHeap();
+    void _refreshHeapIdx(int heapIdx);
+    void _adjustUp(int node);
+    void _adjustDown(int node);
+
+private:
+    state_map m_stateMap;
+    size_t m_size;
+    size_t m_maxBest;
+
+    std::map<CSlmState, int>                           m_heapIdx;
+    std::vector<std::pair<TSentenceScore, CSlmState> > m_scoreHeap;
+};
+
+#endif
diff --git a/src/ime-core/userdict.cpp b/src/ime-core/userdict.cpp
new file mode 100644 (file)
index 0000000..339846f
--- /dev/null
@@ -0,0 +1,319 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright (c) 2007 Sun Microsystems, Inc. All Rights Reserved.
+ *
+ * The contents of this file are subject to the terms of either the GNU Lesser
+ * General Public License Version 2.1 only ("LGPL") or the Common Development and
+ * Distribution License ("CDDL")(collectively, the "License"). You may not use this
+ * file except in compliance with the License. You can obtain a copy of the CDDL at
+ * http://www.opensource.org/licenses/cddl1.php and a copy of the LGPLv2.1 at
+ * http://www.opensource.org/licenses/lgpl-license.php. See the License for the
+ * specific language governing permissions and limitations under the License. When
+ * distributing the software, include this License Header Notice in each file and
+ * include the full text of the License in the License file as well as the
+ * following notice:
+ *
+ * NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND DISTRIBUTION LICENSE
+ * (CDDL)
+ * For Covered Software in this distribution, this License shall be governed by the
+ * laws of the State of California (excluding conflict-of-law provisions).
+ * Any litigation relating to this License shall be subject to the jurisdiction of
+ * the Federal Courts of the Northern District of California and the state courts
+ * of the State of California, with venue lying in Santa Clara County, California.
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by only the CDDL or only
+ * the LGPL Version 2.1, indicate your decision by adding "[Contributor]" elects to
+ * include this software in this distribution under the [CDDL or LGPL Version 2.1]
+ * license." If you don't indicate a single choice of license, a recipient has the
+ * option to distribute your version of this file under either the CDDL or the LGPL
+ * Version 2.1, or to extend the choice of license to its licensees as provided
+ * above. However, if you add LGPL Version 2.1 code and therefore, elected the LGPL
+ * Version 2 license, then the option applies only if the new code is made subject
+ * to such option by the copyright holder.
+ */
+
+#include <assert.h>
+#include <stdlib.h>
+#include "userdict.h"
+
+
+bool
+CUserDict::load(const char  *fname)
+{
+    int rc = sqlite3_open(":memory:", &m_db);
+
+    if (rc != SQLITE_OK) {
+        sqlite3_close(m_db);
+        return false;
+    }
+
+    m_fname = strdup(fname);
+    rc = _copyDb(Load);
+
+    return _createTable() && _createIndexes();
+}
+
+
+void
+CUserDict::free()
+{
+    if (m_fname) {
+        _copyDb(Save);
+        ::free(m_fname);
+        m_fname = NULL;
+    }
+
+    if (m_db) {
+        sqlite3_close(m_db);
+        m_db = NULL;
+    }
+}
+
+
+unsigned
+CUserDict::addWord(CSyllables &syllables, const wstring& word)
+{
+    assert(m_db != NULL);
+    assert(syllables.size() >= 2 && syllables.size() <= MAX_USRDEF_WORD_LEN);
+
+    sqlite3_stmt *stmt;
+    const char *sql_str =
+        "INSERT INTO dict (len, i0, f0, t0, i1, f1, t1, i2, f2, t2, i3, f3, t3, i4, f4, t4, i5, f5, t5, utf8str) \
+         VALUES           (?,   ?,  ?,  ?,  ?,  ?,  ?,  ?,  ?,  ?,  ?,  ?,  ?,  ?,  ?,  ?,  ?,  ?,  ?,  ?);";
+    const char *tail;
+
+    sqlite3_prepare(m_db, sql_str, strlen(sql_str), &stmt, &tail);
+
+    int i = 1;
+    sqlite3_bind_int(stmt, i++, syllables.size());
+
+    CSyllables::iterator it = syllables.begin();
+    CSyllables::iterator ite = syllables.end();
+    for (; it != ite; ++it) {
+        sqlite3_bind_int(stmt, i++, it->initial);
+        sqlite3_bind_int(stmt, i++, it->final);
+        sqlite3_bind_int(stmt, i++, it->tone);
+    }
+
+    while (i <= MAX_USRDEF_WORD_LEN * 3 + 1)
+        sqlite3_bind_int(stmt, i++, 0);
+
+    char buf[MAX_USRDEF_WORD_LEN * 6 + 1];
+    WCSTOMBS(buf, word.c_str(), sizeof(buf) - 1);
+    sqlite3_bind_text(stmt, i, (const char*)buf, strlen(buf), NULL);
+
+    unsigned ret = (SQLITE_DONE == sqlite3_step(stmt)) ?
+                   INI_USRDEF_WID + sqlite3_last_insert_rowid(m_db) :
+                   0;
+
+    sqlite3_finalize(stmt);
+    _copyDb(Save);
+    return ret;
+}
+
+
+void
+CUserDict::removeWord(unsigned wid)
+{
+    assert(m_db != NULL);
+    char    *zErr = NULL;
+    char sql[256] = "DELETE FROM dict WHERE id=";
+
+    if (wid > INI_USRDEF_WID) {
+        sprintf(sql, "%s%d;", sql, (wid - INI_USRDEF_WID));
+        sqlite3_exec(m_db, sql, NULL, NULL, &zErr);
+
+        m_dict.erase(m_dict.find(wid - INI_USRDEF_WID));
+    }
+}
+
+
+void
+CUserDict::getWords(CSyllables &syllables,
+                    std::vector<CPinyinTrie::TWordIdInfo> &result)
+{
+    assert(m_db != NULL);
+
+    char *sql_str;
+    const char *tail;
+    std::string i_conditions, f_conditions, t_conditions;
+    int length = syllables.size();
+    sqlite3_stmt *stmt;
+    int rc;
+    char buf[256];
+
+    if (length > MAX_USRDEF_WORD_LEN)
+        return;
+
+    for (int i = 0; i < length; i++) {
+        sprintf(buf, " and i%d=%d", i, syllables[i].initial);
+        i_conditions += buf;
+
+        if (!syllables[i].final)
+            continue;
+
+        sprintf(buf, " and f%i=%i", i, syllables[i].final);
+        f_conditions += buf;
+
+        if (!syllables[i].tone)
+            continue;
+
+        sprintf(buf, " and t%i=%i", i, syllables[i].tone);
+        t_conditions += buf;
+    }
+
+    sql_str = sqlite3_mprintf(
+        "SELECT id, utf8str FROM dict WHERE len=%i%q%q%q;",
+        length,
+        i_conditions.c_str(),
+        f_conditions.c_str(),
+        t_conditions.c_str());
+
+    rc = sqlite3_prepare(m_db, sql_str, strlen(sql_str), &stmt, &tail);
+    if (rc != SQLITE_OK) {
+        sqlite3_free(sql_str);
+        fprintf(stderr, "SQL error: %s\n", sqlite3_errmsg(m_db));
+        return;
+    }
+
+    unsigned id = 0;
+    TWCHAR cwstr[MAX_USRDEF_WORD_LEN + 1];
+    const unsigned char     *utf8str = NULL;
+    CPinyinTrie::TWordIdInfo word;
+
+    while (SQLITE_ROW == sqlite3_step(stmt)) {
+        id = sqlite3_column_int(stmt, 0);
+        utf8str = sqlite3_column_text(stmt, 1);
+
+        if (id >= MAX_USRDEF_WID - INI_USRDEF_WID)
+            continue;
+
+        memset(&cwstr[0], 0, sizeof(cwstr));
+        MBSTOWCS(cwstr, (const char*)utf8str, MAX_USRDEF_WORD_LEN);
+
+        word.m_id = id + INI_USRDEF_WID;
+        word.m_bSeen = 1;
+        result.push_back(word);
+
+        m_dict.insert(std::make_pair(id, wstring(cwstr)));
+    }
+
+    sqlite3_free(sql_str);
+    sqlite3_finalize(stmt);
+}
+
+
+const TWCHAR*
+CUserDict::operator [](unsigned wid)
+{
+    assert(m_db != NULL);
+
+    sqlite3_stmt *stmt = NULL;
+    int rc = SQLITE_OK;
+    const char *tail;
+    char sql_str[256];
+
+    if (wid <= INI_USRDEF_WID || wid > MAX_USRDEF_WID)
+        return NULL;
+
+    wid -= INI_USRDEF_WID;
+
+    std::map<unsigned, wstring>::const_iterator it = m_dict.find(wid);
+    if (it != m_dict.end())
+        return it->second.c_str();
+
+    sprintf(sql_str, "SELECT utf8str FROM dict WHERE id=%d;", wid);
+
+    rc = sqlite3_prepare(m_db, sql_str, strlen(sql_str), &stmt, &tail);
+    if (rc != SQLITE_OK) {
+        fprintf(stderr, "SQL error: %s\n", sqlite3_errmsg(m_db));
+        return NULL;
+    }
+
+    const TWCHAR *ret = NULL;
+    const unsigned char *utf8str = NULL;
+    TWCHAR cwstr[MAX_USRDEF_WORD_LEN + 1];
+    if (SQLITE_ROW == sqlite3_step(stmt)) {
+        utf8str = sqlite3_column_text(stmt, 0);
+        MBSTOWCS(cwstr, (const char*)utf8str, MAX_USRDEF_WORD_LEN);
+        wstring wstr(cwstr);
+        m_dict.insert(std::make_pair(wid, wstr));
+        ret = wstr.c_str();
+    }
+
+    sqlite3_finalize(stmt);
+    return ret;
+}
+
+int
+CUserDict::_copyDb(DBCopyDirection direction)
+{
+    sqlite3 *disk_db;
+    int rc = sqlite3_open(m_fname, &disk_db);
+
+    if (rc == SQLITE_OK) {
+        sqlite3 *dst = direction == Load ? m_db : disk_db;
+        sqlite3 *src = direction == Save ? m_db : disk_db;
+        sqlite3_backup *backup = sqlite3_backup_init(dst, "main", src, "main");
+        if (backup) {
+            sqlite3_backup_step(backup, -1);
+            sqlite3_backup_finish(backup);
+        }
+        rc = sqlite3_errcode(dst);
+    }
+
+    sqlite3_close(disk_db);
+    return rc;
+}
+
+bool
+CUserDict::_createTable()
+{
+    assert(m_db != NULL);
+
+    char *zErr = NULL;
+    int rc = SQLITE_OK;
+    const char *sql_str =
+        "CREATE TABLE IF NOT EXISTS dict( \
+         id INTEGER PRIMARY KEY, len INTEGER, \
+         i0 INTEGER, i1 INTEGER, i2 INTEGER, i3 INTEGER, i4 INTEGER, i5 INTEGER, \
+         f0 INTEGER, f1 INTEGER, f2 INTEGER, f3 INTEGER, f4 INTEGER, f5 INTEGER, \
+         t0 INTEGER, t1 INTEGER, t2 INTEGER, t3 INTEGER, t4 INTEGER, t5 INTEGER, \
+         utf8str TEXT, UNIQUE (i0, i1, i2, i3, i4, i5, utf8str));";
+
+    rc = sqlite3_exec(m_db, sql_str, NULL, NULL, &zErr);
+    if (rc != SQLITE_OK) {
+        if (zErr != NULL) {
+            fprintf(stderr, "SQL error: %s\n", zErr);
+            sqlite3_free(zErr);
+        }
+        return false;
+    }
+
+    return true;
+}
+
+bool
+CUserDict::_createIndexes()
+{
+    assert(m_db != NULL);
+
+    char *zErr = NULL;
+    int rc = SQLITE_OK;
+    const char * sql_str =
+        "CREATE INDEX IF NOT EXISTS index_0 ON dict (len, i0, i1, i2, i3, i4, i5);";
+
+    rc = sqlite3_exec(m_db, sql_str, NULL, NULL, &zErr);
+    if (rc != SQLITE_OK) {
+        if (zErr != NULL) {
+            fprintf(stderr, "SQL error: %s\n", zErr);
+            sqlite3_free(zErr);
+        }
+        return false;
+    }
+
+    return true;
+}
diff --git a/src/ime-core/userdict.h b/src/ime-core/userdict.h
new file mode 100644 (file)
index 0000000..24c21a1
--- /dev/null
@@ -0,0 +1,83 @@
+// -*- mode: c++ -*-
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright (c) 2007 Sun Microsystems, Inc. All Rights Reserved.
+ *
+ * The contents of this file are subject to the terms of either the GNU Lesser
+ * General Public License Version 2.1 only ("LGPL") or the Common Development and
+ * Distribution License ("CDDL")(collectively, the "License"). You may not use this
+ * file except in compliance with the License. You can obtain a copy of the CDDL at
+ * http://www.opensource.org/licenses/cddl1.php and a copy of the LGPLv2.1 at
+ * http://www.opensource.org/licenses/lgpl-license.php. See the License for the
+ * specific language governing permissions and limitations under the License. When
+ * distributing the software, include this License Header Notice in each file and
+ * include the full text of the License in the License file as well as the
+ * following notice:
+ *
+ * NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND DISTRIBUTION LICENSE
+ * (CDDL)
+ * For Covered Software in this distribution, this License shall be governed by the
+ * laws of the State of California (excluding conflict-of-law provisions).
+ * Any litigation relating to this License shall be subject to the jurisdiction of
+ * the Federal Courts of the Northern District of California and the state courts
+ * of the State of California, with venue lying in Santa Clara County, California.
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by only the CDDL or only
+ * the LGPL Version 2.1, indicate your decision by adding "[Contributor]" elects to
+ * include this software in this distribution under the [CDDL or LGPL Version 2.1]
+ * license." If you don't indicate a single choice of license, a recipient has the
+ * option to distribute your version of this file under either the CDDL or the LGPL
+ * Version 2.1, or to extend the choice of license to its licensees as provided
+ * above. However, if you add LGPL Version 2.1 code and therefore, elected the LGPL
+ * Version 2 license, then the option applies only if the new code is made subject
+ * to such option by the copyright holder.
+ */
+
+#ifndef SUNPY_USERDICT_H
+#define SUNPY_USERDICT_H
+
+#include <sqlite3.h>
+#include "portability.h"
+#include "pinyin/syllable.h"
+#include "lexicon/pytrie.h"
+#include "imi_defines.h"
+
+class CUserDict
+{
+public:
+    CUserDict () : m_fname(NULL), m_db(NULL) {}
+
+    ~CUserDict () { free(); }
+
+    bool load(const char *fname);
+
+    void free();
+
+    unsigned addWord(CSyllables &syllables, const wstring& word);
+
+    void removeWord(unsigned wid);
+
+    void getWords(CSyllables &syllables,
+                  std::vector<CPinyinTrie::TWordIdInfo> &result);
+
+    const TWCHAR* operator [](unsigned wid);
+
+private:
+    enum DBCopyDirection {
+        Load,
+        Save
+    };
+
+    int _copyDb(DBCopyDirection direction);
+    bool _createTable();
+    bool _createIndexes();
+
+    char                       *m_fname;
+    sqlite3                    *m_db;
+    std::map<unsigned, wstring> m_dict;
+};
+
+#endif /* SUNPY_USERDICT_H */
diff --git a/src/ime-core/utils.h b/src/ime-core/utils.h
new file mode 100644 (file)
index 0000000..cd8acac
--- /dev/null
@@ -0,0 +1,137 @@
+// -*- mode: c++ -*-
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright (c) 2007 Sun Microsystems, Inc. All Rights Reserved.
+ *
+ * The contents of this file are subject to the terms of either the GNU Lesser
+ * General Public License Version 2.1 only ("LGPL") or the Common Development and
+ * Distribution License ("CDDL")(collectively, the "License"). You may not use this
+ * file except in compliance with the License. You can obtain a copy of the CDDL at
+ * http://www.opensource.org/licenses/cddl1.php and a copy of the LGPLv2.1 at
+ * http://www.opensource.org/licenses/lgpl-license.php. See the License for the
+ * specific language governing permissions and limitations under the License. When
+ * distributing the software, include this License Header Notice in each file and
+ * include the full text of the License in the License file as well as the
+ * following notice:
+ *
+ * NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND DISTRIBUTION LICENSE
+ * (CDDL)
+ * For Covered Software in this distribution, this License shall be governed by the
+ * laws of the State of California (excluding conflict-of-law provisions).
+ * Any litigation relating to this License shall be subject to the jurisdiction of
+ * the Federal Courts of the Northern District of California and the state courts
+ * of the State of California, with venue lying in Santa Clara County, California.
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by only the CDDL or only
+ * the LGPL Version 2.1, indicate your decision by adding "[Contributor]" elects to
+ * include this software in this distribution under the [CDDL or LGPL Version 2.1]
+ * license." If you don't indicate a single choice of license, a recipient has the
+ * option to distribute your version of this file under either the CDDL or the LGPL
+ * Version 2.1, or to extend the choice of license to its licensees as provided
+ * above. However, if you add LGPL Version 2.1 code and therefore, elected the LGPL
+ * Version 2 license, then the option applies only if the new code is made subject
+ * to such option by the copyright holder.
+ */
+
+#ifndef SUNPY_UTILS_H
+#define SUNPY_UTILS_H
+
+#include <string>
+#include <utility>
+#include <vector>
+
+typedef std::pair<std::string, std::string> string_pair;
+typedef std::vector<string_pair> string_pairs;
+
+class CNonCopyable
+{
+protected:
+    CNonCopyable () {}
+    ~CNonCopyable () {}
+
+private:
+    CNonCopyable (const CNonCopyable&);
+    CNonCopyable& operator =(const CNonCopyable&);
+};
+
+template <typename T, bool isArray = false>
+class CResourceHandler
+{
+public:
+    CResourceHandler(T* p) : m_p(p) {}
+    ~CResourceHandler() { delete m_p; }
+protected:
+    T *m_p;
+};
+
+template <typename T>
+class CResourceHandler <T, true>
+{
+public:
+    CResourceHandler(T* p) : m_p(p) {}
+    ~CResourceHandler() { delete [] m_p; }
+protected:
+    T *m_p;
+};
+
+
+template <typename T>
+class CSharedPtr
+{
+private:
+    typedef CSharedPtr<T> this_type;
+
+    T*          ptr;
+    unsigned*   ref;
+
+public:
+    explicit CSharedPtr (T* p = 0) : ptr(p), ref(new unsigned (1)) {}
+    CSharedPtr (const this_type& p) : ptr(p.ptr), ref(p.ref) { ++(*ref); }
+    ~CSharedPtr () { dispose(); }
+
+    CSharedPtr<T>& operator =(const this_type& p){
+        if (this != &p) {
+            dispose();
+            ptr = p.ptr, ref = p.ref;
+            ++(*ref);
+        }
+        return *this;
+    }
+
+    bool equal(const this_type p) const
+    { return *ptr == *p.ptr; }
+
+    bool operator ==(const this_type& p) const
+    { return ptr == p.ptr && ref == p.ref; }
+
+    T* get()         const { return ptr; }
+
+    operator bool() const { return ptr != 0; }
+    operator T&() const { return *ptr; }
+    T& operator *() const { return *ptr; }
+    T* operator ->() const { return ptr; }
+
+private:
+    void dispose(){
+        if (--(*ref) == 0) {
+            delete ref;
+            delete ptr;
+        }
+    }
+};
+
+template <class T>
+class SingletonHolder
+{
+public:
+    typedef T Type;
+    static T& instance(){
+        static T instance_;
+        return instance_;
+    }
+};
+
+#endif /* SUNPY_UTILS_H */
diff --git a/src/lexicon/Makefile.am b/src/lexicon/Makefile.am
new file mode 100755 (executable)
index 0000000..b16e1bc
--- /dev/null
@@ -0,0 +1,32 @@
+## Makefile.am -- Process this file with automake to produce Makefile.in
+## Copyright (C) 2002 James Su
+##
+## This program is free software; you can redistribute it and/or modify
+## it under the terms of the GNU General Public License as published by
+## the Free Software Foundation; either version 2, or (at your option)
+## any later version.
+##
+## This program is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+## GNU General Public License for more details.
+##
+## You should have received a copy of the GNU General Public License
+## along with this program; if not, write to the Free Software
+## Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+
+MAINTAINERCLEANFILES   = Makefile.in
+INCLUDES=-I$(top_srcdir)\
+         -I$(top_srcdir)/src\
+         -I$(top_srcdir)/src/ime-core\
+         -I$(top_srcdir)/src/lexicon\
+         -I$(top_srcdir)/src/pinyin\
+         -I$(top_srcdir)/src/slm
+         
+noinst_HEADERS = pytrie.h\
+                     pytrie_gen.h\
+                     trie_writer.h
+
+noinst_LTLIBRARIES = liblexicon.la
+liblexicon_la_SOURCES          = pytrie.cpp
diff --git a/src/lexicon/genPYT.cpp b/src/lexicon/genPYT.cpp
new file mode 100644 (file)
index 0000000..d7a227f
--- /dev/null
@@ -0,0 +1,185 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright (c) 2007 Sun Microsystems, Inc. All Rights Reserved.
+ *
+ * The contents of this file are subject to the terms of either the GNU Lesser
+ * General Public License Version 2.1 only ("LGPL") or the Common Development and
+ * Distribution License ("CDDL")(collectively, the "License"). You may not use this
+ * file except in compliance with the License. You can obtain a copy of the CDDL at
+ * http://www.opensource.org/licenses/cddl1.php and a copy of the LGPLv2.1 at
+ * http://www.opensource.org/licenses/lgpl-license.php. See the License for the
+ * specific language governing permissions and limitations under the License. When
+ * distributing the software, include this License Header Notice in each file and
+ * include the full text of the License in the License file as well as the
+ * following notice:
+ *
+ * NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND DISTRIBUTION LICENSE
+ * (CDDL)
+ * For Covered Software in this distribution, this License shall be governed by the
+ * laws of the State of California (excluding conflict-of-law provisions).
+ * Any litigation relating to this License shall be subject to the jurisdiction of
+ * the Federal Courts of the Northern District of California and the state courts
+ * of the State of California, with venue lying in Santa Clara County, California.
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by only the CDDL or only
+ * the LGPL Version 2.1, indicate your decision by adding "[Contributor]" elects to
+ * include this software in this distribution under the [CDDL or LGPL Version 2.1]
+ * license." If you don't indicate a single choice of license, a recipient has the
+ * option to distribute your version of this file under either the CDDL or the LGPL
+ * Version 2.1, or to extend the choice of license to its licensees as provided
+ * above. However, if you add LGPL Version 2.1 code and therefore, elected the LGPL
+ * Version 2 license, then the option applies only if the new code is made subject
+ * to such option by the copyright holder.
+ */
+
+#include <locale.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "pytrie.h"
+#include "pytrie_gen.h"
+#include "../slm/slm.h"
+#include "trie_writer.h"
+
+class CUnigramSorter : public CWordEvaluator {
+public:
+    virtual double
+    getCost(unsigned int wid);
+
+    virtual bool
+    isSeen(unsigned int wid);
+
+    bool
+    open(const char* lm_file)
+    {
+        return m_Model.load(lm_file);
+    }
+
+    void
+    close()
+    {
+        m_Model.free();
+    }
+
+protected:
+
+    CThreadSlm m_Model;
+};
+
+double
+CUnigramSorter::getCost(unsigned int wid)
+{
+    CThreadSlm::TState st(0, 0);
+    return m_Model.transferNegLog(st, wid, st);
+}
+
+bool
+CUnigramSorter::isSeen(unsigned int wid)
+{
+    CThreadSlm::TState st(0, 0);
+    m_Model.transferNegLog(st, wid, st);
+    //printf("    -log(pr(%d)) = %lf\n", wid, logpr);
+    return(st.getLevel() == 1);
+}
+
+/**
+ * This program is used to generate the PINYIN Lexicon. It
+ * Only works on zh_CN.utf8 locale.\n
+ * args:
+ *    -# dictionary file, in utf8 encoding, line-based text file,
+ *       each line looks like\n
+ *       CCC  id  [pinyin'pinyin'pinyin]*
+ *    -# output binary PINYIN Lexicon file name
+ *    -# log file to print the generated PINYIN Lexicon
+ *    -# language model to sort the words of each node
+ */
+void
+ShowUsage(const char* progname)
+{
+    fprintf(
+        stderr,
+        "Usage:\n"
+        "    %s -i lexicon_file -o result_file -l log_file -s slm_file [-e le|be]\n",
+        progname);
+    fprintf(
+        stderr,
+        "Description:\n"
+        "    This program is used to generate the PINYIN Lexicon. It Only works on zh_CN.utf8 locale\n"
+        "\n");
+    exit(100);
+}
+
+int
+main(int argc, char* argv[])
+{
+    setlocale(LC_ALL, "");
+
+    const char* lexicon_file = NULL;
+    const char* result_file = NULL;
+    const char* log_file = NULL;
+    const char* slm_file = NULL;
+    int build_endian = get_host_endian();
+    int opt;
+    while ((opt = getopt(argc, argv, "i:o:l:s:e:")) != -1) {
+        switch (opt) {
+        case 'i':
+            lexicon_file = optarg;
+            break;
+        case 'o':
+            result_file = optarg;
+        case 'l':
+            log_file = optarg;
+            break;
+        case 's':
+            slm_file = optarg;
+            break;
+        case 'e':
+            build_endian = parse_endian(optarg);
+            break;
+        }
+    }
+    if (!lexicon_file || !result_file || !log_file || !slm_file ||
+        build_endian == -1) {
+        ShowUsage(argv[0]);
+    }
+
+    printf("Opening language model..."); fflush(stdout);
+    CUnigramSorter srt;
+    if (!srt.open(slm_file)) {
+        printf("error!\n");
+        return -1;
+    }
+    printf("done!\n"); fflush(stdout);
+
+    CPinyinTrieMaker maker;
+
+    maker.constructFromLexicon(lexicon_file);
+
+    printf("Writing out..."); fflush(stdout);
+    maker.write(result_file, &srt, get_host_endian() != build_endian);
+    printf("done!\n"); fflush(stdout);
+
+    srt.close();
+
+    if (get_host_endian() != build_endian) {
+        printf("host endian is different from build endian. "
+               "log_file will not be written.\n");
+        fflush(stdout);
+        return 0;
+    }
+
+    printf("Printing the lexicon out to log_file..."); fflush(stdout);
+    CPinyinTrie t;
+    t.load(result_file);
+
+    FILE *fp = fopen(log_file, "w");
+    t.print(fp);
+    fclose(fp);
+
+    printf("done!\n");
+
+    return 0;
+}
diff --git a/src/lexicon/pytrie.cpp b/src/lexicon/pytrie.cpp
new file mode 100644 (file)
index 0000000..7e5bf67
--- /dev/null
@@ -0,0 +1,160 @@
+#include <stdio.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <deque>
+
+#include "pytrie.h"
+#include "pinyin_data.h"
+
+#ifdef HAVE_SYS_MMAN_H
+#include <sys/mman.h>
+#endif
+
+bool
+CPinyinTrie::isValid(const TNode* pnode,
+                     bool allowNonComplete,
+                     unsigned csLevel)
+{
+    if ((pnode != NULL) && (csLevel <= pnode->m_csLevel))
+        return(allowNonComplete || (pnode->m_bFullSyllableTransfer == 1));
+    return false;
+}
+
+int
+CPinyinTrie::lengthAt(unsigned int idx) const
+{
+    if (idx < getWordCount() - 1) {
+        return (m_words[idx + 1] - m_words[idx]) - 1;
+    } else if (idx == getWordCount() - 1) {
+        return (((TWCHAR*)(m_mem + m_Size)) - m_words[idx]) - 1;
+    }
+    return 0;
+}
+
+unsigned int
+CPinyinTrie::getSymbolId(const TWCHAR* wstr)
+{
+    std::map<wstring, unsigned>::const_iterator it;
+
+    it = m_SymbolMap.find(wstring(wstr));
+    if (it != m_SymbolMap.end())
+        return it->second;
+    return 0;
+}
+
+unsigned int
+CPinyinTrie::getSymbolId(const wstring & wstr)
+{
+    std::map<wstring, unsigned>::const_iterator it;
+
+    it = m_SymbolMap.find(wstr);
+    if (it != m_SymbolMap.end())
+        return it->second;
+    return 0;
+}
+
+void
+CPinyinTrie::free(void)
+{
+    if (m_mem) {
+#ifdef HAVE_SYS_MMAN_H
+        munmap(m_mem, m_Size);
+#else
+        delete [] m_mem;
+#endif
+        m_mem = NULL;
+    }
+    if (m_words) {
+        delete [] m_words;
+        m_words = NULL;
+    }
+    m_SymbolMap.clear();
+}
+
+bool
+CPinyinTrie::load(const char *fname)
+{
+    free();
+
+    bool suc = false;
+    int fd = open(fname, O_RDONLY);
+    if (fd == -1) return false;
+
+    m_Size = lseek(fd, 0, SEEK_END);
+    lseek(fd, 0, SEEK_SET);
+
+#ifdef HAVE_SYS_MMAN_H
+    suc =
+        (m_mem =
+             (char*)mmap(NULL, m_Size, PROT_READ, MAP_SHARED, fd,
+                         0)) != MAP_FAILED;
+#else
+    suc = (m_mem = new char [m_Size]) != NULL;
+    suc = suc && (read(fd, m_mem, m_Size) > 0);
+#endif
+    close(fd);
+
+    suc = suc && ((m_words = new TWCHAR*[getWordCount()]) != NULL);
+
+    if (suc) {
+        TWCHAR *p = (TWCHAR*)(m_mem + getStringOffset());
+        for (int i = 0, sz = getWordCount(); i < sz; ++i) {
+            m_words[i] = p;
+            while (*p++)
+                ;
+        }
+        for (unsigned i = 1; i < 100; ++i) {
+            if (*m_words[i] != WCH_NULL && *m_words[i] != WCH_LESSTHAN)
+                m_SymbolMap[wstring(m_words[i])] = i;
+        }
+    }
+    return suc;
+}
+
+void
+CPinyinTrie::print(FILE *fp) const
+{
+    std::string prefix;
+    print(getRootNode(), prefix, fp);
+}
+
+void
+CPinyinTrie::print(const TNode* pRoot, std::string& prefix, FILE *fp) const
+{
+    static char buf[1024];
+    if (pRoot->m_nWordId > 0) {
+        fprintf(fp, "%s", prefix.c_str());
+        if (pRoot->m_csLevel)
+            fprintf(fp, "(GBK+)");
+        unsigned int sz = pRoot->m_nWordId;
+        const TWordIdInfo *pwids = pRoot->getWordIdPtr();
+        for (unsigned int i = 0; i < sz; ++i) {
+            unsigned int id = pwids[i].m_id;
+            const TWCHAR *pw = operator[](id);
+            int len = WCSLEN(pw);
+            if (len != lengthAt(id)) {
+                printf(" (lengthAt %d error) ", id);
+            }
+            WCSTOMBS(buf, pw, 1024);
+            fprintf(fp, " %s", buf);
+            if (pwids[i].m_bSeen == 0)
+                fprintf(fp, "[x]");
+            else
+                fprintf(fp, "[o]");
+
+            fprintf(fp, "(%d)", pwids[i].m_cost);
+        }
+        fprintf(fp, "\n");
+    }
+    unsigned int sz = pRoot->m_nTransfer;
+    const TTransUnit* ptrans = pRoot->getTrans();
+    for (unsigned int i = 0; i < sz; ++i) {
+        unsigned s = ptrans[i].m_Syllable;
+        const TNode *pch = transfer(pRoot, s);
+        const char *str = CPinyinData::decodeSyllable(s);
+        if (!str) break;
+        prefix = prefix + str + '\'';
+        print(pch, prefix, fp);
+        prefix.resize(prefix.size() - strlen(str) - 1);
+    }
+}
diff --git a/src/lexicon/pytrie.h b/src/lexicon/pytrie.h
new file mode 100644 (file)
index 0000000..d1bfc7d
--- /dev/null
@@ -0,0 +1,165 @@
+// -*- mode: c++ -*-
+#ifndef __SUNPINYIN_PYTRIE_H__
+#define __SUNPINYIN_PYTRIE_H__
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "../portability.h"
+#include "pinyin/syllable.h"
+#include <map>
+
+#define WORD_ID_WIDTH       24
+
+class CPinyinTrie {
+public:
+    friend class CPinyinTrieMaker;
+
+    struct TTransUnit {
+        TSyllable m_Syllable;
+        unsigned m_Offset;
+    };
+
+    struct TWordIdInfo {
+    #ifdef WORDS_BIGENDIAN
+        unsigned m_bSeen    : 1;
+        unsigned m_cost     : 5;
+        unsigned m_csLevel  : 2;
+        unsigned m_id       : WORD_ID_WIDTH;
+    #else
+        unsigned m_id       : WORD_ID_WIDTH;
+        unsigned m_csLevel  : 2;
+        unsigned m_cost     : 5;
+        unsigned m_bSeen    : 1;
+    #endif
+
+        TWordIdInfo() { memset(this, 0, sizeof(TWordIdInfo)); }
+
+        TWordIdInfo(unsigned id,
+                    unsigned len = 0,
+                    unsigned seen = 0,
+                    unsigned cost = 0,
+                    unsigned cslvl = 0)
+            : m_id(id), m_csLevel(cslvl), m_cost(cost), m_bSeen(seen) { }
+
+        operator unsigned int() const { return m_id; }
+    };
+
+    struct TNode {
+    #ifdef WORDS_BIGENDIAN
+        unsigned m_other      : 5;
+        unsigned m_bFullSyllableTransfer : 1;
+        unsigned m_csLevel    : 2;
+        unsigned m_nTransfer  : 12;
+        unsigned m_nWordId    : 12;
+    #else
+        unsigned m_nWordId    : 12;
+        unsigned m_nTransfer  : 12;
+        unsigned m_csLevel    : 2;
+        unsigned m_bFullSyllableTransfer : 1;
+        unsigned m_other      : 5;
+    #endif
+
+        static unsigned int size_for(unsigned int nTransfer,
+                                     unsigned int nWordId)                    {
+            return sizeof(TNode) + sizeof(TTransUnit) * nTransfer +
+                   sizeof(TWordIdInfo) * nWordId;
+        }
+
+        TNode()
+        { *((unsigned *) this) = 0; }
+
+        bool hasPinyinChild(void) const
+        { return(m_nTransfer > 1); }
+
+        const TTransUnit*getTrans() const
+        { return (TTransUnit *) (this + 1); }
+
+        const TWordIdInfo*getWordIdPtr() const
+        { return (TWordIdInfo *) (((char *) (this +
+                                             1)) + sizeof(TTransUnit) *
+                                  m_nTransfer); }
+
+        unsigned int transfer(unsigned s) const {
+            unsigned int b = 0, e = m_nTransfer;
+            const TTransUnit* ptrans = getTrans();
+            while (b < e) {
+                int m = b + (e - b) / 2;
+                if (ptrans[m].m_Syllable == s)
+                    return ptrans[m].m_Offset;
+                if (ptrans[m].m_Syllable < s)
+                    b = m + 1;
+                else
+                    e = m;
+            }
+            return 0;
+        }
+    };
+
+public:
+    CPinyinTrie() : m_Size(0), m_mem(NULL), m_words(NULL) { }
+
+    ~CPinyinTrie()
+    { free(); }
+
+    bool
+    load(const char* fileName);
+
+    void
+    free(void);
+
+    bool
+    isValid(const TNode* pnode, bool allowNonComplete, unsigned csLevel = 0);
+
+    unsigned int getRootOffset() const
+    { return 3 * sizeof(unsigned int); }
+
+    const TNode*getRootNode() const
+    { return (TNode *) (m_mem + getRootOffset()); }
+
+    const TNode*nodeFromOffset(unsigned int offset) const
+    { return (offset < getRootOffset()) ? NULL : ((TNode *) (m_mem + offset)); }
+
+    unsigned int getWordCount(void) const
+    { return *(unsigned int *) m_mem; }
+
+    unsigned int getNodeCount(void) const
+    { return *(unsigned int *) (m_mem + sizeof(unsigned int)); }
+
+    unsigned int getStringOffset(void) const
+    { return *(unsigned int *) (m_mem + 2 * sizeof(unsigned int)); }
+
+    inline const TNode*transfer(const TNode* pnode, unsigned s) const
+    { return nodeFromOffset(pnode->transfer(s)); }
+
+    inline const TNode*transfer(unsigned s) const
+    { return transfer(getRootNode(), s); }
+
+    unsigned int
+    getSymbolId(const TWCHAR* wstr);
+
+    unsigned int
+    getSymbolId(const wstring & wstr);
+
+    const TWCHAR*operator[](unsigned int idx) const
+    { return m_words[idx]; }
+
+    int
+    lengthAt(unsigned int idx) const;
+
+    void
+    print(FILE *fp) const;
+
+protected:
+    unsigned int m_Size;
+    char                  *m_mem;
+    TWCHAR               **m_words;
+
+    std::map<wstring, unsigned>  m_SymbolMap;
+
+    void
+    print(const TNode* pRoot, std::string& prefix, FILE *fp) const;
+};
+
+#endif /* __SUNPINYIN_PYTRIE_H__*/
diff --git a/src/lexicon/pytrie_gen.cpp b/src/lexicon/pytrie_gen.cpp
new file mode 100644 (file)
index 0000000..1e5d195
--- /dev/null
@@ -0,0 +1,541 @@
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifdef HAVE_ASSERT_H
+#include <assert.h>
+#endif
+
+#ifdef HAVE_ICONV_H
+#include <iconv.h>
+#endif
+
+#include <algorithm>
+
+#include "pytrie_gen.h"
+#include "pinyin_data.h"
+#include "trie_writer.h"
+
+static const char*
+skipSpace(const char* p)
+{
+    while (*p == ' ' || *p == '\t' || *p == '\n' || *p == '\r')
+        ++p;
+    return p;
+}
+
+static const char*
+skipNonSpace(const char* p)
+{
+    while (*p != '\0' && *p != ' ' && *p != '\t' && *p != '\n' && *p != '\r')
+        ++p;
+    return p;
+}
+
+static void
+insertWordId(CPinyinTrieMaker::CWordSet& idset, CPinyinTrieMaker::TWordId id)
+{
+    CPinyinTrieMaker::CWordSet::const_iterator it = idset.find(id);
+    if (it == idset.end())
+        idset.insert(id);
+    else {
+        const CPinyinTrieMaker::TWordId& a = *it;
+        if ((a.anony.m_bHide &&
+             !id.anony.m_bHide) ||
+            (a.anony.m_bHide == id.anony.m_bHide && a.anony.m_cost >
+             id.anony.m_cost)) {
+            idset.erase(it);
+            idset.insert(id);
+        }
+    }
+}
+
+struct TSyllableInfo {
+    std::string m_py;
+    int m_cost;
+
+    TSyllableInfo(const char* py = NULL, int cost = 0) : m_py(py), m_cost(cost)
+    {
+    }
+    bool
+    operator<(const TSyllableInfo& b) const
+    {
+        return m_py < b.m_py;
+    }
+};
+
+#ifdef HAVE_ICONV_H
+bool
+isCorrectConverted(const char* utf8, iconv_t ic, iconv_t ric)
+{
+    static char gbstr[256];
+    static char utstr[256];
+
+    TIConvSrcPtr src = (TIConvSrcPtr)utf8;
+    size_t srclen = strlen((char*)src) + 1;
+    char* dst = (char*)gbstr;
+    size_t dstlen = 256;
+    size_t res = iconv(ic, &src, &srclen, &dst, &dstlen);
+
+    if (res != size_t(-1) && srclen == 0) {
+        // do revert convertion and compare them
+        src = (TIConvSrcPtr)gbstr;
+        srclen = strlen((char*)src) + 1;
+        dst = (char*)utstr;
+        dstlen = 256;
+        res = iconv(ric, &src, &srclen, &dst, &dstlen);
+        if (res != size_t(-1) && srclen == 0)
+            return(strcmp(utf8, utstr) == 0);
+    }
+    return false;
+}
+
+//return: bit 0x1: contains some gbk out of gb2312, bit 0x2: contains some gb18030 outof gbk
+unsigned
+getPureGBEncoding(const char* utf8str)
+{
+    static iconv_t ic_gb = iconv_open("GB2312", "UTF-8");
+    static iconv_t ic_gbk = iconv_open("GBK", "UTF-8");
+    static iconv_t ric_gb = iconv_open("UTF-8", "GB2312");
+    static iconv_t ric_gbk = iconv_open("UTF-8", "GBK");
+
+    unsigned ret = 0;
+
+    if (!isCorrectConverted(utf8str, ic_gb, ric_gb)) {
+        ret = 1; // at least it is contains some GBK char
+        if (!isCorrectConverted(utf8str, ic_gbk, ric_gbk))
+            ret = 3;  //contains some GB18030-only char
+
+        #ifdef DEBUG
+        fprintf(stderr, "==> GB category of (%s) is (0x%x)\n ", utf8str, ret);
+        fflush(stderr);
+        #endif
+    }
+    return ret;
+}
+#else // !HAVE_ICONV_H
+unsigned
+getPureGBEncoding(const char* utf8str)
+{
+    // FIXME
+    return 0x3;
+}
+#endif // HAVE_ICONV_H
+
+bool
+parseLine(char* buf,
+          char* word_buf,
+          unsigned& id,
+          std::set<TSyllableInfo>& pyset)
+{
+    pyset.clear();
+
+    /* ignore the empty lines and comment lines */
+    if (*buf == '\n' || *buf == '#')
+        return 0;
+
+    char* p = (char*)skipSpace(buf);
+    char* t = (char*)skipNonSpace(p);
+    while (p < t) *word_buf++ = *p++;
+    *word_buf = 0;
+
+    p = (char*)skipSpace(p);
+    t = (char*)skipNonSpace(p);
+    if (*t)
+        *t++ = 0;
+    id = atoi(p);
+    p = (char*)skipSpace(t);
+    while (*p) {
+        const char* s = p;
+        t = (char*)skipNonSpace(p);
+        if (*t)
+            *t++ = 0;
+        while ((*p >= 'a' && *p <= 'z') || (*p == '\''))
+            ++p;
+        if ((p > s) && ((*p == 0) || (*p == ':'))) {
+            int cost = 0;
+            if (*p == ':') {
+                *p++ = 0;
+                cost = -log2(atof(p)/100);
+            }
+            pyset.insert(TSyllableInfo(s, cost));
+        }
+        p = (char*)skipSpace(t);
+    }
+    return pyset.size() > 0;
+}
+
+
+CPinyinTrieMaker::CPinyinTrieMaker()
+{
+    m_RootNode.m_bExpanded = true;
+}
+/**********************************************************
+    lexicon文件格式:
+        以行为单位的文本文件。行中是空格或TAB(1个或多个)分
+        隔开的字段。 第一个字段为词,第二个字段是word id。
+        后面的字段中,如果一个字段仅仅由小写字母和'构成,
+        则认为该字段是该词的一个拼音。行长最大4095;
+**********************************************************/
+
+bool
+CPinyinTrieMaker::constructFromLexicon(const char* fileName)
+{
+    static char buf[4096];
+    static char word_buf[2048];
+
+    unsigned id;
+    bool suc = true;
+    std::set<TSyllableInfo> pyset;
+    FILE *fp = fopen(fileName, "r");
+    if (!fp) return false;
+    printf("Adding pinyin and corresponding words..."); fflush(stdout);
+    while (fgets(buf, sizeof(buf), fp) != NULL) {
+        if (!parseLine(buf, word_buf, id, pyset)) {
+            if (word_buf[0] != L'<' && word_buf[0] != 0) {
+                if (m_Lexicon.size() < id + 1) m_Lexicon.resize(id + 1);
+                m_Lexicon[id] = std::string(word_buf);
+            }
+            continue;
+        }
+        unsigned gbcategory = getPureGBEncoding(word_buf);
+
+        std::set<TSyllableInfo>::const_iterator its = pyset.begin();
+        std::set<TSyllableInfo>::const_iterator ite = pyset.end();
+        for (; its != ite; ++its) {
+            const char *pystr = its->m_py.c_str();
+            if (m_Lexicon.size() < id + 1) m_Lexicon.resize(id + 1);
+            m_Lexicon[id] = std::string(word_buf);
+
+            CPinyinTrieMaker::TWordId wid(id, its->m_cost, false, gbcategory);
+            suc = insertFullPinyinPair(pystr, wid) && suc;
+        }
+    }
+    fclose(fp);
+
+    printf("\n    %zd primitive nodes", TNode::m_AllNodes.size());  fflush(stdout);
+
+    threadNonCompletePinyin();
+    printf("\n    %zd total nodes", TNode::m_AllNodes.size());  fflush(stdout);
+
+    std::string pyPrefix = "";
+    printf("\n");  fflush(stdout);
+
+    return suc;
+}
+
+CPinyinTrieMaker::CNodeList CPinyinTrieMaker::TNode::m_AllNodes;
+CPinyinTrieMaker::TNode::TNode()
+    : m_bExpanded(false), m_bFullSyllableTransfer(false)
+{
+    m_AllNodes.push_back(this);
+}
+
+bool
+CPinyinTrieMaker::PNodeSet::operator<(const PNodeSet& another) const
+{
+    CNodeSet::const_iterator t1 = m_pns->begin();
+    CNodeSet::const_iterator t2 = m_pns->end();
+    CNodeSet::const_iterator a1 = another.m_pns->begin();
+    CNodeSet::const_iterator a2 = another.m_pns->end();
+    for (; t1 != t2 && a1 != a2; ++t1, ++a1) {
+        if (*t1 < *a1) return true;
+        if (*t1 > *a1) return false;
+    }
+    return(a1 != a2);
+}
+
+bool
+CPinyinTrieMaker::PNodeSet::operator==(const PNodeSet& another) const
+{
+    CNodeSet::const_iterator t1 = m_pns->begin();
+    CNodeSet::const_iterator t2 = m_pns->end();
+    CNodeSet::const_iterator a1 = another.m_pns->begin();
+    CNodeSet::const_iterator a2 = another.m_pns->end();
+    for (; t1 != t2 && a1 != a2; ++t1, ++a1) {
+        if (*t1 != *a1) return false;
+    }
+    return(a1 == a2 && t1 != t2);
+}
+
+static void
+parseFullPinyin(const char *pinyin, std::vector<TSyllable> &ret)
+{
+    char *buf = strdup(pinyin);
+    char *p = buf, *q = buf;
+    ret.clear();
+
+    while (*p) {
+        if (*p == '\'') {
+            *p = '\0';
+            unsigned s = CPinyinData::encodeSyllable(q);
+            if (s)
+                ret.push_back(TSyllable(s));
+            else
+                printf("\nWarning! unrecognized syllable %s", q);
+            q = p + 1;
+        }
+        p++;
+    }
+
+    if (*q) {
+        unsigned s = CPinyinData::encodeSyllable(q);
+        if (s)
+            ret.push_back(TSyllable(s));
+        else
+            printf("\nWarning! unrecognized syllable %s", q);
+    }
+
+    free(buf);
+}
+
+CPinyinTrieMaker::TNode*
+CPinyinTrieMaker::insertTransfer(TNode* pnode, unsigned s)
+{
+    CTrans::const_iterator itt = pnode->m_Trans.find(s);
+    CTrans::const_iterator ite = pnode->m_Trans.end();
+    if (itt == ite) {
+        TNode *p = new TNode();
+        p->m_bFullSyllableTransfer = true;
+        p->m_bExpanded = true;
+        pnode->m_Trans[s] = p;
+        return p;
+    }
+    return itt->second;
+}
+
+bool
+CPinyinTrieMaker::insertFullPinyinPair(const char* pinyin, TWordId wid)
+{
+    TNode *pnode = &m_RootNode;
+    std::vector<TSyllable> syllables;
+    parseFullPinyin(pinyin, syllables);
+
+    if (syllables.empty())
+        return true;
+
+    std::vector<TSyllable>::const_iterator it = syllables.begin();
+    std::vector<TSyllable>::const_iterator ite = syllables.end();
+
+    for (; it != ite; ++it)
+        pnode = insertTransfer(pnode, *it);
+
+    insertWordId(pnode->m_WordIdSet, wid);
+    return true;
+}
+
+CPinyinTrieMaker::TNode*
+CPinyinTrieMaker::addCombinedTransfers(TNode *pnode,
+                                       unsigned s,
+                                       const CNodeSet& nodes)
+{
+    assert(!nodes.empty());
+
+    TNode *p = NULL;
+    if (nodes.size() == 1) {
+        p = *(nodes.begin());
+    } else {
+        p = new TNode();
+        p->m_cmbNodes = nodes;
+        m_StateMap[&p->m_cmbNodes] = p;
+
+        CNodeSet::const_iterator it = nodes.begin();
+        CNodeSet::const_iterator ite = nodes.end();
+        for (; it != ite; ++it) {
+            CWordSet::const_iterator wit  = (*it)->m_WordIdSet.begin();
+            CWordSet::const_iterator wite = (*it)->m_WordIdSet.end();
+
+            for (; wit != wite; ++wit) {
+                CWordSet::iterator tmp = p->m_WordIdSet.find (*wit);
+
+                if (tmp == p->m_WordIdSet.end()) {
+                    p->m_WordIdSet.insert (*wit);
+                } else if (tmp->anony.m_cost > wit->anony.m_cost) {
+                    p->m_WordIdSet.erase (tmp);
+                    p->m_WordIdSet.insert (*wit);
+                }
+            }
+        }
+    }
+
+    pnode->m_Trans[s] = p;
+    return p;
+}
+
+void
+CPinyinTrieMaker::combineInitialTrans(TNode *pnode)
+{
+    std::map<unsigned, CNodeSet> combTrans;
+
+    CTrans::const_iterator itTrans = pnode->m_Trans.begin();
+    CTrans::const_iterator itTransLast = pnode->m_Trans.end();
+    for (; itTrans != itTransLast; ++itTrans) {
+        TSyllable s = (TSyllable)itTrans->first;
+        if (s.initial) {
+            s.final = s.tone = 0;
+            combTrans[s].insert(itTrans->second);
+        }
+    }
+
+    std::map<unsigned, CNodeSet>::const_iterator itCombTrans = combTrans.begin();
+    for (; itCombTrans != combTrans.end(); ++itCombTrans)
+        addCombinedTransfers(pnode, itCombTrans->first, itCombTrans->second);
+}
+
+void
+CPinyinTrieMaker::expandCombinedNode(TNode *pnode)
+{
+    assert(pnode->m_cmbNodes.size() >= 1);
+
+    std::map<unsigned, CNodeSet> combTrans;
+    CNodeSet::const_iterator itNode = pnode->m_cmbNodes.begin();
+    CNodeSet::const_iterator itNodeLast = pnode->m_cmbNodes.end();
+    for (; itNode != itNodeLast; ++itNode) {
+        CTrans::const_iterator itTrans = (*itNode)->m_Trans.begin();
+        CTrans::const_iterator itTransLast = (*itNode)->m_Trans.end();
+        for (; itTrans != itTransLast; ++itTrans)
+            combTrans[itTrans->first].insert(itTrans->second);
+    }
+
+    std::map<unsigned, CNodeSet>::const_iterator itCombTrans = combTrans.begin();
+    for (; itCombTrans != combTrans.end(); ++itCombTrans) {
+        TNode* p = NULL;
+        unsigned s = itCombTrans->first;
+        CNodeSet nodes = itCombTrans->second;
+
+        CStateMap::const_iterator itStateMap = m_StateMap.find(&nodes);
+        if (itStateMap != m_StateMap.end())
+            p = itStateMap->second;
+        else
+            p = addCombinedTransfers(pnode, s, nodes);
+
+        pnode->m_Trans[s] = p;
+    }
+
+    pnode->m_bExpanded = true;
+}
+
+bool
+CPinyinTrieMaker::threadNonCompletePinyin(void)
+{
+    CNodeList::const_iterator itNode = TNode::m_AllNodes.begin();
+    for (; itNode != TNode::m_AllNodes.end(); ++itNode) {
+        TNode* pnode = *itNode;
+        if (pnode->m_bExpanded)
+            combineInitialTrans(pnode);
+        else
+            expandCombinedNode(pnode);
+    }
+    return true;
+}
+
+bool
+CPinyinTrieMaker::write(const char* fileName, CWordEvaluator* psrt,
+                        bool revert_endian)
+{
+    bool suc = false;
+    FILE* fp = fopen(fileName, "wb");
+    if (fp != NULL) {
+        suc = write(fp, psrt, revert_endian);
+        fclose(fp);
+    }
+    return suc;
+}
+
+bool
+CPinyinTrieMaker::write(FILE *fp, CWordEvaluator* psrt, bool revert_endian)
+{
+    bool suc = true;
+    static TWCHAR wbuf[1024];
+
+    std::map<TNode*, unsigned int> nodeOffsetMap;
+
+    unsigned int nWord = m_Lexicon.size();
+    unsigned int nNode = TNode::m_AllNodes.size();
+    unsigned int lexiconOffset;
+    unsigned int offset = sizeof(unsigned int) * 3;
+
+    CNodeList::const_iterator itNode = TNode::m_AllNodes.begin();
+    CNodeList::const_iterator itNodeLast = TNode::m_AllNodes.end();
+    for (; itNode != itNodeLast; ++itNode) {
+        nodeOffsetMap[*itNode] = offset;
+        offset += CPinyinTrie::TNode::size_for((*itNode)->m_Trans.size(),
+                                               (*itNode)->m_WordIdSet.size());
+    }
+    lexiconOffset = offset;
+    CLexicon::const_iterator itWordStr = m_Lexicon.begin();
+    CLexicon::const_iterator itWordStrLast = m_Lexicon.end();
+    for (; itWordStr != itWordStrLast; ++itWordStr) {
+        MBSTOWCS(wbuf, itWordStr->c_str(), 1024);
+        int sz = WCSLEN(wbuf);
+        offset += (sz + 1) * sizeof(TWCHAR);
+    }
+
+    Writer f(fp, revert_endian);
+
+    suc = f.write(nWord);
+    suc = f.write(nNode);
+    suc = f.write(lexiconOffset);
+
+    itNode = TNode::m_AllNodes.begin();
+    itNodeLast = TNode::m_AllNodes.end();
+
+    for (; itNode != itNodeLast && suc; ++itNode) {
+        CPinyinTrie::TNode outNode;
+        TNode *pnode = *itNode;
+
+        outNode.m_nTransfer = pnode->m_Trans.size();
+        outNode.m_nWordId = pnode->m_WordIdSet.size();
+        outNode.m_bFullSyllableTransfer = pnode->m_bFullSyllableTransfer;
+        outNode.m_csLevel = 0;
+
+        CWordSet::const_iterator itId = pnode->m_WordIdSet.begin();
+        CWordSet::const_iterator itIdLast = pnode->m_WordIdSet.end();
+        for (; itId != itIdLast && outNode.m_csLevel < 3; ++itId) {
+            if (outNode.m_csLevel < itId->anony.m_csLevel)
+                outNode.m_csLevel = itId->anony.m_csLevel;
+        }
+
+        suc = f.write(outNode);
+
+        CTrans::const_iterator itTrans = pnode->m_Trans.begin();
+        CTrans::const_iterator itTransLast = pnode->m_Trans.end();
+        for (; itTrans != itTransLast && suc; ++itTrans) {
+            CPinyinTrie::TTransUnit tru;
+            tru.m_Syllable = itTrans->first;
+            tru.m_Offset = nodeOffsetMap[itTrans->second];
+            assert(tru.m_Offset != 0 && tru.m_Offset < lexiconOffset);
+            suc = f.write(tru);
+        }
+
+        CWordVec vec;
+        itId = pnode->m_WordIdSet.begin();
+        itIdLast = pnode->m_WordIdSet.end();
+        for (; itId != itIdLast; ++itId)
+            vec.push_back(TWordInfo(*itId, psrt->getCost(*itId) + itId->anony.m_cost,
+                                    psrt->isSeen(*itId)));
+        std::make_heap(vec.begin(), vec.end());
+        std::sort_heap(vec.begin(), vec.end());
+
+        CWordVec::const_iterator itv = vec.begin();
+        CWordVec::const_iterator itve = vec.end();
+        for (; itv != itve && suc; ++itv) {
+            CPinyinTrie::TWordIdInfo wi;
+            wi.m_id = itv->m_id.anony.m_id;
+            assert(wi.m_id < nWord);
+            wi.m_csLevel = itv->m_id.anony.m_csLevel;
+            wi.m_bSeen = ((itv->m_bSeen) ? (1) : (0));
+            wi.m_cost = itv->m_id.anony.m_cost;
+            suc = f.write(wi);
+        }
+    }
+
+    itWordStr = m_Lexicon.begin();
+    itWordStrLast = m_Lexicon.end();
+    for (; itWordStr != itWordStrLast && suc; ++itWordStr) {
+        MBSTOWCS(wbuf, itWordStr->c_str(), 1024);
+        int sz = WCSLEN(wbuf);
+        suc = f.write(wbuf, (sz + 1));
+    }
+    return suc;
+}
diff --git a/src/lexicon/pytrie_gen.h b/src/lexicon/pytrie_gen.h
new file mode 100644 (file)
index 0000000..28d9b42
--- /dev/null
@@ -0,0 +1,172 @@
+// -*- mode: c++ -*-
+#ifndef _SUNPINYIN_PYTRIE_GEN_H__
+#define _SUNPINYIN_PYTRIE_GEN_H__
+
+#include "../portability.h"
+
+#include <string>
+#include <vector>
+#include <map>
+#include <set>
+#include <list>
+
+#include "pytrie.h"
+
+class CWordEvaluator {
+public:
+    virtual double
+    getCost(unsigned int wid) = 0;
+
+    virtual bool
+    isSeen(unsigned int wid) = 0;
+};
+
+class CPinyinTrieMaker {
+public:
+    class TNode;
+    class TWordInfo;
+
+    union TWordId {
+        unsigned int m_all;
+        struct TAnony {                     //Some compiler do not support anonymous defaultly
+        #ifdef WORDS_BIGENDIAN
+            unsigned m_bHide    : 1;
+            unsigned m_cost     : 5;
+            unsigned m_csLevel  : 2;
+            unsigned m_id       : WORD_ID_WIDTH;
+        #else
+            unsigned m_id       : WORD_ID_WIDTH;
+            unsigned m_csLevel  : 2;
+            unsigned m_cost     : 5;
+            unsigned m_bHide    : 1;
+        #endif
+        } anony;
+
+public:
+        TWordId() : m_all(0) {
+        }
+        TWordId(const TWordId &b) : m_all(b.m_all) {
+        }
+        TWordId(unsigned id,
+                unsigned cost = 0,
+                unsigned hide = 0,
+                unsigned cslvl = 0){
+            anony.m_id = id;
+            anony.m_cost = cost<31? cost: 31;
+            anony.m_bHide = (hide) ? 1 : 0;
+            anony.m_csLevel = cslvl<3? cslvl: 3;
+        }
+
+        bool operator<(const TWordId& b) const
+        { return anony.m_id < b.anony.m_id; }
+
+        bool operator==(const TWordId& b) const
+        { return anony.m_id == b.anony.m_id; }
+
+        operator unsigned int() const
+        { return anony.m_id; }
+    };
+
+    typedef std::set<TWordId>               CWordSet;
+    typedef std::vector<TWordInfo>          CWordVec;
+    typedef std::map<unsigned, TNode*>      CTrans;
+    typedef std::set<TNode*>                CNodeSet;
+    typedef std::list<TNode*>               CNodeList;
+    typedef std::vector<std::string>        CLexicon;
+
+    class TWordInfo {
+public:
+        TWordId m_id;
+        double m_cost;
+        bool m_bSeen;
+
+        TWordInfo(TWordId id = 0, double cost = 0.0, bool seen = false)
+            : m_id(id), m_cost(cost), m_bSeen(seen){
+            if (m_id.anony.m_bHide) {
+                m_bSeen = false;
+            }
+            m_cost = cost + m_id.anony.m_cost;
+        }
+
+        bool operator<(const TWordInfo& b) const {
+            double fa = (m_bSeen) ? (m_cost - 5000.0) : (m_cost);
+            double fb = (b.m_bSeen) ? (b.m_cost - 5000.0) : (b.m_cost);
+            return(fa < fb);
+        }
+    };
+
+    class PNodeSet {
+public:
+        PNodeSet(const CNodeSet *pns) : m_pns(pns) { }
+
+        PNodeSet(const PNodeSet& another) : m_pns(another.m_pns) { }
+
+        const CNodeSet*operator->(void) { return m_pns; }
+
+        const CNodeSet&operator*(void) { return *m_pns; }
+
+        bool
+        operator<(const PNodeSet& another) const;
+
+        bool
+        operator==(const PNodeSet& another) const;
+
+protected:
+        const CNodeSet *    m_pns;
+    };
+
+    typedef std::map<PNodeSet, TNode*>     CStateMap;
+
+    class TNode {
+public:
+        static CNodeList m_AllNodes;
+public:
+        bool m_bExpanded;
+        bool m_bFullSyllableTransfer;
+        CWordSet m_WordIdSet;
+        CTrans m_Trans;
+        CNodeSet m_cmbNodes;
+public:
+        TNode();
+    };
+
+protected:
+    CStateMap m_StateMap;
+    TNode m_RootNode;
+    CLexicon m_Lexicon;
+
+public:
+    CPinyinTrieMaker();
+
+    ~CPinyinTrieMaker() {} //forget this
+
+    bool
+    constructFromLexicon(const char* fileName);
+
+    bool
+    insertFullPinyinPair(const char* pinyin, TWordId wid);
+
+    bool
+    threadNonCompletePinyin(void);
+
+    bool
+    write(const char* fileName, CWordEvaluator* psrt, bool revert_endian);
+
+    bool
+    write(FILE *fp, CWordEvaluator* psrt, bool revert_endian);
+
+protected:
+    TNode*
+    insertTransfer(TNode* pnode, unsigned s);
+
+    TNode*
+    addCombinedTransfers(TNode *pnode, unsigned s, const CNodeSet& nodes);
+
+    void
+    combineInitialTrans(TNode *pnode);
+
+    void
+    expandCombinedNode(TNode *pnode);
+};
+
+#endif
diff --git a/src/lexicon/trie_writer.cpp b/src/lexicon/trie_writer.cpp
new file mode 100644 (file)
index 0000000..7781d9e
--- /dev/null
@@ -0,0 +1,8 @@
+#include "trie_writer.h"
+
+template <>
+bool revert_write<CPinyinTrie::TTransUnit
+                  > (const CPinyinTrie::TTransUnit& t, FILE *fp)
+{
+    return revert_write(t.m_Syllable, fp) && revert_write(t.m_Offset, fp);
+}
diff --git a/src/lexicon/trie_writer.h b/src/lexicon/trie_writer.h
new file mode 100644 (file)
index 0000000..2b9244a
--- /dev/null
@@ -0,0 +1,105 @@
+// -*- mode: c++ -*-
+#ifndef __SUNPINYIN_PYTRIE_WRITER_H__
+#define __SUNPINYIN_PYTRIE_WRITER_H__
+
+#include "writer.h"
+#include "pytrie.h"
+
+template <>
+class OtherEndian<CPinyinTrie::TNode>
+{
+    struct TNode_BE {
+        unsigned m_other      : 5;
+        unsigned m_bFullSyllableTransfer : 1;
+        unsigned m_csLevel    : 2;
+        unsigned m_nTransfer  : 12;
+        unsigned m_nWordId    : 12;
+    };
+
+    struct TNode_LE {
+        unsigned m_nWordId    : 12;
+        unsigned m_nTransfer  : 12;
+        unsigned m_csLevel    : 2;
+        unsigned m_bFullSyllableTransfer : 1;
+        unsigned m_other      : 5;
+    };
+public:
+    DEFINE_OTHER_TYPE(TNode);
+
+    static TargetType create(const CPinyinTrie::TNode& from){
+        TargetType to;
+        to.m_nTransfer = from.m_nTransfer;
+        to.m_nWordId = from.m_nWordId;
+        to.m_bFullSyllableTransfer = from.m_bFullSyllableTransfer;
+        to.m_csLevel = from.m_csLevel;
+        // we don't care about m_other though
+        to.m_other = from.m_other;
+        return to;
+    }
+};
+
+template<>
+class OtherEndian<TSyllable>
+{
+    struct TSyllable_BE {
+        unsigned other    : 12;
+        unsigned initial  : 8;
+        unsigned final    : 8;
+        unsigned tone     : 4;
+    };
+
+    struct TSyllable_LE {
+        unsigned tone     : 4;
+        unsigned final    : 8;
+        unsigned initial  : 8;
+        unsigned other    : 12;
+    };
+
+public:
+    DEFINE_OTHER_TYPE(TSyllable);
+
+    static TargetType create(const TSyllable& from){
+        TargetType to;
+        to.other = from.other;
+        to.initial = from.initial;
+        to.final = from.final;
+        to.tone = from.tone;
+        return to;
+    }
+};
+
+template <>
+class OtherEndian<CPinyinTrie::TWordIdInfo>
+{
+    struct TWordIdInfo_BE {
+        unsigned m_bSeen    : 1;
+        unsigned m_cost     : 5;
+        unsigned m_csLevel  : 2;
+        unsigned m_id       : WORD_ID_WIDTH;
+    };
+
+    struct TWordIdInfo_LE {
+        unsigned m_id       : WORD_ID_WIDTH;
+        unsigned m_csLevel  : 2;
+        unsigned m_cost     : 5;
+        unsigned m_bSeen    : 1;
+    };
+
+public:
+    DEFINE_OTHER_TYPE(TWordIdInfo);
+
+    static TargetType create(const CPinyinTrie::TWordIdInfo& from){
+        TargetType to;
+        to.m_id = from.m_id;
+        to.m_csLevel = from.m_csLevel;
+        to.m_bSeen = from.m_bSeen;
+        to.m_cost = from.m_cost;
+        return to;
+    }
+};
+
+template <>
+bool revert_write<CPinyinTrie::TTransUnit> (const CPinyinTrie::TTransUnit& t,
+                                            FILE *fp);
+
+#endif //__SUNPINYIN_PYTRIE_WRITER_H__
diff --git a/src/pinyin/Makefile.am b/src/pinyin/Makefile.am
new file mode 100755 (executable)
index 0000000..3c84e7e
--- /dev/null
@@ -0,0 +1,46 @@
+## Makefile.am -- Process this file with automake to produce Makefile.in
+## Copyright (C) 2002 James Su
+##
+## This program is free software; you can redistribute it and/or modify
+## it under the terms of the GNU General Public License as published by
+## the Free Software Foundation; either version 2, or (at your option)
+## any later version.
+##
+## This program is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+## GNU General Public License for more details.
+##
+## You should have received a copy of the GNU General Public License
+## along with this program; if not, write to the Free Software
+## Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+
+MAINTAINERCLEANFILES   = Makefile.in
+INCLUDES=-I$(top_srcdir)\
+         -I$(top_srcdir)/src\
+         -I$(top_srcdir)/src/ime-core\
+         -I$(top_srcdir)/src/lexicon\
+         -I$(top_srcdir)/src/pinyin\
+         -I$(top_srcdir)/src/slm
+         
+noinst_HEADERS = datrie.h\
+                     datrie_impl.h\
+                     hunpin_seg.h\
+                     pinyin_data.h\
+                     pinyin_seg.h\
+                     quanpin_trie.h\
+                     segmentor.h\
+                     shuangpin_data.h\
+                     shuangpin_seg.h\
+                     syllable.h
+
+noinst_LTLIBRARIES = libpinyin.la
+libpinyin_la_SOURCES           = pinyin_data.cpp\
+    pinyin_seg.cpp\
+    shuangpin_data.cpp\
+    shuangpin_seg.cpp\
+    hunpin_seg.cpp
+    
+libpinyin_la_CFLAGS = @GLIB_CFLAGS@
+
diff --git a/src/pinyin/datrie.h b/src/pinyin/datrie.h
new file mode 100644 (file)
index 0000000..5d05469
--- /dev/null
@@ -0,0 +1,88 @@
+// -*- mode: c++ -*-
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright (c) 2007 Sun Microsystems, Inc. All Rights Reserved.
+ *
+ * The contents of this file are subject to the terms of either the GNU Lesser
+ * General Public License Version 2.1 only ("LGPL") or the Common Development and
+ * Distribution License ("CDDL")(collectively, the "License"). You may not use this
+ * file except in compliance with the License. You can obtain a copy of the CDDL at
+ * http://www.opensource.org/licenses/cddl1.php and a copy of the LGPLv2.1 at
+ * http://www.opensource.org/licenses/lgpl-license.php. See the License for the
+ * specific language governing permissions and limitations under the License. When
+ * distributing the software, include this License Header Notice in each file and
+ * include the full text of the License in the License file as well as the
+ * following notice:
+ *
+ * NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND DISTRIBUTION LICENSE
+ * (CDDL)
+ * For Covered Software in this distribution, this License shall be governed by the
+ * laws of the State of California (excluding conflict-of-law provisions).
+ * Any litigation relating to this License shall be subject to the jurisdiction of
+ * the Federal Courts of the Northern District of California and the state courts
+ * of the State of California, with venue lying in Santa Clara County, California.
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by only the CDDL or only
+ * the LGPL Version 2.1, indicate your decision by adding "[Contributor]" elects to
+ * include this software in this distribution under the [CDDL or LGPL Version 2.1]
+ * license." If you don't indicate a single choice of license, a recipient has the
+ * option to distribute your version of this file under either the CDDL or the LGPL
+ * Version 2.1, or to extend the choice of license to its licensees as provided
+ * above. However, if you add LGPL Version 2.1 code and therefore, elected the LGPL
+ * Version 2 license, then the option applies only if the new code is made subject
+ * to such option by the copyright holder.
+ */
+
+#ifndef SUNPY_DATRIE_H
+#define SUNPY_DATRIE_H
+
+#include "portability.h"
+
+template <unsigned lower, unsigned upper>
+unsigned character_based_encoder(unsigned ch){
+    int ret = ch - lower + 1;
+    if (ret <= 0) ret = upper + 1;
+    return ret;
+}
+
+typedef unsigned (*encoder_func_ptr)(unsigned ch);
+template <typename T, encoder_func_ptr encoder =
+              character_based_encoder<'a', 'z'> >
+class CDATrie
+{
+private:
+    typedef CDATrie<T> this_type;
+
+public:
+    CDATrie () : m_mem(0), m_len(0), m_base(0), m_check(0), m_value(0) {};
+    CDATrie (T* base, T* check, int* value, unsigned len)
+        : m_mem(0), m_len(len), m_base(base), m_check(check), m_value(value) {};
+
+    ~CDATrie () { free(); }
+
+    bool load(const char* fname);
+    void free();
+
+    int match_longest(const char * str, unsigned &length);
+    int match_longest(wstring wstr, unsigned &length);
+    template <typename InputIterator>
+    int match_longest(InputIterator first, InputIterator last, unsigned &length);
+
+protected:
+    unsigned walk(unsigned s, unsigned ch, int &v);
+
+    char     * m_mem;
+    unsigned m_memSize;
+
+    unsigned m_len;
+    T        * m_base;
+    T        * m_check;
+    int      * m_value;
+};
+
+#include "datrie_impl.h"
+
+#endif /* SUNPY_DATRIE_H */
diff --git a/src/pinyin/datrie_impl.h b/src/pinyin/datrie_impl.h
new file mode 100644 (file)
index 0000000..92fd0b8
--- /dev/null
@@ -0,0 +1,160 @@
+// -*- mode: c++ -*-
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright (c) 2007 Sun Microsystems, Inc. All Rights Reserved.
+ *
+ * The contents of this file are subject to the terms of either the GNU Lesser
+ * General Public License Version 2.1 only ("LGPL") or the Common Development and
+ * Distribution License ("CDDL")(collectively, the "License"). You may not use this
+ * file except in compliance with the License. You can obtain a copy of the CDDL at
+ * http://www.opensource.org/licenses/cddl1.php and a copy of the LGPLv2.1 at
+ * http://www.opensource.org/licenses/lgpl-license.php. See the License for the
+ * specific language governing permissions and limitations under the License. When
+ * distributing the software, include this License Header Notice in each file and
+ * include the full text of the License in the License file as well as the
+ * following notice:
+ *
+ * NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND DISTRIBUTION LICENSE
+ * (CDDL)
+ * For Covered Software in this distribution, this License shall be governed by the
+ * laws of the State of California (excluding conflict-of-law provisions).
+ * Any litigation relating to this License shall be subject to the jurisdiction of
+ * the Federal Courts of the Northern District of California and the state courts
+ * of the State of California, with venue lying in Santa Clara County, California.
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by only the CDDL or only
+ * the LGPL Version 2.1, indicate your decision by adding "[Contributor]" elects to
+ * include this software in this distribution under the [CDDL or LGPL Version 2.1]
+ * license." If you don't indicate a single choice of license, a recipient has the
+ * option to distribute your version of this file under either the CDDL or the LGPL
+ * Version 2.1, or to extend the choice of license to its licensees as provided
+ * above. However, if you add LGPL Version 2.1 code and therefore, elected the LGPL
+ * Version 2 license, then the option applies only if the new code is made subject
+ * to such option by the copyright holder.
+ */
+
+#include <stdio.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifdef HAVE_SYS_MMAN_H
+#include <sys/mman.h>
+#endif
+
+#include "datrie.h"
+
+template <typename T, encoder_func_ptr encoder>
+bool CDATrie<T, encoder>::load(const char * fname){
+    free();
+
+    bool suc = false;
+    int fd = open(fname, O_RDONLY);
+    if (fd == -1) return false;
+
+    m_memSize = lseek(fd, 0, SEEK_END);
+    lseek(fd, 0, SEEK_SET);
+
+#ifdef HAVE_SYS_MMAN_H
+    suc =
+        (m_mem =
+             (char *) mmap(NULL, m_memSize, PROT_READ, MAP_SHARED, fd,
+                           0)) != MAP_FAILED;
+#else
+    suc = (m_mem = new char [m_memSize]) != NULL;
+    suc = suc && (read(fd, m_mem, m_memSize) > 0);
+#endif /* HAVE_SYS_MMAN_H */
+    close(fd);
+
+    if (!suc)
+        return suc;
+
+    m_len = *((unsigned *) m_mem);
+    unsigned short elm_size = *((unsigned short *) (m_mem + sizeof(m_len)));
+    unsigned short has_value =
+        *((unsigned short *) (m_mem + sizeof(m_len) + sizeof(elm_size)));
+
+    if (sizeof(T) != elm_size)
+        return false;
+
+    m_base = (T *) (m_mem + sizeof(m_len) + sizeof(elm_size) + sizeof(has_value));
+    m_check = m_base + m_len;
+    m_value = has_value ? (int *) (m_check + m_len) : NULL;
+
+    return suc;
+}
+
+template <typename T, encoder_func_ptr encoder>
+void CDATrie<T, encoder>::free(){
+    if (m_mem) {
+#ifdef HAVE_SYS_MMAN_H
+        munmap(m_mem, m_memSize);
+#else
+        delete [] m_mem;
+#endif
+        m_mem = NULL;
+    }
+
+    m_len = 0;
+    m_base = m_check = NULL;
+    m_value = NULL;
+}
+
+template <typename T, encoder_func_ptr encoder>
+unsigned CDATrie<T, encoder>::walk(unsigned s, unsigned ch, int &v){
+    unsigned c = encoder(ch);
+    unsigned t = abs(m_base[s]) + c;
+
+    if (t < m_len && m_check[t] == (T) s && m_base[t]) {
+        if (m_value)
+            v = m_value[t];
+        else
+            v = m_base[t] < 0 ? -1 : 0;
+
+        return t;
+    }
+
+    v = 0;
+    return 0;
+}
+
+template <typename T, encoder_func_ptr encoder>
+int CDATrie<T, encoder>::match_longest(const char *str, unsigned &length){
+    return match_longest(str, str + strlen(str), length);
+}
+
+template <typename T, encoder_func_ptr encoder>
+int CDATrie<T, encoder>::match_longest(wstring wstr, unsigned &length){
+    return match_longest(wstr.begin(), wstr.end(), length);
+}
+
+template <typename T, encoder_func_ptr encoder>
+template <typename InputIterator>
+int CDATrie<T, encoder>::match_longest(InputIterator first,
+                                       InputIterator last,
+                                       unsigned &length){
+    int l = 0, ret_v = 0, curr_state = 0;
+    length = 0;
+
+    for (; first != last; ++first) {
+        unsigned ch = *first;
+        int val;
+        curr_state = walk(curr_state, ch, val);
+        if (!curr_state) break;
+
+        l += 1;
+        if (val) {
+            length = l;
+            ret_v = val;
+        }
+    }
+
+    return ret_v;
+}
diff --git a/src/pinyin/hunpin_seg.cpp b/src/pinyin/hunpin_seg.cpp
new file mode 100644 (file)
index 0000000..0965d98
--- /dev/null
@@ -0,0 +1,383 @@
+/*
+ *  hunpin_seg.cpp
+ *  FIT
+ *
+ *  Created by cererd.long on 10-10-8.
+ *  Copyright 2010 __MyCompanyName__. All rights reserved.
+ *
+ */
+
+#include "hunpin_seg.h"
+#include <cassert>
+#include <functional>
+#include <algorithm>
+#include "pinyin_seg.h"
+#include "quanpin_trie.h"
+
+
+CShuangpinData CHunpinSegmentor::s_shpData;
+
+CHunpinSegmentor::CHunpinSegmentor (EShuangpinType shpType)
+    : m_pGetFuzzySyllablesOp(NULL),
+      m_pytrie(base, check, value, sizeof(base) / sizeof(*base)),
+      m_updatedFrom(0)
+{
+    m_segs.reserve(32);
+    s_shpData.setShuangpinType(shpType);
+}
+
+
+int
+CHunpinSegmentor::_encode(const char* buf, int ret)
+{
+    CMappedYin syls;
+    syls.reserve(8);
+    s_shpData.getMapString(buf, syls);
+    if (syls.empty())
+        return -1;
+
+
+    CMappedYin::const_iterator iter = syls.begin();
+    CMappedYin::const_iterator iter_end = syls.end();
+
+    m_segs.push_back(TSegment(0, 0, 1, IPySegmentor::SYLLABLE));
+    TSegment &s = m_segs.back();
+
+    s.m_len = 2;
+    s.m_start = ret;
+    s.m_syllables.clear();
+    s.m_type = IPySegmentor::SYLLABLE;
+    for (; iter != iter_end; iter++) {
+        s.m_syllables.push_back(s_shpData.encodeSyllable(iter->c_str()));
+    }
+
+    return s.m_start;
+}
+
+int
+CHunpinSegmentor::_encode(const char* buf)
+{
+    CMappedYin syls;
+    syls.reserve(8);
+    s_shpData.getMapString(buf, syls);
+    if (syls.empty())
+        return -1;
+
+    CMappedYin::const_iterator iter = syls.begin();
+    CMappedYin::const_iterator iter_end = syls.end();
+
+    TSegment &s = m_segs.back();
+    s.m_len = 2;
+    s.m_start = m_pystr.size() - s.m_len;
+    s.m_syllables.clear();
+    s.m_type = IPySegmentor::SYLLABLE;
+    for (; iter != iter_end; iter++) {
+        s.m_syllables.push_back(s_shpData.encodeSyllable(iter->c_str()));
+    }
+
+    return s.m_start;
+}
+
+bool
+CHunpinSegmentor::load(const char * pyTrieFileName)
+{
+    return m_pytrie.load(pyTrieFileName);
+}
+
+#if 0
+void
+print_pystr(const std::string pystr)
+{
+    for (const char* c = pystr.c_str();
+         c != pystr.c_str() + pystr.length();
+         ++c) {
+        printf("%c", *c & 0x7f);
+    }
+    printf("<\n");
+}
+#endif
+
+unsigned
+CHunpinSegmentor::push(unsigned ch)
+{
+    m_inputBuf.push_back(ch);
+
+    m_updatedFrom = _push(ch);
+
+
+    return m_updatedFrom;
+}
+
+unsigned
+CHunpinSegmentor::pop()
+{
+    if (m_pystr.empty())
+        return m_updatedFrom = 0;
+
+    unsigned size = m_inputBuf.size();
+    m_inputBuf.resize(size - 1);
+    m_pystr.resize(size - 1);
+
+    unsigned l = m_segs.back().m_len;
+    m_segs.pop_back();
+
+    if (l == 1)
+        return m_updatedFrom = size - 1;
+
+    std::string new_pystr = m_pystr.substr(size - l);
+    m_pystr.resize(size - l);
+
+    m_updatedFrom = _updateWith(new_pystr);
+
+    return m_updatedFrom;
+}
+
+unsigned
+CHunpinSegmentor::insertAt(unsigned idx, unsigned ch)
+{
+    unsigned i, j;
+    _locateSegment(idx, i, j);
+
+    m_inputBuf.insert(idx, 1, ch);
+    m_pystr.insert(idx, 1, ch);
+
+    std::string new_pystr = m_pystr.substr(i);
+    m_pystr.resize(i);
+    m_segs.erase(m_segs.begin() + j, m_segs.end());
+
+    m_updatedFrom = _updateWith(new_pystr);
+
+    return m_updatedFrom;
+}
+
+unsigned
+CHunpinSegmentor::deleteAt(unsigned idx, bool backward)
+{
+    unsigned i, j;
+    if (!backward) idx += 1;
+    _locateSegment(idx, i, j);
+
+    m_inputBuf.erase(idx, 1);
+    m_pystr.erase(idx, 1);
+
+    std::string new_pystr = m_pystr.substr(i);
+    m_pystr.resize(i);
+    m_segs.erase(m_segs.begin() + j, m_segs.end());
+
+    m_updatedFrom = _updateWith(new_pystr);
+
+    return m_updatedFrom;
+}
+
+unsigned
+CHunpinSegmentor::clear(unsigned from)
+{
+    m_inputBuf.resize(from);
+    return _clear(from);
+}
+
+unsigned
+CHunpinSegmentor::_clear(unsigned from)
+{
+    unsigned i, j;
+    _locateSegment(from, i, j);
+
+
+    std::string new_pystr = m_pystr.substr(i, from - i);
+    m_pystr.resize(i);
+    m_segs.erase(m_segs.begin() + j, m_segs.end());
+
+    m_updatedFrom = _updateWith(new_pystr, from);
+
+    return m_updatedFrom;
+}
+
+void
+CHunpinSegmentor::_locateSegment(unsigned idx,
+                                 unsigned &strIdx,
+                                 unsigned &segIdx)
+{
+    strIdx = segIdx = 0;
+
+    TSegmentVec::iterator it = m_segs.begin();
+    TSegmentVec::iterator ite = m_segs.end();
+
+    for (; it != ite; ++it) {
+        if (strIdx + (*it).m_len > idx)
+            break;
+
+        strIdx += (*it).m_len;
+        segIdx += 1;
+    }
+}
+
+// TOTEST
+unsigned
+CHunpinSegmentor::_push(unsigned ch)
+{
+    m_pystr.push_back(ch);
+
+    TSegmentVec::iterator ite = m_segs.size() > 0 ? m_segs.end() -
+                                1 : m_segs.begin() - 1;
+    const unsigned maxStringCount = 6;
+    unsigned syllableCount = 0;
+    unsigned stringCount = 0;
+    for (; ite != m_segs.begin() - 1; ite--) {
+        stringCount += (*ite).m_len;
+        syllableCount++;
+        if (stringCount > maxStringCount) {
+            syllableCount--;
+            break;
+        }
+    }
+
+    unsigned strlen = m_pystr.size();
+    unsigned ret;
+
+    for (int index = syllableCount; index >= 0; index--) {
+        TSegmentVec::iterator it = m_segs.end() - index;
+        unsigned tmpl;
+        unsigned v;
+        if (index != 0) {
+            if ((strlen - (*it).m_start) == 2) {
+                char buf[4];
+                sprintf(buf, "%c%c", m_pystr[(*it).m_start],
+                        m_pystr[(*it).m_start + 1]);
+                int startFrom = _encode(buf);
+                if (startFrom >= 0) break;
+            }
+
+            v = m_pytrie.match_longest(m_pystr.rbegin(),
+                                       m_pystr.rbegin() + strlen -
+                                       (*it).m_start, tmpl);
+
+            if (tmpl == (strlen - (*it).m_start)) {
+                TSegmentVec new_segs(1, TSegment(v, (*it).m_start, tmpl));
+                m_segs.erase(m_segs.end() - index, m_segs.end());
+                std::copy(new_segs.rbegin(), new_segs.rend(),
+                          back_inserter(m_segs));
+
+                break;
+            }
+        } else {
+            v = m_pytrie.match_longest(m_pystr.rbegin(),
+                                       m_pystr.rbegin() + 1, tmpl);
+            if (tmpl == 0) {
+                IPySegmentor::ESegmentType seg_type;
+                if (ch == '\'' && m_inputBuf.size() > 1) {
+                    seg_type = IPySegmentor::SYLLABLE_SEP;
+                } else if (islower(ch)) {
+                    seg_type = IPySegmentor::INVALID;
+                } else {
+                    seg_type = IPySegmentor::STRING;
+                }
+                ret = m_pystr.size() - 1;
+                m_segs.push_back(TSegment(ch, ret, 1, seg_type));
+            } else {
+                ret = m_pystr.size() - 1;
+                m_segs.push_back(TSegment(v, ret, 1));
+            }
+        }
+    }
+
+    TSegment &last_seg = m_segs.back();
+    if (m_pGetFuzzySyllablesOp && m_pGetFuzzySyllablesOp->isEnabled())
+        if (m_segs.back().m_type == SYLLABLE)
+            _addFuzzySyllables(last_seg);
+
+    return last_seg.m_start;
+}
+
+/*
+   //慢算法
+   unsigned CHunpinSegmentor::_push (unsigned ch)
+   {
+        printf("using hunpin_seg");
+        //translation for positive match arithmetic
+        //m_segs.erase (m_segs.begin(), m_segs.end());
+        m_segs.clear();
+        m_pystr.push_back (ch);
+        unsigned strlen = m_pystr.size();
+        unsigned maxlen = 6;
+        unsigned _start = 0;
+
+        while (_start < strlen) {
+                for (unsigned _tn = (maxlen+_start) <= strlen ? maxlen : (strlen - _start) ; _tn > 0 ; _tn--) {
+
+
+                        if (_tn == 2) {
+                                char buf[4];
+                                //printf("\nout,shuang pin output,char1:%c,char2:%c\n",m_pystr[_start],m_pystr[_start+1]);
+
+                                sprintf(buf, "%c%c", m_pystr[_start], m_pystr[_start+1]);
+                                int startFrom = _encode(buf,_start);
+                                if(startFrom >= 0)  {
+                                        //printf("\nin,shuang pin output,char1:%c,char2:%c\n",m_pystr[_start],m_pystr[_start+1]);
+                                        _start += 2;
+                                        break;
+                                }
+                        }
+
+
+                        unsigned tmpl;
+                        int v  = m_pytrie.match_longest ((m_pystr.rbegin() + strlen - _start - _tn), (m_pystr.rbegin() + strlen - _start), tmpl);
+
+                        //printf("\n input match len is %d,size is %d,_start is %d ,end is %d ,start char is %c,end char is %c\n",tmpl,strlen,_start,_start + _tn,m_pystr[_start],m_pystr[_start+_tn-1]);
+
+                        if(tmpl == _tn) {
+                                m_segs.push_back (TSegment (v, _start, _tn));
+                                _start += _tn;
+                                break;
+                        }
+                        else if(_tn == 1 && tmpl == 0) {
+                                IPySegmentor::ESegmentType seg_type;
+                                if (m_pystr[_start] == '\'' && m_inputBuf.size() > 1)
+                                        seg_type = IPySegmentor::SYLLABLE_SEP;
+                                else if (islower (m_pystr[_start]))
+                                        seg_type = IPySegmentor::INVALID;
+                                else
+                                        seg_type = IPySegmentor::STRING;
+
+                                m_segs.push_back (TSegment (m_pystr[_start], _start, 1, seg_type));
+                                _start += 1;
+                                break;
+                        }
+                }
+        }
+
+        TSegment &last_seg = m_segs.back();
+        if (m_pGetFuzzySyllablesOp && m_pGetFuzzySyllablesOp->isEnabled())
+        if ( m_segs.back().m_type == SYLLABLE)
+            _addFuzzySyllables (last_seg);
+
+        return last_seg.m_start;
+   }
+ */
+
+void
+CHunpinSegmentor::_addFuzzySyllables(TSegment& seg)
+{
+    assert(seg.m_type == SYLLABLE);
+
+    seg.m_fuzzy_syllables.clear();
+
+    CSyllables fuzzy_set = (*m_pGetFuzzySyllablesOp)(seg.m_syllables.front());
+    CSyllables::const_iterator it = fuzzy_set.begin();
+    CSyllables::const_iterator ite = fuzzy_set.end();
+
+    for (; it != ite; ++it)
+        seg.m_fuzzy_syllables.push_back(*it);
+}
+
+unsigned
+CHunpinSegmentor::_updateWith(const std::string& new_pystr, unsigned from)
+{
+    unsigned minUpdatedFrom = from;
+    std::string::const_iterator it = new_pystr.begin();
+    for (; it != new_pystr.end(); ++it) {
+        unsigned updatedFrom = _push(*it & 0x7f);
+
+        if (updatedFrom < minUpdatedFrom) minUpdatedFrom = updatedFrom;
+    }
+    return minUpdatedFrom;
+}
diff --git a/src/pinyin/hunpin_seg.h b/src/pinyin/hunpin_seg.h
new file mode 100644 (file)
index 0000000..46750eb
--- /dev/null
@@ -0,0 +1,79 @@
+// -*- mode: c++ -*-
+/*
+ *  hunpin_seg.h
+ *  FIT
+ *
+ *  Created by cererd.long on 10-10-8.
+ *  Copyright 2010 __MyCompanyName__. All rights reserved.
+ *
+ */
+
+
+#ifndef SUNPY_HUNPIN_SEG_H
+#define SUNPY_HUNPIN_SEG_H
+
+
+
+
+#include "datrie.h"
+#include "portability.h"
+#include "shuangpin_data.h"
+#include "segmentor.h"
+#include "pinyin_data.h"
+#include <vector>
+#include <limits.h>
+
+class CHunpinSegmentor : public IPySegmentor
+{
+public:
+    CHunpinSegmentor (EShuangpinType shpType);
+
+    virtual TSegmentVec& getSegments(bool) { return m_segs; }
+
+
+    virtual const wstring& getInputBuffer() { return m_inputBuf; }
+
+    virtual const char* getSylSeps() { return "'"; }
+
+    virtual unsigned push(unsigned ch);
+    virtual unsigned pop();
+    virtual unsigned insertAt(unsigned idx, unsigned ch);
+    virtual unsigned deleteAt(unsigned idx, bool backward = true);
+    virtual unsigned clear(unsigned from = 0);
+
+    virtual unsigned updatedFrom() { return m_updatedFrom; }
+
+    bool load(const char * pyTrieFileName);
+
+    void setGetFuzzySyllablesOp(CGetFuzzySyllablesOp<CPinyinData> *op) {
+        m_pGetFuzzySyllablesOp = op; }
+
+
+
+
+private:
+    inline unsigned _push(unsigned ch);
+    inline unsigned _clear(unsigned from);
+    inline void _addFuzzySyllables(TSegment &seg);
+    inline unsigned _updateWith(const std::string& new_pystr,
+                                unsigned from = UINT_MAX);
+    inline void _locateSegment(unsigned idx, unsigned &strIdx, unsigned &segIdx);
+    int _encode(const char* buf, int ret);
+    int _encode(const char* buf);
+
+
+    CGetFuzzySyllablesOp<CPinyinData>  *m_pGetFuzzySyllablesOp;
+
+
+    CDATrie<short>                      m_pytrie;
+    std::string m_pystr;
+    wstring m_inputBuf;
+    TSegmentVec m_segs;
+    TSegmentVec m_fuzzy_segs;
+    TSegmentVec m_merged_segs;
+
+    unsigned m_updatedFrom;
+    static CShuangpinData s_shpData;
+};
+
+#endif /* SUNPY_PINYIN_SEG_H */
diff --git a/src/pinyin/pinyin_data.cpp b/src/pinyin/pinyin_data.cpp
new file mode 100644 (file)
index 0000000..124771a
--- /dev/null
@@ -0,0 +1,801 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright (c) 2007 Sun Microsystems, Inc. All Rights Reserved.
+ *
+ * The contents of this file are subject to the terms of either the GNU Lesser
+ * General Public License Version 2.1 only ("LGPL") or the Common Development and
+ * Distribution License ("CDDL")(collectively, the "License"). You may not use this
+ * file except in compliance with the License. You can obtain a copy of the CDDL at
+ * http://www.opensource.org/licenses/cddl1.php and a copy of the LGPLv2.1 at
+ * http://www.opensource.org/licenses/lgpl-license.php. See the License for the
+ * specific language governing permissions and limitations under the License. When
+ * distributing the software, include this License Header Notice in each file and
+ * include the full text of the License in the License file as well as the
+ * following notice:
+ *
+ * NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND DISTRIBUTION LICENSE
+ * (CDDL)
+ * For Covered Software in this distribution, this License shall be governed by the
+ * laws of the State of California (excluding conflict-of-law provisions).
+ * Any litigation relating to this License shall be subject to the jurisdiction of
+ * the Federal Courts of the Northern District of California and the state courts
+ * of the State of California, with venue lying in Santa Clara County, California.
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by only the CDDL or only
+ * the LGPL Version 2.1, indicate your decision by adding "[Contributor]" elects to
+ * include this software in this distribution under the [CDDL or LGPL Version 2.1]
+ * license." If you don't indicate a single choice of license, a recipient has the
+ * option to distribute your version of this file under either the CDDL or the LGPL
+ * Version 2.1, or to extend the choice of license to its licensees as provided
+ * above. However, if you add LGPL Version 2.1 code and therefore, elected the LGPL
+ * Version 2 license, then the option applies only if the new code is made subject
+ * to such option by the copyright holder.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "pinyin_data.h"
+
+static const char *initials[] =
+{ "", "b", "p", "m", "f", "d", "t", "n", "l", "g", "k", "h", "j", "q", "x",
+  "zh",
+  "ch", "sh", "r", "z", "c", "s", "y", "w", };
+static const unsigned num_initials = sizeof(initials) / sizeof(*initials);
+
+static const char *finals[] =
+{ "", "a", "o", "e", "ai", "ei", "ao", "ou", "an", "en", "ang", "eng", "er",
+  "i",
+  "ia", "ie", "iao", "iu", "ian", "in", "iang", "ing", "u", "ua", "uo", "uai",
+  "ui", "uan", "un", "uang", "ong", "v", "ue", "iong", };
+static const unsigned num_finals = sizeof(finals) / sizeof(*finals);
+
+static const char *fuzzy_finals[] =
+{ "ia", "iao", "ian", "iang", "ie", "ua", "uai", "uan", "uang", "ue" };
+static const unsigned num_fuzzy_finals = sizeof(fuzzy_finals) /
+                                         sizeof(*fuzzy_finals);
+
+static const unsigned fuzzy_finals_map[] = {
+    0x0e, 0x10, 1,                         /* ia   -> a    len 1 */
+    0x10, 0x60, 2,                         /* iao  -> ao   len 2 */
+    0x12, 0x80, 2,                         /* ian  -> an   len 2 */
+    0x14, 0xa0, 3,                         /* iang -> ang  len 3 */
+    0x0f, 0x30, 1,                         /* ie   -> e    len 1 */
+    0x17, 0x10, 1,                         /* ua   -> a    len 1 */
+    0x19, 0x40, 2,                         /* uai  -> ai   len 2 */
+    0x1b, 0x80, 2,                         /* uan  -> an   len 2 */
+    0x1d, 0xa0, 3,                         /* uang -> ang  len 3 */
+    0x20, 0x30, 1,                         /* ue   -> e    len 1 */
+};
+
+static const unsigned fuzzy_pre_syllables [] = {
+    0x0d0e0, 'n', 0x0d120,                 /* qian */
+    0x09080, 'g', 0x090a0,                 /* gang */
+    0x080e0, 'n', 0x08120,                 /* lian */
+    0x15090, 'g', 0x150b0,                 /* seng */
+    0x04010, 'n', 0x04080,                 /* fan */
+    0x10030, 'n', 0x10090,                 /* chen */
+    0x050e0, 'n', 0x05120,                 /* dian */
+    0x15160, 'n', 0x151c0,                 /* sun */
+    0x07080, 'g', 0x070a0,                 /* nang */
+    0x0a160, 'n', 0x0a1c0,                 /* kun */
+    0x05030, 'n', 0x05090,                 /* den */
+    0x07090, 'g', 0x070b0,                 /* neng */
+    0x03030, 'n', 0x03090,                 /* men */
+    0x09090, 'g', 0x090b0,                 /* geng */
+    0x10080, 'g', 0x100a0,                 /* chang */
+    0x0f010, 'n', 0x0f080,                 /* zhan */
+    0x14010, 'n', 0x14080,                 /* can */
+    0x07130, 'g', 0x07150,                 /* ning */
+    0x17080, 'g', 0x170a0,                 /* wang */
+    0x01090, 'g', 0x010b0,                 /* beng */
+    0x0f1b0, 'g', 0x0f1d0,                 /* zhuang */
+    0x06010, 'n', 0x06080,                 /* tan */
+    0x00090, 'g', 0x000b0,                 /* eng */
+    0x0f080, 'g', 0x0f0a0,                 /* zhang */
+    0x02130, 'g', 0x02150,                 /* ping */
+    0x08010, 'n', 0x08080,                 /* lan */
+    0x0e160, 'n', 0x0e1c0,                 /* xun */
+    0x03010, 'n', 0x03080,                 /* man */
+    0x0c120, 'g', 0x0c140,                 /* jiang */
+    0x0a1b0, 'g', 0x0a1d0,                 /* kuang */
+    0x01130, 'g', 0x01150,                 /* bing */
+    0x13010, 'n', 0x13080,                 /* zan */
+    0x13030, 'n', 0x13090,                 /* zen */
+    0x02080, 'g', 0x020a0,                 /* pang */
+    0x0c0d0, 'n', 0x0c130,                 /* jin */
+    0x14030, 'n', 0x14090,                 /* cen */
+    0x05010, 'n', 0x05080,                 /* dan */
+    0x0f030, 'n', 0x0f090,                 /* zhen */
+    0x01080, 'g', 0x010a0,                 /* bang */
+    0x17090, 'g', 0x170b0,                 /* weng */
+    0x00030, 'n', 0x00090,                 /* en */
+    0x0a080, 'g', 0x0a0a0,                 /* kang */
+    0x09160, 'n', 0x091c0,                 /* gun */
+    0x00030, 'r', 0x000c0,                 /* er */
+    0x0a090, 'g', 0x0a0b0,                 /* keng */
+    0x15080, 'g', 0x150a0,                 /* sang */
+    0x12030, 'n', 0x12090,                 /* ren */
+    0x11160, 'n', 0x111c0,                 /* shun */
+    0x0d160, 'n', 0x0d1c0,                 /* qun */
+    0x16160, 'n', 0x161c0,                 /* yun */
+    0x0e120, 'g', 0x0e140,                 /* xiang */
+    0x12080, 'g', 0x120a0,                 /* rang */
+    0x09170, 'n', 0x091b0,                 /* guan */
+    0x16130, 'g', 0x16150,                 /* ying */
+    0x0a170, 'n', 0x0a1b0,                 /* kuan */
+    0x10010, 'n', 0x10080,                 /* chan */
+    0x160d0, 'n', 0x16130,                 /* yin */
+    0x0e0d0, 'n', 0x0e130,                 /* xin */
+    0x07120, 'g', 0x07140,                 /* niang */
+    0x0b160, 'n', 0x0b1c0,                 /* hun */
+    0x11170, 'n', 0x111b0,                 /* shuan */
+    0x05080, 'g', 0x050a0,                 /* dang */
+    0x00080, 'g', 0x000a0,                 /* ang */
+    0x15010, 'n', 0x15080,                 /* san */
+    0x12090, 'g', 0x120b0,                 /* reng */
+    0x03130, 'g', 0x03150,                 /* ming */
+    0x030d0, 'n', 0x03130,                 /* min */
+    0x07030, 'n', 0x07090,                 /* nen */
+    0x0a010, 'n', 0x0a080,                 /* kan */
+    0x16080, 'g', 0x160a0,                 /* yang */
+    0x05090, 'g', 0x050b0,                 /* deng */
+    0x101b0, 'g', 0x101d0,                 /* chuang */
+    0x04090, 'g', 0x040b0,                 /* feng */
+    0x03090, 'g', 0x030b0,                 /* meng */
+    0x10090, 'g', 0x100b0,                 /* cheng */
+    0x09030, 'n', 0x09090,                 /* gen */
+    0x01010, 'n', 0x01080,                 /* ban */
+    0x07160, 'n', 0x071c0,                 /* nun */
+    0x15030, 'n', 0x15090,                 /* sen */
+    0x04080, 'g', 0x040a0,                 /* fang */
+    0x08160, 'n', 0x081c0,                 /* lun */
+    0x0a030, 'n', 0x0a090,                 /* ken */
+    0x0b1b0, 'g', 0x0b1d0,                 /* huang */
+    0x03080, 'g', 0x030a0,                 /* mang */
+    0x06160, 'n', 0x061c0,                 /* tun */
+    0x0d0d0, 'n', 0x0d130,                 /* qin */
+    0x02090, 'g', 0x020b0,                 /* peng */
+    0x05160, 'n', 0x051c0,                 /* dun */
+    0x10160, 'n', 0x101c0,                 /* chun */
+    0x09010, 'n', 0x09080,                 /* gan */
+    0x13090, 'g', 0x130b0,                 /* zeng */
+    0x06080, 'g', 0x060a0,                 /* tang */
+    0x14080, 'g', 0x140a0,                 /* cang */
+    0x0b090, 'g', 0x0b0b0,                 /* heng */
+    0x0e0e0, 'n', 0x0e120,                 /* xian */
+    0x0f160, 'n', 0x0f1c0,                 /* zhun */
+    0x111b0, 'g', 0x111d0,                 /* shuang */
+    0x11010, 'n', 0x11080,                 /* shan */
+    0x02010, 'n', 0x02080,                 /* pan */
+    0x070d0, 'n', 0x07130,                 /* nin */
+    0x0b080, 'g', 0x0b0a0,                 /* hang */
+    0x0f170, 'n', 0x0f1b0,                 /* zhuan */
+    0x080d0, 'n', 0x08130,                 /* lin */
+    0x091b0, 'g', 0x091d0,                 /* guang */
+    0x0b010, 'n', 0x0b080,                 /* han */
+    0x14160, 'n', 0x141c0,                 /* cun */
+    0x010d0, 'n', 0x01130,                 /* bin */
+    0x11030, 'n', 0x11090,                 /* shen */
+    0x0e130, 'g', 0x0e150,                 /* xing */
+    0x0d120, 'g', 0x0d140,                 /* qiang */
+    0x12160, 'n', 0x121c0,                 /* run */
+    0x11090, 'g', 0x110b0,                 /* sheng */
+    0x10170, 'n', 0x101b0,                 /* chuan */
+    0x0d130, 'g', 0x0d150,                 /* qing */
+    0x0c0e0, 'n', 0x0c120,                 /* jian */
+    0x17010, 'n', 0x17080,                 /* wan */
+    0x0c130, 'g', 0x0c150,                 /* jing */
+    0x16010, 'n', 0x16080,                 /* yan */
+    0x08120, 'g', 0x08140,                 /* liang */
+    0x0b170, 'n', 0x0b1b0,                 /* huan */
+    0x0b030, 'n', 0x0b090,                 /* hen */
+    0x11080, 'g', 0x110a0,                 /* shang */
+    0x0c160, 'n', 0x0c1c0,                 /* jun */
+    0x08130, 'g', 0x08150,                 /* ling */
+    0x14090, 'g', 0x140b0,                 /* ceng */
+    0x020d0, 'n', 0x02130,                 /* pin */
+    0x00010, 'n', 0x00080,                 /* an */
+    0x13080, 'g', 0x130a0,                 /* zang */
+    0x07010, 'n', 0x07080,                 /* nan */
+    0x0f090, 'g', 0x0f0b0,                 /* zheng */
+    0x13160, 'n', 0x131c0,                 /* zun */
+    0x08080, 'g', 0x080a0,                 /* lang */
+    0x0,
+};
+
+static const unsigned fuzzy_pro_syllables [] = {
+    0x09030, 'g', 0x00030,                 /* ge */
+    0x090a0, 'g', 0x000a0,                 /* gang */
+    0x09010, 'g', 0x00010,                 /* ga */
+    0x12070, 'r', 0x00070,                 /* rou */
+    0x07050, 'n', 0x00050,                 /* nei */
+    0x070a0, 'n', 0x000a0,                 /* nang */
+    0x070b0, 'n', 0x000b0,                 /* neng */
+    0x090b0, 'g', 0x000b0,                 /* geng */
+    0x07070, 'n', 0x00070,                 /* nou */
+    0x12030, 'r', 0x00030,                 /* re */
+    0x12090, 'r', 0x00090,                 /* ren */
+    0x09070, 'g', 0x00070,                 /* gou */
+    0x120a0, 'r', 0x000a0,                 /* rang */
+    0x120b0, 'r', 0x000b0,                 /* reng */
+    0x12080, 'r', 0x00080,                 /* ran */
+    0x12060, 'r', 0x00060,                 /* rao */
+    0x07090, 'n', 0x00090,                 /* nen */
+    0x09050, 'g', 0x00050,                 /* gei */
+    0x09090, 'g', 0x00090,                 /* gen */
+    0x09060, 'g', 0x00060,                 /* gao */
+    0x09080, 'g', 0x00080,                 /* gan */
+    0x09040, 'g', 0x00040,                 /* gai */
+    0x07060, 'n', 0x00060,                 /* nao */
+    0x07010, 'n', 0x00010,                 /* na */
+    0x07040, 'n', 0x00040,                 /* nai */
+    0x07080, 'n', 0x00080,                 /* nan */
+    0x07030, 'n', 0x00030,                 /* ne */
+    0x0,
+};
+
+static const char * fuzzy_pairs[] = {
+    "z", "zh",
+    "c", "ch",
+    "s", "sh",
+    "an", "ang",
+    "on", "ong",
+    "en", "eng",
+    "in", "ing",
+    "eng", "ong",
+    "ian", "iang",
+    "uan", "uang",
+    "l", "n",
+    "f", "h",
+    "r", "l",
+    "k", "g",
+};
+static const unsigned num_fuzzy_pairs = sizeof(fuzzy_pairs) /
+                                        sizeof(*fuzzy_pairs) / 2;
+
+static const char * auto_correction_pairs[] = {
+    "ign", "ing",
+    "img", "ing",
+    "uei", "ui",
+    "uen", "un",
+    "iou", "iu",
+};
+static const unsigned num_auto_correction_pairs =
+    sizeof(auto_correction_pairs) / sizeof(*auto_correction_pairs) / 2;
+
+static const TPyTabEntry
+    pinyin_table[] = {
+    { "a", 0x00010 },
+    { "ai", 0x00040 },
+    { "an", 0x00080 },
+    { "ang", 0x000a0 },
+    { "ao", 0x00060 },
+    { "b", 0x01000 },
+    { "ba", 0x01010 },
+    { "bai", 0x01040 },
+    { "ban", 0x01080 },
+    { "bang", 0x010a0 },
+    { "bao", 0x01060 },
+    { "bei", 0x01050 },
+    { "ben", 0x01090 },
+    { "beng", 0x010b0 },
+    { "bi", 0x010d0 },
+    { "bian", 0x01120 },
+    { "biao", 0x01100 },
+    { "bie", 0x010f0 },
+    { "bin", 0x01130 },
+    { "bing", 0x01150 },
+    { "bo", 0x01020 },
+    { "bu", 0x01160 },
+    { "c", 0x14000 },
+    { "ca", 0x14010 },
+    { "cai", 0x14040 },
+    { "can", 0x14080 },
+    { "cang", 0x140a0 },
+    { "cao", 0x14060 },
+    { "ce", 0x14030 },
+    { "cei", 0x14050 },
+    { "cen", 0x14090 },
+    { "ceng", 0x140b0 },
+    { "ch", 0x10000 },
+    { "cha", 0x10010 },
+    { "chai", 0x10040 },
+    { "chan", 0x10080 },
+    { "chang", 0x100a0 },
+    { "chao", 0x10060 },
+    { "che", 0x10030 },
+    { "chen", 0x10090 },
+    { "cheng", 0x100b0 },
+    { "chi", 0x100d0 },
+    { "chong", 0x101e0 },
+    { "chou", 0x10070 },
+    { "chu", 0x10160 },
+    { "chua", 0x10170 },
+    { "chuai", 0x10190 },
+    { "chuan", 0x101b0 },
+    { "chuang", 0x101d0 },
+    { "chui", 0x101a0 },
+    { "chun", 0x101c0 },
+    { "chuo", 0x10180 },
+    { "ci", 0x140d0 },
+    { "cong", 0x141e0 },
+    { "cou", 0x14070 },
+    { "cu", 0x14160 },
+    { "cuan", 0x141b0 },
+    { "cui", 0x141a0 },
+    { "cun", 0x141c0 },
+    { "cuo", 0x14180 },
+    { "d", 0x05000 },
+    { "da", 0x05010 },
+    { "dai", 0x05040 },
+    { "dan", 0x05080 },
+    { "dang", 0x050a0 },
+    { "dao", 0x05060 },
+    { "de", 0x05030 },
+    { "dei", 0x05050 },
+    { "den", 0x05090 },
+    { "deng", 0x050b0 },
+    { "di", 0x050d0 },
+    { "dia", 0x050e0 },
+    { "dian", 0x05120 },
+    { "diao", 0x05100 },
+    { "die", 0x050f0 },
+    { "ding", 0x05150 },
+    { "diu", 0x05110 },
+    { "dong", 0x051e0 },
+    { "dou", 0x05070 },
+    { "du", 0x05160 },
+    { "duan", 0x051b0 },
+    { "dui", 0x051a0 },
+    { "dun", 0x051c0 },
+    { "duo", 0x05180 },
+    { "e", 0x00030 },
+    { "ei", 0x00050 },
+    { "en", 0x00090 },
+    { "eng", 0x000b0 },
+    { "er", 0x000c0 },
+    { "f", 0x04000 },
+    { "fa", 0x04010 },
+    { "fan", 0x04080 },
+    { "fang", 0x040a0 },
+    { "fei", 0x04050 },
+    { "fen", 0x04090 },
+    { "feng", 0x040b0 },
+    { "fiao", 0x04100 },
+    { "fo", 0x04020 },
+    { "fou", 0x04070 },
+    { "fu", 0x04160 },
+    { "g", 0x09000 },
+    { "ga", 0x09010 },
+    { "gai", 0x09040 },
+    { "gan", 0x09080 },
+    { "gang", 0x090a0 },
+    { "gao", 0x09060 },
+    { "ge", 0x09030 },
+    { "gei", 0x09050 },
+    { "gen", 0x09090 },
+    { "geng", 0x090b0 },
+    { "gong", 0x091e0 },
+    { "gou", 0x09070 },
+    { "gu", 0x09160 },
+    { "gua", 0x09170 },
+    { "guai", 0x09190 },
+    { "guan", 0x091b0 },
+    { "guang", 0x091d0 },
+    { "gui", 0x091a0 },
+    { "gun", 0x091c0 },
+    { "guo", 0x09180 },
+    { "h", 0x0b000 },
+    { "ha", 0x0b010 },
+    { "hai", 0x0b040 },
+    { "han", 0x0b080 },
+    { "hang", 0x0b0a0 },
+    { "hao", 0x0b060 },
+    { "he", 0x0b030 },
+    { "hei", 0x0b050 },
+    { "hen", 0x0b090 },
+    { "heng", 0x0b0b0 },
+    { "hong", 0x0b1e0 },
+    { "hou", 0x0b070 },
+    { "hu", 0x0b160 },
+    { "hua", 0x0b170 },
+    { "huai", 0x0b190 },
+    { "huan", 0x0b1b0 },
+    { "huang", 0x0b1d0 },
+    { "hui", 0x0b1a0 },
+    { "hun", 0x0b1c0 },
+    { "huo", 0x0b180 },
+    { "j", 0x0c000 },
+    { "ji", 0x0c0d0 },
+    { "jia", 0x0c0e0 },
+    { "jian", 0x0c120 },
+    { "jiang", 0x0c140 },
+    { "jiao", 0x0c100 },
+    { "jie", 0x0c0f0 },
+    { "jin", 0x0c130 },
+    { "jing", 0x0c150 },
+    { "jiong", 0x0c210 },
+    { "jiu", 0x0c110 },
+    { "ju", 0x0c160 },
+    { "juan", 0x0c1b0 },
+    { "jue", 0x0c200 },
+    { "jun", 0x0c1c0 },
+    { "k", 0x0a000 },
+    { "ka", 0x0a010 },
+    { "kai", 0x0a040 },
+    { "kan", 0x0a080 },
+    { "kang", 0x0a0a0 },
+    { "kao", 0x0a060 },
+    { "ke", 0x0a030 },
+    { "kei", 0x0a050 },
+    { "ken", 0x0a090 },
+    { "keng", 0x0a0b0 },
+    { "kong", 0x0a1e0 },
+    { "kou", 0x0a070 },
+    { "ku", 0x0a160 },
+    { "kua", 0x0a170 },
+    { "kuai", 0x0a190 },
+    { "kuan", 0x0a1b0 },
+    { "kuang", 0x0a1d0 },
+    { "kui", 0x0a1a0 },
+    { "kun", 0x0a1c0 },
+    { "kuo", 0x0a180 },
+    { "l", 0x08000 },
+    { "la", 0x08010 },
+    { "lai", 0x08040 },
+    { "lan", 0x08080 },
+    { "lang", 0x080a0 },
+    { "lao", 0x08060 },
+    { "le", 0x08030 },
+    { "lei", 0x08050 },
+    { "leng", 0x080b0 },
+    { "li", 0x080d0 },
+    { "lia", 0x080e0 },
+    { "lian", 0x08120 },
+    { "liang", 0x08140 },
+    { "liao", 0x08100 },
+    { "lie", 0x080f0 },
+    { "lin", 0x08130 },
+    { "ling", 0x08150 },
+    { "liu", 0x08110 },
+    { "lo", 0x08020 },
+    { "long", 0x081e0 },
+    { "lou", 0x08070 },
+    { "lu", 0x08160 },
+    { "luan", 0x081b0 },
+    { "lue", 0x08200 },
+    { "lun", 0x081c0 },
+    { "luo", 0x08180 },
+    { "lv", 0x081f0 },
+    { "m", 0x03000 },
+    { "ma", 0x03010 },
+    { "mai", 0x03040 },
+    { "man", 0x03080 },
+    { "mang", 0x030a0 },
+    { "mao", 0x03060 },
+    { "me", 0x03030 },
+    { "mei", 0x03050 },
+    { "men", 0x03090 },
+    { "meng", 0x030b0 },
+    { "mi", 0x030d0 },
+    { "mian", 0x03120 },
+    { "miao", 0x03100 },
+    { "mie", 0x030f0 },
+    { "min", 0x03130 },
+    { "ming", 0x03150 },
+    { "miu", 0x03110 },
+    { "mo", 0x03020 },
+    { "mou", 0x03070 },
+    { "mu", 0x03160 },
+    { "n", 0x07000 },
+    { "na", 0x07010 },
+    { "nai", 0x07040 },
+    { "nan", 0x07080 },
+    { "nang", 0x070a0 },
+    { "nao", 0x07060 },
+    { "ne", 0x07030 },
+    { "nei", 0x07050 },
+    { "nen", 0x07090 },
+    { "neng", 0x070b0 },
+    { "ni", 0x070d0 },
+    { "nian", 0x07120 },
+    { "niang", 0x07140 },
+    { "niao", 0x07100 },
+    { "nie", 0x070f0 },
+    { "nin", 0x07130 },
+    { "ning", 0x07150 },
+    { "niu", 0x07110 },
+    { "nong", 0x071e0 },
+    { "nou", 0x07070 },
+    { "nu", 0x07160 },
+    { "nuan", 0x071b0 },
+    { "nue", 0x07200 },
+    { "nun", 0x071c0 },
+    { "nuo", 0x07180 },
+    { "nv", 0x071f0 },
+    { "o", 0x00020 },
+    { "ou", 0x00070 },
+    { "p", 0x02000 },
+    { "pa", 0x02010 },
+    { "pai", 0x02040 },
+    { "pan", 0x02080 },
+    { "pang", 0x020a0 },
+    { "pao", 0x02060 },
+    { "pei", 0x02050 },
+    { "pen", 0x02090 },
+    { "peng", 0x020b0 },
+    { "pi", 0x020d0 },
+    { "pian", 0x02120 },
+    { "piao", 0x02100 },
+    { "pie", 0x020f0 },
+    { "pin", 0x02130 },
+    { "ping", 0x02150 },
+    { "po", 0x02020 },
+    { "pou", 0x02070 },
+    { "pu", 0x02160 },
+    { "q", 0x0d000 },
+    { "qi", 0x0d0d0 },
+    { "qia", 0x0d0e0 },
+    { "qian", 0x0d120 },
+    { "qiang", 0x0d140 },
+    { "qiao", 0x0d100 },
+    { "qie", 0x0d0f0 },
+    { "qin", 0x0d130 },
+    { "qing", 0x0d150 },
+    { "qiong", 0x0d210 },
+    { "qiu", 0x0d110 },
+    { "qu", 0x0d160 },
+    { "quan", 0x0d1b0 },
+    { "que", 0x0d200 },
+    { "qun", 0x0d1c0 },
+    { "r", 0x12000 },
+    { "ran", 0x12080 },
+    { "rang", 0x120a0 },
+    { "rao", 0x12060 },
+    { "re", 0x12030 },
+    { "ren", 0x12090 },
+    { "reng", 0x120b0 },
+    { "ri", 0x120d0 },
+    { "rong", 0x121e0 },
+    { "rou", 0x12070 },
+    { "ru", 0x12160 },
+    { "ruan", 0x121b0 },
+    { "rui", 0x121a0 },
+    { "run", 0x121c0 },
+    { "ruo", 0x12180 },
+    { "s", 0x15000 },
+    { "sa", 0x15010 },
+    { "sai", 0x15040 },
+    { "san", 0x15080 },
+    { "sang", 0x150a0 },
+    { "sao", 0x15060 },
+    { "se", 0x15030 },
+    { "sen", 0x15090 },
+    { "seng", 0x150b0 },
+    { "sh", 0x11000 },
+    { "sha", 0x11010 },
+    { "shai", 0x11040 },
+    { "shan", 0x11080 },
+    { "shang", 0x110a0 },
+    { "shao", 0x11060 },
+    { "she", 0x11030 },
+    { "shei", 0x11050 },
+    { "shen", 0x11090 },
+    { "sheng", 0x110b0 },
+    { "shi", 0x110d0 },
+    { "shou", 0x11070 },
+    { "shu", 0x11160 },
+    { "shua", 0x11170 },
+    { "shuai", 0x11190 },
+    { "shuan", 0x111b0 },
+    { "shuang", 0x111d0 },
+    { "shui", 0x111a0 },
+    { "shun", 0x111c0 },
+    { "shuo", 0x11180 },
+    { "si", 0x150d0 },
+    { "song", 0x151e0 },
+    { "sou", 0x15070 },
+    { "su", 0x15160 },
+    { "suan", 0x151b0 },
+    { "sui", 0x151a0 },
+    { "sun", 0x151c0 },
+    { "suo", 0x15180 },
+    { "t", 0x06000 },
+    { "ta", 0x06010 },
+    { "tai", 0x06040 },
+    { "tan", 0x06080 },
+    { "tang", 0x060a0 },
+    { "tao", 0x06060 },
+    { "te", 0x06030 },
+    { "tei", 0x06050 },
+    { "teng", 0x060b0 },
+    { "ti", 0x060d0 },
+    { "tian", 0x06120 },
+    { "tiao", 0x06100 },
+    { "tie", 0x060f0 },
+    { "ting", 0x06150 },
+    { "tong", 0x061e0 },
+    { "tou", 0x06070 },
+    { "tu", 0x06160 },
+    { "tuan", 0x061b0 },
+    { "tui", 0x061a0 },
+    { "tun", 0x061c0 },
+    { "tuo", 0x06180 },
+    { "w", 0x17000 },
+    { "wa", 0x17010 },
+    { "wai", 0x17040 },
+    { "wan", 0x17080 },
+    { "wang", 0x170a0 },
+    { "wei", 0x17050 },
+    { "wen", 0x17090 },
+    { "weng", 0x170b0 },
+    { "wo", 0x17020 },
+    { "wu", 0x17160 },
+    { "x", 0x0e000 },
+    { "xi", 0x0e0d0 },
+    { "xia", 0x0e0e0 },
+    { "xian", 0x0e120 },
+    { "xiang", 0x0e140 },
+    { "xiao", 0x0e100 },
+    { "xie", 0x0e0f0 },
+    { "xin", 0x0e130 },
+    { "xing", 0x0e150 },
+    { "xiong", 0x0e210 },
+    { "xiu", 0x0e110 },
+    { "xu", 0x0e160 },
+    { "xuan", 0x0e1b0 },
+    { "xue", 0x0e200 },
+    { "xun", 0x0e1c0 },
+    { "y", 0x16000 },
+    { "ya", 0x16010 },
+    { "yan", 0x16080 },
+    { "yang", 0x160a0 },
+    { "yao", 0x16060 },
+    { "ye", 0x16030 },
+    { "yi", 0x160d0 },
+    { "yin", 0x16130 },
+    { "ying", 0x16150 },
+    { "yo", 0x16020 },
+    { "yong", 0x161e0 },
+    { "you", 0x16070 },
+    { "yu", 0x16160 },
+    { "yuan", 0x161b0 },
+    { "yue", 0x16200 },
+    { "yun", 0x161c0 },
+    { "z", 0x13000 },
+    { "za", 0x13010 },
+    { "zai", 0x13040 },
+    { "zan", 0x13080 },
+    { "zang", 0x130a0 },
+    { "zao", 0x13060 },
+    { "ze", 0x13030 },
+    { "zei", 0x13050 },
+    { "zen", 0x13090 },
+    { "zeng", 0x130b0 },
+    { "zh", 0x0f000 },
+    { "zha", 0x0f010 },
+    { "zhai", 0x0f040 },
+    { "zhan", 0x0f080 },
+    { "zhang", 0x0f0a0 },
+    { "zhao", 0x0f060 },
+    { "zhe", 0x0f030 },
+    { "zhei", 0x0f050 },
+    { "zhen", 0x0f090 },
+    { "zheng", 0x0f0b0 },
+    { "zhi", 0x0f0d0 },
+    { "zhong", 0x0f1e0 },
+    { "zhou", 0x0f070 },
+    { "zhu", 0x0f160 },
+    { "zhua", 0x0f170 },
+    { "zhuai", 0x0f190 },
+    { "zhuan", 0x0f1b0 },
+    { "zhuang", 0x0f1d0 },
+    { "zhui", 0x0f1a0 },
+    { "zhun", 0x0f1c0 },
+    { "zhuo", 0x0f180 },
+    { "zi", 0x130d0 },
+    { "zong", 0x131e0 },
+    { "zou", 0x13070 },
+    { "zu", 0x13160 },
+    { "zuan", 0x131b0 },
+    { "zui", 0x131a0 },
+    { "zun", 0x131c0 },
+    { "zuo", 0x13180 },
+};
+
+static int
+pytab_entry_compare(const char *s, TPyTabEntry *v)
+{
+    return strcmp(s, v->pystr);
+}
+
+TSyllable
+CPinyinData::encodeSyllable(const char *pinyin)
+{
+    typedef int (*bsearch_compare)(const void*, const void*);
+    TPyTabEntry *e = (TPyTabEntry*)bsearch(pinyin, pinyin_table,
+                                           sizeof(pinyin_table) /
+                                           sizeof(pinyin_table[0]),
+                                           sizeof(pinyin_table[0]),
+                                           (bsearch_compare)pytab_entry_compare);
+    if (e)
+        return e->id;
+
+    return 0;
+}
+
+const char *
+CPinyinData::decodeSyllable(TSyllable s, const char **i, const char **f)
+{
+    if (i) *i = initials[s.initial];
+    if (f) *f = finals[s.final];
+
+    static char buf[128];
+    snprintf(buf, sizeof(buf), "%s%s", initials[s.initial], finals[s.final]);
+
+    typedef int (*bsearch_compare)(const void*, const void*);
+    TPyTabEntry *e = (TPyTabEntry*)bsearch(buf, pinyin_table,
+                                           sizeof(pinyin_table) /
+                                           sizeof(pinyin_table[0]),
+                                           sizeof(pinyin_table[0]),
+                                           (bsearch_compare)pytab_entry_compare);
+
+    if (e)
+        return e->pystr;
+
+    return NULL;
+}
+
+const char **
+CPinyinData::getAutoCorrectionPairs(unsigned &num)
+{
+    num = num_auto_correction_pairs;
+    return auto_correction_pairs;
+}
+
+const char **
+CPinyinData::getFuzzyPairs(unsigned &num)
+{
+    num = num_fuzzy_pairs;
+    return fuzzy_pairs;
+}
+
+const char **
+CPinyinData::getInitials(unsigned &num)
+{
+    num = num_initials;
+    return initials;
+}
+
+const char **
+CPinyinData::getFinals(unsigned &num)
+{
+    num = num_finals;
+    return finals;
+}
+
+const TPyTabEntry *
+CPinyinData::getPinyinTable(unsigned &num)
+{
+    num = sizeof(pinyin_table) / sizeof(TPyTabEntry);
+    return pinyin_table;
+}
+
+const unsigned *
+CPinyinData::getInnerFuzzyFinalMap(unsigned &num)
+{
+    num = num_fuzzy_finals;
+    return fuzzy_finals_map;
+}
+
+void
+CPinyinData::getFuzzyPreProSyllables(const unsigned **pre_syls,
+                                     const unsigned **pro_syls)
+{
+    *pre_syls = fuzzy_pre_syllables;
+    *pro_syls = fuzzy_pro_syllables;
+}
diff --git a/src/pinyin/pinyin_data.h b/src/pinyin/pinyin_data.h
new file mode 100644 (file)
index 0000000..68f3f4a
--- /dev/null
@@ -0,0 +1,71 @@
+// -*- mode: c++ -*-
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright (c) 2007 Sun Microsystems, Inc. All Rights Reserved.
+ *
+ * The contents of this file are subject to the terms of either the GNU Lesser
+ * General Public License Version 2.1 only ("LGPL") or the Common Development and
+ * Distribution License ("CDDL")(collectively, the "License"). You may not use this
+ * file except in compliance with the License. You can obtain a copy of the CDDL at
+ * http://www.opensource.org/licenses/cddl1.php and a copy of the LGPLv2.1 at
+ * http://www.opensource.org/licenses/lgpl-license.php. See the License for the
+ * specific language governing permissions and limitations under the License. When
+ * distributing the software, include this License Header Notice in each file and
+ * include the full text of the License in the License file as well as the
+ * following notice:
+ *
+ * NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND DISTRIBUTION LICENSE
+ * (CDDL)
+ * For Covered Software in this distribution, this License shall be governed by the
+ * laws of the State of California (excluding conflict-of-law provisions).
+ * Any litigation relating to this License shall be subject to the jurisdiction of
+ * the Federal Courts of the Northern District of California and the state courts
+ * of the State of California, with venue lying in Santa Clara County, California.
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by only the CDDL or only
+ * the LGPL Version 2.1, indicate your decision by adding "[Contributor]" elects to
+ * include this software in this distribution under the [CDDL or LGPL Version 2.1]
+ * license." If you don't indicate a single choice of license, a recipient has the
+ * option to distribute your version of this file under either the CDDL or the LGPL
+ * Version 2.1, or to extend the choice of license to its licensees as provided
+ * above. However, if you add LGPL Version 2.1 code and therefore, elected the LGPL
+ * Version 2 license, then the option applies only if the new code is made subject
+ * to such option by the copyright holder.
+ */
+
+#ifndef _PINYIN_DATA_H_
+#define _PINYIN_DATA_H_
+
+#include <string>
+#include <map>
+#include "syllable.h"
+
+class CPinyinData
+{
+public:
+    static TSyllable encodeSyllable(const char *);
+    static const char *decodeSyllable(TSyllable,
+                                      const char **i = NULL,
+                                      const char **f = NULL);
+
+    static const char **getInitials(unsigned &num);
+    static const char **getFinals(unsigned &num);
+    static const unsigned *getInnerFuzzyFinalMap(unsigned &num);
+    static void getFuzzyPreProSyllables(const unsigned **pre_syls,
+                                        const unsigned **pro_syls);
+
+    static const TPyTabEntry* getPinyinTable(unsigned &num);
+
+    static const char **getAutoCorrectionPairs(unsigned &num);
+    static const char **getFuzzyPairs(unsigned &num);
+
+protected:
+    CPinyinData ();
+    CPinyinData (const CPinyinData&);
+    CPinyinData& operator =(const CPinyinData&);
+};
+
+#endif /* _PINYIN_DATA_H_ */
diff --git a/src/pinyin/pinyin_seg.cpp b/src/pinyin/pinyin_seg.cpp
new file mode 100644 (file)
index 0000000..d70eea1
--- /dev/null
@@ -0,0 +1,502 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright (c) 2007 Sun Microsystems, Inc. All Rights Reserved.
+ *
+ * The contents of this file are subject to the terms of either the GNU Lesser
+ * General Public License Version 2.1 only ("LGPL") or the Common Development and
+ * Distribution License ("CDDL")(collectively, the "License"). You may not use this
+ * file except in compliance with the License. You can obtain a copy of the CDDL at
+ * http://www.opensource.org/licenses/cddl1.php and a copy of the LGPLv2.1 at
+ * http://www.opensource.org/licenses/lgpl-license.php. See the License for the
+ * specific language governing permissions and limitations under the License. When
+ * distributing the software, include this License Header Notice in each file and
+ * include the full text of the License in the License file as well as the
+ * following notice:
+ *
+ * NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND DISTRIBUTION LICENSE
+ * (CDDL)
+ * For Covered Software in this distribution, this License shall be governed by the
+ * laws of the State of California (excluding conflict-of-law provisions).
+ * Any litigation relating to this License shall be subject to the jurisdiction of
+ * the Federal Courts of the Northern District of California and the state courts
+ * of the State of California, with venue lying in Santa Clara County, California.
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by only the CDDL or only
+ * the LGPL Version 2.1, indicate your decision by adding "[Contributor]" elects to
+ * include this software in this distribution under the [CDDL or LGPL Version 2.1]
+ * license." If you don't indicate a single choice of license, a recipient has the
+ * option to distribute your version of this file under either the CDDL or the LGPL
+ * Version 2.1, or to extend the choice of license to its licensees as provided
+ * above. However, if you add LGPL Version 2.1 code and therefore, elected the LGPL
+ * Version 2 license, then the option applies only if the new code is made subject
+ * to such option by the copyright holder.
+ */
+
+#include <cassert>
+#include <functional>
+#include <algorithm>
+#include "pinyin_seg.h"
+#include "quanpin_trie.h"
+
+const char *
+CGetCorrectionPairOp::operator ()(std::string& pystr, unsigned& matched_len)
+{
+    CCorrectionPairVec::iterator it = m_correctionPairs.begin();
+    CCorrectionPairVec::iterator ite = m_correctionPairs.end();
+
+    for (; it != ite; ++it) {
+        std::string& k = it->first;
+        std::string& v = it->second;
+        unsigned l = k.size();
+
+        if (pystr.size() >= l && !pystr.compare(pystr.size() - l, l, k)) {
+            matched_len = l;
+            return v.c_str();
+        }
+    }
+
+    return NULL;
+}
+
+void
+CGetFuzzySegmentsOp::_initMaps()
+{
+    unsigned num_of_fuzzy_finals;
+    const unsigned * fuzzy_final_map = CPinyinData::getInnerFuzzyFinalMap(
+        num_of_fuzzy_finals);
+
+    for (size_t i = 0; i < num_of_fuzzy_finals; ++i) {
+        unsigned f = *(fuzzy_final_map++);
+        unsigned _f = *(fuzzy_final_map++);
+        unsigned l = *(fuzzy_final_map++);
+
+        m_fuzzyFinalMap.insert(std::make_pair(f, std::make_pair(_f, l)));
+    }
+
+    const unsigned *fuzzy_pre_syls, *fuzzy_pro_syls;
+    CPinyinData::getFuzzyPreProSyllables(&fuzzy_pre_syls, &fuzzy_pro_syls);
+
+    while (*fuzzy_pre_syls) {
+        unsigned s = *(fuzzy_pre_syls++);
+        char c = *(fuzzy_pre_syls++);
+        unsigned _s = *(fuzzy_pre_syls++);
+        m_fuzzyPreMap.insert(std::make_pair(s, std::make_pair(c, _s)));
+    }
+
+    while (*fuzzy_pro_syls) {
+        unsigned s = *(fuzzy_pro_syls++);
+        char c = *(fuzzy_pro_syls++);
+        unsigned _s = *(fuzzy_pro_syls++);
+        m_fuzzyProMap.insert(std::make_pair(s, std::make_pair(c, _s)));
+    }
+}
+
+unsigned
+CGetFuzzySegmentsOp::_invalidateSegments(IPySegmentor::TSegmentVec& fuzzy_segs,
+                                         IPySegmentor::TSegment& seg)
+{
+    unsigned invalidatedFrom = UINT_MAX;
+
+    IPySegmentor::TSegmentVec::reverse_iterator it = fuzzy_segs.rbegin();
+    IPySegmentor::TSegmentVec::reverse_iterator ite = fuzzy_segs.rend();
+
+    for (; it != ite; it += 2) {
+        IPySegmentor::TSegment& seg1 = *(it + 1);
+        IPySegmentor::TSegment& seg2 = *it;
+
+        unsigned r = seg2.m_start + seg2.m_len;
+        if (r <= seg.m_start)
+            break;
+
+        invalidatedFrom = seg1.m_start;
+    }
+
+    fuzzy_segs.erase(it.base(), fuzzy_segs.end());
+
+    return invalidatedFrom;
+}
+
+unsigned
+CGetFuzzySegmentsOp::operator ()(IPySegmentor::TSegmentVec& segs,
+                                 IPySegmentor::TSegmentVec& fuzzy_segs,
+                                 wstring& input)
+{
+    IPySegmentor::TSegment&  seg = segs.back();
+    unsigned invalidatedFrom = _invalidateSegments(fuzzy_segs, seg);
+
+    unsigned updatedFrom = UINT_MAX;
+    TSyllable syl = (TSyllable)seg.m_syllables[0];
+
+    if (m_bInnerFuzzyEnabled) { // xian -> xian, xi'an
+        CInnerFuzzyFinalMap::iterator it = m_fuzzyFinalMap.find(syl.final);
+
+        if (it != m_fuzzyFinalMap.end()) {
+            unsigned an_syl = it->second.first;
+            unsigned an_len = it->second.second;
+
+            unsigned xi_len = seg.m_len - an_len;
+            wstring wstr = input.substr(seg.m_start, xi_len);
+
+#ifndef _RW_STD_STL
+            std::string xi_str(wstr.begin(), wstr.end());
+#else
+            std::string xi_str;
+            for (wstring::iterator it = wstr.begin(); it != wstr.end(); ++it)
+                xi_str.push_back(*it);
+#endif
+
+            unsigned xi_syl = CPinyinData::encodeSyllable(xi_str.c_str());
+
+            if (0 == xi_syl)
+                goto RETURN;
+
+            IPySegmentor::TSegment xi = segs.back();
+            xi.m_len = xi_len;
+            xi.m_syllables[0] = xi_syl;
+
+            IPySegmentor::TSegment an = segs.back();
+            an.m_len = an_len;
+            an.m_start += xi_len;
+            an.m_syllables[0] = an_syl;
+            an.m_inner_fuzzy = true;
+
+            fuzzy_segs.push_back(xi);
+            fuzzy_segs.push_back(an);
+
+            updatedFrom = xi.m_start;
+            goto RETURN;
+        }
+    }
+
+    if (segs.size() >= 2) { // fangan -> fang'an, fan'gan
+        IPySegmentor::TSegment& pre_seg = *(segs.end() - 2);
+
+        CFuzzySyllableMap::iterator pre_it = m_fuzzyPreMap.find(
+            pre_seg.m_syllables[0]);
+        CFuzzySyllableMap::iterator it = m_fuzzyProMap.find(syl);
+
+        if (pre_it != m_fuzzyPreMap.end() && it != m_fuzzyProMap.end() &&
+            pre_it->second.first == it->second.first) {
+            IPySegmentor::TSegment fang = segs[segs.size() - 2];
+            fang.m_len++;
+            fang.m_syllables[0] = pre_it->second.second;
+
+            IPySegmentor::TSegment an = segs.back();
+            an.m_start++;
+            an.m_len--;
+            an.m_syllables[0] = it->second.second;
+
+            fuzzy_segs.push_back(fang);
+            fuzzy_segs.push_back(an);
+
+            updatedFrom = fang.m_start;
+            goto RETURN;
+        }
+    }
+
+RETURN:;
+
+    return std::min(updatedFrom, invalidatedFrom);
+}
+
+
+CQuanpinSegmentor::CQuanpinSegmentor ()
+    : m_pGetFuzzySyllablesOp(NULL),
+      m_pGetCorrectionPairOp(NULL),
+      m_pGetFuzzySegmentsOp(NULL),
+      m_pytrie(base, check, value, sizeof(base) / sizeof(*base)),
+      m_updatedFrom(0)
+{
+    m_segs.reserve(32);
+}
+
+bool
+CQuanpinSegmentor::load(const char * pyTrieFileName)
+{
+    return m_pytrie.load(pyTrieFileName);
+}
+
+#ifdef DEBUG
+void
+print_pystr(const std::string pystr)
+{
+    for (const char* c = pystr.c_str();
+         c != pystr.c_str() + pystr.length();
+         ++c) {
+        printf("%c", *c & 0x7f);
+    }
+    printf("<\n");
+}
+#endif
+
+unsigned
+CQuanpinSegmentor::push(unsigned ch)
+{
+    m_inputBuf.push_back(ch);
+
+    if (m_pGetCorrectionPairOp && m_pGetCorrectionPairOp->isEnabled()) {
+        m_pystr.push_back(ch);
+        unsigned l = 0;
+        const char * v = (*m_pGetCorrectionPairOp)(m_pystr, l);
+
+        if (v) {
+            unsigned orig_size = m_segs.size();
+            _clear(m_pystr.size() - l);
+            m_updatedFrom = _updateWith(v);
+
+            if (m_segs.size() >= orig_size) {
+                // does not get better segmentation, revert to original
+                _clear(m_pystr.size() - strlen(v));
+                std::string new_pystr;
+                std::copy(m_inputBuf.end() - l, m_inputBuf.end(),
+                          back_inserter(new_pystr));
+                m_updatedFrom = _updateWith(new_pystr);
+            } else {
+                if (l != strlen(v)) {
+                    // e.g. uen -> un
+                    m_segs.back().m_len += l - strlen(v);
+                    m_pystr.resize(m_inputBuf.length());
+                }
+                std::copy(m_inputBuf.end() - l, m_inputBuf.end(),
+                          m_pystr.end() - l);
+            }
+            return m_updatedFrom;
+        }
+
+        m_pystr.resize(m_pystr.size() - 1);
+    }
+
+    return m_updatedFrom = _push(ch);
+}
+
+unsigned
+CQuanpinSegmentor::pop()
+{
+    if (m_pystr.empty())
+        return m_updatedFrom = 0;
+
+    unsigned size = m_inputBuf.size();
+    m_inputBuf.resize(size - 1);
+    m_pystr.resize(size - 1);
+
+    unsigned l = m_segs.back().m_len;
+    m_segs.pop_back();
+
+    if (l == 1)
+        return m_updatedFrom = size - 1;
+
+    std::string new_pystr = m_pystr.substr(size - l);
+    m_pystr.resize(size - l);
+
+    m_updatedFrom = _updateWith(new_pystr);
+
+    return m_updatedFrom;
+}
+
+unsigned
+CQuanpinSegmentor::insertAt(unsigned idx, unsigned ch)
+{
+    unsigned i, j;
+    _locateSegment(idx, i, j);
+
+    m_inputBuf.insert(idx, 1, ch);
+    m_pystr.insert(idx, 1, ch);
+
+    std::string new_pystr = m_pystr.substr(i);
+    m_pystr.resize(i);
+    m_segs.erase(m_segs.begin() + j, m_segs.end());
+
+    m_updatedFrom = _updateWith(new_pystr);
+
+    return m_updatedFrom;
+}
+
+unsigned
+CQuanpinSegmentor::deleteAt(unsigned idx, bool backward)
+{
+    unsigned i, j;
+    if (!backward) idx += 1;
+    _locateSegment(idx, i, j);
+
+    m_inputBuf.erase(idx, 1);
+    m_pystr.erase(idx, 1);
+
+    std::string new_pystr = m_pystr.substr(i);
+    m_pystr.resize(i);
+    m_segs.erase(m_segs.begin() + j, m_segs.end());
+
+    m_updatedFrom = _updateWith(new_pystr);
+
+    return m_updatedFrom;
+}
+
+unsigned
+CQuanpinSegmentor::clear(unsigned from)
+{
+    m_inputBuf.resize(from);
+    return _clear(from);
+}
+
+unsigned
+CQuanpinSegmentor::_clear(unsigned from)
+{
+    unsigned i, j;
+    _locateSegment(from, i, j);
+
+
+    std::string new_pystr = m_pystr.substr(i, from - i);
+    m_pystr.resize(i);
+    m_segs.erase(m_segs.begin() + j, m_segs.end());
+
+    m_updatedFrom = _updateWith(new_pystr, from);
+
+    return m_updatedFrom;
+}
+
+void
+CQuanpinSegmentor::_locateSegment(unsigned idx,
+                                  unsigned &strIdx,
+                                  unsigned &segIdx)
+{
+    strIdx = segIdx = 0;
+
+    TSegmentVec::iterator it = m_segs.begin();
+    TSegmentVec::iterator ite = m_segs.end();
+
+    for (; it != ite; ++it) {
+        if (strIdx + (*it).m_len > idx)
+            break;
+
+        strIdx += (*it).m_len;
+        segIdx += 1;
+    }
+}
+
+unsigned
+CQuanpinSegmentor::_push(unsigned ch)
+{
+    unsigned l, ret;
+    m_pystr.push_back(ch);
+    int v = m_pytrie.match_longest(m_pystr.rbegin(), m_pystr.rend(), l);
+
+    if (l == 0) { // not a valid syllable character, e.g., \', i, u, or A-Z
+        IPySegmentor::ESegmentType seg_type;
+        if (ch == '\'' && m_inputBuf.size() > 1)
+            seg_type = IPySegmentor::SYLLABLE_SEP;
+        else if (islower(ch))
+            seg_type = IPySegmentor::INVALID;
+        else
+            seg_type = IPySegmentor::STRING;
+
+        ret = m_pystr.size() - 1;
+        m_segs.push_back(TSegment(ch, ret, 1, seg_type));
+    } else if (l == 1) { // possible a new segment
+        int last_idx = m_pystr.size() - 2;
+        if (last_idx >= 0 && (m_pystr[last_idx] & 0x80)) {
+            // check if the last syllable character's highest bitmask is set
+            // e.g., feN, so [feN] + g -> [feng]
+            m_pystr[last_idx] &= 0x7f;
+            unsigned l;
+            int v = m_pytrie.match_longest(m_pystr.rbegin(), m_pystr.rend(), l);
+
+            TSegment &last_seg = m_segs.back();
+            if (l == (unsigned) last_seg.m_len + 1) {
+                last_seg.m_len += 1;
+                last_seg.m_syllables[0] = v;
+                ret = m_pystr.size() - l;
+                goto RETURN;
+            }
+
+            // in case not extensible, change highest bitmask back
+            m_pystr[last_idx] |= 0x80;
+        }
+
+        // push the new 1-length segment
+        ret = m_pystr.size() - 1;
+        m_segs.push_back(TSegment(v, ret, 1));
+    } else if (l == (unsigned) m_segs.back().m_len + 1) {
+        // current segment is extensible, e.g., [xia] + n -> [xian]
+        TSegment &last_seg = m_segs.back();
+        last_seg.m_len += 1;
+        last_seg.m_syllables[0] = v;
+        ret = m_pystr.size() - l;
+    } else {  // other cases
+        TSegment &last_seg = m_segs.back();
+        int i = 0, isum = last_seg.m_len + 1, lsum = l;
+        TSegmentVec new_segs(1, TSegment(v, m_pystr.size() - l, l));
+
+        // e.g., [zh] [o] [n] + g -> [zhonG],
+        if (isum < lsum) {
+            unsigned end_idx = m_pystr.size() - 1;
+            m_pystr[end_idx] |= 0x80;
+        }
+
+        while (isum != lsum) {
+            if (lsum < isum) { // e.g., [die] + r -> [di] [er]
+                v = m_pytrie.match_longest(
+                    m_pystr.rbegin() + lsum, m_pystr.rend(), l);
+                TSegment &last_seg = new_segs.back();
+                new_segs.push_back(TSegment(v, last_seg.m_start - l, l));
+                _addFuzzySyllables(new_segs.back());
+                lsum += l;
+            } else {
+                i += 1;
+                isum += (m_segs.rbegin() + i)->m_len;
+            }
+        }
+
+        m_segs.erase(m_segs.end() - (i + 1), m_segs.end());
+        std::copy(new_segs.rbegin(), new_segs.rend(), back_inserter(m_segs));
+        ret = m_pystr.size() - lsum;
+    }
+
+RETURN:;
+
+    if (m_pGetFuzzySegmentsOp && m_pGetFuzzySegmentsOp->isEnabled())
+        ret =
+            std::min(ret,
+                     (*m_pGetFuzzySegmentsOp)(m_segs, m_fuzzy_segs, m_inputBuf));
+
+    if (m_pGetFuzzySyllablesOp && m_pGetFuzzySyllablesOp->isEnabled()) {
+        if (m_segs.back().m_type == SYLLABLE)
+            _addFuzzySyllables(m_segs.back());
+
+        if (m_fuzzy_segs.size()) {
+            _addFuzzySyllables(*(m_fuzzy_segs.end() - 1));
+            _addFuzzySyllables(*(m_fuzzy_segs.end() - 2));
+        }
+    }
+
+    return ret;
+}
+
+void
+CQuanpinSegmentor::_addFuzzySyllables(TSegment& seg)
+{
+    assert(seg.m_type == SYLLABLE);
+
+    seg.m_fuzzy_syllables.clear();
+
+    CSyllables fuzzy_set = (*m_pGetFuzzySyllablesOp)(seg.m_syllables.front());
+    CSyllables::const_iterator it = fuzzy_set.begin();
+    CSyllables::const_iterator ite = fuzzy_set.end();
+
+    for (; it != ite; ++it)
+        seg.m_fuzzy_syllables.push_back(*it);
+}
+
+unsigned
+CQuanpinSegmentor::_updateWith(const std::string& new_pystr, unsigned from)
+{
+    unsigned minUpdatedFrom = from;
+    std::string::const_iterator it = new_pystr.begin();
+    for (; it != new_pystr.end(); ++it) {
+        unsigned updatedFrom = _push(*it & 0x7f);
+
+        if (updatedFrom < minUpdatedFrom) minUpdatedFrom = updatedFrom;
+    }
+    return minUpdatedFrom;
+}
diff --git a/src/pinyin/pinyin_seg.h b/src/pinyin/pinyin_seg.h
new file mode 100644 (file)
index 0000000..2933c0d
--- /dev/null
@@ -0,0 +1,162 @@
+// -*- mode: c++ -*-
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright (c) 2007 Sun Microsystems, Inc. All Rights Reserved.
+ *
+ * The contents of this file are subject to the terms of either the GNU Lesser
+ * General Public License Version 2.1 only ("LGPL") or the Common Development and
+ * Distribution License ("CDDL")(collectively, the "License"). You may not use this
+ * file except in compliance with the License. You can obtain a copy of the CDDL at
+ * http://www.opensource.org/licenses/cddl1.php and a copy of the LGPLv2.1 at
+ * http://www.opensource.org/licenses/lgpl-license.php. See the License for the
+ * specific language governing permissions and limitations under the License. When
+ * distributing the software, include this License Header Notice in each file and
+ * include the full text of the License in the License file as well as the
+ * following notice:
+ *
+ * NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND DISTRIBUTION LICENSE
+ * (CDDL)
+ * For Covered Software in this distribution, this License shall be governed by the
+ * laws of the State of California (excluding conflict-of-law provisions).
+ * Any litigation relating to this License shall be subject to the jurisdiction of
+ * the Federal Courts of the Northern District of California and the state courts
+ * of the State of California, with venue lying in Santa Clara County, California.
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by only the CDDL or only
+ * the LGPL Version 2.1, indicate your decision by adding "[Contributor]" elects to
+ * include this software in this distribution under the [CDDL or LGPL Version 2.1]
+ * license." If you don't indicate a single choice of license, a recipient has the
+ * option to distribute your version of this file under either the CDDL or the LGPL
+ * Version 2.1, or to extend the choice of license to its licensees as provided
+ * above. However, if you add LGPL Version 2.1 code and therefore, elected the LGPL
+ * Version 2 license, then the option applies only if the new code is made subject
+ * to such option by the copyright holder.
+ */
+
+#ifndef SUNPY_PINYIN_SEG_H
+#define SUNPY_PINYIN_SEG_H
+
+#include "portability.h"
+#include "segmentor.h"
+#include "pinyin_data.h"
+#include "datrie.h"
+#include "ime-core/utils.h"
+
+#include <algorithm>
+#include <climits>
+
+class CGetCorrectionPairOp : private CNonCopyable
+{
+public:
+    typedef std::pair<std::string, std::string> CCorrectionPair;
+    typedef std::vector<CCorrectionPair> CCorrectionPairVec;
+
+    CGetCorrectionPairOp () : m_bEnabled(false) { m_correctionPairs.reserve(8); }
+
+    void setEnable(bool value = true) { m_bEnabled = value; }
+    bool isEnabled() { return m_bEnabled; }
+
+    void setCorrectionPairs(const string_pairs& pairs)
+    { m_correctionPairs = pairs; }
+
+    const char * operator ()(std::string& pystr, unsigned& matched_len);
+
+private:
+    CCorrectionPairVec m_correctionPairs;
+    bool m_bEnabled;
+};
+
+class CGetFuzzySegmentsOp : private CNonCopyable
+{
+public:
+    typedef std::map<unsigned,
+                     std::pair<unsigned, unsigned> > CInnerFuzzyFinalMap;
+    typedef std::map<unsigned, std::pair<char, unsigned> > CFuzzySyllableMap;
+
+    CGetFuzzySegmentsOp () : m_bEnabled(false),
+                             m_bInnerFuzzyEnabled(false) { _initMaps(); }
+    unsigned operator ()(IPySegmentor::TSegmentVec&,
+                         IPySegmentor::TSegmentVec&,
+                         wstring&);
+
+    void setEnable(bool value = true) { m_bEnabled = value; }
+    void setInnerFuzzyEnable(bool value = true) { m_bInnerFuzzyEnabled = value; }
+    bool isEnabled() { return m_bEnabled; }
+
+private:
+    void        _initMaps();
+    unsigned    _invalidateSegments(IPySegmentor::TSegmentVec&,
+                                    IPySegmentor::TSegment&);
+
+    bool m_bEnabled;
+    bool m_bInnerFuzzyEnabled;
+    CInnerFuzzyFinalMap m_fuzzyFinalMap;
+    CFuzzySyllableMap m_fuzzyPreMap;
+    CFuzzySyllableMap m_fuzzyProMap;
+};
+
+class CQuanpinSegmentor : public IPySegmentor
+{
+public:
+    CQuanpinSegmentor ();
+
+    virtual TSegmentVec& getSegments(bool req_aux_segs){
+        if (req_aux_segs && m_pGetFuzzySegmentsOp &&
+            m_pGetFuzzySegmentsOp->isEnabled()) {
+            m_merged_segs.clear();
+            std::merge(m_segs.begin(), m_segs.end(),
+                       m_fuzzy_segs.begin(), m_fuzzy_segs.end(),
+                       back_inserter(m_merged_segs));
+            return m_merged_segs;
+        }
+
+        return m_segs;
+    }
+
+    virtual const wstring& getInputBuffer() { return m_inputBuf; }
+
+    virtual const char* getSylSeps() { return "'"; }
+
+    virtual unsigned push(unsigned ch);
+    virtual unsigned pop();
+    virtual unsigned insertAt(unsigned idx, unsigned ch);
+    virtual unsigned deleteAt(unsigned idx, bool backward = true);
+    virtual unsigned clear(unsigned from = 0);
+
+    virtual unsigned updatedFrom() { return m_updatedFrom; }
+
+    bool load(const char * pyTrieFileName);
+
+    void setGetFuzzySyllablesOp(CGetFuzzySyllablesOp<CPinyinData> *op) {
+        m_pGetFuzzySyllablesOp = op; }
+    void setGetCorrectionPairOp(CGetCorrectionPairOp *op) {
+        m_pGetCorrectionPairOp = op; }
+    void setGetFuzzySegmentsOp(CGetFuzzySegmentsOp  *op) {
+        m_pGetFuzzySegmentsOp = op; }
+
+private:
+    inline unsigned _push(unsigned ch);
+    inline unsigned _clear(unsigned from);
+    inline void _addFuzzySyllables(TSegment &seg);
+    inline unsigned _updateWith(const std::string& new_pystr,
+                                unsigned from = UINT_MAX);
+    inline void _locateSegment(unsigned idx, unsigned &strIdx, unsigned &segIdx);
+
+    CGetFuzzySyllablesOp<CPinyinData>  *m_pGetFuzzySyllablesOp;
+    CGetCorrectionPairOp               *m_pGetCorrectionPairOp;
+    CGetFuzzySegmentsOp                *m_pGetFuzzySegmentsOp;
+
+    CDATrie<short>                      m_pytrie;
+    std::string m_pystr;
+    wstring m_inputBuf;
+    TSegmentVec m_segs;
+    TSegmentVec m_fuzzy_segs;
+    TSegmentVec m_merged_segs;
+
+    unsigned m_updatedFrom;
+};
+
+#endif /* SUNPY_PINYIN_SEG_H */
diff --git a/src/pinyin/quanpin_trie.h b/src/pinyin/quanpin_trie.h
new file mode 100644 (file)
index 0000000..01f7e99
--- /dev/null
@@ -0,0 +1,6 @@
+static short base[] = {0, -26, -2, -3, -4, -51, -6, -29, -83, 80, -10, -11, -12, -13, -123, -106, -16, -17, -22, -19, -20, 146, 77, -23, -24, -25, -26, -27, -28, -29, -30, 0, -32, -33, -173, 173, 0, -37, -38, -39, -40, 0, -42, 136, 0, -45, -46, 109, 0, -49, 0, -51, -52, 0, -54, -55, 0, 0, -58, -199, 199, 0, -62, -63, -64, -65, 0, 0, 0, -69, -70, -71, 210, 0, 0, 0, -76, -77, 0, 0, 0, -235, -82, -83, -84, -265, -86, -87, 84, -89, -90, -91, -92, -93, -94, 0, -96, -97, -98, -99, -100, 293, -102, -103, -104, -105, -106, -323, -108, -109, -110, 0, -112, 0, 0, 0, -116, -195, -118, -119, -120, 0, -122, 0, -368, 0, 0, 347, -418, -129, 0, -131, 443, 0, 0, 0, 0, -513, 0, 0, 0, -563, 0, 0, 393, 538, 0, 0, -148, -149, -150, 584, -152, -153, -461, 461, -156, -157, -158, -159, -160, -486, -162, -163, -164, -165, -166, 0, 0, -169, -170, -171, -172, 0, 0, 0, -176, -177, 0, 0, 0, 0, 0, -183, 0, -185, 0, 0, 0, 0, -190, 0, -192, 0, 0, 0, 0, -197, -198, -199, 0, -201, -202, -203, 0, 0, 0, 0, 0, -209, 0, -211, -212, -213, -214, -215, -216, 0, -218, -219, -220, -221, -222, -223, -224, -225, 0, -227, 0, 0, 0, 0, 0, 0, -234, -235, 0, -237, -238, -239, 0, 0, -242, -256, 0, 0, -246, -247, -248, -249, 0, -251, 0, 0, -254, -255, 255, 0, -258, -259, 0, -261, -262, -267, 0, 0, -266, -267, -268, -269, -270, -271, -272, -276, 0, -275, -276, -277, -278, -279, 0, -281, -282, 0, 0, -285, -286, 0, -288, 0, 0, -291, 0, -293, 0, -295, -296, -297, 0, 0, -300, -303, -302, 0, -304, 0, -306, 0, 0, 0, 0, -311, -312, -313, 0, 0, 0, 0, 0, -319, 0, 0, -322, 0, 0, -325, -326, -327, 0, -329, -330, -609, 609, 0, -334, -335, -336, -337, 0, -339, 0, -341, -342, -343, 0, 0, 0, 0, -348, -349, -350, -351, 0, 0, -354, -359, 0, 0, -358, -359, 0, -361, -362, 0, 0, -365, -366, -367, 0, 0, -370, -371, -372, -373, -374, -375, -635, 635, -378, -379, -380, -381, -382, 0, -384, -385, -386, -387, -388, 659, 0, -391, 0, -393, -394, 0, -396, -397, 0, 0, -400, -469, 0, -403, -404, -405, 0, -407, 0, 0, -410, -411, -412, -413, 0, 0, 0, -417, -418, -419, -420, -421, -422, 0, -424, -425, -424, -427, 0, -429, 0, -431, -432, 0, -434, 0, -436, -437, 0, 0, 0, -441, 0, -443, -444, -445, 0, 0, 0, 0, -450, 0, 0, -453, 0, -455, -456, -457, 0, -459, -460, 0, 0, 0, -464, -465, 0, -467, -468, 0, 0, -471, -472, -473, -474, -475, 0, 0, -478, 0, -480, 0, 0, 0, 0, -485, 0, -487, -488, -489, -490, 0, -492, -493, -581, -495, 0, -497, -498, -499, -500, 0, -502, 0, -504, -505, -506, 0, 0, 0, 0, -511, -512, 0, 0, -515, -516, -517, 0, -519, -520, -678, 678, 0, -524, -525, -526, -527, 0, -529, 0, -531, -532, -533, 536, 0, -536, 0, -538, -539, -540, 0, -542, -543, -697, 0, 0, -547, -548, 0, -550, -551, -552, 0, -554, -555, 0, 0, -558, 0, 0, 0, -562, -563, 0, -565, -566, -567, 0, -569, -570, -598, 0, 0, -574, -575, -576, -577, 0, -579, 0, -581, -582, -583, -584, 0, -586, -587, -588, -589, 0, -591, -639, 636, 0, -595, -596, 0, -598, 0, -600, -601, -602, -603, -604, 0, 0, -607, 0, -609, -610, -611, -612, -613, 0, -615, 0, -617, 0, -619, 0, -621, -622, -623, -624, -625, -626, 0, -628, -629, 0, 0, 0, -633, 0, -635, 0, -637, -638, -639, 0, 0, -642, 0, 0, -645, -646, -647, -648, -649, 0, -651, -652, -653, -654, -655, 0, 0, 0, -659, -660, -661, -662, -663, 0, -665, -666, -677, 0, -669, -670, -671, 0, -673, 0, 0, -676, -677, -678, -679, -680, -681, 0, -683, -684, -685, 0, 0, -688, 0, -690, 0, -692, 0, 0, -695, -696, -697, 0, 0, -700, 0, -702, -703, -704, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -716, 0, 0, 0, 0, 0, 0, -723};
+
+static short check[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 7, 0, 1, 1, 1, 0, 1, 0, 1, 1, 0, 5, 5, 0, 0, 5, 5, 5, 0, 5, 5, 5, 5, 0, 0, 0, 5, 5, 5, 5, 0, 0, 0, 5, 5, 0, 0, 0, 9, 9, 9, 9, 9, 8, 88, 9, 22, 9, 22, 9, 9, 9, 0, 9, 9, 9, 9, 9, 9, 8, 88, 9, 9, 9, 15, 15, 8, 88, 0, 15, 0, 0, 0, 47, 47, 15, 15, 47, 0, 15, 0, 14, 0, 0, 15, 14, 15, 0, 15, 14, 0, 0, 0, 0, 43, 0, 0, 0, 43, 0, 0, 14, 43, 0, 0, 21, 21, 21, 43, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 0, 0, 21, 21, 21, 21, 0, 0, 0, 34, 35, 0, 0, 0, 0, 0, 35, 0, 35, 0, 0, 0, 0, 35, 0, 34, 0, 0, 0, 0, 35, 117, 34, 0, 60, 59, 60, 0, 0, 0, 0, 0, 60, 0, 60, 60, 60, 117, 60, 60, 0, 59, 60, 72, 117, 72, 60, 72, 59, 0, 72, 0, 0, 0, 0, 0, 0, 72, 72, 0, 81, 81, 81, 0, 0, 81, 81, 0, 0, 81, 81, 81, 81, 0, 81, 0, 0, 81, 81, 81, 0, 81, 243, 0, 81, 256, 256, 0, 0, 256, 85, 85, 85, 263, 85, 85, 85, 0, 243, 85, 85, 85, 85, 0, 85, 243, 0, 0, 85, 263, 0, 85, 0, 0, 85, 0, 263, 0, 273, 101, 101, 0, 0, 101, 101, 273, 0, 101, 0, 301, 0, 0, 0, 0, 101, 101, 101, 0, 0, 0, 0, 0, 101, 0, 0, 301, 0, 0, 107, 107, 107, 0, 301, 107, 107, 107, 0, 107, 107, 107, 107, 0, 107, 0, 107, 107, 107, 0, 0, 0, 0, 107, 107, 127, 127, 0, 0, 127, 127, 0, 0, 127, 127, 0, 127, 355, 0, 0, 127, 127, 127, 0, 0, 124, 124, 124, 127, 124, 124, 124, 124, 355, 124, 124, 124, 124, 0, 124, 355, 124, 124, 124, 124, 0, 124, 0, 124, 124, 0, 144, 144, 0, 0, 144, 144, 0, 144, 144, 144, 0, 144, 0, 0, 144, 144, 144, 144, 0, 0, 0, 144, 144, 144, 128, 128, 128, 0, 128, 128, 128, 426, 0, 128, 0, 128, 128, 0, 128, 0, 128, 128, 0, 0, 0, 128, 0, 426, 128, 132, 0, 0, 0, 0, 426, 0, 0, 132, 0, 132, 132, 132, 0, 132, 132, 0, 0, 0, 154, 155, 0, 132, 132, 0, 0, 155, 401, 155, 155, 155, 0, 0, 155, 0, 154, 0, 0, 0, 0, 155, 0, 154, 401, 161, 161, 0, 161, 161, 161, 401, 0, 161, 161, 161, 161, 0, 161, 0, 161, 161, 161, 0, 0, 0, 0, 161, 161, 0, 0, 137, 137, 137, 0, 137, 137, 137, 137, 0, 137, 137, 137, 137, 0, 137, 0, 137, 137, 137, 137, 0, 137, 0, 137, 137, 145, 0, 145, 534, 534, 0, 0, 534, 145, 0, 145, 145, 145, 0, 145, 145, 0, 0, 145, 0, 0, 0, 145, 145, 0, 141, 141, 141, 0, 141, 141, 141, 0, 0, 141, 141, 141, 141, 0, 141, 0, 141, 141, 141, 494, 0, 141, 151, 151, 141, 0, 151, 151, 151, 0, 151, 151, 0, 151, 0, 494, 571, 151, 151, 151, 0, 0, 494, 0, 151, 151, 332, 331, 332, 0, 332, 0, 571, 0, 332, 0, 332, 332, 332, 571, 332, 332, 0, 331, 332, 0, 0, 0, 332, 0, 331, 0, 377, 376, 377, 0, 0, 592, 0, 0, 377, 593, 377, 377, 377, 0, 377, 377, 593, 376, 377, 0, 0, 0, 377, 593, 376, 389, 389, 0, 592, 389, 389, 0, 389, 389, 389, 0, 389, 0, 0, 389, 389, 389, 389, 667, 521, 0, 389, 389, 389, 0, 0, 522, 0, 522, 0, 522, 0, 0, 522, 667, 521, 0, 0, 544, 0, 522, 667, 521, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 544, 0, 0, 0, 0, 0, 0, 544};
+
+static int value[] = {0, 16, 4096, 81920, 20480, 48, 16384, 36864, 45056, 0, 49152, 40960, 32768, 12288, 28672, 32, 8192, 53248, 73728, 86016, 24576, 0, 0, 94208, 57344, 90112, 77824, 192, 4112, 81936, 20496, 0, 16400, 36880, 45072, 0, 0, 40976, 32784, 12304, 28688, 0, 8208, 0, 0, 86032, 24592, 0, 0, 94224, 0, 90128, 77840, 0, 81968, 20528, 0, 0, 36912, 45104, 0, 0, 41008, 32816, 12336, 28720, 0, 0, 0, 73776, 86064, 24624, 0, 0, 0, 0, 90160, 77872, 0, 0, 0, 64, 4304, 82128, 20688, 80, 65536, 65744, 0, 33264, 49360, 29168, 32976, 12496, 28880, 0, 8400, 53456, 73936, 86224, 24784, 0, 69632, 69840, 57552, 90320, 78032, 96, 4128, 61440, 61648, 0, 16416, 0, 0, 0, 37232, 45424, 32800, 12320, 41328, 0, 8224, 0, 128, 0, 0, 0, 144, 94240, 0, 90144, 0, 0, 0, 0, 0, 160, 0, 0, 0, 176, 0, 0, 0, 0, 0, 0, 4448, 82272, 20832, 0, 16736, 37216, 45408, 0, 49504, 41312, 33120, 12640, 29024, 112, 8544, 53600, 74080, 86368, 24928, 0, 0, 94560, 57696, 90464, 78176, 0, 0, 0, 65552, 20704, 0, 0, 0, 0, 0, 49376, 0, 32992, 0, 0, 0, 0, 53472, 0, 69648, 0, 0, 0, 0, 57568, 65904, 61456, 0, 4336, 65584, 20720, 0, 0, 0, 0, 0, 49392, 0, 33008, 12528, 28912, 70000, 8432, 53488, 0, 69680, 24816, 49664, 61808, 33280, 57584, 29184, 61488, 0, 53760, 0, 0, 0, 0, 0, 0, 57856, 90624, 0, 4160, 81984, 20544, 0, 0, 36928, 45120, 0, 0, 41024, 32832, 12352, 28736, 0, 8256, 0, 0, 86080, 24640, 0, 0, 94272, 65600, 0, 77888, 37264, 45456, 0, 0, 41360, 4176, 82000, 20560, 65936, 16464, 36944, 45136, 0, 69696, 41040, 32848, 12368, 28752, 0, 8272, 61504, 0, 0, 24656, 70032, 0, 94288, 0, 0, 77904, 0, 61840, 0, 69712, 82336, 20896, 0, 0, 37280, 45472, 61520, 0, 41376, 0, 65952, 0, 0, 0, 0, 74144, 86432, 24992, 0, 0, 0, 0, 0, 78240, 0, 0, 70048, 0, 0, 4192, 82016, 20576, 0, 61856, 36960, 45152, 0, 0, 41056, 32864, 12384, 28768, 0, 8288, 0, 73824, 86112, 24672, 0, 0, 0, 0, 90208, 77920, 82304, 20864, 0, 0, 37248, 45440, 0, 0, 41344, 33152, 0, 29056, 65920, 0, 0, 74112, 86400, 24960, 0, 0, 4224, 82048, 20608, 78208, 16512, 36992, 45184, 0, 70016, 41088, 32896, 12416, 28800, 0, 8320, 61824, 73856, 86144, 24704, 0, 0, 94336, 0, 90240, 77952, 0, 82368, 20928, 0, 0, 37312, 45504, 0, 49600, 41408, 33216, 0, 29120, 0, 0, 53696, 74176, 86464, 25024, 0, 0, 0, 57792, 90560, 78272, 4240, 82064, 20624, 0, 16528, 37008, 45200, 65680, 0, 41104, 0, 12432, 28816, 0, 8336, 0, 73872, 86160, 0, 0, 0, 94352, 0, 69776, 77968, 4400, 0, 0, 0, 0, 61584, 0, 0, 49456, 0, 33072, 12592, 28976, 0, 8496, 53552, 0, 0, 0, 65888, 20752, 0, 57648, 90416, 0, 0, 49424, 65984, 33040, 12560, 28944, 0, 0, 53520, 0, 69984, 0, 0, 0, 0, 57616, 0, 61792, 70080, 82032, 20592, 0, 16496, 36976, 45168, 61888, 0, 41072, 32880, 12400, 28784, 0, 8304, 0, 73840, 86128, 24688, 0, 0, 0, 0, 90224, 77936, 0, 0, 4256, 82080, 20640, 0, 16544, 37024, 45216, 0, 0, 41120, 32928, 12448, 28832, 0, 8352, 0, 73888, 86176, 24736, 0, 0, 94368, 0, 90272, 77984, 4432, 0, 20816, 37328, 45520, 0, 0, 41424, 49488, 0, 33104, 12624, 29008, 0, 8528, 53584, 0, 0, 24912, 0, 0, 0, 57680, 90448, 0, 4272, 82096, 20656, 0, 16560, 37040, 45232, 0, 0, 41136, 32944, 12464, 28848, 0, 8368, 0, 73904, 86192, 24752, 65648, 0, 94384, 82400, 20960, 78000, 0, 37344, 45536, 0, 0, 41440, 33248, 0, 29152, 0, 69744, 65712, 74208, 86496, 25056, 0, 0, 61552, 0, 90592, 78304, 4352, 65632, 20736, 0, 16640, 0, 69808, 0, 49408, 0, 33024, 12544, 28928, 61616, 8448, 53504, 0, 69728, 24832, 0, 0, 0, 57600, 0, 61536, 0, 4384, 65664, 20768, 0, 0, 66016, 0, 0, 49440, 49680, 33056, 12576, 28960, 0, 8480, 53536, 53776, 69760, 24864, 0, 0, 0, 57632, 57872, 61568, 82352, 20912, 0, 61920, 37296, 45488, 0, 49584, 41392, 33200, 0, 29104, 0, 0, 53680, 74160, 86448, 25008, 65968, 65696, 0, 57776, 90544, 78256, 0, 0, 49472, 0, 33088, 0, 28992, 0, 0, 53568, 70064, 69792, 0, 0, 66000, 0, 57664, 61872, 61600, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 70096, 0, 0, 0, 0, 0, 0, 61904};
+
diff --git a/src/pinyin/segmentor.h b/src/pinyin/segmentor.h
new file mode 100644 (file)
index 0000000..9af15f1
--- /dev/null
@@ -0,0 +1,97 @@
+// -*- mode: c++ -*-
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright (c) 2007 Sun Microsystems, Inc. All Rights Reserved.
+ *
+ * The contents of this file are subject to the terms of either the GNU Lesser
+ * General Public License Version 2.1 only ("LGPL") or the Common Development and
+ * Distribution License ("CDDL")(collectively, the "License"). You may not use this
+ * file except in compliance with the License. You can obtain a copy of the CDDL at
+ * http://www.opensource.org/licenses/cddl1.php and a copy of the LGPLv2.1 at
+ * http://www.opensource.org/licenses/lgpl-license.php. See the License for the
+ * specific language governing permissions and limitations under the License. When
+ * distributing the software, include this License Header Notice in each file and
+ * include the full text of the License in the License file as well as the
+ * following notice:
+ *
+ * NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND DISTRIBUTION LICENSE
+ * (CDDL)
+ * For Covered Software in this distribution, this License shall be governed by the
+ * laws of the State of California (excluding conflict-of-law provisions).
+ * Any litigation relating to this License shall be subject to the jurisdiction of
+ * the Federal Courts of the Northern District of California and the state courts
+ * of the State of California, with venue lying in Santa Clara County, California.
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by only the CDDL or only
+ * the LGPL Version 2.1, indicate your decision by adding "[Contributor]" elects to
+ * include this software in this distribution under the [CDDL or LGPL Version 2.1]
+ * license." If you don't indicate a single choice of license, a recipient has the
+ * option to distribute your version of this file under either the CDDL or the LGPL
+ * Version 2.1, or to extend the choice of license to its licensees as provided
+ * above. However, if you add LGPL Version 2.1 code and therefore, elected the LGPL
+ * Version 2 license, then the option applies only if the new code is made subject
+ * to such option by the copyright holder.
+ */
+
+#ifndef SUNPY_SEGMENTOR_H
+#define SUNPY_SEGMENTOR_H
+
+#include "portability.h"
+#include "syllable.h"
+#include <vector>
+
+struct IPySegmentor {
+    enum ESegmentType
+    { SYLLABLE, SYLLABLE_SEP, INVALID, STRING };
+
+    struct TSegment {
+        TSegment (ESegmentType type = SYLLABLE) : m_type(type),
+                                                  m_inner_fuzzy(0) {}
+        TSegment (unsigned syllable,
+                  unsigned start,
+                  unsigned length,
+                  ESegmentType type = SYLLABLE)
+            : m_start(start), m_len(length), m_type(type), m_inner_fuzzy(0)
+        { m_syllables.push_back(syllable); }
+
+        bool operator <(const TSegment& other) const {
+            if (m_start < other.m_start)
+                return true;
+
+            if (m_start == other.m_start)
+                return m_len < m_len;
+
+            return false;
+        }
+
+        // if segment is a STRING type, m_syllables may contain the string buffer without the '\0'
+        std::vector<unsigned>           m_syllables;
+        std::vector<unsigned>           m_fuzzy_syllables;
+        unsigned m_start        : 16;
+        unsigned m_len          : 8;
+        ESegmentType m_type         : 7;
+        bool m_inner_fuzzy  : 1;
+    };
+
+    // it requires the segments are sorted by its m_start field
+    typedef std::vector<TSegment>  TSegmentVec;
+
+    virtual ~IPySegmentor () {}
+    virtual TSegmentVec& getSegments(bool req_aux_segs = true) = 0;
+    virtual const wstring& getInputBuffer() = 0;
+    virtual const char* getSylSeps() = 0;
+
+    virtual unsigned push(unsigned ch) = 0;
+    virtual unsigned pop() = 0;
+    virtual unsigned insertAt(unsigned idx, unsigned ch) = 0;
+    virtual unsigned deleteAt(unsigned idx, bool backward = true) = 0;
+    virtual unsigned clear(unsigned from = 0) = 0;
+    virtual void     notify_best_segpath(std::vector<unsigned>& seg_path) {}
+
+    virtual unsigned updatedFrom() = 0;
+};
+
+#endif
diff --git a/src/pinyin/shuangpin_data.cpp b/src/pinyin/shuangpin_data.cpp
new file mode 100644 (file)
index 0000000..44a12e9
--- /dev/null
@@ -0,0 +1,386 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright (c) 2007 Sun Microsystems, Inc. All Rights Reserved.
+ *
+ * The contents of this file are subject to the terms of either the GNU Lesser
+ * General Public License Version 2.1 only ("LGPL") or the Common Development and
+ * Distribution License ("CDDL")(collectively, the "License"). You may not use this
+ * file except in compliance with the License. You can obtain a copy of the CDDL at
+ * http://www.opensource.org/licenses/cddl1.php and a copy of the LGPLv2.1 at
+ * http://www.opensource.org/licenses/lgpl-license.php. See the License for the
+ * specific language governing permissions and limitations under the License. When
+ * distributing the software, include this License Header Notice in each file and
+ * include the full text of the License in the License file as well as the
+ * following notice:
+ *
+ * NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND DISTRIBUTION LICENSE
+ * (CDDL)
+ * For Covered Software in this distribution, this License shall be governed by the
+ * laws of the State of California (excluding conflict-of-law provisions).
+ * Any litigation relating to this License shall be subject to the jurisdiction of
+ * the Federal Courts of the Northern District of California and the state courts
+ * of the State of California, with venue lying in Santa Clara County, California.
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by only the CDDL or only
+ * the LGPL Version 2.1, indicate your decision by adding "[Contributor]" elects to
+ * include this software in this distribution under the [CDDL or LGPL Version 2.1]
+ * license." If you don't indicate a single choice of license, a recipient has the
+ * option to distribute your version of this file under either the CDDL or the LGPL
+ * Version 2.1, or to extend the choice of license to its licensees as provided
+ * above. However, if you add LGPL Version 2.1 code and therefore, elected the LGPL
+ * Version 2 license, then the option applies only if the new code is made subject
+ * to such option by the copyright holder.
+ */
+
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <algorithm>
+#include <cassert>
+#include "syllable.h"
+#include "pinyin_data.h"
+#include "shuangpin_data.h"
+
+#define INITIAL_NUM 26
+#define FINAL_NUM   34
+#define ZEROINITIAL_NUM 12
+
+static const char *initials[INITIAL_NUM] =
+{ "", "", "", "b", "p", "m", "f", "d", "t", "n", "l",
+  "g", "k", "h", "j", "q", "x", "zh",
+  "ch", "sh", "r", "z", "c", "s", "y", "w", };
+
+static const char *finals[FINAL_NUM] = { "", "a", "o", "e", "ai", "ei", "ao",
+                                         "ou", "an", "en", "ang", "eng", "er",
+                                         "i", "ia", "ie", "iao", "iu", "ian",
+                                         "in", "iang", "ing", "u",
+                                         "ua", "uo", "uai", "ui", "uan", "un",
+                                         "uang", "ong", "v", "ue", "iong", };
+
+
+//MS2003 shuangpin plan map table
+static const char ms2003_mapinitials[INITIAL_NUM] =
+{ '\0', '\0', 'o', 'b', 'p', 'm', 'f', 'd',
+  't', 'n', 'l', 'g', 'k',
+  'h', 'j', 'q', 'x', 'v', 'i', 'u', 'r', 'z', 'c', 's',
+  'y', 'w', };
+
+static const char ms2003_mapfinals[FINAL_NUM] =
+{ '\0', 'a', 'o', 'e', 'l', 'z', 'k',
+  'b', 'j', 'f', 'h', 'g', 'r',
+  'i', 'w', 'x', 'c', 'q', 'm', 'n', 'd', ';', 'u',
+  'w', 'o', 'y', 'v', 'r', 'p',
+  'd', 's', 'v', 't', 's', };
+
+static TZeroInitial ms2003_zeroinitials[] = {
+    { "a", "oa" },
+    { "ai", "ol" },
+    { "an", "oj" },
+    { "ang", "oh" },
+    { "ao", "ok" },
+    { "e", "oe" },
+    { "ei", "oz" },
+    { "en", "of" },
+    { "eng", "og" },
+    { "er", "or" },
+    { "o", "oo" },
+    { "ou", "ob" },
+};
+
+
+//ZhiNengABC shuangpin plan map table
+static const char abc_mapinitials[INITIAL_NUM] =
+{ '\0', '\0', 'o', 'b', 'p', 'm', 'f', 'd',
+  't', 'n', 'l', 'g', 'k', 'h',
+  'j', 'q', 'x', 'a', 'e', 'v', 'r', 'z', 'c', 's',
+  'y', 'w', };
+
+static const char abc_mapfinals[FINAL_NUM] =
+{ '\0', 'a', 'o', 'e', 'l', 'q', 'k',
+  'b', 'j', 'f', 'h', 'g', 'r',
+  'i', 'd', 'x', 'z', 'r', 'w', 'c', 't', 'y', 'u',
+  'd', 'o', 'c', 'm', 'p', 'n',
+  't', 's', 'v', 'm', 's', };
+
+static TZeroInitial abc_zeroinitials[] = {
+    { "a", "oa" },
+    { "ai", "ol" },
+    { "an", "oj" },
+    { "ang", "oh" },
+    { "ao", "ok" },
+    { "e", "oe" },
+    { "ei", "oq" },
+    { "en", "of" },
+    { "eng", "og" },
+    { "er", "or" },
+    { "o", "oo" },
+    { "ou", "ob" },
+};
+
+//ZiGuang shuangpin plan map table
+static const char ziguang_mapinitials[INITIAL_NUM] =
+{ '\0', '\0', 'o', 'b', 'p', 'm', 'f', 'd',
+  't', 'n', 'l', 'g', 'k',
+  'h', 'j', 'q', 'x', 'u', 'a', 'i', 'r', 'z', 'c', 's',
+  'y', 'w', };
+
+static const char ziguang_mapfinals[FINAL_NUM] =
+{ '\0', 'a', 'o', 'e', 'p', 'k', 'q',
+  'z', 'r', 'w', 's', 't', 'j',
+  'i', 'x', 'd', 'b', 'j', 'f', 'y', 'g', ';', 'u',
+  'x', 'o', 'y', 'n', 'l', 'm',
+  'g', 'h', 'v', 'n', 'h', };
+
+static TZeroInitial ziguang_zeroinitials[] = {
+    { "a", "oa" },
+    { "ai", "op" },
+    { "an", "or" },
+    { "ang", "os" },
+    { "ao", "oq" },
+    { "e", "oe" },
+    { "ei", "ok" },
+    { "en", "ow" },
+    { "eng", "ot" },
+    { "er", "oj" },
+    { "o", "oo" },
+    { "ou", "oz" },
+};
+
+//PinYinJiaJia shuangpin plan map table
+static const char pyjiajia_mapinitials[INITIAL_NUM] =
+{ '\0', '\0', 'o', 'b', 'p', 'm', 'f', 'd',
+  't', 'n', 'l', 'g', 'k',
+  'h', 'j', 'q', 'x', 'v', 'u', 'i', 'r', 'z', 'c', 's',
+  'y', 'w', };
+
+static const char pyjiajia_mapfinals[FINAL_NUM] =
+{ '\0', 'a', 'o', 'e', 's', 'w', 'd',
+  'p', 'f', 'r', 'g', 't',
+  'q', 'i', 'b', 'm', 'k', 'n', 'j', 'l', 'h', 'q', 'u',
+  'b', 'o', 'x', 'v', 'c',
+  'z', 'h', 'y', 'v', 'x', 'y', };
+
+static TZeroInitial pyjiajia_zeroinitials[] = {
+    { "a", "oa" },
+    { "ai", "os" },
+    { "an", "of" },
+    { "ang", "og" },
+    { "ao", "od" },
+    { "e", "oe" },
+    { "ei", "ow" },
+    { "en", "or" },
+    { "eng", "ot" },
+    { "er", "oq" },
+    { "o", "oo" },
+    { "ou", "op" },
+};
+
+//Ziranma shuangpin plan map table
+static const char ziranma_mapinitials[INITIAL_NUM] =
+{ 'a', 'e', 'o', 'b', 'p', 'm', 'f', 'd',
+  't', 'n', 'l', 'g', 'k',
+  'h', 'j', 'q', 'x', 'v', 'i', 'u', 'r', 'z', 'c', 's',
+  'y', 'w', };
+
+static const char ziranma_mapfinals[FINAL_NUM] =
+{ '\0', 'a', 'o', 'e', 'l', 'z', 'k',
+  'b', 'j', 'f', 'h', 'g',
+  '\0', 'i', 'w', 'x', 'c', 'q', 'm', 'n', 'd', 'y', 'u',
+  'w', 'o', 'y', 'v', 'r', 'p',
+  'd', 's', 'v', 't', 's', };
+
+static TZeroInitial ziranma_zeroinitials[] = {
+    { "a", "aa" },
+    { "ai", "ai" },
+    { "an", "an" },
+    { "ang", "ah" },
+    { "ao", "ao" },
+    { "e", "ee" },
+    { "ei", "ei" },
+    { "en", "en" },
+    { "eng", "eg" },
+    { "er", "er" },
+    { "o", "oo" },
+    { "ou", "ou" },
+};
+
+//Ziranma shuangpin plan map table
+static const char xiaohe_mapinitials[INITIAL_NUM] =
+{ 'a', 'e', 'o', 'b', 'p', 'm', 'f', 'd',
+  't', 'n', 'l', 'g', 'k',
+  'h', 'j', 'q', 'x', 'v', 'i', 'u', 'r', 'z', 'c', 's',
+  'y', 'w', };
+
+static const char xiaohe_mapfinals[FINAL_NUM] =
+{ '\0', 'a', 'o', 'e', 'd', 'w', 'c',
+  'z', 'j', 'f', 'h', 'g', '\0',
+  'i', 'x', 'p', 'n', 'q', 'm', 'b', 'l', 'k', 'u',
+  'x', 'o', 'k', 'v', 'r', 'y',
+  'l', 's', 'v', 't', 's', };
+
+static TZeroInitial xiaohe_zeroinitials[] = {
+    { "a", "aa" },
+    { "ai", "ai" },
+    { "an", "an" },
+    { "ang", "ah" },
+    { "ao", "ao" },
+    { "e", "ee" },
+    { "ei", "ei" },
+    { "en", "en" },
+    { "eng", "eg" },
+    { "er", "er" },
+    { "o", "oo" },
+    { "ou", "ou" },
+};
+
+CShuangpinData::CShuangpinData (EShuangpinType shpPlan) : m_shuangpinPlan(NULL)
+{
+    _genCodingMap();
+    _genKeyboardMap(shpPlan);
+}
+
+CShuangpinData::~CShuangpinData()
+{
+    delete m_shuangpinPlan;
+}
+
+TSyllable
+CShuangpinData::encodeSyllable(const char *pinyin)
+{
+    std::map<std::string, TSyllable>::iterator iter;
+    iter = m_codingmap.find(pinyin);
+    if (iter != m_codingmap.end()) {
+        return iter->second;
+    }
+    return (TSyllable)0;
+}
+
+const char *
+CShuangpinData::decodeSyllable(TSyllable s, const char **i, const char **f)
+{
+    return NULL;
+}
+
+int
+CShuangpinData::getMapString(const char *shpstr, CMappedYin &syls)
+{
+    assert(shpstr != NULL);
+    assert(m_shuangpinPlan->mapinitials != NULL);
+
+    const char *ch = shpstr;
+    int len = strlen(shpstr);
+    char buf[32] = "\0";
+
+    syls.clear();
+    switch (len) {
+    case 1:
+        for (int i = 0; i < INITIAL_NUM; i++) {
+            if (*ch == m_shuangpinPlan->mapinitials[i]) {
+                syls.push_back(std::string(initials[i]));
+                return 1;
+            }
+        }
+        break;
+    case 2:
+        if (m_shuangpinPlan->zeroinitals != NULL) {
+            for (int i = 0; i < ZEROINITIAL_NUM; i++) {
+                if (!strcmp(shpstr, m_shuangpinPlan->zeroinitals[i].mapshp)) {
+                    syls.push_back(std::string(m_shuangpinPlan->zeroinitals[i].
+                                               syl));
+                    return 1;
+                }
+            }
+        }
+
+        for (int i = 0; i < INITIAL_NUM; i++) {
+            if (*ch == m_shuangpinPlan->mapinitials[i]) {
+                for (int j = 0; j < FINAL_NUM; j++) {
+                    if (*(ch + 1) == m_shuangpinPlan->mapfinals[j]) {
+                        sprintf(buf, "%s%s", initials[i], finals[j]);
+                        std::map<std::string, TSyllable>::iterator iter;
+                        iter = m_codingmap.find(buf);
+                        if (iter != m_codingmap.end()) {
+                            syls.push_back(std::string(buf));
+                        }
+                    }
+                }
+            }
+        }
+        break;
+    default:
+        //Invalid shuangpin input character number, return 0;
+        break;
+    }
+
+    return syls.size();
+}
+
+void
+CShuangpinData::setShuangpinType(EShuangpinType shpType)
+{
+    if (shpType == getShuangpinType()) {
+        return;
+    }
+    _genKeyboardMap(shpType);
+}
+
+
+void
+CShuangpinData::_genCodingMap()
+{
+    unsigned len;
+    const TPyTabEntry *pinyin_table = CPinyinData::getPinyinTable(len);
+
+    for (size_t i = 0; i < len; ++i) {
+        m_codingmap.insert(CEncodingMap::value_type(pinyin_table[i].pystr,
+                                                    pinyin_table[i].id));
+    }
+}
+
+void
+CShuangpinData::_genKeyboardMap(EShuangpinType shyType)
+{
+    if (m_shuangpinPlan == NULL) {
+        m_shuangpinPlan = new TShuangpinPlan;
+        memset(m_shuangpinPlan, 0, sizeof(TShuangpinPlan));
+    }
+    m_shuangpinPlan->type = shyType;
+    switch (shyType) {
+    case MS2003:
+        m_shuangpinPlan->mapinitials = (char*)ms2003_mapinitials;
+        m_shuangpinPlan->mapfinals = (char*)ms2003_mapfinals;
+        m_shuangpinPlan->zeroinitals = ms2003_zeroinitials;
+        break;
+    case ABC:
+        m_shuangpinPlan->mapinitials = (char*)abc_mapinitials;
+        m_shuangpinPlan->mapfinals = (char*)abc_mapfinals;
+        m_shuangpinPlan->zeroinitals = abc_zeroinitials;
+        break;
+    case ZIGUANG:
+        m_shuangpinPlan->mapinitials = (char*)ziguang_mapinitials;
+        m_shuangpinPlan->mapfinals = (char*)ziguang_mapfinals;
+        m_shuangpinPlan->zeroinitals = ziguang_zeroinitials;
+        break;
+    case PINYINJIAJIA:
+        m_shuangpinPlan->mapinitials = (char*)pyjiajia_mapinitials;
+        m_shuangpinPlan->mapfinals = (char*)pyjiajia_mapfinals;
+        m_shuangpinPlan->zeroinitals = pyjiajia_zeroinitials;
+        break;
+    case ZIRANMA:
+        m_shuangpinPlan->mapinitials = (char*)ziranma_mapinitials;
+        m_shuangpinPlan->mapfinals = (char*)ziranma_mapfinals;
+        m_shuangpinPlan->zeroinitals = ziranma_zeroinitials;
+        break;
+    case XIAOHE:
+        m_shuangpinPlan->mapinitials = (char*)xiaohe_mapinitials;
+        m_shuangpinPlan->mapfinals = (char*)xiaohe_mapfinals;
+        m_shuangpinPlan->zeroinitals = xiaohe_zeroinitials;
+        break;
+    default:
+        break;
+    }
+}
diff --git a/src/pinyin/shuangpin_data.h b/src/pinyin/shuangpin_data.h
new file mode 100644 (file)
index 0000000..c62c6ac
--- /dev/null
@@ -0,0 +1,101 @@
+// -*- mode: c++ -*-
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright (c) 2007 Sun Microsystems, Inc. All Rights Reserved.
+ *
+ * The contents of this file are subject to the terms of either the GNU Lesser
+ * General Public License Version 2.1 only ("LGPL") or the Common Development and
+ * Distribution License ("CDDL")(collectively, the "License"). You may not use this
+ * file except in compliance with the License. You can obtain a copy of the CDDL at
+ * http://www.opensource.org/licenses/cddl1.php and a copy of the LGPLv2.1 at
+ * http://www.opensource.org/licenses/lgpl-license.php. See the License for the
+ * specific language governing permissions and limitations under the License. When
+ * distributing the software, include this License Header Notice in each file and
+ * include the full text of the License in the License file as well as the
+ * following notice:
+ *
+ * NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND DISTRIBUTION LICENSE
+ * (CDDL)
+ * For Covered Software in this distribution, this License shall be governed by the
+ * laws of the State of California (excluding conflict-of-law provisions).
+ * Any litigation relating to this License shall be subject to the jurisdiction of
+ * the Federal Courts of the Northern District of California and the state courts
+ * of the State of California, with venue lying in Santa Clara County, California.
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by only the CDDL or only
+ * the LGPL Version 2.1, indicate your decision by adding "[Contributor]" elects to
+ * include this software in this distribution under the [CDDL or LGPL Version 2.1]
+ * license." If you don't indicate a single choice of license, a recipient has the
+ * option to distribute your version of this file under either the CDDL or the LGPL
+ * Version 2.1, or to extend the choice of license to its licensees as provided
+ * above. However, if you add LGPL Version 2.1 code and therefore, elected the LGPL
+ * Version 2 license, then the option applies only if the new code is made subject
+ * to such option by the copyright holder.
+ */
+
+#ifndef _SHUANGPIN_DATA_H_
+#define _SHUANGPIN_DATA_H_
+
+#include <string>
+#include <map>
+
+#include "ime-core/utils.h"
+#include "syllable.h"
+
+enum EShuangpinType {
+    MS2003,
+    ABC,
+    ZIRANMA,
+    PINYINJIAJIA,
+    ZIGUANG,
+    XIAOHE,
+    USERDEFINE,
+};
+
+typedef struct _TZeroinitial {
+    const char  *syl;
+    const char  *mapshp;
+} TZeroInitial;
+
+typedef struct _TShungpinPlan {
+    EShuangpinType type;
+    char *mapinitials;
+    char *mapfinals;
+    TZeroInitial *zeroinitals;
+} TShuangpinPlan;
+
+
+typedef std::vector<std::string>         CMappedYin;
+typedef std::map<std::string, TSyllable> CEncodingMap;
+typedef std::map <char, CMappedYin*>     CKeyMap;
+
+class CShuangpinData : private CNonCopyable
+{
+public:
+    CShuangpinData (EShuangpinType shpPlan = MS2003);
+    ~CShuangpinData ();
+
+
+
+    TSyllable encodeSyllable(const char *);
+    const char *decodeSyllable(TSyllable,
+                               const char **i = NULL,
+                               const char **f = NULL);
+
+    int getMapString(const char *ch, CMappedYin & syls);
+    EShuangpinType getShuangpinType() const { return m_shuangpinPlan->type; }
+    void setShuangpinType(EShuangpinType shpPlan);
+
+protected:
+    void  _genCodingMap();
+    void  _genKeyboardMap(EShuangpinType shyType);
+
+    CEncodingMap m_codingmap;
+    TShuangpinPlan *m_shuangpinPlan;
+    CKeyMap m_keymap;
+};
+
+#endif /* _PINYIN_DATA_H_ */
diff --git a/src/pinyin/shuangpin_seg.cpp b/src/pinyin/shuangpin_seg.cpp
new file mode 100644 (file)
index 0000000..20d1da8
--- /dev/null
@@ -0,0 +1,357 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright (c) 2007 Sun Microsystems, Inc. All Rights Reserved.
+ *
+ * The contents of this file are subject to the terms of either the GNU Lesser
+ * General Public License Version 2.1 only ("LGPL") or the Common Development and
+ * Distribution License ("CDDL")(collectively, the "License"). You may not use this
+ * file except in compliance with the License. You can obtain a copy of the CDDL at
+ * http://www.opensource.org/licenses/cddl1.php and a copy of the LGPLv2.1 at
+ * http://www.opensource.org/licenses/lgpl-license.php. See the License for the
+ * specific language governing permissions and limitations under the License. When
+ * distributing the software, include this License Header Notice in each file and
+ * include the full text of the License in the License file as well as the
+ * following notice:
+ *
+ * NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND DISTRIBUTION LICENSE
+ * (CDDL)
+ * For Covered Software in this distribution, this License shall be governed by the
+ * laws of the State of California (excluding conflict-of-law provisions).
+ * Any litigation relating to this License shall be subject to the jurisdiction of
+ * the Federal Courts of the Northern District of California and the state courts
+ * of the State of California, with venue lying in Santa Clara County, California.
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by only the CDDL or only
+ * the LGPL Version 2.1, indicate your decision by adding "[Contributor]" elects to
+ * include this software in this distribution under the [CDDL or LGPL Version 2.1]
+ * license." If you don't indicate a single choice of license, a recipient has the
+ * option to distribute your version of this file under either the CDDL or the LGPL
+ * Version 2.1, or to extend the choice of license to its licensees as provided
+ * above. However, if you add LGPL Version 2.1 code and therefore, elected the LGPL
+ * Version 2 license, then the option applies only if the new code is made subject
+ * to such option by the copyright holder.
+ */
+
+#include <cassert>
+#include <climits>
+#include "shuangpin_seg.h"
+
+CShuangpinData CShuangpinSegmentor::s_shpData;
+
+CShuangpinSegmentor::CShuangpinSegmentor (EShuangpinType shpType)
+    : m_updatedFrom(0), m_nAlpha(0), m_hasInvalid(false), m_nLastValidPos(0)
+{
+    m_segs.reserve(32);
+    m_pystr.reserve(32);
+    s_shpData.setShuangpinType(shpType);
+}
+
+unsigned
+CShuangpinSegmentor::push(unsigned ch)
+{
+    m_inputBuf.push_back(ch);
+
+    return m_updatedFrom = _push(ch);
+}
+
+unsigned
+CShuangpinSegmentor::pop()
+{
+    if (m_pystr.empty())
+        return m_updatedFrom = 0;
+
+    unsigned size = m_inputBuf.size();
+
+    EShuangpinType shpType = s_shpData.getShuangpinType();
+    bool isInputPy = (islower(m_pystr[size - 1]) ||
+                      (m_pystr[size - 1] == ';' &&
+                       (shpType == MS2003 || shpType == ZIGUANG)));
+    if (!isInputPy) {
+        m_nAlpha -= 1;
+    }
+
+    m_inputBuf.resize(size - 1);
+    m_pystr.resize(size - 1);
+
+    unsigned l = m_segs.back().m_len;
+    m_segs.pop_back();
+
+    if (size == 1 || m_segs.back().m_type != IPySegmentor::INVALID) {
+        m_hasInvalid = false;
+    }
+    if (l == 1)
+        return m_updatedFrom = size - 1;
+
+    std::string new_pystr = m_pystr.substr(size - l);
+    m_pystr.resize(size - l);
+
+    m_updatedFrom = UINT_MAX;
+    std::string::const_iterator it = new_pystr.begin();
+    for (; it != new_pystr.end(); ++it) {
+        unsigned tmp = _push((*it) & 0x7f);
+        if (tmp < m_updatedFrom) m_updatedFrom = tmp;
+    }
+
+    return m_updatedFrom;
+}
+
+unsigned
+CShuangpinSegmentor::insertAt(unsigned idx, unsigned ch)
+{
+    unsigned pyIdx, segIdx;
+    _locateSegment(idx, pyIdx, segIdx);
+
+    m_inputBuf.insert(idx, 1, ch);
+    m_pystr.insert(idx, 1, ch);
+
+    std::string new_pystr = m_pystr.substr(pyIdx);
+    m_pystr.resize(pyIdx);
+    m_segs.erase(m_segs.begin() + segIdx, m_segs.end());
+
+    if (m_nLastValidPos == idx) {
+        m_hasInvalid = false;
+    } else if (m_nLastValidPos + 1 == idx) {
+        m_hasInvalid = false;
+        int nSize = m_pystr.size();
+        if (islower(m_pystr[nSize - 1])) {
+            m_nLastValidPos = idx - 1;
+            new_pystr.insert((size_t)0, 1, m_pystr[nSize - 1]);
+            m_pystr.erase(nSize - 1, 1);
+            m_segs.erase(m_segs.begin() + segIdx - 1);
+        }
+    } else if (m_nLastValidPos + 1 > idx) {
+        m_hasInvalid = false;
+        m_nLastValidPos = idx;
+    }
+    m_nAlpha = _getNumberOfNonAlpha();
+
+    m_updatedFrom = UINT_MAX;
+    std::string::const_iterator it = new_pystr.begin();
+    for (; it != new_pystr.end(); ++it) {
+        unsigned tmp = _push((*it) & 0x7f);
+        if (tmp < m_updatedFrom) m_updatedFrom = tmp;
+    }
+
+    return m_updatedFrom;
+}
+
+unsigned
+CShuangpinSegmentor::deleteAt(unsigned idx, bool backward)
+{
+    unsigned pyIdx, segIdx;
+    if (!backward) idx += 1;
+    _locateSegment(idx, pyIdx, segIdx);
+
+    m_inputBuf.erase(idx, 1);
+    m_pystr.erase(idx, 1);
+
+    std::string new_pystr = m_pystr.substr(pyIdx);
+    m_pystr.resize(pyIdx);
+    TSegmentVec tmp_segs(m_segs.begin() + segIdx + 1, m_segs.end());
+    m_segs.erase(m_segs.begin() + segIdx, m_segs.end());
+
+    if (m_nLastValidPos + 1 < idx) {
+        //del invalid ch, and do not effect current status.
+        m_pystr.insert(idx, new_pystr);
+        m_segs.insert(m_segs.end(), tmp_segs.begin(), tmp_segs.end());
+        return m_inputBuf.size() - 1;
+    } else {
+        m_hasInvalid = false;
+        m_nAlpha = _getNumberOfNonAlpha();
+    }
+
+    m_updatedFrom = UINT_MAX;
+    std::string::const_iterator it = new_pystr.begin();
+    for (; it != new_pystr.end(); ++it) {
+        unsigned tmp = _push((*it) & 0x7f);
+        if (tmp < m_updatedFrom) m_updatedFrom = tmp;
+    }
+
+    return m_updatedFrom;
+}
+
+unsigned
+CShuangpinSegmentor::clear(unsigned from)
+{
+    m_inputBuf.resize(from);
+    return _clear(from);
+}
+
+unsigned
+CShuangpinSegmentor::_clear(unsigned from)
+{
+    unsigned i, j;
+    _locateSegment(from, i, j);
+
+    std::string new_pystr = m_pystr.substr(i, from - i);
+    m_pystr.resize(i);
+    m_nAlpha = _getNumberOfNonAlpha();
+
+    m_segs.erase(m_segs.begin() + j, m_segs.end());
+
+    if (m_nLastValidPos + 1 >= from) {
+        m_hasInvalid = false;
+    }
+
+    m_updatedFrom = from;
+
+    for (std::string::const_iterator it = new_pystr.begin();
+         it != new_pystr.end(); ++it) {
+        unsigned tmp = _push((*it) & 0x7f);
+        if (tmp < m_updatedFrom) m_updatedFrom = tmp;
+    }
+
+    return m_updatedFrom;
+}
+
+int
+CShuangpinSegmentor::_getNumberOfNonAlpha() const
+{
+    int nNonAlpha = 0;
+    for (const char* c = m_pystr.c_str(); *c != 0; ++c) {
+        if (!islower(*c))
+            ++nNonAlpha;
+    }
+    return nNonAlpha;
+}
+
+void
+CShuangpinSegmentor::_locateSegment(unsigned idx,
+                                    unsigned &strIdx,
+                                    unsigned &segIdx)
+{
+    strIdx = segIdx = 0;
+
+    TSegmentVec::const_iterator it = m_segs.begin();
+    TSegmentVec::const_iterator ite = m_segs.end();
+
+    for (; it != ite; ++it) {
+        if (strIdx + it->m_len > idx)
+            break;
+
+        strIdx += it->m_len;
+        segIdx += 1;
+    }
+}
+
+int
+CShuangpinSegmentor::_encode(const char* buf, char ch, bool isComplete)
+{
+    CMappedYin syls;
+    syls.reserve(8);
+    s_shpData.getMapString(buf, syls);
+    if (syls.empty())
+        return -1;
+
+    const int len = m_pystr.size();
+    CMappedYin::const_iterator iter = syls.begin();
+    CMappedYin::const_iterator iter_end = syls.end();
+
+    if (isComplete) {
+        TSegment &s = m_segs.back();
+        s.m_len = 2;
+        s.m_start = len - s.m_len;
+        s.m_syllables.clear();
+        s.m_type = IPySegmentor::SYLLABLE;
+        for (; iter != iter_end; iter++) {
+            s.m_syllables.push_back(s_shpData.encodeSyllable(iter->c_str()));
+        }
+        m_nLastValidPos += 1;
+        return s.m_start;
+    } else {
+        TSegment s;
+        s.m_len = 1;
+        s.m_start = len - s.m_len;
+        m_nLastValidPos += 1;
+
+        for (; iter != iter_end; ++iter) {
+            TSyllable syl = s_shpData.encodeSyllable(iter->c_str());
+            if ((int)syl != 0) {
+                s.m_syllables.push_back(syl);
+                m_segs.push_back(s);
+            } else {
+                m_segs.push_back(TSegment(ch, s.m_start, 1,
+                                          IPySegmentor::STRING));
+            }
+        }
+        return s.m_start;
+    }
+}
+
+unsigned
+CShuangpinSegmentor::_push(unsigned ch)
+{
+    int startFrom = 0;
+    bool isInputPy;
+    EShuangpinType shpType;
+
+    m_pystr.push_back(ch);
+    const int len = m_pystr.size();
+    if (m_hasInvalid) {
+        startFrom = len - 1;
+        m_segs.push_back(TSegment(ch, startFrom, 1, IPySegmentor::INVALID));
+        goto RETURN;
+    }
+
+    shpType = s_shpData.getShuangpinType();
+    isInputPy = (islower(ch) ||
+                 (ch == ';' && (shpType == MS2003 || shpType == ZIGUANG)));
+
+    if (!isInputPy) {
+        startFrom = len - 1;
+
+        IPySegmentor::ESegmentType seg_type;
+        if (ch == '\'' && m_inputBuf.size() > 1)
+            seg_type = IPySegmentor::SYLLABLE_SEP;
+        else
+            seg_type = IPySegmentor::STRING;
+        m_segs.push_back(TSegment(ch, startFrom, 1, seg_type));
+        m_nAlpha += 1;
+        m_nLastValidPos += 1;
+    } else {
+        bool bCompleted = !((len - m_nAlpha) % 2) && isInputPy;
+        char buf[4];
+        if (bCompleted) {
+            sprintf(buf, "%c%c", m_pystr[len - 2], ch);
+        } else {
+            sprintf(buf, "%c", ch);
+        }
+        startFrom = _encode(buf, ch, bCompleted);
+        if (startFrom < 0) {
+            m_hasInvalid = true;
+            startFrom = m_pystr.size() - 1;
+            m_segs.push_back(TSegment(ch, startFrom, 1, IPySegmentor::INVALID));
+        }
+    }
+
+RETURN:;
+
+    if (m_pGetFuzzySyllablesOp && m_pGetFuzzySyllablesOp->isEnabled())
+        if (m_segs.back().m_type == SYLLABLE)
+            _addFuzzySyllables(m_segs.back());
+
+    return startFrom;
+}
+
+void
+CShuangpinSegmentor::_addFuzzySyllables(TSegment& seg)
+{
+    assert(seg.m_type == SYLLABLE);
+
+    seg.m_fuzzy_syllables.clear();
+
+    std::vector<unsigned>::iterator it = seg.m_syllables.begin();
+    std::vector<unsigned>::iterator ite = seg.m_syllables.end();
+    for (; it != ite; ++it) {
+        CSyllables fuzzy_set = (*m_pGetFuzzySyllablesOp)(*it);
+
+        CSyllables::const_iterator _it = fuzzy_set.begin();
+        CSyllables::const_iterator _ite = fuzzy_set.end();
+        for (; _it != _ite; ++_it)
+            seg.m_fuzzy_syllables.push_back(*_it);
+    }
+}
+
diff --git a/src/pinyin/shuangpin_seg.h b/src/pinyin/shuangpin_seg.h
new file mode 100644 (file)
index 0000000..296557b
--- /dev/null
@@ -0,0 +1,89 @@
+// -*- mode: c++ -*-
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright (c) 2007 Sun Microsystems, Inc. All Rights Reserved.
+ *
+ * The contents of this file are subject to the terms of either the GNU Lesser
+ * General Public License Version 2.1 only ("LGPL") or the Common Development and
+ * Distribution License ("CDDL")(collectively, the "License"). You may not use this
+ * file except in compliance with the License. You can obtain a copy of the CDDL at
+ * http://www.opensource.org/licenses/cddl1.php and a copy of the LGPLv2.1 at
+ * http://www.opensource.org/licenses/lgpl-license.php. See the License for the
+ * specific language governing permissions and limitations under the License. When
+ * distributing the software, include this License Header Notice in each file and
+ * include the full text of the License in the License file as well as the
+ * following notice:
+ *
+ * NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND DISTRIBUTION LICENSE
+ * (CDDL)
+ * For Covered Software in this distribution, this License shall be governed by the
+ * laws of the State of California (excluding conflict-of-law provisions).
+ * Any litigation relating to this License shall be subject to the jurisdiction of
+ * the Federal Courts of the Northern District of California and the state courts
+ * of the State of California, with venue lying in Santa Clara County, California.
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by only the CDDL or only
+ * the LGPL Version 2.1, indicate your decision by adding "[Contributor]" elects to
+ * include this software in this distribution under the [CDDL or LGPL Version 2.1]
+ * license." If you don't indicate a single choice of license, a recipient has the
+ * option to distribute your version of this file under either the CDDL or the LGPL
+ * Version 2.1, or to extend the choice of license to its licensees as provided
+ * above. However, if you add LGPL Version 2.1 code and therefore, elected the LGPL
+ * Version 2 license, then the option applies only if the new code is made subject
+ * to such option by the copyright holder.
+ */
+
+#ifndef SUNPY_SHUANGPIN_SEG_H
+#define SUNPY_SHUANGPIN_SEG_H
+
+#include "portability.h"
+#include "shuangpin_data.h"
+#include "segmentor.h"
+#include "pinyin_data.h"
+#include <vector>
+
+class CShuangpinSegmentor : public IPySegmentor
+{
+public:
+    CShuangpinSegmentor (EShuangpinType shpType);
+
+    virtual TSegmentVec& getSegments(bool) { return m_segs; }
+    virtual const wstring& getInputBuffer() { return m_inputBuf; }
+    virtual const char* getSylSeps() { return "'"; }
+
+    virtual unsigned push(unsigned ch);
+    virtual unsigned pop();
+    virtual unsigned insertAt(unsigned idx, unsigned ch);
+    virtual unsigned deleteAt(unsigned idx, bool backward = true);
+    virtual unsigned clear(unsigned from = 0);
+
+    virtual unsigned updatedFrom() { return m_updatedFrom; }
+
+    void setGetFuzzySyllablesOp(CGetFuzzySyllablesOp<CPinyinData> *op) {
+        m_pGetFuzzySyllablesOp = op; }
+
+private:
+    unsigned _push(unsigned ch);
+    unsigned _clear(unsigned from);
+    int _getNumberOfNonAlpha() const;
+    int _encode(const char* buf, char ch, bool isComplete);
+    void _locateSegment(unsigned idx, unsigned &strIdx, unsigned &segIdx);
+
+    inline void _addFuzzySyllables(TSegment &seg);
+
+    static CShuangpinData s_shpData;
+    std::string m_pystr;
+    wstring m_inputBuf;
+    TSegmentVec m_segs;
+    unsigned m_updatedFrom;
+    int m_nAlpha;                                     /* number of non-py chars in m_pystr*/
+    bool m_hasInvalid;                                /* true if there is invalid py in m_pystr */
+    unsigned m_nLastValidPos;
+
+    CGetFuzzySyllablesOp<CPinyinData>  *m_pGetFuzzySyllablesOp;
+};
+
+#endif /* SUNPY_SHUANGPIN_SEG_H */
diff --git a/src/pinyin/syllable.h b/src/pinyin/syllable.h
new file mode 100644 (file)
index 0000000..3f38122
--- /dev/null
@@ -0,0 +1,178 @@
+// -*- mode: c++ -*-
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright (c) 2007 Sun Microsystems, Inc. All Rights Reserved.
+ *
+ * The contents of this file are subject to the terms of either the GNU Lesser
+ * General Public License Version 2.1 only ("LGPL") or the Common Development and
+ * Distribution License ("CDDL")(collectively, the "License"). You may not use this
+ * file except in compliance with the License. You can obtain a copy of the CDDL at
+ * http://www.opensource.org/licenses/cddl1.php and a copy of the LGPLv2.1 at
+ * http://www.opensource.org/licenses/lgpl-license.php. See the License for the
+ * specific language governing permissions and limitations under the License. When
+ * distributing the software, include this License Header Notice in each file and
+ * include the full text of the License in the License file as well as the
+ * following notice:
+ *
+ * NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND DISTRIBUTION LICENSE
+ * (CDDL)
+ * For Covered Software in this distribution, this License shall be governed by the
+ * laws of the State of California (excluding conflict-of-law provisions).
+ * Any litigation relating to this License shall be subject to the jurisdiction of
+ * the Federal Courts of the Northern District of California and the state courts
+ * of the State of California, with venue lying in Santa Clara County, California.
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by only the CDDL or only
+ * the LGPL Version 2.1, indicate your decision by adding "[Contributor]" elects to
+ * include this software in this distribution under the [CDDL or LGPL Version 2.1]
+ * license." If you don't indicate a single choice of license, a recipient has the
+ * option to distribute your version of this file under either the CDDL or the LGPL
+ * Version 2.1, or to extend the choice of license to its licensees as provided
+ * above. However, if you add LGPL Version 2.1 code and therefore, elected the LGPL
+ * Version 2 license, then the option applies only if the new code is made subject
+ * to such option by the copyright holder.
+ */
+
+#ifndef __SUNPINYIN_SYLLABLE_H__
+#define __SUNPINYIN_SYLLABLE_H__
+
+#include <vector>
+#include <string>
+#include <map>
+#include <cstdio>
+
+#include "ime-core/utils.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+struct TSyllable {
+#ifdef WORDS_BIGENDIAN
+    unsigned other    : 12;
+    unsigned initial  : 8;
+    unsigned final    : 8;
+    unsigned tone     : 4;
+#else
+    unsigned tone     : 4;
+    unsigned final    : 8;
+    unsigned initial  : 8;
+    unsigned other    : 12;
+#endif
+    TSyllable (unsigned int s = 0)
+    { *((unsigned *) this) = s; }
+
+    TSyllable (int i, int f, int t)
+    : tone(t), final(f), initial(i), other(0) { }
+
+    operator unsigned int() const
+    { return *((unsigned *) this); }
+
+    bool isFullSyllable() const
+    { return final != 0; }
+
+    bool operator ==(const TSyllable & syl) const {
+        return (unsigned int ) *this == (unsigned int) (syl);
+    }
+
+    bool operator !=(const TSyllable & syl) const {
+        return !(*this == syl);
+    }
+
+    bool operator ==(const unsigned s) const {
+        return (unsigned int) *this == s;
+    }
+};
+
+typedef struct _TPyTabEntry {
+    const char *pystr;
+    unsigned id;
+} TPyTabEntry;
+
+typedef std::vector<TSyllable> CSyllables;
+
+template <class PinyinDataPolicy>
+class CGetFuzzySyllablesOp : private CNonCopyable
+{
+public:
+    typedef std::multimap<const std::string, std::string> CFuzzyMap;
+
+    CGetFuzzySyllablesOp () : m_bEnableFuzzies(false) {}
+
+    void setEnableFuzzies(bool value = true) { m_bEnableFuzzies = value; }
+    void setEnableSimplerInitials(bool value =
+                                      true) { m_bEnableSimplerInitials = value; }
+    bool isEnabled() { return m_bEnableFuzzies || m_bEnableSimplerInitials; }
+
+    void clearFuzzyMap()
+    { m_fuzzyMap.clear(); }
+
+    void initFuzzyMap(const string_pairs& fuzzyPairs, bool duplex = true){
+        string_pairs::const_iterator it = fuzzyPairs.begin();
+        string_pairs::const_iterator ite = fuzzyPairs.end();
+
+        for (; it != ite; ++it) {
+            const std::string i = it->first;
+            const std::string j = it->second;
+
+            if (m_fuzzyMap.find(i) == m_fuzzyMap.end())
+                m_fuzzyMap.insert(std::pair<const std::string, std::string> (i,
+                                                                             j));
+
+            if (duplex && m_fuzzyMap.find(j) == m_fuzzyMap.end())
+                m_fuzzyMap.insert(std::pair<const std::string, std::string> (j,
+                                                                             i));
+        }
+    }
+
+    CSyllables operator ()(TSyllable s){
+        CSyllables ret;
+        static char buf[128];
+
+        const char *i, *f;
+        PinyinDataPolicy::decodeSyllable(s, &i, &f);
+
+        if (m_bEnableSimplerInitials && !m_bEnableFuzzies && *f != '\0')
+            return ret;
+
+        std::vector<const char *> iset;
+        std::vector<const char *> fset;
+
+        iset.push_back(i);
+        fset.push_back(f);
+
+        CFuzzyMap::const_iterator it;
+        for (it = m_fuzzyMap.lower_bound(i);
+             it != m_fuzzyMap.upper_bound(i);
+             ++it)
+            iset.push_back((it->second).c_str());
+
+        for (it = m_fuzzyMap.lower_bound(f);
+             it != m_fuzzyMap.upper_bound(f);
+             ++it)
+            fset.push_back((it->second).c_str());
+
+        std::vector<const char *>::const_iterator iset_it = iset.begin();
+        for (; iset_it != iset.end(); ++iset_it) {
+            std::vector<const char *>::const_iterator fset_it = fset.begin();
+            for (; fset_it != fset.end(); ++fset_it) {
+                snprintf(buf, sizeof(buf), "%s%s", *iset_it, *fset_it);
+                TSyllable ts = PinyinDataPolicy::encodeSyllable(buf);
+                if (ts && ts != s)
+                    ret.push_back(ts);
+            }
+        }
+
+        return ret;
+    }
+
+private:
+    CFuzzyMap m_fuzzyMap;
+    bool m_bEnableFuzzies;
+    bool m_bEnableSimplerInitials;
+};
+
+#endif
diff --git a/src/portability.cpp b/src/portability.cpp
new file mode 100644 (file)
index 0000000..58a06a6
--- /dev/null
@@ -0,0 +1,290 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright (c) 2007 Sun Microsystems, Inc. All Rights Reserved.
+ *
+ * The contents of this file are subject to the terms of either the GNU Lesser
+ * General Public License Version 2.1 only ("LGPL") or the Common Development and
+ * Distribution License ("CDDL")(collectively, the "License"). You may not use this
+ * file except in compliance with the License. You can obtain a copy of the CDDL at
+ * http://www.opensource.org/licenses/cddl1.php and a copy of the LGPLv2.1 at
+ * http://www.opensource.org/licenses/lgpl-license.php. See the License for the
+ * specific language governing permissions and limitations under the License. When
+ * distributing the software, include this License Header Notice in each file and
+ * include the full text of the License in the License file as well as the
+ * following notice:
+ *
+ * NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND DISTRIBUTION LICENSE
+ * (CDDL)
+ * For Covered Software in this distribution, this License shall be governed by the
+ * laws of the State of California (excluding conflict-of-law provisions).
+ * Any litigation relating to this License shall be subject to the jurisdiction of
+ * the Federal Courts of the Northern District of California and the state courts
+ * of the State of California, with venue lying in Santa Clara County, California.
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by only the CDDL or only
+ * the LGPL Version 2.1, indicate your decision by adding "[Contributor]" elects to
+ * include this software in this distribution under the [CDDL or LGPL Version 2.1]
+ * license." If you don't indicate a single choice of license, a recipient has the
+ * option to distribute your version of this file under either the CDDL or the LGPL
+ * Version 2.1, or to extend the choice of license to its licensees as provided
+ * above. However, if you add LGPL Version 2.1 code and therefore, elected the LGPL
+ * Version 2 license, then the option applies only if the new code is made subject
+ * to such option by the copyright holder.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifdef HAVE_ASSERT_H
+#include <assert.h>
+#endif
+
+#include "portability.h"
+
+#include <stdlib.h>
+
+TLongExpFloat::TLongExpFloat(double d)
+{
+    if (d != 0.0 && d != -0.0) {
+        TDoubleAnatomy da(d);
+        m_exp = da.getExp();
+        da.clearExp();
+        m_base = da.getValue();
+    } else {
+        m_base = d;
+        m_exp = 0;
+    }
+}
+
+TLongExpFloat
+TLongExpFloat::operator*(const TLongExpFloat& b) const
+{
+    double d = this->m_base * b.m_base;
+    TLongExpFloat reda(d);
+    reda.m_exp += this->m_exp + b.m_exp;
+    return reda;
+}
+
+TLongExpFloat
+TLongExpFloat::operator/(const TLongExpFloat& b) const
+{
+    double d = this->m_base / b.m_base;
+    TLongExpFloat reda(d);
+    reda.m_exp += (this->m_exp - b.m_exp);
+    return reda;
+}
+
+bool
+TLongExpFloat::operator<(const TLongExpFloat& b) const
+{
+    if (m_base >= 0.0 && b.m_base >= 0.0) {
+        return(m_exp < b.m_exp || (m_exp == b.m_exp && m_base < b.m_base));
+    } else if (m_base < 0.0 && b.m_base < 0.0) {
+        return(m_exp > b.m_exp || (m_exp == b.m_exp && m_base < b.m_base));
+    } else if (m_base < 0.0 && b.m_base >= 0.0)
+        return true;
+    else
+        return false;
+}
+
+bool
+TLongExpFloat::operator<=(const TLongExpFloat& b) const
+{
+    if (m_base >= 0.0 && b.m_base >= 0.0) {
+        return(m_exp < b.m_exp || (m_exp == b.m_exp && m_base <= b.m_base));
+    } else if (m_base < 0.0 && b.m_base < 0.0) {
+        return(m_exp > b.m_exp || (m_exp == b.m_exp && m_base <= b.m_base));
+    } else if (m_base < 0.0 && b.m_base >= 0.0)
+        return true;
+    else
+        return false;
+}
+
+bool
+TLongExpFloat::operator==(const TLongExpFloat& b) const
+{
+    return(m_base == b.m_base && m_exp == b.m_exp);
+}
+
+void
+TLongExpFloat::toString(std::string& str) const
+{
+    char buf[256];
+    toString(buf);
+    str = buf;
+}
+
+#ifdef HAVE_ICONV_H
+#include <iconv.h>
+
+/**
+ * convert UTF-8 string pointed by s into UCS-4 Wide String at pwcs.
+ * No more than n wide char could be converted into target buffer.
+ * return -1 means error.
+ * other means the converted wide char number do not count the end 0.
+ */
+size_t
+MBSTOWCS(TWCHAR *pwcs, const char* s, size_t n)
+{
+#ifndef WORDS_BIGENDIAN
+    static iconv_t ic = iconv_open("UCS-4LE", "UTF-8");
+#else
+    static iconv_t ic = iconv_open("UCS-4BE", "UTF-8");
+#endif
+
+    assert(ic != (iconv_t)-1);
+
+    // To eliminate the const char* and char* diffirence in differnt system
+    TIConvSrcPtr src = (TIConvSrcPtr)s;
+    size_t srclen = std::strlen(s) + 1;
+    char* dst = (char*)pwcs;
+    size_t dstlen = n * sizeof(TWCHAR);
+
+    size_t res = iconv(ic, &src, &srclen, &dst, &dstlen);
+
+    if (res != size_t(-1) && srclen == 0) {
+        n -= dstlen / sizeof(TWCHAR);
+        return (n > 0) ? (n - 1) : 0;
+    } else {
+        return size_t(-1);
+    }
+}
+
+/**
+ * convert UCS-4 string pointed by pwcs into UTF-8 String at s.
+ * No more than n byte could be converted into target buffer.
+ * return -1 means error.
+ * Other means the converted byte number do not count the end 0.
+ */
+size_t
+WCSTOMBS(char* s, const TWCHAR* pwcs, size_t n)
+{
+#ifndef WORDS_BIGENDIAN
+    static iconv_t ic = iconv_open("UTF-8", "UCS-4LE");
+#else
+    static iconv_t ic = iconv_open("UTF-8", "UCS-4BE");
+#endif
+
+    assert(ic != (iconv_t)-1);
+
+    TIConvSrcPtr src = (TIConvSrcPtr)pwcs;
+    size_t srclen = (WCSLEN(pwcs) + 1) * sizeof(TWCHAR);
+    char* dst = (char*)s;
+    size_t dstlen = n;
+
+    size_t res = iconv(ic, &src, &srclen, &dst, &dstlen);
+
+    if (res != size_t(-1) && srclen == 0) {
+        n -= dstlen;
+        return (n > 0) ? (n - 1) : 0;
+    } else {
+        return size_t(-1);
+    }
+}
+
+#else // !HAVE_ICONV_H
+
+size_t
+MBSTOWCS(TWCHAR *pwcs, const char* s, size_t n)
+{
+    const unsigned char *src = (const unsigned char*)s;
+    TWCHAR* dst = pwcs;
+
+    while (dst - pwcs < n) {
+        if (*src < 0xc0 || *src >= 0xfe) {
+            if (*src < 0x80) *dst++ = *src;
+            if (*src++ == 0) break;
+            continue;
+        }
+
+        for (int bytes = 2; bytes <= 6; bytes++) {
+            if ((*src & ~(0xff >> (bytes + 1))) !=
+                (((1 << bytes) - 1) << (8 - bytes))) continue;
+            if (bytes > 4) {
+                src += bytes;
+            } else {
+                *dst =
+                    TWCHAR(*src++ & (0xff >> (bytes + 1))) << (6 * (bytes - 1));
+                for (; bytes-- > 1; src++) *dst |=
+                        TWCHAR(*src & 0x3f) << (6 * (bytes - 1));
+                dst++;
+            }
+            break;
+        }
+    }
+
+    return(dst - pwcs);
+}
+
+size_t
+WCSTOMBS(char* s, const TWCHAR* pwcs, size_t n)
+{
+    char* dst = s;
+
+    while (dst - s < n) {
+        if (*pwcs < 0x80 || *pwcs > 0x10ffff) {
+            if (*pwcs < 0x80) *dst++ = *pwcs;
+            if (*pwcs++ == 0) break;
+            continue;
+        }
+
+        int bytes = *pwcs < 0x800 ? 2 : (*pwcs < 0xffff ? 3 : 4);
+        dst += bytes;
+        if (dst - s > n) return -1;
+
+        TWCHAR c = *pwcs++;
+        int nbyte = bytes;
+        char *tmp = dst - 1;
+
+        for (; nbyte > 0; c >>= 6, nbyte--)
+            *tmp-- =
+                (nbyte ==
+                 1 ? (((1 << bytes) - 1) << (8 - bytes)) : 0x80) | (c & 0x3f);
+    }
+
+    return(dst - s);
+}
+
+#endif // HAVE_ICONV_H
+
+/**
+ * return the wide string len at pwcs, not count the end 0.
+ */
+size_t
+WCSLEN(const TWCHAR* pwcs)
+{
+    size_t sz = 0;
+    if (pwcs) {
+        while (*pwcs++)
+            ++sz;
+    }
+    return sz;
+}
+
+#if !defined (HAVE_STRNDUP)
+extern "C" char *
+strndup(const char *s, size_t n)
+{
+    size_t nMost;
+    char *p = NULL;
+
+    if (!s)
+        return NULL;
+
+#ifdef __cplusplus
+    nMost = std::min(strlen(s) + 1, n + 1);
+#else
+    nMost = min(strlen(s) + 1, n + 1);
+#endif
+    p = (char*)malloc(nMost);
+    memcpy(p, s, nMost);
+    p[nMost - 1] = '\0';
+
+    return p;
+}
+#endif //HAVE_STRNDUP
+
diff --git a/src/portability.h b/src/portability.h
new file mode 100644 (file)
index 0000000..d6116f5
--- /dev/null
@@ -0,0 +1,333 @@
+// -*- mode: c++ -*-
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright (c) 2007 Sun Microsystems, Inc. All Rights Reserved.
+ *
+ * The contents of this file are subject to the terms of either the GNU Lesser
+ * General Public License Version 2.1 only ("LGPL") or the Common Development and
+ * Distribution License ("CDDL")(collectively, the "License"). You may not use this
+ * file except in compliance with the License. You can obtain a copy of the CDDL at
+ * http://www.opensource.org/licenses/cddl1.php and a copy of the LGPLv2.1 at
+ * http://www.opensource.org/licenses/lgpl-license.php. See the License for the
+ * specific language governing permissions and limitations under the License. When
+ * distributing the software, include this License Header Notice in each file and
+ * include the full text of the License in the License file as well as the
+ * following notice:
+ *
+ * NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND DISTRIBUTION LICENSE
+ * (CDDL)
+ * For Covered Software in this distribution, this License shall be governed by the
+ * laws of the State of California (excluding conflict-of-law provisions).
+ * Any litigation relating to this License shall be subject to the jurisdiction of
+ * the Federal Courts of the Northern District of California and the state courts
+ * of the State of California, with venue lying in Santa Clara County, California.
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by only the CDDL or only
+ * the LGPL Version 2.1, indicate your decision by adding "[Contributor]" elects to
+ * include this software in this distribution under the [CDDL or LGPL Version 2.1]
+ * license." If you don't indicate a single choice of license, a recipient has the
+ * option to distribute your version of this file under either the CDDL or the LGPL
+ * Version 2.1, or to extend the choice of license to its licensees as provided
+ * above. However, if you add LGPL Version 2.1 code and therefore, elected the LGPL
+ * Version 2 license, then the option applies only if the new code is made subject
+ * to such option by the copyright holder.
+ */
+
+#ifndef ___SUN_SLM_PORTABILITY_H___
+#define ___SUN_SLM_PORTABILITY_H___
+
+#include <stdio.h>
+#include <math.h>
+#include <stdint.h>
+#include <string>
+#include <cstring>
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#ifdef __cplusplus
+#include <algorithm>
+#else
+#include <sys/ddi.h>
+#endif //__cpluscplus
+#endif //ifdef HAVE_UNISTD_H
+
+#ifndef HOST_OS_GNUC_2
+    #if defined(DEBUG) && !defined(NDEBUG)
+        #define DEBUG_print(fmt, ...)   fprintf(stderr, fmt, ...)
+    #else
+        #define DEBUG_print(fmt, ...)   (int(0))
+    #endif
+#else // HOST_OS_GNUC_2
+    #if defined(DEBUG) && !defined(NDEBUG)
+        #define DEBUG_print(fmt, a ...)   fprintf(stderr, fmt, a ...)
+    #else
+        #define DEBUG_print(fmt, a ...)   (int(0))
+    #endif
+#endif // !HOST_OS_GNUC_2
+
+#ifndef HAVE_LOG2
+inline double log2(double x) { return log(x) / M_LN2; }
+#endif
+
+#if defined(sun) // Solaris/HP-UX 's iconv is const char**
+typedef const char* TIConvSrcPtr;
+#else
+typedef char* TIConvSrcPtr;
+#endif
+
+union TDoubleAnatomy {
+public:
+    TDoubleAnatomy(double d) : m_value(d){
+    }
+
+    int getExp(void) const
+    { return anony.m_exp - 0x3FF; }
+
+    double getValue(void) const
+    { return m_value; }
+
+    void clearExp(void)
+    { anony.m_exp = 0x3FF; }
+
+public:
+    double m_value;
+    struct TAnony {
+#ifndef WORDS_BIGENDIAN
+        unsigned m_other2 : 32;
+        unsigned m_other1 : 20;
+        unsigned m_exp    : 11;
+        unsigned m_neg    : 1;
+#else
+        unsigned m_neg    : 1;
+        unsigned m_exp    : 11;
+        unsigned m_other1 : 20;
+        unsigned m_other2 : 32;
+#endif
+    } anony;
+};
+
+struct TLongExpFloat {
+public:
+    TLongExpFloat(const TLongExpFloat& b) : m_base(b.m_base), m_exp(b.m_exp) { }
+
+    TLongExpFloat(int exp = 0, double base = 0.0) : m_base(base), m_exp(exp) { }
+
+    TLongExpFloat(double d);
+
+    TLongExpFloat
+    operator*(const TLongExpFloat& b) const;
+
+    TLongExpFloat
+    operator/(const TLongExpFloat& b) const;
+
+    bool
+    operator<(const TLongExpFloat& b) const;
+
+    bool
+    operator<=(const TLongExpFloat& b) const;
+
+    bool
+    operator==(const TLongExpFloat& b) const;
+
+    void
+    toString(std::string& str) const;
+
+    void toString(char* buf) const
+    { if (buf) sprintf(buf, "%10lf*2^%d", m_base, m_exp); }
+
+    double log2() const { return ::log2(m_base) + m_exp; }
+
+private:
+    double m_base;
+    int m_exp;
+};
+
+/**
+ * UCS4 wide character type, system dependent
+ * Multibytes string in this program is UTF-8 only
+ */
+typedef unsigned int TWCHAR;
+
+#if !defined(WORDS_BIGENDIAN)
+    #define  TWCHAR_ICONV_NAME  "UCS-4LE"
+#else
+    #define  TWCHAR_ICONV_NAME  "UCS-4BE"
+#endif
+
+typedef TWCHAR TSIMWordId;
+
+const TSIMWordId SIM_ID_NOT_WORD = (0x0);
+const TSIMWordId SIM_ID_UNKNOWN_CN = (2);
+const TSIMWordId SIM_ID_SEN_TOKEN = (10);
+const TSIMWordId SIM_ID_DIGIT = (20);
+const TSIMWordId SIM_ID_SIMBOL = (21);
+const TSIMWordId SIM_ID_DUMMY_WORD = (69);
+const TSIMWordId SIM_ID_NONWORD = (69);
+const TSIMWordId SIM_ID_ALLWORD = (69);
+const TSIMWordId SIM_ID_REALWORD_START = (70);
+const TSIMWordId SIM_ID_CNWORD_START = (100);
+
+const TWCHAR WCH_NULL = 0;
+const TWCHAR WCH_RETURN = '\n';
+const TWCHAR WCH_TAB = '\t';
+const TWCHAR WCH_SPACE = ' ';
+const TWCHAR WCH_LESSTHAN = '<';
+const TWCHAR WCH_GREATERTHAN = '>';
+
+const TWCHAR WCH_DOUBLESPACE = 0x3000;
+const TWCHAR WCH_JUHAO = 0x3002;
+const TWCHAR WCH_WENHAO = 0xFF1F;
+const TWCHAR WCH_TANHAO = 0xFF01;
+const TWCHAR WCH_FENHAO = 0xFF1B;
+const TWCHAR WCH_MAOHAO = 0xFF1A;
+const TWCHAR WCH_DOUHAO = 0xFF0C;
+const TWCHAR WCH_ZUOKUOHAO = 0x201C;
+const TWCHAR WCH_YOUKUOHAO = 0x201D;
+const TWCHAR WCH_SHENGLUEHAO = 0x2026;
+
+
+size_t MBSTOWCS(TWCHAR *pwcs, const char* s, size_t n);
+
+size_t WCSTOMBS(char* s, const TWCHAR* pwcs, size_t n);
+
+size_t WCSLEN(const TWCHAR* ws);
+
+namespace std {
+#ifdef HOST_OS_GNUC_2
+struct string_char_traits<TWCHAR>
+#else // !HOST_OS_GNUC_2
+template<>
+struct char_traits<TWCHAR>
+#endif // HOST_OS_GNUC_2
+{
+    typedef TWCHAR char_type;
+    typedef unsigned int int_type;
+#ifndef HOST_OS_GNUC_2
+    typedef streamoff off_type;
+    typedef wstreampos pos_type;
+    typedef mbstate_t state_type;
+#endif // !HOST_OS_GNUC_2
+
+    static void assign(char_type& __c1, const char_type& __c2)
+    { __c1 = __c2; }
+
+    static bool eq(const char_type& __c1, const char_type& __c2)
+    { return __c1 == __c2; }
+
+    static bool lt(const char_type& __c1, const char_type& __c2)
+    { return __c1 < __c2; }
+
+    static int compare(const char_type* __s1, const char_type* __s2,
+                       size_t __n)           {
+        for (size_t i = 0; i < __n; ++i) {
+            if (*__s1 < *__s2)
+                return -1;
+            else if (*__s1++ == *__s2++)
+                continue;
+            else
+                return 1;
+        }
+        return 0;
+    }
+
+    static size_t length(const char_type* __s)
+    { return WCSLEN(__s); }
+
+    static char_type*copy(char_type* __s1, const char_type* __s2,
+                          size_t __n)                 {
+        return static_cast<char_type*>(memcpy(__s1, __s2, __n *
+                                              sizeof(char_type)));
+    }
+
+    static char_type*move(char_type* __s1, const char_type* __s2,
+                          int_type __n)                 {
+        return static_cast<char_type*>(memmove(__s1, __s2, __n *
+                                               sizeof(char_type)));
+    }
+
+#ifndef HOST_OS_GNUC_2
+    static const char_type*find(const char_type* __s,
+                                size_t __n,
+                                const char_type& __a)                       {
+        while (__n--) {
+            if (*__s++ == __a)
+                return __s;
+        }
+        return NULL;
+    }
+
+    static char_type to_char_type(const int_type& __c) { return char_type(__c); }
+
+    static int_type to_int_type(const char_type& __c) { return int_type(__c); }
+
+    static bool eq_int_type(const int_type& __c1, const int_type& __c2)
+    { return __c1 == __c2; }
+
+    static int_type eof() { return static_cast<int_type>(WEOF); }
+
+    static int_type not_eof(const int_type& __c)
+    { return eq_int_type(__c, eof()) ? 0 : __c; }
+
+    static char_type*assign(char_type* __s, size_t __n,
+                            char_type __a)                 {
+        for (char_type *p = __s; __n--; )
+            *p++ = __a;
+        return __s;
+    }
+#else // HOST_OS_GNUC_2
+    static bool ne(const char_type& __c1, const char_type& __c2)
+    { return __c1 != __c2; }
+
+    static char_type eos()
+    { return 0; }
+
+    static bool is_del(char_type a)
+    { return a == WCH_SPACE; }
+
+    static char_type* set(char_type* __s, char_type __a, size_t __n){
+        for (char_type *p = __s; __n--; )
+            *p++ = __a;
+        return __s;
+    }
+#endif // !HOST_OS_GNUC_2
+};
+}; // namespace std
+
+#ifndef HOST_OS_GNUC_2
+typedef std::basic_string<TWCHAR>   wstring;
+#else // HOST_OS_GNUC_2
+class wstring : public std::basic_string<TWCHAR>
+{
+public:
+    inline wstring() : std::basic_string<TWCHAR>((TWCHAR) 0) {}
+    inline wstring(const TWCHAR* c) : std::basic_string<TWCHAR>(c) {}
+    inline wstring(const TWCHAR* c, size_t n) : std::basic_string<TWCHAR>(c,
+                                                                          n) {}
+    inline void push_back(TWCHAR c) { this->append(1, c); }
+    inline void clear(void) { this->resize(0); }
+    inline const TWCHAR* c_str(void) const {
+        static TWCHAR null_s = 0;
+        if (this->length() == 0) return &null_s;
+        *(const_cast<TWCHAR*>(this->data()) + this->length()) = 0;
+        return this->data();
+    }
+};
+#endif // !HOST_OS_GNUC_2
+
+#ifdef _RW_STD_STL
+template <class Iterator>
+inline long distance(Iterator pos1, Iterator pos2){
+    long d = 0;
+    distance(pos1, pos2, d);
+    return d;
+}
+#endif
+
+#if !defined (HAVE_STRNDUP)
+extern "C" char *strndup(const char *s, size_t n);
+#endif //HAVE_STRNDUP
+
+#endif
diff --git a/src/slm/Makefile.am b/src/slm/Makefile.am
new file mode 100755 (executable)
index 0000000..5267f40
--- /dev/null
@@ -0,0 +1,31 @@
+## Makefile.am -- Process this file with automake to produce Makefile.in
+## Copyright (C) 2002 James Su
+##
+## This program is free software; you can redistribute it and/or modify
+## it under the terms of the GNU General Public License as published by
+## the Free Software Foundation; either version 2, or (at your option)
+## any later version.
+##
+## This program is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+## GNU General Public License for more details.
+##
+## You should have received a copy of the GNU General Public License
+## along with this program; if not, write to the Free Software
+## Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+
+MAINTAINERCLEANFILES   = Makefile.in
+
+INCLUDES=-I$(top_srcdir)\
+         -I$(top_srcdir)/src\
+         -I$(top_srcdir)/src/ime-core\
+         -I$(top_srcdir)/src/lexicon\
+         -I$(top_srcdir)/src/pinyin\
+         -I$(top_srcdir)/src/slm
+         
+noinst_HEADERS = slm.h
+noinst_LTLIBRARIES = libslm.la
+libslm_la_SOURCES              = slm.cpp
+libslm_la_CFLAGS = @GLIB_CFLAGS@
diff --git a/src/slm/getWordFreq/getWordFreq.cpp b/src/slm/getWordFreq/getWordFreq.cpp
new file mode 100644 (file)
index 0000000..bdcc728
--- /dev/null
@@ -0,0 +1,162 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright (c) 2007 Sun Microsystems, Inc. All Rights Reserved.
+ *
+ * The contents of this file are subject to the terms of either the GNU Lesser
+ * General Public License Version 2.1 only ("LGPL") or the Common Development and
+ * Distribution License ("CDDL")(collectively, the "License"). You may not use this
+ * file except in compliance with the License. You can obtain a copy of the CDDL at
+ * http://www.opensource.org/licenses/cddl1.php and a copy of the LGPLv2.1 at
+ * http://www.opensource.org/licenses/lgpl-license.php. See the License for the
+ * specific language governing permissions and limitations under the License. When
+ * distributing the software, include this License Header Notice in each file and
+ * include the full text of the License in the License file as well as the
+ * following notice:
+ *
+ * NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND DISTRIBUTION LICENSE
+ * (CDDL)
+ * For Covered Software in this distribution, this License shall be governed by the
+ * laws of the State of California (excluding conflict-of-law provisions).
+ * Any litigation relating to this License shall be subject to the jurisdiction of
+ * the Federal Courts of the Northern District of California and the state courts
+ * of the State of California, with venue lying in Santa Clara County, California.
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by only the CDDL or only
+ * the LGPL Version 2.1, indicate your decision by adding "[Contributor]" elects to
+ * include this software in this distribution under the [CDDL or LGPL Version 2.1]
+ * license." If you don't indicate a single choice of license, a recipient has the
+ * option to distribute your version of this file under either the CDDL or the LGPL
+ * Version 2.1, or to extend the choice of license to its licensees as provided
+ * above. However, if you add LGPL Version 2.1 code and therefore, elected the LGPL
+ * Version 2 license, then the option applies only if the new code is made subject
+ * to such option by the copyright holder.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#include <math.h>
+#include <unistd.h>
+#include <stdlib.h>
+
+#include <vector>
+#include <iostream>
+
+#include "../slm.h"
+
+using namespace std;
+
+static void
+showUsage()
+{
+    cerr << "Usage:\n";
+    cerr << "getWordFreq [-s corpus_size] [-v] [-e] -m slm_file -l lexicon\n";
+    cerr << "    default corpus_size is 300000000 if not given\n";
+    cerr <<
+    "    -v means output other information after word and freq for each line\n";
+    cerr << "    -e give format for ervin\n";
+    exit(10);
+}
+
+static char* slm_file = NULL;
+static char* lexicon_file = NULL;
+static int corpus_size = 300000000;
+static bool verbose = false;
+static bool ervin = false;
+
+static bool
+getParameters(int argc, char* argv[])
+{
+    int ch;
+    while ((ch = getopt(argc, argv, "m:l:s:ve")) != -1) {
+        switch (ch) {
+        case 'm':
+            slm_file = strdup(optarg); break;
+        case 'l':
+            lexicon_file = strdup(optarg); break;
+        case 's':
+            corpus_size = atoi(optarg); break;
+        case 'v':
+            verbose = true; break;
+        case 'e':
+            ervin = true; break;
+        default:
+            return false;
+        }
+    }
+    return(slm_file && lexicon_file && corpus_size > 10);
+}
+
+static char buf[8192];
+
+static void
+tagFile(FILE *fp, CThreadSlm& slm)
+{
+    int freq = 0;
+    while (fgets(buf, sizeof(buf), fp) != NULL) {
+        freq = 0;
+        char* wrd = strtok(buf, "\n\r \t");
+        char* idstr = strtok(NULL, "\n\r \t");
+        char* info = strtok(NULL, "\n\r");
+        if (wrd && idstr) {
+            int id = atoi(idstr);
+            if (id > 0) {
+                CThreadSlm::TState st;
+                double neglogpr = slm.transfer(st, (unsigned int)id, st);
+                if (st.getLevel() == 1) {
+                    freq = int(exp(-neglogpr) * corpus_size);
+                }
+            }
+        }
+        if (wrd) {
+            if (ervin) {
+                vector<char* > pyv;
+                if (info) {
+                    for (char *p = strtok(info, " \t\n\r");
+                         p != NULL;
+                         p = strtok(NULL, " \t\n\t"))
+                        pyv.push_back(p);
+                }
+                for (int i = 0, sz = pyv.size(); i < sz; ++i) {
+                    cout << wrd << " " << pyv[i] << " " << freq << "\n";
+                }
+            } else if (idstr && verbose) {
+                cout << wrd << " " << idstr << " " << freq;
+                if (info)
+                    cout << " " << info;
+                cout << "\n";
+            } else {
+                cout << wrd << " " << freq << "\n";
+            }
+        }
+    }
+}
+
+int
+main(int argc, char*argv[])
+{
+    if (!getParameters(argc, argv))
+        showUsage();
+
+    FILE *fp;
+    CThreadSlm slm;
+    if (slm.load(slm_file, true) && (fp = fopen(lexicon_file, "r")) != NULL) {
+        tagFile(fp, slm);
+        slm.free();
+        fclose(fp);
+        return 0;
+    } else {
+        slm.free();
+        return 20;
+    }
+}
+
+
+
+
diff --git a/src/slm/ids2ngram/idngram.h b/src/slm/ids2ngram/idngram.h
new file mode 100644 (file)
index 0000000..a75fcdc
--- /dev/null
@@ -0,0 +1,116 @@
+// -*- mode: c++ -*-
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright (c) 2007 Sun Microsystems, Inc. All Rights Reserved.
+ *
+ * The contents of this file are subject to the terms of either the GNU Lesser
+ * General Public License Version 2.1 only ("LGPL") or the Common Development and
+ * Distribution License ("CDDL")(collectively, the "License"). You may not use this
+ * file except in compliance with the License. You can obtain a copy of the CDDL at
+ * http://www.opensource.org/licenses/cddl1.php and a copy of the LGPLv2.1 at
+ * http://www.opensource.org/licenses/lgpl-license.php. See the License for the
+ * specific language governing permissions and limitations under the License. When
+ * distributing the software, include this License Header Notice in each file and
+ * include the full text of the License in the License file as well as the
+ * following notice:
+ *
+ * NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND DISTRIBUTION LICENSE
+ * (CDDL)
+ * For Covered Software in this distribution, this License shall be governed by the
+ * laws of the State of California (excluding conflict-of-law provisions).
+ * Any litigation relating to this License shall be subject to the jurisdiction of
+ * the Federal Courts of the Northern District of California and the state courts
+ * of the State of California, with venue lying in Santa Clara County, California.
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by only the CDDL or only
+ * the LGPL Version 2.1, indicate your decision by adding "[Contributor]" elects to
+ * include this software in this distribution under the [CDDL or LGPL Version 2.1]
+ * license." If you don't indicate a single choice of license, a recipient has the
+ * option to distribute your version of this file under either the CDDL or the LGPL
+ * Version 2.1, or to extend the choice of license to its licensees as provided
+ * above. However, if you add LGPL Version 2.1 code and therefore, elected the LGPL
+ * Version 2 license, then the option applies only if the new code is made subject
+ * to such option by the copyright holder.
+ */
+
+#ifndef _SIM_IDNGRAM_H
+#define _SIM_IDNGRAM_H
+
+#include "../../portability.h"
+#include "../sim_fmerge.h"
+
+template<int N>
+class CSIM_Idngram {
+public:
+    TSIMWordId ids[N];
+public:
+    CSIM_Idngram()
+    { for (int i = 0; i < N; ++i) ids[i] = 0; }
+    CSIM_Idngram & operator=(const CSIM_Idngram& r){
+        for (int i = 0; i < N; ++i)
+            ids[i] = r.ids[i];
+        return *this;
+    }
+    bool operator<(const CSIM_Idngram& r) const {
+        for (int i = 0; i < N; ++i) {
+            if (ids[i] < r.ids[i])
+                return true;
+            else if (ids[i] > r.ids[i])
+                return false;
+        }
+        return false;
+    }
+
+    bool operator>(const CSIM_Idngram& r) const {
+        for (int i = 0; i < N; ++i) {
+            if (ids[i] > r.ids[i])
+                return true;
+            else if (ids[i] < r.ids[i])
+                return false;
+        }
+        return false;
+    }
+
+    bool operator==(const CSIM_Idngram& r) const {
+        for (int i = 0; i < N; ++i)
+            if (ids[i] != r.ids[i]) return false;
+        return true;
+    }
+};
+
+
+template<int N>
+class CSIM_IdngramFreq : public CSIM_Idngram<N> {
+public:
+    CSIM_IdngramFreq()
+        : CSIM_Idngram<N>(), freq(0) { }
+    CSIM_IdngramFreq& operator=(const CSIM_IdngramFreq& r){
+        for (int i = 0; i < N; ++i)
+            this->ids[i] = r.ids[i];
+        freq = r.freq;
+        return *this;
+    }
+    bool read(FILE *fp, size_t& start_offset, size_t last_offset){
+        if (start_offset + size() <= last_offset) {
+            fseek(fp, start_offset, SEEK_SET);
+            if (fread(this->ids, sizeof(TSIMWordId), N,
+                      fp) == N &&
+                fread(&freq, sizeof(unsigned int), 1, fp) == 1) {
+                start_offset += size();
+                return true;
+            }
+        }
+        return false;
+    }
+
+protected:
+    size_t size() { return N * sizeof(TSIMWordId) + sizeof(unsigned int); }
+
+public:
+    unsigned int freq;
+};
+
+#endif
diff --git a/src/slm/ids2ngram/idngram_merge.cpp b/src/slm/ids2ngram/idngram_merge.cpp
new file mode 100644 (file)
index 0000000..1e52b8e
--- /dev/null
@@ -0,0 +1,148 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright (c) 2007 Sun Microsystems, Inc. All Rights Reserved.
+ *
+ * The contents of this file are subject to the terms of either the GNU Lesser
+ * General Public License Version 2.1 only ("LGPL") or the Common Development and
+ * Distribution License ("CDDL")(collectively, the "License"). You may not use this
+ * file except in compliance with the License. You can obtain a copy of the CDDL at
+ * http://www.opensource.org/licenses/cddl1.php and a copy of the LGPLv2.1 at
+ * http://www.opensource.org/licenses/lgpl-license.php. See the License for the
+ * specific language governing permissions and limitations under the License. When
+ * distributing the software, include this License Header Notice in each file and
+ * include the full text of the License in the License file as well as the
+ * following notice:
+ *
+ * NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND DISTRIBUTION LICENSE
+ * (CDDL)
+ * For Covered Software in this distribution, this License shall be governed by the
+ * laws of the State of California (excluding conflict-of-law provisions).
+ * Any litigation relating to this License shall be subject to the jurisdiction of
+ * the Federal Courts of the Northern District of California and the state courts
+ * of the State of California, with venue lying in Santa Clara County, California.
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by only the CDDL or only
+ * the LGPL Version 2.1, indicate your decision by adding "[Contributor]" elects to
+ * include this software in this distribution under the [CDDL or LGPL Version 2.1]
+ * license." If you don't indicate a single choice of license, a recipient has the
+ * option to distribute your version of this file under either the CDDL or the LGPL
+ * Version 2.1, or to extend the choice of license to its licensees as provided
+ * above. However, if you add LGPL Version 2.1 code and therefore, elected the LGPL
+ * Version 2 license, then the option applies only if the new code is made subject
+ * to such option by the copyright holder.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifdef HAVE_ASSERT_H
+#include <assert.h>
+#endif
+
+#ifdef HAVE_GETOPT_H
+#include <getopt.h>
+#endif
+
+#include <stdio.h>
+#include <vector>
+#include <algorithm>
+
+#include "../sim_fmerge.h"
+#include "idngram.h"
+#include "idngram_merge.h"
+
+static struct option long_options[] =
+{
+    { "NMax", 1, 0, 'n' },
+    { "out", 1, 0, 'o' },
+    { 0, 0, 0, 0 }
+};
+
+static int N = 0;
+// static int paraMax = 0;
+static char* output = NULL;
+// static char* swapfile = NULL;
+
+void
+ShowUsage()
+{
+    printf("Usage:\n\tidngram_merge options idngramfile[ idngramfile...]\n");
+    printf("\nDescription:\n");
+    printf(
+        "   This program merge multiple idngram file, each of them are sorted [id1,...,idN,freq] array, into one idngram file. For those id1..idN which appear in more than one files, only one item appear in the final file, and its freq are sumed.\n");
+    printf("\nOptions:\n");
+    printf("\t  -n N           # N-gram\n");
+    printf("\t  -o outputfile  # finale merged idngram file\n");
+    printf("\nExample:\n");
+    printf("   Following example merge 2 id3gram files into a large one:\n");
+    printf(
+        "\tidngram_merge -n3 -o all.id3gram first.id3gram second.id3gram\n\n");
+}
+
+static void
+getParameters(int argc, char* const argv[])
+{
+    int option_index = 0;
+    int c;
+    while ((c =
+                getopt_long(argc, argv, "n:o:", long_options,
+                            &option_index)) != -1) {
+        switch (c) {
+        case 'n':
+            N = atoi(strdup(optarg));
+            break;
+        case 'o':
+            output = strdup(optarg);
+            break;
+        default:
+            ShowUsage();
+            exit(1000);
+        }
+    }
+    if (N < 1 || N > 3 || output == NULL) {
+        ShowUsage();
+        exit(1000);
+    }
+}
+
+int
+main(int argc, char* argv[])
+{
+    getParameters(argc, argv);
+    FILE *out = fopen(output, "wb+");
+    std::vector<FILE* > idngram_files;
+
+    if (optind >= argc) ShowUsage();
+    while (optind < argc) {
+        printf("Open %s:...", argv[optind]);
+        FILE *fp = fopen(argv[optind++], "rb");
+        if (fp == NULL) {
+            printf("error!\n");
+            exit(200);
+        }
+        idngram_files.push_back(fp);
+        printf("\n");
+    }
+    printf("Merging...");
+    switch (N) {
+    case 1:
+        ProcessingIdngramMerge<1>(out, idngram_files);
+        break;
+    case 2:
+        ProcessingIdngramMerge<2>(out, idngram_files);
+        break;
+    case 3:
+        ProcessingIdngramMerge<3>(out, idngram_files);
+        break;
+    }
+    printf("\n");
+    fclose(out);
+    for (size_t i = 0; i < idngram_files.size(); i++)
+        fclose(idngram_files[i]);
+    return 0;
+}
+
diff --git a/src/slm/ids2ngram/idngram_merge.h b/src/slm/ids2ngram/idngram_merge.h
new file mode 100644 (file)
index 0000000..1567b8e
--- /dev/null
@@ -0,0 +1,105 @@
+// -*- mode: c++ -*-
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright (c) 2007 Sun Microsystems, Inc. All Rights Reserved.
+ *
+ * The contents of this file are subject to the terms of either the GNU Lesser
+ * General Public License Version 2.1 only ("LGPL") or the Common Development and
+ * Distribution License ("CDDL")(collectively, the "License"). You may not use this
+ * file except in compliance with the License. You can obtain a copy of the CDDL at
+ * http://www.opensource.org/licenses/cddl1.php and a copy of the LGPLv2.1 at
+ * http://www.opensource.org/licenses/lgpl-license.php. See the License for the
+ * specific language governing permissions and limitations under the License. When
+ * distributing the software, include this License Header Notice in each file and
+ * include the full text of the License in the License file as well as the
+ * following notice:
+ *
+ * NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND DISTRIBUTION LICENSE
+ * (CDDL)
+ * For Covered Software in this distribution, this License shall be governed by the
+ * laws of the State of California (excluding conflict-of-law provisions).
+ * Any litigation relating to this License shall be subject to the jurisdiction of
+ * the Federal Courts of the Northern District of California and the state courts
+ * of the State of California, with venue lying in Santa Clara County, California.
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by only the CDDL or only
+ * the LGPL Version 2.1, indicate your decision by adding "[Contributor]" elects to
+ * include this software in this distribution under the [CDDL or LGPL Version 2.1]
+ * license." If you don't indicate a single choice of license, a recipient has the
+ * option to distribute your version of this file under either the CDDL or the LGPL
+ * Version 2.1, or to extend the choice of license to its licensees as provided
+ * above. However, if you add LGPL Version 2.1 code and therefore, elected the LGPL
+ * Version 2 license, then the option applies only if the new code is made subject
+ * to such option by the copyright holder.
+ */
+
+#ifndef _SIM_IDNGRAM_MERGE_H
+#define _SIM_IDNGRAM_MERGE_H
+
+#include <stdio.h>
+#include <map>
+#include <vector>
+#include <algorithm>
+#include <climits>
+
+#include "../sim_fmerge.h"
+#include "idngram.h"
+
+template<int N>
+void DoIdngramMerge(FILE*out,
+                    CMultiWayFileMerger<CSIM_IdngramFreq<N> > &merger){
+    merger.start();
+    CSIM_IdngramFreq<N> prevItem;
+    while (true) {
+        file_para<CSIM_IdngramFreq<N> > * ppara = merger.getBest();
+        TUnitAndParaInfo<CSIM_IdngramFreq<N> > & upi = *(*ppara);
+        if (upi.runOut) {
+            if (prevItem.freq != 0) {
+                fwrite(prevItem.ids, sizeof(TSIMWordId), N, out);
+                fwrite(&(prevItem.freq), sizeof(unsigned int), 1, out);
+            }
+            break;
+        }
+        CSIM_IdngramFreq<N>& ng = upi.unit;
+        if (!(prevItem == ng)) {
+            if (prevItem.freq != 0) {
+                fwrite(prevItem.ids, sizeof(TSIMWordId), N, out);
+                fwrite(&(prevItem.freq), sizeof(unsigned int), 1, out);
+            }
+            prevItem = ng;
+        } else {
+            assert(prevItem.freq < UINT_MAX);
+            prevItem.freq += ng.freq;
+        }
+        merger.next();
+    }
+}
+
+template<int N>
+void ProcessingIdngramMerge(FILE *swap,
+                            FILE* out,
+                            std::vector<long>& para_offsets){
+    CMultiWayFileMerger<CSIM_IdngramFreq<N> > merger;
+    long s = 0;
+    for (size_t i = 0; i < para_offsets.size(); i++) {
+        merger.addPara(swap, s, para_offsets[i]);
+        s = para_offsets[i];
+    }
+    DoIdngramMerge<N>(out, merger);
+}
+
+template<int N>
+void ProcessingIdngramMerge(FILE* out, std::vector<FILE* >& file_list){
+    CMultiWayFileMerger<CSIM_IdngramFreq<N> > merger;
+    for (size_t i = 0; i < file_list.size(); ++i) {
+        fseek(file_list[i], 0, SEEK_END);
+        merger.addPara(file_list[i], 0, ftell(file_list[i]));
+    }
+    DoIdngramMerge<N>(out, merger);
+}
+
+#endif
+
diff --git a/src/slm/ids2ngram/ids2ngram.cpp b/src/slm/ids2ngram/ids2ngram.cpp
new file mode 100644 (file)
index 0000000..d5a020a
--- /dev/null
@@ -0,0 +1,216 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright (c) 2007 Sun Microsystems, Inc. All Rights Reserved.
+ *
+ * The contents of this file are subject to the terms of either the GNU Lesser
+ * General Public License Version 2.1 only ("LGPL") or the Common Development and
+ * Distribution License ("CDDL")(collectively, the "License"). You may not use this
+ * file except in compliance with the License. You can obtain a copy of the CDDL at
+ * http://www.opensource.org/licenses/cddl1.php and a copy of the LGPLv2.1 at
+ * http://www.opensource.org/licenses/lgpl-license.php. See the License for the
+ * specific language governing permissions and limitations under the License. When
+ * distributing the software, include this License Header Notice in each file and
+ * include the full text of the License in the License file as well as the
+ * following notice:
+ *
+ * NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND DISTRIBUTION LICENSE
+ * (CDDL)
+ * For Covered Software in this distribution, this License shall be governed by the
+ * laws of the State of California (excluding conflict-of-law provisions).
+ * Any litigation relating to this License shall be subject to the jurisdiction of
+ * the Federal Courts of the Northern District of California and the state courts
+ * of the State of California, with venue lying in Santa Clara County, California.
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by only the CDDL or only
+ * the LGPL Version 2.1, indicate your decision by adding "[Contributor]" elects to
+ * include this software in this distribution under the [CDDL or LGPL Version 2.1]
+ * license." If you don't indicate a single choice of license, a recipient has the
+ * option to distribute your version of this file under either the CDDL or the LGPL
+ * Version 2.1, or to extend the choice of license to its licensees as provided
+ * above. However, if you add LGPL Version 2.1 code and therefore, elected the LGPL
+ * Version 2 license, then the option applies only if the new code is made subject
+ * to such option by the copyright holder.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifdef HAVE_ASSERT_H
+#include <assert.h>
+#endif
+
+#ifdef HAVE_GETOPT_H
+#include <getopt.h>
+#endif
+
+#include <stdio.h>
+#include <map>
+#include <vector>
+#include <algorithm>
+#include <climits>
+
+#include "../sim_fmerge.h"
+#include "idngram.h"
+#include "idngram_merge.h"
+
+template<int N>
+void
+WriteOut(FILE* out, std::map<CSIM_Idngram<N>, unsigned int> & map)
+{
+    typedef typename std::map<CSIM_Idngram<N>,
+                              unsigned int>::iterator TMapIterator;
+    TMapIterator its = map.begin(), ite = map.end();
+    for (; its != ite; ++its) {
+        fwrite(its->first.ids, sizeof(TSIMWordId), N, out);
+        fwrite(&(its->second), sizeof(unsigned int), 1, out);
+    }
+    map.clear();
+}
+
+template<int N>
+void
+ProcessingRead(FILE *fp,
+               FILE* swap,
+               std::vector<long>& para_offsets,
+               size_t paraMax)
+{
+    typedef CSIM_Idngram<N> TNgram;
+    typedef typename std::map<CSIM_Idngram<N>, unsigned int> TMap;
+
+    TMap map;
+    TNgram ngram;
+
+    TSIMWordId* ids = ngram.ids;
+    fread(ids, sizeof(TSIMWordId), N - 1, fp);
+    while (fread(ids + N - 1, sizeof(TSIMWordId), 1, fp) == 1) {
+        assert(map[ngram] < UINT_MAX);
+        ++map[ngram];
+        if (map.size() >= paraMax) {
+            printf("."); fflush(stdout);
+            WriteOut(swap, map);
+            para_offsets.push_back(ftell(swap));
+        }
+        for (int i = 0; i < N - 1; ++i) ids[i] = ids[i + 1];
+    }
+    if (map.size() > 0) {
+        printf("."); fflush(stdout);
+        WriteOut(swap, map);
+        para_offsets.push_back(ftell(swap));
+    }
+}
+
+static struct option long_options[] =
+{
+    { "NMax", 1, 0, 'n' },
+    { "out", 1, 0, 'o' },
+    { "swap", 1, 0, 's' },
+    { "para", 1, 0, 'p' },
+    { 0, 0, 0, 0 }
+};
+
+static int N = 0;
+static int paraMax = 0;
+static char* output = NULL;
+static char* swapfile = NULL;
+
+void
+ShowUsage()
+{
+    printf("Usage:\n\tids2ngram options idsfile[ idsfile...]\n");
+    printf("\nDescription\n");
+    printf(
+        "   This program generate idngram file, which is a sorted [id1,..idN,freq] array, from binary id stream files.\n");
+    printf("\nInput:\n");
+    printf("\tBinary id stream files looks like [id0,...,idX]\n");
+    printf("\nOptions:\n");
+    printf("\t  -n N               # N-gram\n");
+    printf("\t  -s swapfile        # intermedia temporary file\n");
+    printf(
+        "\t  -o outputfile      # result idngram file [id1, ... idN, freq]*\n");
+    printf("\t  -p para_size       # maxium ngram-items per para\n");
+    printf("\nExample:\n");
+    printf(
+        "   Following example will use three input idstream file idsfile[1,2,3] to generate the idngram file all.id3gram. Each para (internal map size or hash size) would be 1024000, using swap file for temp result. All temp para result would final be merged to got the final result.\n");
+    printf(
+        "\tids2idngram -n 3 -s /tmp/swap -o all.id3gram -p 1024000 idsfile1 idsfile2 idsfile3\n\n");
+    exit(100);
+}
+
+static void
+getParameters(int argc, char* const argv[])
+{
+    int option_index = 0;
+    int c;
+    while ((c =
+                getopt_long(argc, argv, "p:n:s:o:", long_options,
+                            &option_index)) != -1) {
+        switch (c) {
+        case 'n':
+            N = atoi(strdup(optarg));
+            break;
+        case 'p':
+            paraMax = atoi(strdup(optarg));
+            break;
+        case 'o':
+            output = strdup(optarg);
+            break;
+        case 's':
+            swapfile = strdup(optarg);
+            break;
+        default:
+            ShowUsage();
+        }
+    }
+    if (N < 1 || N > 3 || paraMax < 1024 || output == NULL || swapfile == NULL)
+        ShowUsage();
+}
+
+static std::vector<long> para_offsets;
+
+int
+main(int argc, char* argv[])
+{
+    getParameters(argc, argv);
+    FILE *swap = fopen(swapfile, "wb+");
+    FILE *out = fopen(output, "wb+");
+    if (optind >= argc) ShowUsage();
+    while (optind < argc) {
+        printf("Processing %s:", argv[optind]); fflush(stdout);
+        FILE *fp = fopen(argv[optind], "rb");
+        switch (N) {
+        case 1:
+            ProcessingRead<1>(fp, swap, para_offsets, paraMax);
+            break;
+        case 2:
+            ProcessingRead<2>(fp, swap, para_offsets, paraMax);
+            break;
+        case 3:
+            ProcessingRead<3>(fp, swap, para_offsets, paraMax);
+            break;
+        }
+        fclose(fp);
+        printf("\n"); fflush(stdout);
+        ++optind;
+    }
+    printf("Merging..."); fflush(stdout);
+    switch (N) {
+    case 1:
+        ProcessingIdngramMerge<1>(swap, out, para_offsets);
+        break;
+    case 2:
+        ProcessingIdngramMerge<2>(swap, out, para_offsets);
+        break;
+    case 3:
+        ProcessingIdngramMerge<3>(swap, out, para_offsets);
+        break;
+    }
+    printf("Done\n"); fflush(stdout);
+    fclose(out);
+    fclose(swap);
+    return 0;
+}
+
diff --git a/src/slm/mmseg/mmseg.cpp b/src/slm/mmseg/mmseg.cpp
new file mode 100644 (file)
index 0000000..cf449e7
--- /dev/null
@@ -0,0 +1,321 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright (c) 2007 Sun Microsystems, Inc. All Rights Reserved.
+ *
+ * The contents of this file are subject to the terms of either the GNU Lesser
+ * General Public License Version 2.1 only ("LGPL") or the Common Development and
+ * Distribution License ("CDDL")(collectively, the "License"). You may not use this
+ * file except in compliance with the License. You can obtain a copy of the CDDL at
+ * http://www.opensource.org/licenses/cddl1.php and a copy of the LGPLv2.1 at
+ * http://www.opensource.org/licenses/lgpl-license.php. See the License for the
+ * specific language governing permissions and limitations under the License. When
+ * distributing the software, include this License Header Notice in each file and
+ * include the full text of the License in the License file as well as the
+ * following notice:
+ *
+ * NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND DISTRIBUTION LICENSE
+ * (CDDL)
+ * For Covered Software in this distribution, this License shall be governed by the
+ * laws of the State of California (excluding conflict-of-law provisions).
+ * Any litigation relating to this License shall be subject to the jurisdiction of
+ * the Federal Courts of the Northern District of California and the state courts
+ * of the State of California, with venue lying in Santa Clara County, California.
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by only the CDDL or only
+ * the LGPL Version 2.1, indicate your decision by adding "[Contributor]" elects to
+ * include this software in this distribution under the [CDDL or LGPL Version 2.1]
+ * license." If you don't indicate a single choice of license, a recipient has the
+ * option to distribute your version of this file under either the CDDL or the LGPL
+ * Version 2.1, or to extend the choice of license to its licensees as provided
+ * above. However, if you add LGPL Version 2.1 code and therefore, elected the LGPL
+ * Version 2 license, then the option applies only if the new code is made subject
+ * to such option by the copyright holder.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifdef HAVE_ASSERT_H
+#include <assert.h>
+#endif
+
+#ifdef HAVE_GETOPT_H
+#include <getopt.h>
+#endif
+
+#include <stdio.h>
+#include <unistd.h>
+#include <locale.h>
+
+#include "../sim_dict.h"
+#include "../sim_sen.h"
+
+static struct option long_options[] =
+{
+    { "dict", 1, 0, 'd' },
+    { "format", 1, 0, 'f' },
+    { "show-id", 0, 0, 'i' },
+    { "s-tok", 1, 0, 's' },
+    { "ambiguious-id", 1, 0, 'a' },
+    { 0, 0, 0, 0 }
+};
+
+static char* s_strDictFile = NULL;
+static bool s_bTextOut = false;
+static bool s_bShowId = false;
+static TSIMWordId s_iSTOKID = 10;
+static TSIMWordId s_iAmbiID = 0;
+
+static CSIMDict *s_dict = NULL;
+
+static void
+ShowUsage()
+{
+    fprintf(stderr, "\nUsage:\n");
+    fprintf(
+        stderr,
+        "mmseg -d dict_file [-f (text|bin)] [-i] [-s STOK_ID] [-a AMBI_ID]\n\n");
+    fprintf(stderr, "  -f --format:\n");
+    fprintf(stderr,
+            "    Output Format, can be 'text' or 'bin'. default 'bin'\n");
+    fprintf(
+        stderr,
+        "    Normally, in text mode, word text are output, while in binary mode,\n");
+    fprintf(stderr,
+            "    binary short integer of the word-ids are written to stdout.\n");
+    fprintf(stderr, "  -s --stok:\n");
+    fprintf(stderr, "    Sentence token id. Default 10.\n");
+    fprintf(
+        stderr,
+        "    It will be written to output in binary mode after every sentence.\n");
+    fprintf(stderr, "  -i --show-id:\n");
+    fprintf(
+        stderr,
+        "    Show Id info. Under text output format mode, attach id after known.\n");
+    fprintf(stderr, "    words. If under binary mode, print id(s) in text.\n");
+    fprintf(stderr, "  -a --ambiguious-id:\n");
+    fprintf(
+        stderr,
+        "    Ambiguious means ABC => A BC or AB C. If specified (AMBI-ID != 0), \n");
+    fprintf(
+        stderr,
+        "    The sequence ABC will not be segmented, in binary mode, the AMBI-ID \n");
+    fprintf(
+        stderr,
+        "    is written out; in text mode, <ambi>ABC</ambi> will be output. Default \n");
+    fprintf(stderr, "    is 0.\n");
+    fprintf(stderr, "\n");
+    fprintf(stderr, "Notes:\n");
+    fprintf(stderr,
+            "  Under binary mode, consecutive id of 0 are merged into one 0.\n");
+    fprintf(
+        stderr,
+        "  Under text mode, no space are inserted between unknown-words. \n");
+    fprintf(stderr, "\n");
+    fprintf(stderr, "\n");
+    exit(1000);
+}
+
+static void
+getParameters(int argc, char* argv[])
+{
+    int c;
+    while ((c =
+                getopt_long(argc, argv, "d:if:s:a:", long_options,
+                            NULL)) != -1) {
+        switch (c) {
+        case 'd':
+            s_strDictFile = strdup(optarg);
+            break;
+        case 'i':
+            s_bShowId = true;
+            break;
+        case 'f':
+            s_bTextOut = (strcmp(optarg, "text") == 0);
+            break;
+        case 's':
+            s_iSTOKID = atoi(optarg);
+            break;
+        case 'a':
+            s_iAmbiID = atoi(optarg);
+            break;
+        default:
+            ShowUsage();
+            break;
+        }
+    }
+    if (s_strDictFile == NULL)
+        ShowUsage();
+}
+
+static void
+output_stok(int& nWords)
+{
+    if (s_bShowId) {
+        if (nWords > 0)
+            printf(" ");
+        printf("%d", unsigned(s_iSTOKID));
+    } else {
+        fwrite(&s_iSTOKID, sizeof(TSIMWordId), 1, stdout);
+    }
+    ++nWords;
+}
+
+static void
+output(int len,
+       const TWCHAR* p,
+       TSIMWordId idprev,
+       TSIMWordId idcur,
+       int& nWords)
+{
+    static char mbword[1024];
+    static TWCHAR wcword[1024];
+
+    bool bRealGap = (idcur != SIM_ID_NOT_WORD || idprev != SIM_ID_NOT_WORD);
+    if (s_bTextOut) {
+        for (int i = 0; i < len; ++i, ++p)
+            wcword[i] = *p;
+        wcword[len] = 0;
+        WCSTOMBS(mbword, wcword, sizeof(mbword));
+        if (bRealGap && idprev == SIM_ID_NOT_WORD)
+            printf("(%d)", unsigned(idprev));
+        if (bRealGap && (nWords > 0))
+            printf(" ");
+        (s_iAmbiID && idcur == s_iAmbiID) ? printf("<ambi>%s</ambi>", mbword) :
+        printf("%s", mbword);
+        if (s_bShowId && idcur != SIM_ID_NOT_WORD)
+            printf("(%d)", unsigned(idcur));
+    } else {
+        if (bRealGap) {
+            if (s_bShowId) {
+                if (nWords > 0)
+                    printf(" ");
+                printf("%d", unsigned(idcur));
+            } else
+                fwrite(&idcur, sizeof(TSIMWordId), 1, stdout);
+        }
+    }
+    if (bRealGap)
+        ++nWords;
+}
+
+/**
+ * Return 最大交集歧义长度. For example, ABCDEF if ABC CD DEF are words.
+ * if return len > word_len, then ambiguious exists at word [p p+len)...
+ */
+int
+getAmbiLen(const TWCHAR* p, int word_len)
+{
+    const CSIMDict::TState* pstate;
+
+    for (int i = 1; i < word_len && *(p + i) != WCH_NULL; ++i) {
+        int len = s_dict->matchLongest(s_dict->getRoot(), pstate, p + i);
+        if (word_len < i + len)
+            word_len = i + len;
+    }
+
+    return word_len;
+}
+
+static bool
+processSingleFile(FILE* fp, int &nWords, int &nAmbis)
+{
+    nWords = 0;
+    nAmbis = 0;
+
+    wstring sntnc;
+    CSIMCharReader *pReader = new CSIMCharReader(fp);
+    CSIMCharReader::iterator iter = pReader->begin();
+    TSIMWordId idcur, idprev = s_iSTOKID;
+
+    if (!s_bTextOut)
+        output_stok(nWords);
+
+    while (true) {
+        if (ReadSentence(sntnc, iter, false) == false)
+            break;
+
+        for (const TWCHAR *p = sntnc.c_str(); (*p); ) {
+            const CSIMDict::TState* pstate;
+            int len = s_dict->matchLongest(s_dict->getRoot(), pstate, p);
+            if (len <= 0) {
+                idcur = SIM_ID_NOT_WORD;
+                len = 1;
+            } else
+                idcur = pstate->word_id;
+
+            if (s_iAmbiID != WCH_NULL) {
+                int ambiLen = getAmbiLen(p, len);
+                if (ambiLen > len) {
+                    len = ambiLen;
+                    idcur = s_iAmbiID;
+                    ++nAmbis;
+                }
+            }
+
+            output(len, p, idprev, idcur, nWords);
+
+            idprev = idcur;
+            p += len;
+        }
+
+        if (!s_bTextOut) {
+            output_stok(nWords);
+            idprev = s_iSTOKID;
+        }
+    }
+
+    fflush(stdout);
+    return true;
+}
+
+int
+main(int argc, char *argv[])
+{
+    int nWords, nAmbis;
+
+    setlocale(LC_ALL, "");
+    getParameters(argc, argv);
+    argc -= optind;
+    argv += optind;
+
+    fprintf(stderr, "Loading lexicon..."); fflush(stderr);
+    s_dict = new CSIMDict();
+    if (!s_dict->parseText(s_strDictFile)) {
+        fprintf(stderr, "fail\n"); fflush(stderr);
+        exit(1001);
+    }
+    fprintf(stderr, "done"); fflush(stderr);
+
+    if (argc == 0) {
+        fprintf(stderr, "\nProcessing from stdin..."); fflush(stderr);
+        processSingleFile(stdin, nWords, nAmbis);
+        fprintf(stderr, "%d words, %d ambiguious. Done!\n", nWords, nAmbis);
+        fflush(stderr);
+    } else {
+        for (int i = 0; i < argc; ++i) {
+            fprintf(stderr, "\nProcessing %s...", argv[i]); fflush(stderr);
+            FILE *fp = fopen(argv[i], "r");
+            if (fp != NULL) {
+                processSingleFile(fp, nWords, nAmbis);
+                fprintf(stderr,
+                        "@Offset %ld, %d words, %d ambiguious. Done!\n",
+                        ftell(fp),
+                        nWords,
+                        nAmbis); fflush(stderr);
+            } else {
+                fprintf(stderr, "Can not Open!!!!!!!\n"); fflush(stderr);
+            }
+            fclose(fp);
+        }
+    }
+
+    s_dict->close();
+    delete s_dict;
+    s_dict = NULL;
+    return 0;
+}
diff --git a/src/slm/sim_dict.cpp b/src/slm/sim_dict.cpp
new file mode 100644 (file)
index 0000000..78ee993
--- /dev/null
@@ -0,0 +1,187 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright (c) 2007 Sun Microsystems, Inc. All Rights Reserved.
+ *
+ * The contents of this file are subject to the terms of either the GNU Lesser
+ * General Public License Version 2.1 only ("LGPL") or the Common Development and
+ * Distribution License ("CDDL")(collectively, the "License"). You may not use this
+ * file except in compliance with the License. You can obtain a copy of the CDDL at
+ * http://www.opensource.org/licenses/cddl1.php and a copy of the LGPLv2.1 at
+ * http://www.opensource.org/licenses/lgpl-license.php. See the License for the
+ * specific language governing permissions and limitations under the License. When
+ * distributing the software, include this License Header Notice in each file and
+ * include the full text of the License in the License file as well as the
+ * following notice:
+ *
+ * NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND DISTRIBUTION LICENSE
+ * (CDDL)
+ * For Covered Software in this distribution, this License shall be governed by the
+ * laws of the State of California (excluding conflict-of-law provisions).
+ * Any litigation relating to this License shall be subject to the jurisdiction of
+ * the Federal Courts of the Northern District of California and the state courts
+ * of the State of California, with venue lying in Santa Clara County, California.
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by only the CDDL or only
+ * the LGPL Version 2.1, indicate your decision by adding "[Contributor]" elects to
+ * include this software in this distribution under the [CDDL or LGPL Version 2.1]
+ * license." If you don't indicate a single choice of license, a recipient has the
+ * option to distribute your version of this file under either the CDDL or the LGPL
+ * Version 2.1, or to extend the choice of license to its licensees as provided
+ * above. However, if you add LGPL Version 2.1 code and therefore, elected the LGPL
+ * Version 2 license, then the option applies only if the new code is made subject
+ * to such option by the copyright holder.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "sim_dict.h"
+
+
+void
+CSIMDict::freeSubTree(CSIMDict::TState& root)
+{
+    if (root.follow != NULL) {
+        Map_Type &map = *(root.follow);
+        for (Map_Type::iterator it = map.begin(), last = map.end();
+             it != last;
+             ++it)
+            freeSubTree(it->second);
+        delete root.follow;
+        root.follow = NULL;
+    }
+}
+
+const CSIMDict::TState*
+CSIMDict::step(const CSIMDict::TState* root, TWCHAR wch)
+{
+    if ((root != NULL) && (root->follow != NULL) && wch != WCH_NULL) {
+        Map_Type::iterator it = root->follow->find(TWCHAR(wch));
+        if (it != root->follow->end())
+            return &(it->second);
+    }
+    return NULL;
+}
+
+int
+CSIMDict::matchLongest(const CSIMDict::TState* root,
+                       CSIMDict::PState &  result,
+                       const TWCHAR* str)
+{
+    int lastWordLen = 0, len = 0;
+    result = root;
+    while (root != NULL) {
+        if (root->word_id != SIM_ID_NOT_WORD) {
+            result = root;
+            lastWordLen = len;
+        }
+        ++len;
+        root = step(root, *str++);
+    }
+    return lastWordLen;
+}
+
+bool
+CSIMDict::parseText(const char* filename)
+{
+    FILE * fp = NULL;
+    static char buf[1024];
+    static TWCHAR wword[sizeof(buf)];
+    unsigned int id;
+
+    try {
+        if ((fp = fopen(filename, "r")) == NULL)
+            return false;
+        while (fgets(buf, 1024, fp) != NULL) {
+            if (*buf == '\n' || *buf == '#')
+                continue;
+
+            char* p = buf;
+            while (*p == ' ' || *p == '\t')
+                ++p;
+            char* pstart = p;
+            while (*p != 0 && *p != ' ' && *p != '\t')
+                ++p;
+            if (*p == 0)
+                continue;
+            *p++ = 0;
+            while (*p == ' ' || *p == '\t')
+                ++p;
+            if (!(*p >= '0' && *p <= '9')) continue;
+            for (id = 0; *p >= '0' && *p <= '9'; ++p)
+                id = 10 * id + (*p - '0');
+
+            if (id < SIM_ID_REALWORD_START)
+                continue;
+            if (MBSTOWCS(wword, pstart, sizeof(buf)) != (size_t)-1) {
+                insertWord(wword, TSIMWordId(id));
+            } else {
+                fprintf(stderr,
+                        "mbs to wcs conversion error for : %s %d\n",
+                        buf,
+                        id);
+                exit(100);
+            }
+        }
+        fclose(fp);
+    } catch (...) {
+        if (fp != NULL)
+            fclose(fp);
+        buf[sizeof(buf) - 1] = 0;
+        fprintf(stderr,
+                "Catch exception when loading dictionary at %s, exiting...",
+                buf);
+        exit(200);
+    }
+    return true;
+}
+
+void
+CSIMDict::insertWord(const TWCHAR* wstr, TSIMWordId id)
+{
+    TState* ps = &m_root;
+    while (*wstr) {
+        TWCHAR ch(*wstr++);
+        TSIMWordId nodeId = (*wstr) ? SIM_ID_NOT_WORD : id;
+        if (ps->follow == NULL) {
+            ps->follow = new Map_Type();
+        }
+        Map_Type & map = *(ps->follow);
+        Map_Type::iterator it = map.find(ch);
+        if (it != map.end() && nodeId != SIM_ID_NOT_WORD &&
+            it->second.word_id != SIM_ID_NOT_WORD && it->second.word_id !=
+            nodeId) {
+            throw new int(100);
+        }
+        if (it != map.end()) {
+            if (nodeId != SIM_ID_NOT_WORD)
+                it->second.word_id = nodeId;
+            ps = &(it->second);
+        } else {
+            ps = &(map[ch] = TState(nodeId));
+        }
+    }
+}
+
+void
+CSIMDict::InnerPrint(FILE* fp, wstring & wstr, const TState* pnode)
+{
+    if (pnode != NULL && pnode->word_id != SIM_ID_NOT_WORD) {
+        char* buf = new char[wstr.size() * 2 + 2];
+        WCSTOMBS(buf, wstr.c_str(), wstr.size() * 2 + 2);
+        fprintf(fp, "%s %d\n", buf, unsigned(pnode->word_id));
+        delete[] buf;
+    }
+    if (pnode != NULL && pnode->follow != NULL) {
+        Map_Type::iterator it, ite = pnode->follow->end();
+        for (it = pnode->follow->begin(); it != ite; ++it) {
+            TWCHAR wch = TWCHAR(it->first);
+            wstr.push_back(wch);
+            InnerPrint(fp, wstr, &(it->second));
+            wstr.erase(wstr.size() - 1, 1);
+        }
+    }
+}
diff --git a/src/slm/sim_dict.h b/src/slm/sim_dict.h
new file mode 100644 (file)
index 0000000..e37624c
--- /dev/null
@@ -0,0 +1,81 @@
+// -*- mode: c++ -*-
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright (c) 2007 Sun Microsystems, Inc. All Rights Reserved.
+ *
+ * The contents of this file are subject to the terms of either the GNU Lesser
+ * General Public License Version 2.1 only ("LGPL") or the Common Development and
+ * Distribution License ("CDDL")(collectively, the "License"). You may not use this
+ * file except in compliance with the License. You can obtain a copy of the CDDL at
+ * http://www.opensource.org/licenses/cddl1.php and a copy of the LGPLv2.1 at
+ * http://www.opensource.org/licenses/lgpl-license.php. See the License for the
+ * specific language governing permissions and limitations under the License. When
+ * distributing the software, include this License Header Notice in each file and
+ * include the full text of the License in the License file as well as the
+ * following notice:
+ *
+ * NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND DISTRIBUTION LICENSE
+ * (CDDL)
+ * For Covered Software in this distribution, this License shall be governed by the
+ * laws of the State of California (excluding conflict-of-law provisions).
+ * Any litigation relating to this License shall be subject to the jurisdiction of
+ * the Federal Courts of the Northern District of California and the state courts
+ * of the State of California, with venue lying in Santa Clara County, California.
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by only the CDDL or only
+ * the LGPL Version 2.1, indicate your decision by adding "[Contributor]" elects to
+ * include this software in this distribution under the [CDDL or LGPL Version 2.1]
+ * license." If you don't indicate a single choice of license, a recipient has the
+ * option to distribute your version of this file under either the CDDL or the LGPL
+ * Version 2.1, or to extend the choice of license to its licensees as provided
+ * above. However, if you add LGPL Version 2.1 code and therefore, elected the LGPL
+ * Version 2 license, then the option applies only if the new code is made subject
+ * to such option by the copyright holder.
+ */
+
+#ifndef _SunAGCIM_Dict_H_
+#define _SunAGCIM_Dict_H_
+
+#include "../portability.h"
+
+#include <map>
+#include <string>
+
+class CSIMDict {
+public:
+    struct TState;
+    typedef const TState * PState;
+    struct TState {
+        TSIMWordId word_id;
+        std::map<TWCHAR, TState>* follow;
+        TState(TSIMWordId wid = SIM_ID_NOT_WORD) : word_id(wid), follow(NULL) { }
+    };
+    typedef std::map<TWCHAR, TState> Map_Type;
+
+    CSIMDict() : m_root() {}
+    ~CSIMDict() { close(); }
+
+    bool parseText(const char* filename);
+    void close(){ freeSubTree(m_root); m_root = TState(); }
+
+    const TState* getRoot() const { return &m_root; }
+    int     matchLongest(const CSIMDict::TState* root,
+                         CSIMDict::PState &  result,
+                         const TWCHAR* str);
+
+    static const TState* step(const CSIMDict::TState* root, TWCHAR wch);
+    void PrintOut(FILE* fp) { wstring ws; InnerPrint(fp, ws, getRoot()); }
+
+protected:
+    TState m_root;
+
+protected:
+    void freeSubTree(TState& root);
+    void insertWord(const TWCHAR* wstr, TSIMWordId id);
+    void InnerPrint(FILE* fp, wstring & wstr, const TState* pnode);
+};
+
+#endif
diff --git a/src/slm/sim_fmerge.h b/src/slm/sim_fmerge.h
new file mode 100644 (file)
index 0000000..b0c61d2
--- /dev/null
@@ -0,0 +1,157 @@
+// -*- mode: c++ -*-
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright (c) 2007 Sun Microsystems, Inc. All Rights Reserved.
+ *
+ * The contents of this file are subject to the terms of either the GNU Lesser
+ * General Public License Version 2.1 only ("LGPL") or the Common Development and
+ * Distribution License ("CDDL")(collectively, the "License"). You may not use this
+ * file except in compliance with the License. You can obtain a copy of the CDDL at
+ * http://www.opensource.org/licenses/cddl1.php and a copy of the LGPLv2.1 at
+ * http://www.opensource.org/licenses/lgpl-license.php. See the License for the
+ * specific language governing permissions and limitations under the License. When
+ * distributing the software, include this License Header Notice in each file and
+ * include the full text of the License in the License file as well as the
+ * following notice:
+ *
+ * NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND DISTRIBUTION LICENSE
+ * (CDDL)
+ * For Covered Software in this distribution, this License shall be governed by the
+ * laws of the State of California (excluding conflict-of-law provisions).
+ * Any litigation relating to this License shall be subject to the jurisdiction of
+ * the Federal Courts of the Northern District of California and the state courts
+ * of the State of California, with venue lying in Santa Clara County, California.
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by only the CDDL or only
+ * the LGPL Version 2.1, indicate your decision by adding "[Contributor]" elects to
+ * include this software in this distribution under the [CDDL or LGPL Version 2.1]
+ * license." If you don't indicate a single choice of license, a recipient has the
+ * option to distribute your version of this file under either the CDDL or the LGPL
+ * Version 2.1, or to extend the choice of license to its licensees as provided
+ * above. However, if you add LGPL Version 2.1 code and therefore, elected the LGPL
+ * Version 2 license, then the option applies only if the new code is made subject
+ * to such option by the copyright holder.
+ */
+
+#ifndef _SIM_FILE_MERGE_H
+#define _SIM_FILE_MERGE_H
+
+#include "../portability.h"
+
+#include <stdio.h>
+#include <deque>
+#include <vector>
+#include <algorithm>
+
+template<class unit_type>
+class TUnitAndParaInfo {
+public:
+    typedef unit_type TUnit;
+    TUnitAndParaInfo() : unit(), runOut(false) {}
+public:
+    TUnit unit;
+    bool runOut;
+};
+
+template<class unit_type>
+class file_para
+{
+public:
+    typedef unit_type TUnit;
+    typedef TUnitAndParaInfo<TUnit> UnitAndParaInfo;
+    typedef std::deque<UnitAndParaInfo> TItemBuf;
+    typedef typename TItemBuf::iterator TIBIterator;
+    typedef typename TItemBuf::const_iterator TIBConstIterator;
+
+    file_para(FILE* p_file, size_t start, size_t end)
+        : fp(p_file), runOut(false), cur_offset(start), last_offset(end),
+          buf() {}
+
+    UnitAndParaInfo& operator*(){
+        if (buf.size() == 0) {
+            for (int i = 0; i < BUF_SIZE; ++i) {
+                buf.push_back(UnitAndParaInfo());
+                UnitAndParaInfo& e = buf.back();
+                e.runOut = runOut = !(e.unit.read(fp, cur_offset, last_offset));
+                if (runOut) break;
+            }
+        }
+        return buf.front();
+    }
+
+    file_para& operator++(){
+        if (buf.size() == 0)
+            this->operator*();
+        buf.pop_front();
+        return *this;
+    }
+
+    bool operator<(file_para& another){
+        const UnitAndParaInfo& me = this->operator*();
+        const UnitAndParaInfo& you = *another;
+        if (me.runOut) {
+            if (you.runOut)
+                return((char *) &me < (char *) &you);
+            else
+                return true;
+        } else {
+            if (you.runOut)
+                return false;
+            else {
+                if (me.unit > you.unit) return true;
+                if (me.unit == you.unit) return((char *) &me < (char *) &you);
+                return false;
+            }
+        }
+    }
+
+private:
+    static const int BUF_SIZE = 1024;
+    FILE * fp;
+    bool runOut;
+    size_t cur_offset, last_offset;
+    TItemBuf buf;
+};
+
+template <class PPara>
+class PtrCompare {
+public:
+    bool operator()(const PPara& p1, const PPara& p2)
+    { return(*p1 < *p2); }
+};
+
+template<class unit_type>
+class CMultiWayFileMerger
+{
+public:
+    typedef file_para<unit_type> TPara;
+    typedef std::vector<TPara*> TParaVec;
+
+    void addPara(FILE *fp, size_t first_offset, size_t last_offset) {
+        paras.push_back(new TPara(fp, first_offset, last_offset));
+    }
+
+    void start() {
+        std::make_heap(paras.begin(), paras.end(), PtrCompare<TPara*>());
+    }
+    TPara* getBest(){ //You then have to deal same items form different part
+        std::pop_heap(paras.begin(), paras.end(), PtrCompare<TPara*>());
+        return paras.back();
+    }
+    void next(){
+        ++(*(paras.back()));
+        std::push_heap(paras.begin(), paras.end(), PtrCompare<TPara*>());
+    }
+    ~CMultiWayFileMerger() {
+        for (size_t i = 0; i < paras.size(); i++) {
+            delete paras[i];
+        }
+    }
+private:
+    TParaVec paras;
+};
+
+#endif
diff --git a/src/slm/sim_sen.cpp b/src/slm/sim_sen.cpp
new file mode 100644 (file)
index 0000000..4883b00
--- /dev/null
@@ -0,0 +1,88 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright (c) 2007 Sun Microsystems, Inc. All Rights Reserved.
+ *
+ * The contents of this file are subject to the terms of either the GNU Lesser
+ * General Public License Version 2.1 only ("LGPL") or the Common Development and
+ * Distribution License ("CDDL")(collectively, the "License"). You may not use this
+ * file except in compliance with the License. You can obtain a copy of the CDDL at
+ * http://www.opensource.org/licenses/cddl1.php and a copy of the LGPLv2.1 at
+ * http://www.opensource.org/licenses/lgpl-license.php. See the License for the
+ * specific language governing permissions and limitations under the License. When
+ * distributing the software, include this License Header Notice in each file and
+ * include the full text of the License in the License file as well as the
+ * following notice:
+ *
+ * NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND DISTRIBUTION LICENSE
+ * (CDDL)
+ * For Covered Software in this distribution, this License shall be governed by the
+ * laws of the State of California (excluding conflict-of-law provisions).
+ * Any litigation relating to this License shall be subject to the jurisdiction of
+ * the Federal Courts of the Northern District of California and the state courts
+ * of the State of California, with venue lying in Santa Clara County, California.
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by only the CDDL or only
+ * the LGPL Version 2.1, indicate your decision by adding "[Contributor]" elects to
+ * include this software in this distribution under the [CDDL or LGPL Version 2.1]
+ * license." If you don't indicate a single choice of license, a recipient has the
+ * option to distribute your version of this file under either the CDDL or the LGPL
+ * Version 2.1, or to extend the choice of license to its licensees as provided
+ * above. However, if you add LGPL Version 2.1 code and therefore, elected the LGPL
+ * Version 2 license, then the option applies only if the new code is made subject
+ * to such option by the copyright holder.
+ */
+
+#include <stdlib.h>
+#include "sim_sen.h"
+
+TWCHAR &
+SIMCharReaderIterator::operator*() const
+{
+    FILE *fp = reader->fp;
+    std::deque<TWCHAR> & buf = reader->buf;
+
+    for (int i = buf.size(); i <= idx; ) {
+        wint_t wch = fgetwc(fp);
+        if (wch == 0) {
+            wch = 0x20; // make it like a space
+        }
+        if (wch == WEOF) {
+            if (feof(fp)) {
+                buf.push_back(TWCHAR(0));
+                return buf.back();
+            } else {
+                fprintf(stderr, "File read error %d\n", ferror(fp));
+                throw new int(60);
+            }
+        } else {
+            buf.push_back(wch);
+            ++i;
+        }
+    }
+    if (idx >= (int) buf.size() && buf.back() == WCH_NULL)
+        return buf.back();
+    return buf[idx];
+}
+
+SIMCharReaderIterator&
+SIMCharReaderIterator::operator++()
+{
+    std::deque<TWCHAR>& buf = reader->buf;
+    TWCHAR wch = this->operator*();
+    if (wch) {
+        if (idx == 0)
+            buf.pop_front();
+        else
+            ++idx;
+    }
+    return *this;
+}
+
+SIMCharReaderIterator
+SIMCharReaderIterator::operator+(int i)
+{
+    return SIMCharReaderIterator(reader, idx + i);
+}
diff --git a/src/slm/sim_sen.h b/src/slm/sim_sen.h
new file mode 100644 (file)
index 0000000..5c36b36
--- /dev/null
@@ -0,0 +1,120 @@
+// -*- mode: c++ -*-
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright (c) 2007 Sun Microsystems, Inc. All Rights Reserved.
+ *
+ * The contents of this file are subject to the terms of either the GNU Lesser
+ * General Public License Version 2.1 only ("LGPL") or the Common Development and
+ * Distribution License ("CDDL")(collectively, the "License"). You may not use this
+ * file except in compliance with the License. You can obtain a copy of the CDDL at
+ * http://www.opensource.org/licenses/cddl1.php and a copy of the LGPLv2.1 at
+ * http://www.opensource.org/licenses/lgpl-license.php. See the License for the
+ * specific language governing permissions and limitations under the License. When
+ * distributing the software, include this License Header Notice in each file and
+ * include the full text of the License in the License file as well as the
+ * following notice:
+ *
+ * NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND DISTRIBUTION LICENSE
+ * (CDDL)
+ * For Covered Software in this distribution, this License shall be governed by the
+ * laws of the State of California (excluding conflict-of-law provisions).
+ * Any litigation relating to this License shall be subject to the jurisdiction of
+ * the Federal Courts of the Northern District of California and the state courts
+ * of the State of California, with venue lying in Santa Clara County, California.
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by only the CDDL or only
+ * the LGPL Version 2.1, indicate your decision by adding "[Contributor]" elects to
+ * include this software in this distribution under the [CDDL or LGPL Version 2.1]
+ * license." If you don't indicate a single choice of license, a recipient has the
+ * option to distribute your version of this file under either the CDDL or the LGPL
+ * Version 2.1, or to extend the choice of license to its licensees as provided
+ * above. However, if you add LGPL Version 2.1 code and therefore, elected the LGPL
+ * Version 2 license, then the option applies only if the new code is made subject
+ * to such option by the copyright holder.
+ */
+
+#ifndef _SIM_SENTENCIZER_H
+#define _SIM_SENTENCIZER_H
+
+#include "../portability.h"
+
+#include <stdlib.h>
+#include <deque>
+
+class CSIMCharReader;
+
+class SIMCharReaderIterator {
+public:
+    SIMCharReaderIterator(CSIMCharReader* the_reader = NULL, int the_idx = 0)
+        : reader(the_reader), idx(the_idx) { }
+    SIMCharReaderIterator& operator++();
+    SIMCharReaderIterator operator+(int i);
+    TWCHAR & operator*() const;
+
+private:
+    CSIMCharReader* reader;
+    int idx;
+};
+
+class CSIMCharReader {
+    friend class SIMCharReaderIterator;
+
+public:
+    typedef SIMCharReaderIterator iterator;
+
+public:
+    CSIMCharReader(FILE* afp) : fp(afp), buf() { }
+    iterator begin() { return iterator(this, 0); }
+
+private:
+    FILE *fp;
+    std::deque<TWCHAR> buf;
+};
+
+template <class iterator>
+bool ReadSentence(wstring& wstr, iterator& first, bool bIgnoreCRLF = false){
+    wstr.clear();
+    TWCHAR ch, chnext, ch2;
+    int brk = 0;
+    for (; (ch = *first) != WCH_NULL; ++first) {
+        chnext = *(first + 1);
+        ch2 = *(first + 2);
+        if ((ch == WCH_RETURN) && bIgnoreCRLF && (chnext != WCH_RETURN))
+            continue;
+        if (ch == WCH_JUHAO || ch == WCH_WENHAO || ch == WCH_TANHAO ||
+            ch == WCH_TANHAO || ch == WCH_SHENGLUEHAO)
+            brk = 1;
+        else if (ch == WCH_DOUHAO && chnext == WCH_DOUHAO)
+            brk = 1;
+        else if (ch == WCH_RETURN || ch == WCH_TAB)
+            brk = 2;
+        else if (ch == WCH_SPACE) {
+            if (chnext == WCH_RETURN) {
+                if (ch2 == WCH_SPACE || ch2 == WCH_TAB || ch2 == WCH_RETURN)
+                    brk = 2;
+            } else if (chnext == WCH_SPACE || chnext == WCH_TAB)
+                brk = 2;
+        }
+        if (brk != 0)
+            break;
+        wstr.push_back(ch);
+    }
+    if (brk == 2 && wstr.size() == 0) {
+        do {
+            wstr.push_back(*first);
+            ch = *(++first);
+        } while (ch == WCH_SPACE || ch == WCH_TAB || ch == WCH_RETURN);
+    } else if (brk == 1) {
+        do {
+            wstr.push_back(*first);
+            ch = *(++first);
+        } while (ch == WCH_JUHAO || ch == WCH_WENHAO || ch == WCH_TANHAO ||
+                 ch == WCH_FENHAO || ch == WCH_MAOHAO || ch == WCH_SHENGLUEHAO);
+    }
+    return(wstr.size() > 0);
+}
+
+#endif
diff --git a/src/slm/sim_slm.cpp b/src/slm/sim_slm.cpp
new file mode 100644 (file)
index 0000000..ba651b9
--- /dev/null
@@ -0,0 +1,162 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright (c) 2007 Sun Microsystems, Inc. All Rights Reserved.
+ *
+ * The contents of this file are subject to the terms of either the GNU Lesser
+ * General Public License Version 2.1 only ("LGPL") or the Common Development and
+ * Distribution License ("CDDL")(collectively, the "License"). You may not use this
+ * file except in compliance with the License. You can obtain a copy of the CDDL at
+ * http://www.opensource.org/licenses/cddl1.php and a copy of the LGPLv2.1 at
+ * http://www.opensource.org/licenses/lgpl-license.php. See the License for the
+ * specific language governing permissions and limitations under the License. When
+ * distributing the software, include this License Header Notice in each file and
+ * include the full text of the License in the License file as well as the
+ * following notice:
+ *
+ * NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND DISTRIBUTION LICENSE
+ * (CDDL)
+ * For Covered Software in this distribution, this License shall be governed by the
+ * laws of the State of California (excluding conflict-of-law provisions).
+ * Any litigation relating to this License shall be subject to the jurisdiction of
+ * the Federal Courts of the Northern District of California and the state courts
+ * of the State of California, with venue lying in Santa Clara County, California.
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by only the CDDL or only
+ * the LGPL Version 2.1, indicate your decision by adding "[Contributor]" elects to
+ * include this software in this distribution under the [CDDL or LGPL Version 2.1]
+ * license." If you don't indicate a single choice of license, a recipient has the
+ * option to distribute your version of this file under either the CDDL or the LGPL
+ * Version 2.1, or to extend the choice of license to its licensees as provided
+ * above. However, if you add LGPL Version 2.1 code and therefore, elected the LGPL
+ * Version 2 license, then the option applies only if the new code is made subject
+ * to such option by the copyright holder.
+ */
+
+#include <stdio.h>
+#include <math.h>
+
+#include "sim_slm.h"
+
+bool
+CSIMSlm::Load(const char* fname)
+{
+    bool suc = false;
+    FILE* fp = fopen(fname, "rb");
+    if (fp != NULL && fread(&N, sizeof(N), 1, fp) == 1 &&
+        fread(&bUseLogPr, sizeof(bUseLogPr), 1, fp) == 1) {
+        sz = new int[N + 1];
+        level = new void* [N + 1];
+        fread(sz, sizeof(int), N + 1, fp);
+        for (int lvl = 0; lvl <= N; ++lvl) {
+            if (lvl < N) {
+                level[lvl] = new TNode [sz[lvl]];
+                fread(level[lvl], sizeof(TNode), sz[lvl], fp);
+            } else {
+                level[lvl] = new TLeaf [sz[lvl]];
+                fread(level[lvl], sizeof(TLeaf), sz[lvl], fp);
+            }
+        }
+        suc = true;
+    }
+    fclose(fp);
+    return suc;
+}
+
+void
+CSIMSlm::Free()
+{
+    delete [] sz;
+    for (int lvl = 0; lvl <= N; ++lvl) {
+        if (lvl == N)
+            delete [] ((TLeaf*)level[lvl]);
+        else
+            delete [] ((TNode*)level[lvl]);
+    }
+    level = NULL;
+    sz = NULL;
+    bUseLogPr = 0;
+    N = 0;
+}
+
+double
+CSIMSlm::getNegLogPr(int n, TSIMWordId* hw)
+{
+    double val = (bUseLogPr) ? (getPrAsLog(n, hw)) : (getPrDirect(n, hw));
+    return (bUseLogPr) ? (val) : (-log(val));
+}
+
+double
+CSIMSlm::getPr(int n, TSIMWordId* hw)
+{
+    double val = (bUseLogPr) ? (getPrAsLog(n, hw)) : (getPrDirect(n, hw));
+    return (bUseLogPr) ? (exp(-val)) : (val);
+}
+
+/**
+ * Only used when this model using -log(pr) value, also
+ * the return value is also -log(pr) value
+ */
+double
+CSIMSlm::getPrAsLog(int n, TSIMWordId* hw)
+{
+    void* pstate = ((TNode*)level[0]);
+    double bow = 0.0;
+    if (n > N) {
+        hw += (N - n);
+        n = N;
+    }
+    for (int lvl = 0; lvl < n && pstate != NULL; ++lvl) {
+        int h = ((TNode*)pstate)->child;
+        int t = (((TNode*)pstate) + 1)->child;
+        if (lvl == n - 1)
+            bow = ((TNode*)pstate)->bow;
+        if (lvl == N - 1) {
+            TLeaf* p = (TLeaf*)level[lvl + 1];
+            pstate = (void*)binary_find_id(p + h, p + t, hw[lvl]);
+        } else {
+            TNode* p = (TNode*)level[lvl + 1];
+            pstate = (void*)binary_find_id(p + h, p + t, hw[lvl]);
+        }
+    }
+    if (pstate == NULL) {
+        return bow + getPrAsLog(n - 1, hw + 1);
+    } else {
+        return ((TLeaf*)pstate)->pr;  // as we derive TNode from TLeaf
+    }
+}
+
+/**
+ * Only used when this model using direct pr value, also
+ * the return value is also direct pr value.
+ */
+double
+CSIMSlm::getPrDirect(int n, TSIMWordId* hw)
+{
+    void* pstate = ((TNode*)level[0]);
+    double bow = 1.0;
+    if (n > N) {
+        hw += (N - n);
+        n = N;
+    }
+    for (int lvl = 0; lvl < n && pstate != NULL; ++lvl) {
+        int h = ((TNode*)pstate)->child;
+        int t = (((TNode*)pstate) + 1)->child;
+        if (lvl == n - 1)
+            bow = ((TNode*)pstate)->bow;
+        if (lvl == N - 1) {
+            TLeaf* p = (TLeaf*)level[lvl + 1];
+            pstate = (void*)binary_find_id(p + h, p + t, hw[lvl]);
+        } else {
+            TNode* p = (TNode*)level[lvl + 1];
+            pstate = (void*)binary_find_id(p + h, p + t, hw[lvl]);
+        }
+    }
+    if (pstate == NULL) {
+        return bow * getPrDirect(n - 1, hw + 1);
+    } else {
+        return ((TLeaf*)pstate)->pr;  // as we derive TNode from TLeaf
+    }
+}
diff --git a/src/slm/sim_slm.h b/src/slm/sim_slm.h
new file mode 100644 (file)
index 0000000..9dfc590
--- /dev/null
@@ -0,0 +1,138 @@
+// -*- mode: c++ -*-
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright (c) 2007 Sun Microsystems, Inc. All Rights Reserved.
+ *
+ * The contents of this file are subject to the terms of either the GNU Lesser
+ * General Public License Version 2.1 only ("LGPL") or the Common Development and
+ * Distribution License ("CDDL")(collectively, the "License"). You may not use this
+ * file except in compliance with the License. You can obtain a copy of the CDDL at
+ * http://www.opensource.org/licenses/cddl1.php and a copy of the LGPLv2.1 at
+ * http://www.opensource.org/licenses/lgpl-license.php. See the License for the
+ * specific language governing permissions and limitations under the License. When
+ * distributing the software, include this License Header Notice in each file and
+ * include the full text of the License in the License file as well as the
+ * following notice:
+ *
+ * NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND DISTRIBUTION LICENSE
+ * (CDDL)
+ * For Covered Software in this distribution, this License shall be governed by the
+ * laws of the State of California (excluding conflict-of-law provisions).
+ * Any litigation relating to this License shall be subject to the jurisdiction of
+ * the Federal Courts of the Northern District of California and the state courts
+ * of the State of California, with venue lying in Santa Clara County, California.
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by only the CDDL or only
+ * the LGPL Version 2.1, indicate your decision by adding "[Contributor]" elects to
+ * include this software in this distribution under the [CDDL or LGPL Version 2.1]
+ * license." If you don't indicate a single choice of license, a recipient has the
+ * option to distribute your version of this file under either the CDDL or the LGPL
+ * Version 2.1, or to extend the choice of license to its licensees as provided
+ * above. However, if you add LGPL Version 2.1 code and therefore, elected the LGPL
+ * Version 2 license, then the option applies only if the new code is made subject
+ * to such option by the copyright holder.
+ */
+
+#ifndef _SIM_SLM_H
+#define _SIM_SLM_H
+
+#include "../portability.h"
+
+class CSlmBuilder;
+
+/* only used as middle-result, please use thread slm for applications. */
+class CSIMSlm {
+    friend class CSlmBuilder;
+public:
+    typedef unsigned int FREQ_TYPE;
+    typedef float PR_TYPE;
+
+    struct TLeaf {
+        TSIMWordId id;
+        union {
+            FREQ_TYPE freq;     //for builder, not for use
+            PR_TYPE pr;
+        };
+public:
+        TLeaf(TSIMWordId theId = 0, FREQ_TYPE fr = 0) : id(theId), freq(fr)
+        { }
+        bool operator<(const TLeaf & r) const
+        { return id < r.id; }
+        bool operator>(const TLeaf & r) const
+        { return id > r.id; }
+        bool operator==(const TLeaf & r) const
+        { return id == r.id; }
+    };
+
+    struct TNode : public TLeaf {
+        int child;
+        PR_TYPE bow;
+public:
+        TNode(TSIMWordId theId = 0,
+              int ch = 0,
+              FREQ_TYPE fr = 0,
+              PR_TYPE theBOW = 0.0)
+            : TLeaf(theId, fr), child(ch), bow(theBOW)
+        { }
+    };
+
+public:
+    bool Load(const char* fname);
+    void Free();
+
+    unsigned isUseLogPr() const
+    { return bUseLogPr; }
+
+    double getPr(int n, TSIMWordId* hw);
+    double getNegLogPr(int n, TSIMWordId* hw);
+
+    CSIMSlm() : N(0), sz(NULL), level(NULL), bUseLogPr(0) {}
+
+protected:
+    double getPrAsLog(int n, TSIMWordId* hw);
+    double getPrDirect(int n, TSIMWordId* hw);
+
+protected:
+    int N;
+    int* sz;
+    void** level;
+    unsigned bUseLogPr;
+};
+
+
+template<class _NodeT_>
+_NodeT_* binary_find(_NodeT_* base, int h, int t, const _NodeT_ & val){
+    while (h < t) {
+        int m = (h + t) / 2;
+        _NodeT_* pm = base + m;
+        if (*pm < val)
+            h = m + 1;
+        else if (*pm == val)
+            return pm;
+        else
+            t = m;
+    }
+    return NULL;
+}
+
+template <class _NodeT_>
+_NodeT_* binary_find_id(_NodeT_ *ph, _NodeT_* pt, TSIMWordId id){
+    int h = 0, t = pt - ph;
+    while (h < t) {
+        int m = (h + t) / 2;
+        _NodeT_ * pm = ph + m;
+        if (pm->id == id)
+            return pm;
+        else if (pm->id < id)
+            h = m + 1;
+        else
+            t = m;
+    }
+    return NULL;
+}
+
+#endif
+
diff --git a/src/slm/sim_slmbuilder.cpp b/src/slm/sim_slmbuilder.cpp
new file mode 100644 (file)
index 0000000..2dc07bc
--- /dev/null
@@ -0,0 +1,633 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright (c) 2007 Sun Microsystems, Inc. All Rights Reserved.
+ *
+ * The contents of this file are subject to the terms of either the GNU Lesser
+ * General Public License Version 2.1 only ("LGPL") or the Common Development and
+ * Distribution License ("CDDL")(collectively, the "License"). You may not use this
+ * file except in compliance with the License. You can obtain a copy of the CDDL at
+ * http://www.opensource.org/licenses/cddl1.php and a copy of the LGPLv2.1 at
+ * http://www.opensource.org/licenses/lgpl-license.php. See the License for the
+ * specific language governing permissions and limitations under the License. When
+ * distributing the software, include this License Header Notice in each file and
+ * include the full text of the License in the License file as well as the
+ * following notice:
+ *
+ * NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND DISTRIBUTION LICENSE
+ * (CDDL)
+ * For Covered Software in this distribution, this License shall be governed by the
+ * laws of the State of California (excluding conflict-of-law provisions).
+ * Any litigation relating to this License shall be subject to the jurisdiction of
+ * the Federal Courts of the Northern District of California and the state courts
+ * of the State of California, with venue lying in Santa Clara County, California.
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by only the CDDL or only
+ * the LGPL Version 2.1, indicate your decision by adding "[Contributor]" elects to
+ * include this software in this distribution under the [CDDL or LGPL Version 2.1]
+ * license." If you don't indicate a single choice of license, a recipient has the
+ * option to distribute your version of this file under either the CDDL or the LGPL
+ * Version 2.1, or to extend the choice of license to its licensees as provided
+ * above. However, if you add LGPL Version 2.1 code and therefore, elected the LGPL
+ * Version 2 license, then the option applies only if the new code is made subject
+ * to such option by the copyright holder.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifdef HAVE_ASSERT_H
+#include <assert.h>
+#endif
+
+#include <stdlib.h>
+#include <math.h>
+#include <vector>
+#include <algorithm>
+
+#include "sim_slmbuilder.h"
+
+void
+CSlmGTDiscounter::init(int n, CSlmBuilder::FREQ_TYPE *nr)
+{
+    if (dis != NULL)
+        delete [] dis;
+    dis = new double[--n];
+    if (thres > n) thres = n;
+    for (int freq = 1; freq < n; ++freq) {
+        if (nr[freq] == 0 || nr[freq + 1] == 0)
+            dis[freq] = 1.0;
+        else
+            dis[freq] = double(nr[freq + 1]) / nr[freq];
+        printf("%lf ", dis[freq]); fflush(stdout);
+    }
+}
+
+double
+CSlmGTDiscounter::discount(int freq)
+{
+    double newfreq = freq * ((freq < thres) ? dis[freq] : hd);
+    if (newfreq >= double(freq))
+        newfreq = freq * hd;
+    return newfreq;
+}
+
+void
+CSlmAbsoluteDiscounter::init(int n, CSlmBuilder::FREQ_TYPE *nr)
+{
+    // normally, c should not greater than 1.0, yet when cut-off is used, it could be so.
+    if (c <= 0.0) {
+        c = double(nr[1]) / (nr[1] + 2.0 * nr[2]);
+        printf("parameter c=%lf", c); fflush(stdout);
+    } else {
+        printf("Using given parameter c=%lf", c); fflush(stdout);
+    }
+}
+
+double
+CSlmAbsoluteDiscounter::discount(int freq)
+{
+    return (freq > 0) ? (freq - c) : (0.0);
+}
+
+void
+CSlmLinearDiscounter::init(int n, CSlmBuilder::FREQ_TYPE *nr)
+{
+    if (dis <= 0.0 || dis >= 1.0) {
+        dis = 1.0 - double(nr[1]) / nr[0];
+        printf("parameter d=%lf", dis); fflush(stdout);
+    } else {
+        printf("Using given parameter d=%lf", dis); fflush(stdout);
+    }
+}
+
+double
+CSlmLinearDiscounter::discount(int freq)
+{
+    return freq * dis;
+}
+
+// n=1 for unigram, n=2 for bigram;
+// level[0] is for psuedo 0 gram, ...
+void
+CSlmBuilder::Create(int n)
+{
+    assert(n != 0);
+    nlevel = n;
+    level = new void * [n + 1];
+    for (int i = 0; i < n; ++i) {
+        level[i] = new std::vector<TNode>;
+        if (i) ((TNodeLevel*)level[i])->reserve(1024);
+    }
+    //Add leaf level
+    level[n] = new std::vector<TLeaf>;
+    ((TLeafLevel*)level[n])->reserve(1024);
+
+    //Add psuedo root node
+    ((TNodeLevel*)level[0])->push_back(TNode(0, 0, 0));
+
+    //Initialize the nr[n+1][SLM_MAX_R] 2-D array
+    nr = new FREQ_TYPE[n + 1][SLM_MAX_R];
+    for (int lvl = 0; lvl < n + 1; ++lvl)
+        for (int r = 0; r < SLM_MAX_R; ++r)
+            nr[lvl][r] = 0;
+}
+
+void
+CSlmBuilder::SetCut(FREQ_TYPE threshold[])
+{
+    if (cut != NULL)
+        delete [] cut;
+    cut = new FREQ_TYPE[nlevel + 1];
+    for (int i = 0; i < nlevel; ++i)
+        cut[i + 1] = threshold[i];
+}
+
+void
+CSlmBuilder::SetDiscounter(CSlmDiscounter* dis[])
+{
+    if (discounter != NULL)
+        delete [] discounter;
+    discounter = new CSlmDiscounter* [nlevel + 1];
+    for (int i = 0; i < nlevel; ++i)
+        discounter[i + 1] = dis[i];
+}
+
+void
+CSlmBuilder::SetBreakerIds(int nId, TSIMWordId brks[])
+{
+    breaker.clear();
+    for (int i = 0; i < nId; ++i)
+        breaker.push_back(brks[i]);
+    std::make_heap(breaker.begin(), breaker.end());
+    std::sort_heap(breaker.begin(), breaker.end());
+}
+
+void
+CSlmBuilder::SetExcludeIds(int nId, TSIMWordId excludes[])
+{
+    m_excludes.clear();
+    for (int i = 0; i < nId; ++i)
+        m_excludes.push_back(excludes[i]);
+    std::make_heap(m_excludes.begin(), m_excludes.end());
+    std::sort_heap(m_excludes.begin(), m_excludes.end());
+}
+
+bool
+CSlmBuilder::isBreakId(TSIMWordId id)
+{
+    return std::binary_search(breaker.begin(), breaker.end(), id);
+}
+
+bool
+CSlmBuilder::isExcludeId(TSIMWordId id)
+{
+    return std::binary_search(m_excludes.begin(), m_excludes.end(), id);
+}
+
+void
+CSlmBuilder::AddNGram(TSIMWordId* ngram, FREQ_TYPE fr)
+{
+    int ch;
+    bool brk = isExcludeId(*ngram);
+
+    for (int i = 1; i < nlevel; ++i) {
+        TNodeLevel* pnl = (TNodeLevel*)(level[i]);
+        if (pnl->capacity() == pnl->size()) {
+            size_t newsz = 2 * pnl->capacity();
+            if (pnl->capacity() > 1024 * 1024)
+                newsz = pnl->capacity() + 1024 * 1024;
+            pnl->reserve(newsz);
+        }
+    }
+    TLeafLevel* pll = (TLeafLevel*)(level[nlevel]);
+    if (pll->capacity() == pll->size()) {
+        size_t newsz = 2 * pll->capacity();
+        if (pll->capacity() > 1024 * 1024)
+            newsz = pll->capacity() + 1024 * 1024;
+        pll->reserve(newsz);
+    }
+
+    if (!brk)
+        (*(TNodeLevel*)(level[0]))[0].freq += fr;
+
+    bool branch = false;
+    for (int i = 1; (!brk && i < nlevel); ++i) {
+        std::vector<TNode> & pv = *(TNodeLevel*)(level[i - 1]);
+        std::vector<TNode> & v = *(TNodeLevel*)(level[i]);
+        branch = branch || (pv.back().child >= (int) v.size()) ||
+                 (v.back().id != ngram[i - 1]);
+        if (branch) {
+            if (i == nlevel - 1)
+                ch = ((TLeafLevel*)(level[i + 1]))->size();
+            else
+                ch = ((TNodeLevel*)(level[i + 1]))->size();
+            v.push_back(TNode(ngram[i - 1], ch, fr));
+        } else {
+            v.back().freq += fr;
+        }
+        brk = (i > 1 && isBreakId(ngram[i - 1])) || isExcludeId(ngram[i]);
+    }
+
+    // Insert to the leaf level
+    if (!brk) {
+        if (fr > cut[nlevel]) {
+            TLeafLevel& v = *(TLeafLevel*)(level[nlevel]);
+            v.push_back(TLeaf(ngram[nlevel - 1], fr));
+        } else {
+            nr[nlevel][0] += fr;
+            nr[nlevel][fr] += fr;
+        }
+    }
+}
+
+void
+CSlmBuilder::CountNr()
+{
+    printf("\nCounting Nr..."); fflush(stdout);
+    for (int lvl = 1; lvl < nlevel; ++lvl) {
+        TNodeLevel& v = *(TNodeLevel*)(level[lvl]);
+        for (TNodeIterator it = v.begin(), ite = v.end(); it != ite; ++it) {
+            FREQ_TYPE freq = it->freq;
+            nr[lvl][0] += freq;
+            if (freq < (int) SLM_MAX_R && freq > 0)
+                nr[lvl][freq] += freq;
+        }
+    }
+    TLeafLevel& v = *(TLeafLevel*)(level[nlevel]);
+    for (TLeafIterator it = v.begin(), ite = v.end(); it != ite; ++it) {
+        FREQ_TYPE freq = it->freq;
+        nr[nlevel][0] += freq;
+        if (freq < (int) SLM_MAX_R && freq > 0)
+            nr[nlevel][freq] += freq;
+    }
+    printf("\n"); fflush(stdout);
+}
+
+int
+CSlmBuilder::CutLeafLevel(TNodeIterator pfirst,
+                          TNodeIterator plast,
+                          TLeafIterator chfirst,
+                          TLeafIterator chlast,
+                          int thred)
+{
+    int idxfirst, idxchk;
+    TLeafIterator chchk = chfirst;
+    for (idxfirst = idxchk = 0; chchk != chlast; ++chchk, ++idxchk) {
+        //do not cut item whoese 1. freq > thred; 2. psuedo tail
+        if ((int) chchk->freq > thred || (chchk + 1) == chlast) {
+            if (idxfirst < idxchk)
+                *chfirst = *chchk;
+            for (; pfirst != plast && pfirst->child <= idxchk; ++pfirst)
+                pfirst->child = idxfirst;
+            ++idxfirst;
+            ++chfirst;
+        }
+    }
+    assert(pfirst == plast);
+    return idxfirst;
+}
+
+int
+CSlmBuilder::CutNodeLevel(TNodeIterator pfirst,
+                          TNodeIterator plast,
+                          TNodeIterator chfirst,
+                          TNodeIterator chlast,
+                          int thred)
+{
+    int idxfirst, idxchk;
+    TNodeIterator chchk = chfirst;
+    for (idxfirst = idxchk = 0; chchk != chlast; ++chchk, ++idxchk) {
+        //do not cut item whoese 1. freq > thred; 2. psuedo tail; 3. leading children
+        TNodeIterator chnext = chchk + 1;
+        if ((int) chchk->freq > thred || chnext == chlast ||
+            (chnext->child != chchk->child)) {
+            if (idxfirst < idxchk)
+                *chfirst = *chchk;
+            for (; pfirst != plast && pfirst->child <= idxchk; ++pfirst)
+                pfirst->child = idxfirst;
+            ++idxfirst;
+            ++chfirst;
+        }
+    }
+    assert(pfirst == plast);
+    return idxfirst;
+}
+
+void
+CSlmBuilder::Cut()
+{
+    printf("\nCuting according freq..."); fflush(stdout);
+    for (int lvl = nlevel; lvl > 0; --lvl) {
+        printf("\n    Cut level %d with threshold %d...", lvl, cut[lvl]);
+        fflush(stdout);
+        TNodeLevel& parent = *(TNodeLevel*)(level[lvl - 1]);
+        if (lvl == nlevel) {
+            if (cut[lvl] > 0) {
+                TLeafLevel& v = *(TLeafLevel*)(level[lvl]);
+                int newsize = CutLeafLevel(parent.begin(),
+                                           parent.end(), v.begin(),
+                                           v.end(), cut[lvl]);
+                v.erase(v.begin() + newsize, v.end());
+            }
+        } else {
+            if (cut[lvl] > 0) {
+                TNodeLevel& v = *(TNodeLevel*)(level[lvl]);
+                int newsize = CutNodeLevel(parent.begin(),
+                                           parent.end(), v.begin(),
+                                           v.end(), cut[lvl]);
+                v.erase(v.begin() + newsize, v.end());
+            }
+        }
+    }
+    printf("\n"); fflush(stdout);
+}
+
+void
+CSlmBuilder::AppendTails()
+{
+    printf("\nAppending psuedo tail node for each level..."); fflush(stdout);
+    for (int lvl = 0; lvl < nlevel; ++lvl) {
+        int child_size = 0;
+        if (lvl == nlevel - 1) {
+            child_size = ((TLeafLevel*)(level[lvl + 1]))->size();
+        } else {
+            child_size = ((TNodeLevel*)(level[lvl + 1]))->size();
+        }
+        TNodeLevel& v = *(TNodeLevel*)(level[lvl]);
+        v.push_back(TNode(0x00FFFFFF, child_size, 1));
+    }
+    //also make a psuedo tail node for the leaf level
+    ((TLeafLevel*)(level[nlevel]))->push_back(TLeaf(0, 1));
+    printf("\n"); fflush(stdout);
+}
+
+template<class TChildLevel>
+void
+DiscountOneLevel(CSlmBuilder::TNodeLevel& v,
+                 TChildLevel& ch,
+                 CSlmDiscounter* disc,
+                 int bUseLogPr)
+{
+    CSlmBuilder::TNodeIterator it = v.begin();
+    CSlmBuilder::TNodeIterator ite = v.begin() + (v.size() - 1);
+    for (; it != ite; ++it) { //do not calc the psuedo tail item
+        CSlmBuilder::TNodeIterator itnext = it + 1;
+        double root_freq = it->freq;
+        for (int h = it->child, t = itnext->child; h < t; ++h) {
+            double pr = disc->discount(ch[h].freq) / root_freq;
+            assert(pr > 0.0 && pr < 1.0);
+            if (bUseLogPr) {
+                ch[h].pr = CSlmBuilder::PR_TYPE(-log(pr));
+            } else {
+                ch[h].pr = CSlmBuilder::PR_TYPE(pr);
+            }
+        }
+    }
+}
+
+void
+CSlmBuilder::Discount()
+{
+    printf("\nDiscounting...");
+    for (int lvl = nlevel; lvl > 0; --lvl) {
+        printf("\n    Initializing level %d's %s discount method: ",
+               lvl,
+               discounter[lvl]->getName());
+        discounter[lvl]->init(SLM_MAX_R, nr[lvl]);
+    }
+    printf("\n");
+    for (int lvl = nlevel - 1; lvl >= 0; --lvl) {
+        printf("\n    Discounting level %d ...", lvl + 1); fflush(stdout);
+        TNodeLevel& v = *(TNodeLevel*)(level[lvl]);
+        if (lvl == nlevel - 1) { //its child is leaf
+            TLeafLevel& ch = *(TLeafLevel*)(level[lvl + 1]);
+            DiscountOneLevel(v, ch, discounter[lvl + 1], bUseLogPr);
+        } else {
+            TNodeLevel& ch = *(TNodeLevel*)(level[lvl + 1]);
+            DiscountOneLevel(v, ch, discounter[lvl + 1], bUseLogPr);
+        }
+    }
+    printf("\n    Giving psuedo root level 0 a distribution...");
+    //make the psuedo 0-gram a equal distribution
+    TNodeLevel& v0 = *(TNodeLevel*)(level[0]);
+    if (bUseLogPr) {
+        v0[0].pr = PR_TYPE(-log(double(1.0) / m_nWord));
+    } else {
+        v0[0].pr = PR_TYPE(double(1.0) / m_nWord);
+    }
+    printf("\n"); fflush(stdout);
+}
+
+template<class chIterator>
+double
+CalcNodeBow(CSlmBuilder* builder,
+            int lvl,
+            TSIMWordId words[],
+            chIterator chh,
+            chIterator cht,
+            int bUseLogPr)
+{
+    if (chh == cht) return 1.0;
+    double sumnext = 0.0, sum = 0.0;
+    for (; chh < cht; ++chh) {
+        if (bUseLogPr) {
+            sumnext += exp(-(chh->pr));
+        } else {
+            sumnext += double(chh->pr);
+        }
+        words[lvl + 1] = chh->id;
+        sum += builder->getPr(lvl, words + 2);
+    }
+    assert(sumnext > 0.0 && sumnext < 1.05);
+    assert(sum < 1.05 && sum > 0.0);
+    //消除计算误差的影响
+    if (sumnext >= 1.0 || sum >= 1.0) {
+        double bow = ((sumnext > sum) ? sumnext : sum) + 0.0001;
+        bow = (bow - sumnext) / (bow - sum);
+        printf(
+            "\n (sigma(p(w|h)=%lf, sigma(p(w|h')=%lf) bow ==> %lf due to Calculation precision for %d-gram:",
+            sumnext,
+            sum,
+            bow,
+            lvl);
+        for (int i = 1; i <= lvl; ++i)
+            printf("%d ", words[i]);
+        return bow;
+    }
+    return (1.0 - sumnext) / (1.0 - sum);
+}
+
+void
+CSlmBuilder::CalcBOW()
+{
+    printf("\nCalculating Back-Off Weight...");
+    for (int lvl = 0; lvl < nlevel; ++lvl) {
+        printf("\n    Processing level %d ", lvl); fflush(stdout);
+        TNode* base[16]; //it should be lvl+1, yet some compiler does not support it
+        int idx[16];     //it should be lvl+1, yet some compiler does not support it
+        for (int i = 0; i <= lvl; ++i) {
+            base[i] = &((*(TNodeLevel*)level[i])[0]);
+            idx[i] = 0;
+        }
+        TSIMWordId words[17];  //it should be lvl+2, yet some compiler do not support it
+        int sz = ((TNodeLevel*)(level[lvl]))->size() - 1;
+        printf("(%d items)...", sz + 1); fflush(stdout);
+        for (; idx[lvl] < sz; ++idx[lvl]) {
+            words[lvl] = base[lvl][idx[lvl]].id;
+            for (int k = lvl - 1; k >= 0; --k) {
+                while (base[k][idx[k] + 1].child <= idx[k + 1])
+                    ++idx[k];
+                words[k] = base[k][idx[k]].id;
+            }
+            TNode & node = base[lvl][idx[lvl]];
+            TNode & nodenext = *((&node) + 1);
+            double bow;
+            if (lvl == nlevel - 1) {
+                TLeaf * ch = &((*(TLeafLevel*)level[lvl + 1])[0]);
+                bow = CalcNodeBow(this,
+                                  lvl,
+                                  words,
+                                  ch + node.child,
+                                  ch + nodenext.child,
+                                  bUseLogPr);
+            } else {
+                TNode * ch = &((*(TNodeLevel*)level[lvl + 1])[0]);
+                bow = CalcNodeBow(this,
+                                  lvl,
+                                  words,
+                                  ch + node.child,
+                                  ch + nodenext.child,
+                                  bUseLogPr);
+            }
+            if (bUseLogPr) {
+                node.bow = PR_TYPE(-log(bow));
+            } else {
+                node.bow = PR_TYPE(bow);
+            }
+        }
+    }
+    printf("\n"); fflush(stdout);
+}
+
+double
+CSlmBuilder::getPr(int n, TSIMWordId *words)
+{
+    int lvl;
+    double bow = 1.0;
+    void* pnode = &((*(TNodeLevel*)level[0])[0]);
+
+    assert(n <= nlevel);
+
+    if (n == 0) {
+        if (bUseLogPr) {
+            return exp(-((TNode*)pnode)->pr);
+        } else {
+            return ((TNode*)pnode)->pr;
+        }
+    }
+
+    for (lvl = 0; pnode != NULL && lvl < n; ++lvl) {
+        if (bUseLogPr) {
+            bow = exp(-((TNode*)pnode)->bow);
+        } else {
+            bow = ((TNode*)pnode)->bow;
+        }
+        pnode = FindChild(lvl, (TNode*)pnode, words[lvl]);
+    }
+
+    if (pnode != NULL) { // find the whole string
+        if (bUseLogPr) {
+            return exp(-((TLeaf*)pnode)->pr);
+        } else {
+            return ((TLeaf*)pnode)->pr;
+        }
+    } else if (lvl == n - 1) { // only find the history
+        return bow * getPr(n - 1, words + 1);
+    } else { //even not find the history
+        return getPr(n - 1, words + 1);
+    }
+}
+
+void*
+CSlmBuilder::FindChild(int lvl, TNode* root, TSIMWordId id)
+{
+    int chh = root->child, cht = (root + 1)->child;
+    if (lvl == nlevel - 1) {
+        TLeaf* pleaf = &((*(TLeafLevel*)level[lvl + 1])[0]);
+        return (void*)binary_find(pleaf, chh, cht, TLeaf(id));
+    } else {
+        TNode* pnode = &((*(TNodeLevel*)level[lvl + 1])[0]);
+        return (void*)binary_find(pnode, chh, cht, TNode(id));
+    }
+}
+
+void
+CSlmBuilder::Build()
+{
+    CountNr();
+    AppendTails();
+    Cut();
+    Discount();
+    CalcBOW();
+}
+
+void
+CSlmBuilder::Write(FILE *out)
+{
+    fwrite(&nlevel, sizeof(nlevel), 1, out);
+    fwrite(&bUseLogPr, sizeof(bUseLogPr), 1, out);
+    for (int lvl = 0; lvl <= nlevel; ++lvl) {
+        int sz = 0;
+        if (lvl == nlevel)
+            sz = ((TLeafLevel*)(level[lvl]))->size();
+        else
+            sz = ((TNodeLevel*)(level[lvl]))->size();
+        fwrite(&sz, sizeof(sz), 1, out);
+    }
+    for (int lvl = 0; lvl < nlevel; ++lvl) {
+        TNodeLevel& v = *(TNodeLevel*)(level[lvl]);
+        for (TNodeIterator it = v.begin(), ite = v.end(); it != ite; ++it)
+            fwrite(&(*it), sizeof(TNode), 1, out);
+    }
+    TLeafLevel& v = *(TLeafLevel*)(level[nlevel]);
+    for (TLeafIterator it = v.begin(), ite = v.end(); it != ite; ++it)
+        fwrite(&(*it), sizeof(TLeaf), 1, out);
+}
+
+void
+CSlmBuilder::Close(void)
+{
+    if (level != NULL) {
+        for (int lvl = 0; lvl <= nlevel; ++lvl) {
+            if (lvl == nlevel)
+                delete (TLeafLevel*)(level[lvl]);
+            else
+                delete (TNodeLevel*)(level[lvl]);
+        }
+        delete [] level;
+        level = NULL;
+    }
+    if (cut != NULL) {
+        delete [] cut;
+        cut = NULL;
+    }
+    if (discounter != NULL) {
+        for (int lvl = 1; lvl <= nlevel; ++lvl) {
+            delete discounter[lvl];
+        }
+        delete [] discounter;
+        discounter = NULL;
+    }
+    if (nr != NULL) {
+        delete [] nr;
+        nr = NULL;
+    }
+    breaker.clear();
+    m_nWord = 0;
+    nlevel = 0;
+}
+
diff --git a/src/slm/sim_slmbuilder.h b/src/slm/sim_slmbuilder.h
new file mode 100644 (file)
index 0000000..cb69a8e
--- /dev/null
@@ -0,0 +1,165 @@
+// -*- mode: c++ -*-
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright (c) 2007 Sun Microsystems, Inc. All Rights Reserved.
+ *
+ * The contents of this file are subject to the terms of either the GNU Lesser
+ * General Public License Version 2.1 only ("LGPL") or the Common Development and
+ * Distribution License ("CDDL")(collectively, the "License"). You may not use this
+ * file except in compliance with the License. You can obtain a copy of the CDDL at
+ * http://www.opensource.org/licenses/cddl1.php and a copy of the LGPLv2.1 at
+ * http://www.opensource.org/licenses/lgpl-license.php. See the License for the
+ * specific language governing permissions and limitations under the License. When
+ * distributing the software, include this License Header Notice in each file and
+ * include the full text of the License in the License file as well as the
+ * following notice:
+ *
+ * NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND DISTRIBUTION LICENSE
+ * (CDDL)
+ * For Covered Software in this distribution, this License shall be governed by the
+ * laws of the State of California (excluding conflict-of-law provisions).
+ * Any litigation relating to this License shall be subject to the jurisdiction of
+ * the Federal Courts of the Northern District of California and the state courts
+ * of the State of California, with venue lying in Santa Clara County, California.
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by only the CDDL or only
+ * the LGPL Version 2.1, indicate your decision by adding "[Contributor]" elects to
+ * include this software in this distribution under the [CDDL or LGPL Version 2.1]
+ * license." If you don't indicate a single choice of license, a recipient has the
+ * option to distribute your version of this file under either the CDDL or the LGPL
+ * Version 2.1, or to extend the choice of license to its licensees as provided
+ * above. However, if you add LGPL Version 2.1 code and therefore, elected the LGPL
+ * Version 2 license, then the option applies only if the new code is made subject
+ * to such option by the copyright holder.
+ */
+
+#ifndef _SIM_SLM_BUILDER_H
+#define _SIM_SLM_BUILDER_H
+
+#include "../portability.h"
+
+#include "sim_slm.h"
+
+class CSlmDiscounter;
+
+class CSlmBuilder {
+public:
+    static const int SLM_MAX_R = 16;
+    typedef CSIMSlm::FREQ_TYPE FREQ_TYPE;
+    typedef CSIMSlm::PR_TYPE PR_TYPE;
+    typedef CSIMSlm::TNode TNode;
+    typedef CSIMSlm::TLeaf TLeaf;
+
+public:
+    CSlmBuilder()
+        : nlevel(0), bUseLogPr(0), level(NULL), m_nWord(0), cut(NULL),
+          discounter(NULL), nr(NULL), breaker(), m_excludes() { }
+    ~CSlmBuilder()
+    { Close(); }
+
+    void Create(int n);
+    void SetNumberOfWord(int nWord) { this->m_nWord = nWord; }
+    void SetCut(FREQ_TYPE threshold[]);
+    void SetDiscounter(CSlmDiscounter * dis[]);
+    void SetBreakerIds(int nId, TSIMWordId brks[]);
+    void SetExcludeIds(int nId, TSIMWordId excludes[]);
+    void SetUseLogPr(int bUse)
+    { bUseLogPr = bUse; }
+
+    void AddNGram(TSIMWordId* ngram, FREQ_TYPE fr);
+    void Build();
+    void Write(FILE* out);
+    void Close();
+
+    //get pr(w[n-1] | w[0]...w[n-2]) on constructed partial model (low levels)
+    double getPr(int n, TSIMWordId* w);
+
+public:
+    typedef std::vector<TNode> TNodeLevel;
+    typedef std::vector<TLeaf> TLeafLevel;
+    typedef TNodeLevel::iterator TNodeIterator;
+    typedef TLeafLevel::iterator TLeafIterator;
+
+protected:
+    bool isBreakId(TSIMWordId id);
+    bool isExcludeId(TSIMWordId id);
+    void CountNr();
+    void AppendTails();
+    void Cut();
+    void Discount();
+    void CalcBOW();
+    void*FindChild(int lvl, TNode* root, TSIMWordId id);
+    int  CutNodeLevel(TNodeIterator pfirst, TNodeIterator plast,
+                      TNodeIterator chfirst, TNodeIterator chlast, int thred);
+    int  CutLeafLevel(TNodeIterator pfirst, TNodeIterator plast,
+                      TLeafIterator chfirst, TLeafIterator chlast, int thred);
+
+private:
+    int nlevel, bUseLogPr;
+    void** level;
+    //level[0] is psudeo root level, level[1] is unigram level, ..., all are vector type
+
+    int m_nWord;
+    FREQ_TYPE* cut; // cut[1] is not cut threshold for 1-gram, ...
+    CSlmDiscounter** discounter; // discounter[1] is for 1-gram...
+    FREQ_TYPE(*nr)[SLM_MAX_R]; //nr[1][SLM_MAX_R] is for 1-gram...
+    std::vector<TSIMWordId> breaker;
+    std::vector<TSIMWordId> m_excludes;
+};
+
+class CSlmDiscounter {
+public:
+    virtual ~CSlmDiscounter() {}
+    // n is array size, nr is FREQ_TYPE[n], nr[0] is corpuse size,or sigma r*nr;
+    // nr[1] is number of ngram items with freq 1, ...
+    virtual void init(int n, CSlmBuilder::FREQ_TYPE *nr) = 0;
+
+    // freq is the ngram frequence, not the conditional pr
+    virtual double discount(int freq) = 0;
+    virtual const char* getName() = 0;
+};
+
+//Good-Turing discount
+class CSlmGTDiscounter : public CSlmDiscounter {
+public:
+    CSlmGTDiscounter(int threshold = 10, double highfreq_discount =
+                     0.95) : thres(threshold), hd(highfreq_discount),
+                             dis(NULL) {}
+    virtual void init(int n, CSlmBuilder::FREQ_TYPE *nr);
+    virtual double discount(int freq);
+    virtual const char* getName()
+    { return "Good-Turing"; }
+protected:
+    int thres;
+    double hd;
+    double *dis;
+};
+
+class CSlmAbsoluteDiscounter : public CSlmDiscounter {
+public:
+    CSlmAbsoluteDiscounter(double substract = 0.0) : c(substract) {}
+    //c == 0 mean this value should be count according to r[]
+    virtual void init(int n, CSlmBuilder::FREQ_TYPE *nr);
+    virtual double discount(int freq);  // return freq - c
+    virtual const char* getName()
+    { return "Absolution"; }
+protected:
+    double c;
+};
+
+class CSlmLinearDiscounter : public CSlmDiscounter {
+public:
+    CSlmLinearDiscounter(double shrink = 0.0) : dis(shrink) {}
+    //dis == 0 mean this value should be count according to r[]
+    virtual void init(int n, CSlmBuilder::FREQ_TYPE *nr);
+    virtual double discount(int freq);  // return freq * dis
+    virtual const char* getName()
+    { return "Linear"; }
+protected:
+    double dis;
+};
+
+#endif
diff --git a/src/slm/slm.cpp b/src/slm/slm.cpp
new file mode 100644 (file)
index 0000000..a8e8d6b
--- /dev/null
@@ -0,0 +1,308 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright (c) 2007 Sun Microsystems, Inc. All Rights Reserved.
+ *
+ * The contents of this file are subject to the terms of either the GNU Lesser
+ * General Public License Version 2.1 only ("LGPL") or the Common Development and
+ * Distribution License ("CDDL")(collectively, the "License"). You may not use this
+ * file except in compliance with the License. You can obtain a copy of the CDDL at
+ * http://www.opensource.org/licenses/cddl1.php and a copy of the LGPLv2.1 at
+ * http://www.opensource.org/licenses/lgpl-license.php. See the License for the
+ * specific language governing permissions and limitations under the License. When
+ * distributing the software, include this License Header Notice in each file and
+ * include the full text of the License in the License file as well as the
+ * following notice:
+ *
+ * NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND DISTRIBUTION LICENSE
+ * (CDDL)
+ * For Covered Software in this distribution, this License shall be governed by the
+ * laws of the State of California (excluding conflict-of-law provisions).
+ * Any litigation relating to this License shall be subject to the jurisdiction of
+ * the Federal Courts of the Northern District of California and the state courts
+ * of the State of California, with venue lying in Santa Clara County, California.
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by only the CDDL or only
+ * the LGPL Version 2.1, indicate your decision by adding "[Contributor]" elects to
+ * include this software in this distribution under the [CDDL or LGPL Version 2.1]
+ * license." If you don't indicate a single choice of license, a recipient has the
+ * option to distribute your version of this file under either the CDDL or the LGPL
+ * Version 2.1, or to extend the choice of license to its licensees as provided
+ * above. However, if you add LGPL Version 2.1 code and therefore, elected the LGPL
+ * Version 2 license, then the option applies only if the new code is made subject
+ * to such option by the copyright holder.
+ */
+
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <math.h>
+#include <errno.h>
+#include <string.h>
+
+#include "slm.h"
+
+#ifdef HAVE_SYS_MMAN_H
+#include <sys/mman.h>
+#elif defined(BEOS_OS)
+#include <be/kernel/OS.h>
+#endif
+
+bool
+CThreadSlm::load(const char* fname, bool MMap)
+{
+    int fd = open(fname, O_RDONLY);
+    if (fd == -1) {
+        fprintf(stderr, "open %s: %s\n", fname, strerror(errno));
+        return false;
+    }
+
+    m_bufSize = lseek(fd, 0, SEEK_END);
+    lseek(fd, 0, SEEK_SET);
+
+    m_bMMap = MMap;
+    if (m_bMMap) {
+#ifdef HAVE_SYS_MMAN_H
+        void* p = mmap(NULL, m_bufSize, PROT_READ, MAP_SHARED, fd, 0);
+        if (p == MAP_FAILED) {
+            close(fd);
+            return false;
+        }
+        m_buf = (char*)p;
+#elif defined(BEOS_OS)
+        char *p = NULL;
+        area_id area = create_area("tmp", (void**)&p, B_ANY_ADDRESS,
+                                   (m_bufSize +
+                                    (B_PAGE_SIZE - 1)) & ~(B_PAGE_SIZE - 1),
+                                   B_NO_LOCK, B_READ_AREA | B_WRITE_AREA);
+        if (area < 0) {
+            close(fd);
+            return false;
+        }
+        m_buf = p;
+
+        for (ssize_t len = m_bufSize; len > 0; ) {
+            ssize_t n = read(fd, p, len);
+            if (n < 0) break;
+            p += n;
+            len -= n;
+        }
+#else // Other OS
+        #error "No implementation for mmap()"
+#endif // HAVE_SYS_MMAN_H
+    } else {
+        if ((m_buf = new char[m_bufSize]) == NULL) {
+            close(fd);
+            return false;
+        }
+        if (read(fd, m_buf, m_bufSize) != m_bufSize) {
+            perror("read lm");
+            delete [] m_buf; m_buf = NULL;
+            close(fd);
+            return false;
+        }
+    }
+    close(fd);
+
+    m_N = *(unsigned*)m_buf;
+    m_UseLogPr = *(((unsigned*)m_buf) + 1);
+    m_LevelSizes = ((unsigned*)m_buf) + 2;
+    m_prTable =
+        (float*)(m_buf + 2 * sizeof(unsigned) + (m_N + 1) * sizeof(unsigned));
+    m_bowTable = m_prTable + (1 << BITS_PR);
+
+    TNode* pn = (TNode*)(m_bowTable + (1 << BITS_BOW));
+
+    //Solaris CC would cause error in runtime if using some thing like
+    //following even using (void**) conversion. So add PtrVoid definition
+    //m_Levels = new (void*) [m_N + 1];
+    m_Levels = new PtrVoid[m_N + 1];
+
+    for (size_t lvl = 0; lvl <= m_N; ++lvl) {
+        m_Levels[lvl] = (void*)pn;
+        pn += m_LevelSizes[lvl];
+    }
+    return true;
+}
+
+void
+CThreadSlm::free()
+{
+    if (m_Levels) {
+        delete [] m_Levels;
+    }
+    if (m_buf) {
+        if (m_bMMap) {
+#ifdef HAVE_SYS_MMAN_H
+            munmap(m_buf, m_bufSize);
+#elif defined(BEOS_OS)
+            delete_area(area_for(m_buf));
+#else // Other OS
+            #error "No implementation for munmap()"
+#endif // HAVE_SYS_MMAN_H
+        } else {
+            delete [] m_buf;
+        }
+    }
+    m_buf = NULL;
+    m_Levels = NULL;
+}
+
+template<class NodeT>
+unsigned int
+find_id(NodeT* base, unsigned int h, unsigned int t, unsigned int id)
+{
+    unsigned int tail = t;
+    while (h < t) {
+        int m = h + (t - h) / 2;
+        NodeT* pm = base + m;
+        unsigned int thisId = pm->wid();
+        if (thisId < id)
+            h = m + 1;
+        else if (thisId > id)
+            t = m;
+        else
+            return m;
+    }
+    return tail;
+}
+
+/**
+ * return value as the model suggested. The history state must be historified
+ * or the history's level should be 0. when level == 0 but idx != 0, the
+ * history is a psuedo unigram state used for this model to combine another
+ * bigram cache language model
+ */
+double
+CThreadSlm::rawTransfer(TState history, unsigned int wid, TState& result)
+{
+    unsigned int lvl = history.getLevel();
+    unsigned int pos = history.getIdx();
+
+    double cost = (m_UseLogPr) ? 0.0 : 1.0;
+
+    // NON_Word id must be dealed with special, let it transfer to root
+    // without any cost
+    if (ID_NOT_WORD == wid) {
+        result = 0;
+        return cost;
+    }
+
+    while (true) {
+        //for psuedo cache model unigram state
+        TNode* pn = ((TNode*)m_Levels[lvl]) + ((lvl) ? pos : 0);
+
+        unsigned int t = (pn + 1)->ch();
+
+        if (lvl < m_N - 1) {
+            TNode* pBase = (TNode*)m_Levels[lvl + 1];
+            unsigned int idx = find_id(pBase, pn->ch(), t, wid);
+            if (idx != t) {
+                result.setIdx(idx);
+                result.setLevel(lvl + 1);
+                double pr = m_prTable[pBase[idx].pr()];
+                return (m_UseLogPr) ? (cost + pr) : (cost * pr);
+            }
+        } else {
+            TLeaf* pBase = (TLeaf*)m_Levels[lvl + 1];
+            unsigned int idx = find_id(pBase, pn->ch(), t, wid);
+            if (idx != t) {
+                result.setIdx(idx);
+                result.setLevel(lvl + 1);
+                double pr = m_prTable[pBase[idx].pr()];
+                return (m_UseLogPr) ? (cost + pr) : (cost * pr);
+            }
+        }
+
+        if (m_UseLogPr)
+            cost += m_bowTable[pn->bow()];
+        else
+            cost *= m_bowTable[pn->bow()];
+        if (lvl == 0)
+            break;
+        lvl = pn->bol();
+        pos = pn->bon();
+    }
+    result.setLevel(0);
+    result.setIdx(0);
+    if (m_UseLogPr)
+        return cost + m_prTable[((TNode*)m_Levels[0])->pr()];
+    else
+        return cost * m_prTable[((TNode*)m_Levels[0])->pr()];
+}
+
+double
+CThreadSlm::transferNegLog(TState history, unsigned int wid, TState& result)
+{
+    double cost = rawTransfer(history, wid, result);
+    if (m_UseLogPr)
+        return cost;
+    else
+        return -log(cost);
+}
+
+double
+CThreadSlm::transfer(TState history, unsigned int wid, TState& result)
+{
+    double cost = rawTransfer(history, wid, result);
+    if (!m_UseLogPr)
+        return cost;
+    else
+        return exp(-cost);
+}
+
+unsigned int
+CThreadSlm::lastWordId(TState st)
+{
+    unsigned int lvl = st.getLevel();
+    if (lvl >= m_N) {
+        const TLeaf* pn = ((const TLeaf*)m_Levels[m_N]) + st.getIdx();
+        return pn->wid();
+    } else if (lvl > 0) {
+        const TNode *pn = ((const TNode*)m_Levels[st.getLevel()]) + st.getIdx();
+        return pn->wid();
+    } else {
+        unsigned int idx = st.getIdx();
+        if (idx == 0) {
+            const TNode *pn = ((const TNode*)m_Levels[st.getLevel()]) +
+                              st.getIdx();
+            return pn->wid();
+        }
+        return idx; // return the psuedo state word id
+    }
+}
+
+CThreadSlm::TState
+CThreadSlm::history_state_of(TState st)
+{
+    if (st.getLevel() >= m_N) {
+        TLeaf* pl = ((TLeaf*)m_Levels[m_N]) + st.getIdx();
+        return TState(pl->bol(), pl->bon());
+    } else {
+        TNode* pn = ((TNode*)m_Levels[st.getLevel()]) + st.getIdx();
+        if (pn->ch() == (pn + 1)->ch())
+            return TState(pn->bol(), pn->bon());
+        else
+            return st;
+    }
+}
+
+CThreadSlm::TState&
+CThreadSlm::historify(TState& st)
+{
+    if (st.getLevel() >= m_N) {
+        TLeaf* pl = ((TLeaf*)m_Levels[m_N]) + st.getIdx();
+        st.setLevel(pl->bol());
+        st.setIdx(pl->bon());
+    } else {
+        TNode* pn = ((TNode*)m_Levels[st.getLevel()]) + st.getIdx();
+        if (pn->ch() == (pn + 1)->ch()) {
+            st.setLevel(pn->bol());
+            st.setIdx(pn->bon());
+        }
+    }
+    return st;
+}
diff --git a/src/slm/slm.h b/src/slm/slm.h
new file mode 100644 (file)
index 0000000..501146a
--- /dev/null
@@ -0,0 +1,351 @@
+// -*- mode: c++ -*-
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright (c) 2007 Sun Microsystems, Inc. All Rights Reserved.
+ *
+ * The contents of this file are subject to the terms of either the GNU Lesser
+ * General Public License Version 2.1 only ("LGPL") or the Common Development and
+ * Distribution License ("CDDL")(collectively, the "License"). You may not use this
+ * file except in compliance with the License. You can obtain a copy of the CDDL at
+ * http://www.opensource.org/licenses/cddl1.php and a copy of the LGPLv2.1 at
+ * http://www.opensource.org/licenses/lgpl-license.php. See the License for the
+ * specific language governing permissions and limitations under the License. When
+ * distributing the software, include this License Header Notice in each file and
+ * include the full text of the License in the License file as well as the
+ * following notice:
+ *
+ * NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND DISTRIBUTION LICENSE
+ * (CDDL)
+ * For Covered Software in this distribution, this License shall be governed by the
+ * laws of the State of California (excluding conflict-of-law provisions).
+ * Any litigation relating to this License shall be subject to the jurisdiction of
+ * the Federal Courts of the Northern District of California and the state courts
+ * of the State of California, with venue lying in Santa Clara County, California.
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by only the CDDL or only
+ * the LGPL Version 2.1, indicate your decision by adding "[Contributor]" elects to
+ * include this software in this distribution under the [CDDL or LGPL Version 2.1]
+ * license." If you don't indicate a single choice of license, a recipient has the
+ * option to distribute your version of this file under either the CDDL or the LGPL
+ * Version 2.1, or to extend the choice of license to its licensees as provided
+ * above. However, if you add LGPL Version 2.1 code and therefore, elected the LGPL
+ * Version 2 license, then the option applies only if the new code is made subject
+ * to such option by the copyright holder.
+ */
+
+#ifndef _SUN_AGC_SLM_H
+#define _SUN_AGC_SLM_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "../portability.h"
+
+#include <stdio.h>
+
+/**
+ * Thread slm make the following modifications to simple back-off language model
+ *    -# Word id are limited to 18 bits, about 240K word ids
+ *    -# Compact all float value of -log(pr) into 65536 (16 bits)
+ *       level and use a table to map the index to a float value;
+ *    -# Compact all float value of -log(pr) into 16384 (14 bits)
+ *       level and use a table to map the index to a float value;
+ *    -# threading infomation embed into binary model file. Threading include
+ *         - bol(back-off-level) from current level
+ *         - bon(back-off-node)'s index in the bol level array
+ *         .
+ *       The thread could be used:
+ *         - when leaf node are arrived, it could use (bol,bon) as history for
+ *           history node.
+ *         - when a word could not be found in current node (cl, cn)'s children,
+ *           searching could be transfered to (bol, bon) directly and continue
+ *           searching the target word
+ *    -# Add a basic type TState in Language model, a state is pair of\n
+ *           (level, array_idx_of_the level)
+ *    -# change all get probability interface to\n
+ *          double transfer(TState& history, unsigned int wid, TState& result);
+ */
+class CThreadSlm {
+public:
+    enum {
+        BITS_BOW        = 14,
+        BITS_PR         = 16,
+        ID_NOT_WORD     = 69,
+    };
+
+    /**
+     * (level:idx) located a state in the language model very well
+     * Please note the psuedo unigram state, with level == 0, but idx > 0
+     * it's for used with bigram cache model
+     */
+    union TState {
+        TState(const TState &b) : m_all(b.m_all) {
+        }
+        TState(unsigned level = 0, unsigned idx = 0) {
+            anony.m_Level = level; anony.m_Idx = idx;
+        }
+
+        TState& operator++()              { ++anony.m_Idx; return *this; }
+
+        void setIdx(unsigned int idx)     { anony.m_Idx = idx; }
+        void setLevel(unsigned int lvl)   { anony.m_Level = lvl; }
+
+        unsigned int getLevel() const { return anony.m_Level; }
+        unsigned int getIdx() const { return anony.m_Idx; }
+        operator unsigned() const { return m_all; }
+
+        bool isTailState() const { return getIdx() <= 1; }
+
+        bool operator==(const TState & b) const {
+            return m_all == b.m_all;
+        }
+        bool operator<(const TState & b) const {
+            return unsigned(*this) < unsigned(b);
+        }
+
+private:
+        unsigned int m_all;
+#ifndef WORDS_BIGENDIAN
+        struct TAnonymous {
+            unsigned m_Idx   : 24;
+            unsigned m_Level : 8;
+        } anony;
+#else
+        struct TAnonymous {
+            unsigned m_Level : 8;
+            unsigned m_Idx   : 24;
+        } anony;
+#endif
+    };
+
+    /**
+     * Machine dependent
+     */
+    struct TNode {
+public:
+        unsigned int wid() const {
+            return m_wid;
+        }
+
+        unsigned int bow() const {
+            return m_bow;
+        }
+
+        unsigned int pr()  const {
+            return m_pr;
+        }
+
+        unsigned int bon() const {
+            return m_bon;
+        }
+
+        unsigned int bol() const {
+            return m_bol;
+        }
+
+        unsigned int ch()  const {
+            return((m_ch_hi << 16) + m_ch_lo);
+        }
+
+        void set_wid(unsigned int wid){
+            m_wid = wid;
+        }
+
+        void set_bow(unsigned int bow){
+            m_bow = bow;
+        }
+
+        void set_pr(unsigned int pr){
+            m_pr = pr;
+        }
+
+        void set_bon(unsigned int bon){
+            m_bon = bon;
+        }
+
+        void set_bol(unsigned int bol){
+            m_bol = bol;
+        }
+
+        void set_ch(unsigned int ch){
+            m_ch_hi = ((ch >> 16) & 0x7F);
+            m_ch_lo = (ch & 0xFFFF);
+        }
+
+protected:
+#ifndef WORDS_BIGENDIAN
+        unsigned m_wid       : 18;
+        unsigned m_bow       : 14;
+        unsigned m_pr        : 16;
+        unsigned m_ch_lo     : 16;
+        unsigned m_bon       : 23;
+        unsigned m_bol       : 2;
+        unsigned m_ch_hi     : 7;
+#else
+        unsigned m_ch_hi     : 7;
+        unsigned m_bol       : 2;
+        unsigned m_bon       : 23;
+        unsigned m_ch_lo     : 16;
+        unsigned m_pr        : 16;
+        unsigned m_bow       : 14;
+        unsigned m_wid       : 18;
+#endif
+
+private:
+        /**
+         * Machine dependent
+           union TChildIdx {
+           public:
+            inline TChildIdx(unsigned val) : m_all(val) { }
+            inline TChildIdx(const TChildIdx& b) : m_all(b.m_all) { }
+            inline TChildIdx(unsigned int hi, unsigned lo) : m_all(0) { anony.m_hi = hi; anony.m_lo = lo; }
+
+            inline unsigned int lo() { return anony.m_lo; }
+            inline unsigned int hi() { return anony.m_hi; }
+            inline unsigned int all(){ return m_all; }
+
+            inline unsigned int set_lo(unsigned int lo) { return (anony.m_lo = lo); }
+            inline unsigned int set_hi(unsigned int hi) { return (anony.m_hi = hi); }
+            inline unsigned int set_all(unsigned int all) { return (m_all = all); }
+
+           private:
+            unsigned int m_all;
+         *#ifndef WORDS_BIGENDIAN
+            struct TAnony {
+                unsigned m_lo :16;
+                unsigned m_hi : 7;
+                unsigned NOUSE: 9;
+            } anony;
+         *#else
+            struct TAnony {
+                unsigned NOUSE: 9;
+                unsigned m_hi : 7;
+                unsigned m_lo :16;
+            } anony;
+         *#endif
+           };
+         */
+    };
+
+    /**
+     * Machine dependent
+     */
+    struct TLeaf {
+public:
+        inline unsigned int wid() const { return m_wid; }
+        inline unsigned int bon() const { return m_bon; }
+        inline unsigned int bol() const { return m_bol; }
+        inline unsigned int pr()  const { return((m_pr_hi << 14) + m_pr_lo); }
+
+        inline void set_wid(unsigned int wid) { m_wid = wid; }
+        inline void set_bon(unsigned int bon) { m_bon = bon; }
+        inline void set_bol(unsigned int bol) { m_bol = bol; }
+        inline void set_pr(unsigned int pr)   { m_pr_hi = ((pr >> 14) & 0x3);
+                                                m_pr_lo = pr & 0x3FFF; }
+
+protected:
+#ifndef WORDS_BIGENDIAN
+        unsigned m_wid       : 18;
+        unsigned m_pr_lo     : 14;
+        unsigned m_bon       : 23;
+        unsigned m_bol       : 2;
+        unsigned m_pr_hi     : 2;
+#else
+        unsigned m_pr_hi     : 2;
+        unsigned m_bol       : 2;
+        unsigned m_bon       : 23;
+        unsigned m_pr_lo     : 14;
+        unsigned m_wid       : 18;
+#endif
+
+private:
+        /*
+            union TPr {
+            public:
+                inline TPr(unsigned int val) : m_all(val) { }
+                inline TPr(const TPr & b) : m_all(b.m_all) { }
+                inline TPr(unsigned int hi, unsigned lo) : m_all(0) { anony.m_hi=hi, anony.m_lo=lo; }
+
+                inline unsigned int lo() { return anony.m_lo; }
+                inline unsigned int hi() { return anony.m_hi; }
+                inline unsigned int all(){ return m_all; }
+
+                inline unsigned int set_lo(unsigned int lo) { return (anony.m_lo = lo); }
+                inline unsigned int set_hi(unsigned int hi) { return (anony.m_hi = hi); }
+                inline unsigned int set_all(unsigned int all) { return (m_all = all); }
+
+            private:
+                unsigned int m_all;
+           #ifndef WORDS_BIGENDIAN
+                struct TAnony {
+                    unsigned m_lo  :14;
+                    unsigned m_hi  : 2;
+                    unsigned NONUSE:16;
+                } anony;
+           #else
+                struct TAnony {
+                    unsigned NONUSE:16;
+                    unsigned m_hi  : 2;
+                    unsigned m_lo  :14;
+                } anony;
+           #endif
+            };
+         */
+    };
+
+public:
+    CThreadSlm()
+        : m_N(0), m_UseLogPr(0), m_Levels(NULL), m_LevelSizes(NULL),
+          m_bowTable(NULL), m_prTable(NULL), m_bMMap(false), m_buf(NULL) { }
+
+    ~CThreadSlm() { free(); }
+
+    bool
+    load(const char* fname, bool MMap = false);
+
+    unsigned isUseLogPr() const
+    { return m_UseLogPr; }
+
+    void
+    free();
+
+    double
+    transferNegLog(TState history, unsigned int wid, TState& result);
+
+    double
+    transfer(TState history, unsigned int wid, TState& result);
+
+    TState
+    history_state_of(TState st);
+
+    TState&
+    historify(TState& st);
+
+    unsigned int
+    lastWordId(TState st);
+
+protected:
+    double
+    rawTransfer(TState history, unsigned int wid, TState& result);
+
+protected:
+    typedef  void*   PtrVoid;
+
+    unsigned m_N;
+    unsigned m_UseLogPr;
+    void    **m_Levels;
+    unsigned *m_LevelSizes;
+    float    *m_bowTable;
+    float    *m_prTable;
+
+private:
+    ssize_t m_bufSize;
+    bool m_bMMap;
+    char     *m_buf;
+};
+
+#endif
diff --git a/src/slm/slmbuild/slmbuild.cpp b/src/slm/slmbuild/slmbuild.cpp
new file mode 100644 (file)
index 0000000..d021f8c
--- /dev/null
@@ -0,0 +1,262 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright (c) 2007 Sun Microsystems, Inc. All Rights Reserved.
+ *
+ * The contents of this file are subject to the terms of either the GNU Lesser
+ * General Public License Version 2.1 only ("LGPL") or the Common Development and
+ * Distribution License ("CDDL")(collectively, the "License"). You may not use this
+ * file except in compliance with the License. You can obtain a copy of the CDDL at
+ * http://www.opensource.org/licenses/cddl1.php and a copy of the LGPLv2.1 at
+ * http://www.opensource.org/licenses/lgpl-license.php. See the License for the
+ * specific language governing permissions and limitations under the License. When
+ * distributing the software, include this License Header Notice in each file and
+ * include the full text of the License in the License file as well as the
+ * following notice:
+ *
+ * NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND DISTRIBUTION LICENSE
+ * (CDDL)
+ * For Covered Software in this distribution, this License shall be governed by the
+ * laws of the State of California (excluding conflict-of-law provisions).
+ * Any litigation relating to this License shall be subject to the jurisdiction of
+ * the Federal Courts of the Northern District of California and the state courts
+ * of the State of California, with venue lying in Santa Clara County, California.
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by only the CDDL or only
+ * the LGPL Version 2.1, indicate your decision by adding "[Contributor]" elects to
+ * include this software in this distribution under the [CDDL or LGPL Version 2.1]
+ * license." If you don't indicate a single choice of license, a recipient has the
+ * option to distribute your version of this file under either the CDDL or the LGPL
+ * Version 2.1, or to extend the choice of license to its licensees as provided
+ * above. However, if you add LGPL Version 2.1 code and therefore, elected the LGPL
+ * Version 2 license, then the option applies only if the new code is made subject
+ * to such option by the copyright holder.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifdef HAVE_ASSERT_H
+#include <assert.h>
+#endif
+
+#ifdef HAVE_GETOPT_H
+#include <getopt.h>
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <locale.h>
+
+#include <vector>
+#include <algorithm>
+
+#include "../sim_slmbuilder.h"
+
+static struct option long_options[] =
+{
+    { "ngram", 1, 0, 'n' },
+    { "out", 1, 0, 'o' },
+    { "cut", 1, 0, 'c' },
+    { "discount", 1, 0, 'd' },
+    { "wordcount", 1, 0, 'w' },
+    { "breakid", 1, 0, 'b' },
+    { "excludeid", 1, 0, 'e' },
+    { "log", 1, 0, 'l' },
+    { NULL, 0, 0, 0 }
+};
+
+static void
+ShowUsage(void)
+{
+    printf(
+        "\
+Usage:\n\
+  slmbuild options idngram\n\
+\n\
+Description:\n\
+  This program generate language model from idngram file.\n\
+\n\
+Options:\n\
+  -n --ngram     N            # 1 for unigram, 2 for bigram, 3 for trigram...\n\
+  -o --out       output       # output file name\n\
+  -l --log                    # using -log(pr), default use pr directly\n\
+  -w --wordcount N            # Lexicon size, number of different word\n\
+  -b --brk       id[,id...]   # set the ids which should be treat as breaker\n\
+  -e --exclude   id[,id...]   # set the ids which should not be put into LM\n\
+  -c --cut       c1[,c2...]   # k-gram whose freq <= c[k] are droped\n\
+  -d --discount  method,param # the k-th -d parm specify the discount method \n\
+      for k-gram. Possible values for method/param:\n\
+          GT,R,dis  : GT discount for r <= R, r is the freq of a ngram.\n\
+                      Linear discount for those r > R, i.e. r'=r*dis\n\
+                      0 << dis < 1.0, for example 0.999 \n\
+          ABS,[dis] : Absolute discount r'=r-dis. And dis is optional\n\
+                      0 < dis < cut[k]+1.0, normally dis < 1.0.\n\
+          LIN,[dis] : Linear discount r'=r*dis. And dis is optional\n\
+                      0 < dis < 1.0\n\
+\n\
+Notes:\n\
+      -n must be given before -c -b. And -c must give right number of cut-off,\n\
+  also -d must appear exactly N times specify discount for 1-gram, 2-gram..., \n\
+  respectively.\n\
+      BREAKER-IDs could be SentenceTokens or ParagraphTokens. Concepturally,\n\
+  these ids has no meaning when they appeared in the middle of n-gram.\n\
+      EXCLUDE-IDs could be ambiguious-ids. Concepturally, n-grams which\n\
+  contain those ids are meaningless.\n\
+      We can not erase ngrams according to BREAKER-IDS and EXCLUDE-IDs directly\n\
+  from IDNGRAM file, because some low-level information still useful in it.\n\
+\n\
+Example:\n\
+      Following example read 'all.id3gram' and write trigram model 'all.slm'.\n\
+  At 1-gram level, use Good-Turing discount with cut-off 0, R=8, dis=0.9995. At\n\
+  2-gram level, use Absolute discount with cut-off 3, dis auto-calc. At 3-gram\n\
+  level, use Absolute discount with cut-off 2, dis auto-calc. Word id 10,11,12\n\
+  are breakers (sentence/para/paper breaker, etc). Exclude-ID is 9. Lexicon \n\
+  contains 200000 words. The result languagme model use -log(pr).\n\
+\n\
+        slmbuild -l -n 3 -o all.slm -w 200000 -c 0,3,2 -d GT,8,0.9995\n\
+                 -d ABS -d ABS -b 10,11,12 -e 9 all.id3gram\n\
+\n");
+    exit(100);
+}
+
+static int N = 0;
+static CSlmBuilder builder;
+static char* inputfilename = NULL;
+static char* outfilename = NULL;
+static std::vector<CSlmDiscounter *> discounter;
+
+static void
+getParameters(int argc, char* argv[])
+{
+    int c = 0;
+    char *ac = NULL, *cuts = NULL, *idstring = NULL, *dis_str = NULL;
+    std::vector<TSIMWordId> ids;
+    std::vector<CSlmBuilder::FREQ_TYPE> threshold;
+    bool bUseLogPr = false;
+
+    while ((c =
+                getopt_long(argc, argv, "lw:n:c:d:o:b:e:", long_options,
+                            NULL)) != -1) {
+        int n, rmax, cut;
+        double dis = 0;
+        switch (c) {
+        case 'l':
+            bUseLogPr = true;
+            break;
+        case 'o':
+            outfilename = strdup(optarg);
+            break;
+        case 'n':
+            N = atoi(optarg);
+            builder.Create(N);
+            break;
+        case 'w':
+            n = atoi(optarg);
+            builder.SetNumberOfWord(n);
+            break;
+        case 'c':
+            cuts = strdup(optarg);
+            ac = strtok(cuts, ",");
+            while (ac != NULL) {
+                cut = atoi(ac);
+                threshold.push_back(CSlmBuilder::FREQ_TYPE(cut));
+                ac = strtok(NULL, ",");
+            }
+            builder.SetCut(&(threshold[0]));
+            free(cuts);
+            break;
+        case 'b':
+            idstring = strdup(optarg);
+            ac = strtok(idstring, ",");
+            while (ac != NULL) {
+                n = atoi(ac);
+                ids.push_back(n);
+                ac = strtok(NULL, ",");
+            }
+            builder.SetBreakerIds(ids.size(), &(ids[0]));
+            free(idstring);
+            break;
+        case 'e':
+            idstring = strdup(optarg);
+            ac = strtok(idstring, ",");
+            while (ac != NULL) {
+                n = atoi(ac);
+                ids.push_back(n);
+                ac = strtok(NULL, ",");
+            }
+            builder.SetExcludeIds(ids.size(), &(ids[0]));
+            free(idstring);
+            break;
+        case 'd':
+            dis_str = strdup(optarg);
+            ac = strtok(dis_str, ",");
+            if (strcmp(ac, "GT") == 0) {
+                ac = strtok(NULL, ",");
+                rmax = atoi(ac);
+                ac = strtok(NULL, ",");
+                dis = atof(ac);
+                discounter.push_back(new CSlmGTDiscounter(rmax, dis));
+            } else if (strcmp(ac, "ABS") == 0) {
+                if ((ac = strtok(NULL, ",")) != NULL)
+                    dis = atof(ac);
+                discounter.push_back(new CSlmAbsoluteDiscounter(dis));
+            } else if (strcmp(ac, "LIN") == 0) {
+                if ((ac = strtok(NULL, ",")) != NULL)
+                    dis = atof(ac);
+                discounter.push_back(new CSlmLinearDiscounter(dis));
+            }
+            break;
+        default:
+            ShowUsage();
+        }
+    }
+
+    builder.SetUseLogPr(((bUseLogPr) ? 1 : 0));
+    if (optind == argc - 1) {
+        inputfilename = strdup(argv[optind]);
+        builder.SetDiscounter(&(discounter[0]));
+    } else {
+        fprintf(stderr, "Parameter input_file error\n");
+        for (int i = optind; i < argc; ++i)
+            fprintf(stderr, "%s ", argv[i]);
+        fprintf(stderr, "\n");
+        ShowUsage();
+    }
+}
+
+int
+main(int argc, char* argv[])
+{
+    getParameters(argc, argv);
+
+    TSIMWordId * ngram = new TSIMWordId[N + 1];
+    CSlmBuilder::FREQ_TYPE freq;
+
+    printf("Reading and Processing raw idngram..."); fflush(stdout);
+    FILE *fp = fopen(inputfilename, "rb");
+    int nItems = 0;
+    while (fread(ngram, sizeof(TSIMWordId), N, fp) == (size_t) N
+           && fread(&freq, sizeof(freq), 1, fp) == 1) {
+        builder.AddNGram(ngram, freq);
+        ++nItems;
+    }
+    fclose(fp);
+    delete ngram;
+    printf("%d ngrams.\n", nItems); fflush(stdout);
+
+    builder.Build();
+
+    printf("\nWriting result file..."); fflush(stdout);
+    FILE *out = fopen(outfilename, "wb");
+    builder.Write(out);
+    fclose(out);
+    printf("\n"); fflush(stdout);
+
+    return 0;
+}
diff --git a/src/slm/slminfo/slminfo.cpp b/src/slm/slminfo/slminfo.cpp
new file mode 100644 (file)
index 0000000..c010e4d
--- /dev/null
@@ -0,0 +1,294 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright (c) 2007 Sun Microsystems, Inc. All Rights Reserved.
+ *
+ * The contents of this file are subject to the terms of either the GNU Lesser
+ * General Public License Version 2.1 only ("LGPL") or the Common Development and
+ * Distribution License ("CDDL")(collectively, the "License"). You may not use this
+ * file except in compliance with the License. You can obtain a copy of the CDDL at
+ * http://www.opensource.org/licenses/cddl1.php and a copy of the LGPLv2.1 at
+ * http://www.opensource.org/licenses/lgpl-license.php. See the License for the
+ * specific language governing permissions and limitations under the License. When
+ * distributing the software, include this License Header Notice in each file and
+ * include the full text of the License in the License file as well as the
+ * following notice:
+ *
+ * NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND DISTRIBUTION LICENSE
+ * (CDDL)
+ * For Covered Software in this distribution, this License shall be governed by the
+ * laws of the State of California (excluding conflict-of-law provisions).
+ * Any litigation relating to this License shall be subject to the jurisdiction of
+ * the Federal Courts of the Northern District of California and the state courts
+ * of the State of California, with venue lying in Santa Clara County, California.
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by only the CDDL or only
+ * the LGPL Version 2.1, indicate your decision by adding "[Contributor]" elects to
+ * include this software in this distribution under the [CDDL or LGPL Version 2.1]
+ * license." If you don't indicate a single choice of license, a recipient has the
+ * option to distribute your version of this file under either the CDDL or the LGPL
+ * Version 2.1, or to extend the choice of license to its licensees as provided
+ * above. However, if you add LGPL Version 2.1 code and therefore, elected the LGPL
+ * Version 2 license, then the option applies only if the new code is made subject
+ * to such option by the copyright holder.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifdef HAVE_ASSERT_H
+#include <assert.h>
+#endif
+
+#ifdef HAVE_GETOPT_H
+#include <getopt.h>
+#endif
+
+#include <stdio.h>
+#include <math.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <map>
+
+#include "../sim_slm.h"
+
+void
+ShowUsage()
+{
+    printf("Usage:\n");
+    printf("    slminfo [options] slm_file\n");
+    printf("\nDescription:\n");
+    printf(
+        "    slminfo tell information of back-off language model 'slm_file'. It can also print the model to ARPA format.\n");
+    printf(
+        "  When no options given, slminfo will only print number of items in each level of the language model.\n");
+    printf("\nOptions:\n");
+    printf("    -v             # Verbose mode, printing arpa format.\n");
+    printf(
+        "    -p             # Prefer normal probability than -log(Pr) which is default. Valid under -v option.\n");
+    printf(
+        "    -l dict_file   # Lexicon. Valid under -v option. Substitute the word-id with word-text in the output.\n");
+    printf("\n");
+    exit(100);
+}
+
+static bool verbose = false;
+static char* lexicon_filename = NULL;
+static bool output_log_pr = true;
+
+static struct option long_options[] =
+{
+    { "verbose", 0, 0, 'v' },
+    { "pr", 0, 0, 'p' },
+    { "lexicon", 1, 0, 'l' },
+    { 0, 0, 0, 0 }
+};
+
+static void
+getParameters(int argc, char* argv[])
+{
+    int c, option_index = 0;
+    while ((c =
+                getopt_long(argc, argv, "vpl:", long_options,
+                            &option_index)) != -1) {
+        switch (c) {
+        case 'v':
+            verbose = true;
+            break;
+        case 'l':
+            lexicon_filename = strdup(optarg);
+            break;
+        case 'p':
+            output_log_pr = false;
+            break;
+        default:
+            ShowUsage();
+        }
+    }
+    if (output_log_pr == false && !verbose) ShowUsage();
+    if (lexicon_filename != NULL && !verbose) ShowUsage();
+    if (optind != argc - 1) ShowUsage();
+}
+
+typedef std::map<TSIMWordId, std::string> TReverseLexicon;
+
+void
+PrintARPALevel(int lvl, FILE* fp, TReverseLexicon* plexicon, bool output_log_pr)
+{
+    int N, bLogPrFile;
+
+    fseek(fp, 0, SEEK_SET);
+    fread(&N, sizeof(int), 1, fp);
+    fread(&bLogPrFile, sizeof(bLogPrFile), 1, fp);
+
+    assert(N < 16);
+    int sz[16];            //it should be N+1, Yet some compiler do not support int sz[N+1]
+    long level_offset[16]; //it should be N+1, Yet some compiler do not support it
+
+    fread(sz, sizeof(int), N + 1, fp);
+    long offset = ftell(fp);
+    for (int i = 0; i <= N; ++i) {
+        level_offset[i] = offset;
+        offset += sz[i] * sizeof(CSIMSlm::TNode);
+    }
+
+    // TSIMWordId ngram[16];
+    int idx[16];   //it should be N+1, Yet some compiler do not support it
+    CSIMSlm::TNode nodes[16][2];  //it should be N+1, Yet some compiler do not support it
+    for (int i = 0; i <= lvl; ++i) {
+        idx[i] = 0;
+        if (i == N) {
+            fseek(fp,
+                  level_offset[i] + sizeof(CSIMSlm::TLeaf) * idx[i],
+                  SEEK_SET);
+            fread(&(nodes[i][0]), sizeof(CSIMSlm::TLeaf), 1, fp);
+            fread(&(nodes[i][1]), sizeof(CSIMSlm::TLeaf), 1, fp);
+        } else {
+            fseek(fp,
+                  level_offset[i] + sizeof(CSIMSlm::TNode) * idx[i],
+                  SEEK_SET);
+            fread(&(nodes[i][0]), sizeof(CSIMSlm::TNode), 2, fp);
+        }
+    }
+
+    printf("/%d-gram:%d/\n", lvl, sz[lvl] - 1);
+    while (idx[lvl] < sz[lvl] - 1) {
+        for (int i = lvl - 1; i > 0; --i) {
+            bool change = false;
+            while (nodes[i][1].child <= idx[i + 1]) {
+                change = true;
+                //load next item
+                ++idx[i];
+                nodes[i][0] = nodes[i][1];
+                fseek(fp, level_offset[i] + sizeof(CSIMSlm::TNode) *
+                      (idx[i] + 1), SEEK_SET);
+                fread(&(nodes[i][1]), sizeof(CSIMSlm::TNode), 1, fp);
+            }
+            if (change == false) break;
+        }
+
+        for (int i = 1; i <= lvl; ++i) {
+            TSIMWordId word_id = nodes[i][0].id;
+            if (plexicon != NULL)
+                printf("%s ", (*plexicon)[word_id].c_str());
+            else
+                printf("%d ", int(word_id));
+        }
+        if (bLogPrFile) {
+            if (output_log_pr)
+                printf("%20.17lf ", double(nodes[lvl][0].pr));
+            else
+                printf("%20.17lf ", exp(-double(nodes[lvl][0].pr)));
+            if (lvl != N) {
+                if (output_log_pr)
+                    printf("%20.17lf", double(nodes[lvl][0].bow));
+                else
+                    printf("%20.17lf", exp(-double(nodes[lvl][0].bow)));
+            }
+        } else {
+            if (output_log_pr)
+                printf("%20.17lf ", -log(double(nodes[lvl][0].pr)));
+            else
+                printf("%20.17lf ", double(nodes[lvl][0].pr));
+            if (lvl != N) {
+                if (output_log_pr)
+                    printf("%20.17lf", -log(double(nodes[lvl][0].bow)));
+                else
+                    printf("%20.17lf", double(nodes[lvl][0].bow));
+            }
+        }
+        printf("\n");
+
+        ++idx[lvl];
+        nodes[lvl][0] = nodes[lvl][1];
+        if (lvl == N) {
+            fseek(fp, level_offset[lvl] + sizeof(CSIMSlm::TLeaf) *
+                  (idx[lvl] + 1), SEEK_SET);
+            fread(&(nodes[lvl][1]), sizeof(CSIMSlm::TLeaf), 1, fp);
+        } else {
+            fseek(fp, level_offset[lvl] + sizeof(CSIMSlm::TNode) *
+                  (idx[lvl] + 1), SEEK_SET);
+            fread(&(nodes[lvl][1]), sizeof(CSIMSlm::TNode), 1, fp);
+        }
+    }
+}
+
+void
+PrintARPA(FILE* fp, const char* lexicon_filename, bool output_log_pr)
+{
+    static int id;
+    static char word[10240];
+
+    int N;
+    TReverseLexicon* plexicon = NULL;
+    if (lexicon_filename != NULL) {
+        plexicon = new TReverseLexicon();
+        FILE* f_lex = fopen(lexicon_filename, "r");
+        while (fgets(word, 10240, f_lex) != NULL) {
+            if (strlen(word) > 0) {
+                char* p = word;
+                while (*p == ' ' || *p == '\t')
+                    ++p;
+                while (*p != 0 && *p != ' ' && *p != '\t')
+                    ++p;
+                if (*p == 0) continue;
+                *p++ = 0;
+                while (*p == ' ' || *p == '\t')
+                    ++p;
+                if (!(*p >= '0' && *p <= '9')) continue;
+                for (id = 0; *p >= '0' && *p <= '9'; ++p)
+                    id = 10 * id + (*p - '0');
+                (*plexicon)[TSIMWordId(id)] = std::string(word);
+            }
+        }
+        fclose(f_lex);
+    }
+    fseek(fp, 0, SEEK_SET);
+    fread(&N, sizeof(N), 1, fp);
+    for (int lvl = 1; lvl <= N; ++lvl)
+        PrintARPALevel(lvl, fp, plexicon, output_log_pr);
+}
+
+void
+PrintSimple(FILE* fp)
+{
+    int N;
+    int nItem;
+    int bLogPrFile;
+
+    fseek(fp, 0, SEEK_SET);
+    fread(&N, sizeof(N), 1, fp);
+    fread(&bLogPrFile, sizeof(bLogPrFile), 1, fp);
+    printf("This is a %d-gram back-off model, ", N);
+    printf("%s\n", (bLogPrFile) ? ("using -log(pr)") : ("using direct pr"));
+    for (int i = 0; i <= N; ++i) {
+        fread(&nItem, sizeof(nItem), 1, fp);
+        printf("  %d items in %d-level\n", nItem - 1, i);
+    }
+}
+
+int
+main(int argc, char* argv[])
+{
+    FILE* fp = NULL;
+
+    getParameters(argc, argv);
+
+    if ((fp = fopen(argv[argc - 1], "rb+")) == NULL) {
+        printf("Can not open back-off language model file %s\n", argv[argc - 1]);
+        return 99;
+    }
+
+    if (!verbose)
+        PrintSimple(fp);
+    else
+        PrintARPA(fp, lexicon_filename, output_log_pr);
+
+    fclose(fp);
+
+    return 0;
+}
diff --git a/src/slm/slmprune/slmprune.cpp b/src/slm/slmprune/slmprune.cpp
new file mode 100644 (file)
index 0000000..0afbb4a
--- /dev/null
@@ -0,0 +1,489 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright (c) 2007 Sun Microsystems, Inc. All Rights Reserved.
+ *
+ * The contents of this file are subject to the terms of either the GNU Lesser
+ * General Public License Version 2.1 only ("LGPL") or the Common Development and
+ * Distribution License ("CDDL")(collectively, the "License"). You may not use this
+ * file except in compliance with the License. You can obtain a copy of the CDDL at
+ * http://www.opensource.org/licenses/cddl1.php and a copy of the LGPLv2.1 at
+ * http://www.opensource.org/licenses/lgpl-license.php. See the License for the
+ * specific language governing permissions and limitations under the License. When
+ * distributing the software, include this License Header Notice in each file and
+ * include the full text of the License in the License file as well as the
+ * following notice:
+ *
+ * NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND DISTRIBUTION LICENSE
+ * (CDDL)
+ * For Covered Software in this distribution, this License shall be governed by the
+ * laws of the State of California (excluding conflict-of-law provisions).
+ * Any litigation relating to this License shall be subject to the jurisdiction of
+ * the Federal Courts of the Northern District of California and the state courts
+ * of the State of California, with venue lying in Santa Clara County, California.
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by only the CDDL or only
+ * the LGPL Version 2.1, indicate your decision by adding "[Contributor]" elects to
+ * include this software in this distribution under the [CDDL or LGPL Version 2.1]
+ * license." If you don't indicate a single choice of license, a recipient has the
+ * option to distribute your version of this file under either the CDDL or the LGPL
+ * Version 2.1, or to extend the choice of license to its licensees as provided
+ * above. However, if you add LGPL Version 2.1 code and therefore, elected the LGPL
+ * Version 2 license, then the option applies only if the new code is made subject
+ * to such option by the copyright holder.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifdef HAVE_ASSERT_H
+#include <assert.h>
+#endif
+
+#include <stdio.h>
+#include <math.h>
+
+#include "../sim_slm.h"
+#include <algorithm>
+
+class TNodeInfo {
+public:
+    double d;
+#ifndef WORDS_BIGENDIAN
+    unsigned child : 1;
+    unsigned idx : 31;
+#else
+    unsigned idx : 31;
+    unsigned child : 1;
+#endif
+
+public:
+    TNodeInfo(double distance = 0.0, int pos = 0, bool children =
+                  0) : d(distance)
+    {
+        idx = pos; child = (children == 0) ? 0 : 1;
+    }
+
+    bool
+    operator<(const TNodeInfo& r) const
+    {
+        return ((child ^ r.child) == 0) ? (d < r.d) : (child == 0);
+    }
+
+    bool
+    operator==(const TNodeInfo& r) const
+    {
+        return(child == r.child && d == r.d);
+    }
+};
+
+class CSlmPruner : public CSIMSlm {
+public:
+    CSlmPruner() : CSIMSlm(), cut(NULL)
+    {
+    }
+
+    ~CSlmPruner()
+    {
+        if (cut) delete [] cut;
+    }
+
+    void SetCut(int* nCut);
+    void SetReserve(int* nReserve);
+    void Prune();
+    void Write(const char* filename);
+
+protected:
+    void PruneLevel(int lvl);
+    double CalcDistance(int lvl, int* idx, TSIMWordId* hw);
+    void CalcBOW();
+
+protected:
+    int* cut;
+    int cache_level, cache_idx; // to accelerate the pruning method
+    double cache_PA, cache_PB;
+};
+
+void
+CSlmPruner::Prune()
+{
+    printf("Erasing items using Entropy distance"); fflush(stdout);
+    for (int lvl = N; lvl > 0; --lvl)
+        PruneLevel(lvl);
+    printf("\n"); fflush(stdout);
+    CalcBOW();
+}
+void
+CSlmPruner::Write(const char* filename)
+{
+    FILE* out = fopen(filename, "wb");
+    fwrite(&N, sizeof(N), 1, out);
+    fwrite(&bUseLogPr, sizeof(bUseLogPr), 1, out);
+    fwrite(sz, sizeof(int), N + 1, out);
+    for (int i = 0; i < N; ++i) {
+        fwrite(level[i], sizeof(TNode), sz[i], out);
+    }
+    fwrite(level[N], sizeof(TLeaf), sz[N], out);
+    fclose(out);
+}
+
+void
+CSlmPruner::SetReserve(int* nReserve)
+{
+    cut = new int [N + 1];
+    cut[0] = 0;
+    for (int lvl = 1; lvl <= N; ++lvl) {
+        cut[lvl] = sz[lvl] - 1 - nReserve[lvl];
+        if (cut[lvl] < 0) cut[lvl] = 0;
+    }
+}
+
+void
+CSlmPruner::SetCut(int* nCut)
+{
+    cut = new int [N + 1];
+    cut[0] = 0;
+    for (int lvl = 1; lvl <= N; ++lvl)
+        cut[lvl] = nCut[lvl];
+}
+
+template <class chIterator>
+int
+CutLevel(CSIMSlm::TNode* pfirst,
+         CSIMSlm::TNode* plast,
+         chIterator chfirst,
+         chIterator chlast,
+         bool bUseLogPr)
+{
+    int idxfirst, idxchk;
+    chIterator chchk = chfirst;
+    for (idxfirst = idxchk = 0; chchk != chlast; ++chchk, ++idxchk) {
+        //cut item whoese pr == 1.0; and not psuedo tail
+        if (chchk->pr != ((bUseLogPr) ? 0.0 : 1.0) || (chchk + 1) == chlast) {
+            if (idxfirst < idxchk) *chfirst = *chchk;
+            while (pfirst != plast && pfirst->child <= idxchk)
+                pfirst++->child = idxfirst;
+            ++idxfirst;
+            ++chfirst;
+        }
+    }
+    return idxfirst;
+}
+
+void
+CSlmPruner::PruneLevel(int lvl)
+{
+    cache_level = cache_idx = -1;
+
+    if (cut[lvl] <= 0) {
+        printf("\n  Level %d (%d items), no need to cut as your command!",
+               lvl,
+               sz[lvl] - 1); fflush(stdout);
+        return;
+    }
+
+    printf("\n  Level %d (%d items), allocating...", lvl, sz[lvl] - 1); fflush(
+        stdout);
+
+    int n = sz[lvl] - 1; //do not count last psuedo tail
+    if (cut[lvl] >= n) cut[lvl] = n - 1;
+    TNodeInfo* pbuf = new TNodeInfo[n];
+    TSIMWordId hw[16]; // it should be lvl+1, yet some compiler do not support it
+    int idx[16];       // it should be lvl+1, yet some compiler do not support it
+
+    printf(", Calculating..."); fflush(stdout);
+    for (int i = 0; i <= lvl; ++i)
+        idx[i] = 0;
+    while (idx[lvl] < n) {
+        if (lvl == N) {
+            hw[lvl] = (((TLeaf*)level[lvl]) + idx[lvl])->id;
+        } else {
+            hw[lvl] = (((TNode*)level[lvl]) + idx[lvl])->id;
+        }
+        for (int j = lvl - 1; j >= 0; --j) {
+            TNode* pnode = ((TNode*)level[j]) + idx[j];
+            for (; (pnode + 1)->child <= idx[j + 1]; ++pnode, ++idx[j])
+                ;
+            hw[j] = pnode->id;
+        }
+        bool has_child = false;
+        if (lvl != N) {
+            TNode* pn = ((TNode*)level[lvl]) + idx[lvl];
+            if ((pn + 1)->child > pn->child)
+                has_child = true;
+        }
+        pbuf[idx[lvl]].child = (has_child) ? 1 : 0;
+        pbuf[idx[lvl]].idx = idx[lvl];
+        if (!has_child)
+            pbuf[idx[lvl]].d = CalcDistance(lvl, idx, hw);
+        ++idx[lvl];
+    }
+    printf(", sorting...");
+    std::make_heap(pbuf, pbuf + n);
+    std::sort_heap(pbuf, pbuf + n);
+
+    int k = 0;
+    // because pr in model can not be 1.0, so we use this to mark a item to be prune
+    for (TNodeInfo* pinfo = pbuf;
+         k < cut[lvl] && pinfo->child == 0;
+         ++k, ++pinfo) {
+        if (lvl == N) {
+            if (bUseLogPr)
+                (((TLeaf*)level[lvl]) + pinfo->idx)->pr = 0.0;  // -log(1.0)
+            else
+                (((TLeaf*)level[lvl]) + pinfo->idx)->pr = 1.0;
+        } else {
+            if (bUseLogPr)
+                (((TNode*)level[lvl]) + pinfo->idx)->pr = 0.0;  // -log(1.0)
+            else
+                (((TNode*)level[lvl]) + pinfo->idx)->pr = 1.0;  // -log(1.0)
+        }
+    }
+    printf("(cut %d items), build parent ptr...", k); fflush(stdout);
+    if (lvl == N) {
+        k =
+            CutLevel((TNode*)level[lvl - 1],
+                     ((TNode*)level[lvl - 1]) + sz[lvl - 1],
+                     (TLeaf*)level[lvl],
+                     ((TLeaf*)level[lvl]) + sz[lvl],
+                     bUseLogPr);
+    } else {
+        k =
+            CutLevel((TNode*)level[lvl - 1],
+                     ((TNode*)level[lvl - 1]) + sz[lvl - 1],
+                     (TNode*)level[lvl],
+                     ((TNode*)level[lvl]) + sz[lvl],
+                     bUseLogPr);
+    }
+    sz[lvl] = k; //k is new size
+    printf("done!");
+    delete [] pbuf;
+    cache_level = cache_idx = -1;
+}
+
+template<class chIterator>
+double
+CalcNodeBow(CSlmPruner* pruner,
+            int lvl,
+            TSIMWordId words[],
+            chIterator chh,
+            chIterator cht,
+            bool bUseLogPr)
+{
+    double sumnext = 0.0, sum = 0.0;
+    if (chh == cht)
+        return 1.0;
+    for (; chh < cht; ++chh) {
+        if (bUseLogPr)
+            sumnext += exp(-double(chh->pr));
+        else
+            sumnext += double(chh->pr);
+        words[lvl + 1] = chh->id;
+        sum += pruner->getPr(lvl, words + 2);
+    }
+    assert(sumnext >= 0.0 && sumnext < 1.0);
+    assert(sum >= 0.0 && sum < 1.0);
+    return (1.0 - sumnext) / (1.0 - sum);
+}
+
+void
+CSlmPruner::CalcBOW()
+{
+    printf("\nUpdating back-off weight"); fflush(stdout);
+    for (int lvl = 0; lvl < N; ++lvl) {
+        printf("\n    Level %d...", lvl); fflush(stdout);
+        TNode* base[16]; //it should be lvl+1, yet some compiler do not support it
+        int idx[16];     //it should be lvl+1, yet some compiler do not support it
+        for (int i = 0; i <= lvl; ++i) {
+            base[i] = (TNode*)level[i];
+            idx[i] = 0;
+        }
+        TSIMWordId words[17];   //it should be lvl+2, yet some compiler do not support it
+        for (int lsz = sz[lvl] - 1; idx[lvl] < lsz; ++idx[lvl]) {
+            words[lvl] = base[lvl][idx[lvl]].id;
+            for (int k = lvl - 1; k >= 0; --k) {
+                while (base[k][idx[k] + 1].child <= idx[k + 1])
+                    ++idx[k];
+                words[k] = base[k][idx[k]].id;
+            }
+            TNode & node = base[lvl][idx[lvl]];
+            TNode & nodenext = *((&node) + 1);
+
+            double bow = 1.0;
+            if (lvl == N - 1) {
+                TLeaf* ch = (TLeaf*)level[lvl + 1];
+                bow =
+                    CalcNodeBow(this, lvl, words, &(ch[node.child]),
+                                &(ch[nodenext.child]), bUseLogPr);
+            } else {
+                TNode* ch = (TNode*)level[lvl + 1];
+                bow =
+                    CalcNodeBow(this, lvl, words, &(ch[node.child]),
+                                &(ch[nodenext.child]), bUseLogPr);
+            }
+            if (bUseLogPr)
+                node.bow = PR_TYPE(-log(bow));
+            else
+                node.bow = PR_TYPE(bow);
+        }
+    }
+    printf("\n"); fflush(stdout);
+}
+
+double
+CSlmPruner::CalcDistance(int lvl, int* idx, TSIMWordId* hw)
+{
+    double PA, PB, PHW, PH_W, PH, BOW, _BOW, pr, p_r;
+    TSIMWordId w = hw[lvl];
+
+    PH = 1.0;
+    TNode* parent = ((TNode*)level[lvl - 1]) + idx[lvl - 1];
+    if (bUseLogPr)
+        BOW = exp(-double(parent->bow));  //Fix original bug to use the BOW directly
+    else
+        BOW = double(parent->bow);
+
+    for (int i = 1; i < lvl; ++i)
+        PH *= getPr(i, hw + 1 + (lvl - i));
+    assert(PH <= 1.0 && PH > 0.0);
+
+    if (lvl == N) {
+        if (bUseLogPr)
+            PHW = exp(-((((TLeaf*)level[lvl]) + idx[lvl])->pr));
+        else
+            PHW = ((((TLeaf*)level[lvl]) + idx[lvl])->pr);
+        assert(w == (((TLeaf*)level[lvl]) + idx[lvl])->id);
+    } else {
+        if (bUseLogPr)
+            PHW = exp(-((((TNode*)level[lvl]) + idx[lvl])->pr));
+        else
+            PHW = ((((TNode*)level[lvl]) + idx[lvl])->pr);
+        assert(w == (((TNode*)level[lvl]) + idx[lvl])->id);
+    }
+    PH_W = getPr(lvl - 1, hw + 2);
+    assert(PHW > 0.0 && PHW < 1.0);
+    assert(PH_W > 0.0 && PH_W < 1.0);
+
+    if (cache_level != lvl - 1 || cache_idx != idx[lvl - 1]) {
+        cache_level = lvl - 1;
+        cache_idx = idx[lvl - 1];
+        cache_PA = cache_PB = 1.0;
+        for (int h = parent->child, t = (parent + 1)->child; h < t; ++h) {
+            TSIMWordId id;
+            if (lvl == N) {
+                if (bUseLogPr)
+                    pr = exp(-((((TLeaf*)level[lvl]) + h)->pr));
+                else
+                    pr = ((((TLeaf*)level[lvl]) + h)->pr);
+                id = (((TLeaf*)level[lvl]) + h)->id;
+            } else {
+                if (bUseLogPr)
+                    pr = exp(-((((TNode*)level[lvl]) + h)->pr));
+                else
+                    pr = ((((TNode*)level[lvl]) + h)->pr);
+                id = (((TNode*)level[lvl]) + h)->id;
+            }
+            assert(pr > 0.0 && pr < 1.0);
+            cache_PA -= pr;
+
+            hw[lvl] = id;
+            p_r = getPr(lvl - 1, hw + 2);  // Fix bug from pr = getPr(lvl-1, hw+1)
+            assert(p_r > 0.0 && p_r < 1.0);
+            cache_PB -= p_r;
+        }
+        assert(cache_PA > -0.01 && cache_PB > -0.01);
+        if (cache_PA < 0.00001 || cache_PB < 0.00001) {
+            printf("\n precision problem on %d gram:", lvl - 1);
+            for (int i = 1; i < lvl; ++i) printf("%d ", idx[i]);
+            printf("   ");
+            if (cache_PA < 0.00001) {
+                printf("{1.0 - sigma p(w|h)} ==> 0.00001");
+                cache_PA = 0.00001;
+            }
+            if (cache_PB < 0.00001) {
+                printf("{1.0 - sigma p(w|h')} ==> 0.00001");
+                cache_PB = 0.00001;
+            }
+        }
+    }
+    PA = cache_PA;
+    PB = cache_PB;
+
+    _BOW = (PA + PHW) / (PB + PH_W); // Fix bug from "(1.0-PA+PHW)/(1.0-PB+PH_W);"
+
+    assert(BOW > 0.0);
+    assert(_BOW > 0.0);
+    assert(PA + PHW < 1.01);     // %1 error rate
+    assert(PB + PH_W < 1.01);    // %1 error rate
+
+    /*
+     * PH = P(h), PHW = P(w|h), PH_W = P(w|h'), _BOW = bow'(h) (the new bow)
+     * BOW = bow(h) (the original bow), PA = sum_{w_i:C(w_i,h)=0} P(w_i|h),
+     * PB = sum_{w_i:C(w_i,h)=0} P(w_i|h')
+     */
+    return -(PH *
+             (PHW *
+              (log(PH_W) + log(_BOW) - log(PHW)) + PA * (log(_BOW) - log(BOW))));
+}
+
+void
+ShowUsage(void)
+{
+    printf("Usage:\n");
+    printf("    slmprune input_slm result_slm [R|C] num1 num2...\n");
+    printf("\nDescription:\n");
+    printf(
+        "\
+      This program uses entropy-based method to prune the size of back-off \n\
+  language model 'input_slm' to a specific size and write to 'result_slm'. \n\
+  the third parameter [R|C] means the following numbers is the number for\n\
+  (R)eserve or (C)ut. If (C)ut, the num[k] means how many items in level K\n\
+  would be cut. If (R)eserve, num[k] means how many item would be reserved\n\
+  in level k. \n\
+      Note that we do not ensure that during pruning process,  exactly the\n\
+  the given number of items are cut or reserved, because some items may \n\
+  contains high level children, so could not be cut. \n\
+      Also it's your responsiblity to give right number of arguments based\n\
+  on 'input_slm'.\n\
+\nSee Also:\n\
+    To get information of the back-off language model, try 'slminfo'.\n\n");
+}
+
+int nCut[32];
+const char* srcfilename, *tgtfilename;
+
+int
+main(int argc, char* argv[])
+{
+    memset(nCut, 0, sizeof(nCut));
+    if (argc < 5) {
+        ShowUsage(); exit(100);
+    }
+    srcfilename = argv[1];
+    tgtfilename = argv[2];
+    bool bCut = (argv[3][0] == 'C' || argv[3][0] == 'c');
+
+    CSlmPruner pruner;
+    printf("Reading language model %s...", srcfilename); fflush(stdout);
+    pruner.Load(srcfilename);
+    printf("done!\n"); fflush(stdout);
+
+    for (int i = 4; i < argc && i < 100; ++i)
+        nCut[i - 3] = atoi(argv[i]);
+
+    if (bCut)
+        pruner.SetCut(nCut);
+    else
+        pruner.SetReserve(nCut);
+    pruner.Prune();
+
+    printf("Writing target language model %s...", tgtfilename); fflush(stdout);
+    pruner.Write(tgtfilename);
+    printf("done!\n\n"); fflush(stdout);
+
+    pruner.Free();
+    return 0;
+}
diff --git a/src/slm/slmseg/slmseg.cpp b/src/slm/slmseg/slmseg.cpp
new file mode 100644 (file)
index 0000000..f41d20e
--- /dev/null
@@ -0,0 +1,487 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright (c) 2007 Sun Microsystems, Inc. All Rights Reserved.
+ *
+ * The contents of this file are subject to the terms of either the GNU Lesser
+ * General Public License Version 2.1 only ("LGPL") or the Common Development and
+ * Distribution License ("CDDL")(collectively, the "License"). You may not use this
+ * file except in compliance with the License. You can obtain a copy of the CDDL at
+ * http://www.opensource.org/licenses/cddl1.php and a copy of the LGPLv2.1 at
+ * http://www.opensource.org/licenses/lgpl-license.php. See the License for the
+ * specific language governing permissions and limitations under the License. When
+ * distributing the software, include this License Header Notice in each file and
+ * include the full text of the License in the License file as well as the
+ * following notice:
+ *
+ * NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND DISTRIBUTION LICENSE
+ * (CDDL)
+ * For Covered Software in this distribution, this License shall be governed by the
+ * laws of the State of California (excluding conflict-of-law provisions).
+ * Any litigation relating to this License shall be subject to the jurisdiction of
+ * the Federal Courts of the Northern District of California and the state courts
+ * of the State of California, with venue lying in Santa Clara County, California.
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by only the CDDL or only
+ * the LGPL Version 2.1, indicate your decision by adding "[Contributor]" elects to
+ * include this software in this distribution under the [CDDL or LGPL Version 2.1]
+ * license." If you don't indicate a single choice of license, a recipient has the
+ * option to distribute your version of this file under either the CDDL or the LGPL
+ * Version 2.1, or to extend the choice of license to its licensees as provided
+ * above. However, if you add LGPL Version 2.1 code and therefore, elected the LGPL
+ * Version 2 license, then the option applies only if the new code is made subject
+ * to such option by the copyright holder.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifdef HAVE_ASSERT_H
+#include <assert.h>
+#endif
+
+#ifdef HAVE_GETOPT_H
+#include <getopt.h>
+#endif
+
+#include <stdio.h>
+#include <unistd.h>
+#include <locale.h>
+
+#include <vector>
+#include <map>
+#include <algorithm>
+
+#include "../sim_dict.h"
+#include "../sim_sen.h"
+#include "../slm.h"
+
+static struct option long_options[] =
+{
+    { "dict", 1, 0, 'd' },
+    { "format", 1, 0, 'f' },
+    { "show-id", 0, 0, 'i' },
+    { "s-tok", 1, 0, 's' },
+    { "model", 1, 0, 'm' },
+    { 0, 0, 0, 0 }
+};
+
+static char* s_strDictFile = NULL;
+static char* s_strSlmFile = NULL;
+static bool s_bTextOut = false;
+static bool s_bShowId = false;
+static TSIMWordId s_iSTOKID = 10;
+
+static CSIMDict *s_dict = NULL;
+static CThreadSlm *s_tslm = NULL;
+
+static void
+ShowUsage()
+{
+    fprintf(stderr, "\nUsage:\n");
+    fprintf(
+        stderr,
+        "slmseg -d dict_file [-f (text|bin)] [-i] [-s STOK_ID] [-m lm_file]\n\n");
+    fprintf(stderr, "  -f --format:\n");
+    fprintf(stderr,
+            "    Output Format, can be 'text' or 'bin'. default 'bin'\n");
+    fprintf(
+        stderr,
+        "    Normally, in text mode, word text are output, while in binary mode,\n");
+    fprintf(stderr,
+            "    binary short integer of the word-ids are writed to stdout.\n");
+    fprintf(stderr, "  -s --stok:\n");
+    fprintf(stderr, "    Sentence token id. Default 10.\n");
+    fprintf(
+        stderr,
+        "    It will be write to output in binary mode after every sentence.\n");
+    fprintf(stderr, "  -i --show-id:\n");
+    fprintf(
+        stderr,
+        "    Show Id info. Under text output format mode, Attach id after known-words.\n");
+    fprintf(stderr, "                  Under binary mode, print id in text.\n");
+    fprintf(stderr, "  -m --model:\n");
+    fprintf(stderr, "    Language model file name");
+    fprintf(stderr, "\n");
+    fprintf(stderr, "Notes:\n");
+    fprintf(stderr,
+            "  Under binary mode, consecutive id of 0 are merged into one 0.\n");
+    fprintf(stderr,
+            "  Under text mode, no space are insert between unknown-words. \n");
+    fprintf(stderr, "\n");
+    fprintf(stderr, "\n");
+    exit(1000);
+}
+
+static void
+getParameters(int argc, char* argv[])
+{
+    int c;
+    while ((c =
+                getopt_long(argc, argv, "d:if:s:m:", long_options,
+                            NULL)) != -1) {
+        switch (c) {
+        case 'd':
+            s_strDictFile = strdup(optarg);
+            break;
+        case 'i':
+            s_bShowId = true;
+            break;
+        case 'f':
+            s_bTextOut = (strcmp(optarg, "text") == 0);
+            break;
+        case 's':
+            s_iSTOKID = atoi(optarg);
+            break;
+        case 'm':
+            s_strSlmFile = strdup(optarg);
+            break;
+        default:
+            ShowUsage();
+            break;
+        }
+    }
+    if (s_strDictFile == NULL)
+        ShowUsage();
+}
+
+static void
+output_stok(int& nWords)
+{
+    if (s_bShowId) {
+        if (nWords > 0)
+            printf(" ");
+        printf("%d", unsigned(s_iSTOKID));
+    } else {
+        fwrite(&s_iSTOKID, sizeof(TSIMWordId), 1, stdout);
+    }
+    ++nWords;
+}
+
+static void
+output(int len,
+       const TWCHAR* p,
+       TSIMWordId idprev,
+       TSIMWordId idcur,
+       int& nWords)
+{
+    static char mbword[1024];
+    static TWCHAR wcword[1024];
+
+    bool bRealGap = (idcur != SIM_ID_NOT_WORD || idprev != SIM_ID_NOT_WORD);
+    if (s_bTextOut) {
+        for (int i = 0; i < len; ++i, ++p)
+            wcword[i] = *p;
+        wcword[len] = 0;
+        WCSTOMBS(mbword, wcword, sizeof(mbword));
+        if (bRealGap && idprev == SIM_ID_NOT_WORD)
+            printf("(%d)", unsigned(idprev));
+        if (bRealGap && (nWords > 0))
+            printf(" ");
+        printf("%s", mbword);
+        if (s_bShowId && idcur != SIM_ID_NOT_WORD)
+            printf("(%d)", unsigned(idcur));
+    } else {
+        if (bRealGap) {
+            if (s_bShowId) {
+                if (nWords > 0)
+                    printf(" ");
+                printf("%d", unsigned(idcur));
+            } else
+                fwrite(&idcur, sizeof(TSIMWordId), 1, stdout);
+        }
+    }
+    if (bRealGap)
+        ++nWords;
+}
+
+struct TLatticeWord {
+    int m_left;
+    int m_right;
+    int m_wordId;
+
+    TLatticeWord(int left = 0, int right = 0, int wid = 0)
+        : m_left(left), m_right(right), m_wordId(wid)
+    {
+    }
+};
+
+typedef std::vector<TLatticeWord> TLatticeWordVec;
+
+struct TLatticeStateValue {
+    double m_pr;
+    TLatticeWord*         mp_btword;
+    CThreadSlm::TState m_btstate;
+
+    TLatticeStateValue(double pr = 0.0,
+                       TLatticeWord* btword = NULL,
+                       CThreadSlm::TState btstate = CThreadSlm::TState())
+        : m_pr(pr), mp_btword(btword), m_btstate(btstate)
+    {
+    }
+};
+
+typedef std::map<CThreadSlm::TState, TLatticeStateValue> TLatticeColumnStates;
+
+struct TLatticeColumn {
+    TLatticeWordVec m_wordstarting;
+    TLatticeColumnStates m_states;
+};
+
+typedef std::vector<TLatticeColumn> CLattice;
+
+inline void
+insertLatticeWord(CLattice& lattice, TLatticeWord word)
+{
+    lattice[word.m_left].m_wordstarting.push_back(word);
+}
+
+int
+getAmbiLen(const TWCHAR* p, int word_len)
+{
+    const CSIMDict::TState* pstate;
+
+    for (int i = 1; (i < word_len) && *(p + i) != WCH_NULL; ++i) {
+        int len = s_dict->matchLongest(s_dict->getRoot(), pstate, p + i);
+        if (word_len < i + len)
+            word_len = i + len;
+    }
+
+    return word_len;
+}
+
+void
+fullSegBuildLattice(wstring& sntnc, int left, int len, CLattice& lattice)
+{
+    for (int right = left + len; left < right; ++left) {
+        bool found = false;
+
+        const TWCHAR* p = sntnc.c_str() + left;
+        const CSIMDict::TState* pds = s_dict->getRoot();
+        for (len = 0; left + len < right; ++len) {
+            if ((pds = s_dict->step(pds, *p++)) == NULL)
+                break;
+            if (pds->word_id != SIM_ID_NOT_WORD) {
+                found = true;
+                insertLatticeWord(lattice,
+                                  TLatticeWord(left, left + len + 1,
+                                               pds->word_id));
+            }
+        }
+        if (!found)
+            insertLatticeWord(lattice,
+                              TLatticeWord(left, left + 1, SIM_ID_NOT_WORD));
+    }
+}
+
+/**
+ * Lattice head should have one state, with its TState using slm's root. its
+ * pr = 0 and its mp_btword == NULL;
+ * Lattice tail must contain no word, and it previous node contain only one word
+ * with its right = left+1, right == tail.
+ * The lattice should ensure the lattice path existing
+ */
+void
+buildLattice(wstring &sntnc, CLattice& lattice)
+{
+    lattice.clear();
+    lattice.resize(sntnc.size() + 2);
+
+    unsigned int idcur = SIM_ID_NOT_WORD;
+    lattice[0].m_states[CThreadSlm::TState()] = TLatticeStateValue(
+        0.0,
+        NULL,
+        CThreadSlm::
+        TState());
+
+    for (int i = 0, sz = sntnc.size(); i < sz; ) {
+        const CSIMDict::TState* pstate;
+        const TWCHAR* p = sntnc.c_str() + i;
+        int len = s_dict->matchLongest(s_dict->getRoot(), pstate, p);
+        if (len <= 0) {
+            idcur = SIM_ID_NOT_WORD;
+            len = 1;
+        } else {
+            idcur = pstate->word_id;
+        }
+        int ambilen = getAmbiLen(p, len);
+
+        if (ambilen <= len) {
+            insertLatticeWord(lattice, TLatticeWord(i, i + len, idcur));
+            i += len;
+        } else {
+            fullSegBuildLattice(sntnc, i, ambilen, lattice);
+            i += ambilen;
+        }
+    }
+    lattice[sntnc.size()].m_wordstarting.push_back(TLatticeWord(sntnc.size(),
+                                                                sntnc.size() +
+                                                                1, s_iSTOKID));
+}
+
+void
+searchBest(CLattice& lattice)
+{
+    for (int i = 0, sz = lattice.size(); i < sz; ++i) {
+        TLatticeColumnStates & states = lattice[i].m_states;
+        TLatticeColumnStates::iterator itss = states.begin();
+        TLatticeColumnStates::iterator itse = states.end();
+        for (; itss != itse; ++itss) {
+            TLatticeWordVec::iterator itws = lattice[i].m_wordstarting.begin();
+            TLatticeWordVec::iterator itwe = lattice[i].m_wordstarting.end();
+            for (; itws != itwe; ++itws) {
+                CThreadSlm::TState his = itss->first;
+                double pr = itss->second.m_pr;
+                pr += s_tslm->transferNegLog(his, itws->m_wordId, his);
+                TLatticeColumnStates & rss = lattice[itws->m_right].m_states;
+                s_tslm->historify(his);
+                TLatticeColumnStates::iterator itn = rss.find(his);
+                if (itn == rss.end()) {
+                    rss[his] = TLatticeStateValue(pr, &(*itws), itss->first);
+                } else {
+                    if (itn->second.m_pr > pr) {
+                        rss[his] = TLatticeStateValue(pr, &(*itws), itss->first);
+                    }
+                }
+            }
+        }
+    }
+}
+
+void
+getBestPath(CLattice& lattice, TLatticeWordVec& segResult)
+{
+    TLatticeColumnStates & states = lattice.back().m_states;
+    TLatticeColumnStates::iterator its = states.begin();
+
+    TLatticeWord* pbtword = its->second.mp_btword;
+    CThreadSlm::TState btstate = its->second.m_btstate;
+    its = lattice[pbtword->m_left].m_states.find(btstate);
+    assert(its != lattice[pbtword->m_left].m_states.end());
+
+    segResult.clear();
+    while (true) {
+        pbtword = its->second.mp_btword;
+        if (pbtword != NULL) {
+#ifndef HOST_OS_GNUC_2
+            segResult.push_back(*pbtword);
+#else // HOST_OS_GNUC_2
+            segResult.insert(segResult.begin(), *pbtword);
+#endif // !HOST_OS_GNUC_2
+            btstate = its->second.m_btstate;
+            its = lattice[pbtword->m_left].m_states.find(btstate);
+            assert(its != lattice[pbtword->m_left].m_states.end());
+        } else {
+            break;
+        }
+    }
+#ifndef HOST_OS_GNUC_2
+    std::reverse(segResult.begin(), segResult.end());
+#endif // HOST_OS_GNUC_2
+}
+
+static bool
+processSingleFile(FILE* fp, int &nWords, int &nAmbis)
+{
+    nWords = 0;
+    nAmbis = 0;
+
+    wstring sntnc;
+    CSIMCharReader *pReader = new CSIMCharReader(fp);
+    CSIMCharReader::iterator iter = pReader->begin();
+    TSIMWordId idcur, idprev = s_iSTOKID;
+
+    if (!s_bTextOut)
+        output_stok(nWords);
+
+    while (true) {
+        if (ReadSentence(sntnc, iter, false) == false)
+            break;
+
+        CLattice lattice;
+        buildLattice(sntnc, lattice);
+        searchBest(lattice);
+
+        TLatticeWordVec segResult;
+        getBestPath(lattice, segResult);
+
+        for (int i = 0, sz = segResult.size(); i < sz; ++i) {
+            const TWCHAR *p = sntnc.c_str() + segResult[i].m_left;
+            int len = segResult[i].m_right - segResult[i].m_left;
+            idcur = segResult[i].m_wordId;
+
+            output(len, p, idprev, idcur, nWords);
+            idprev = idcur;
+        }
+
+        if (!s_bTextOut) {
+            output_stok(nWords);
+            idprev = s_iSTOKID;
+        }
+    }
+
+    fflush(stdout);
+    return true;
+}
+
+int
+main(int argc, char *argv[])
+{
+    int nWords, nAmbis;
+
+    setlocale(LC_ALL, "");
+    getParameters(argc, argv);
+    argc -= optind;
+    argv += optind;
+
+    fprintf(stderr, "Loading lexicon...");
+    fflush(stderr);
+    s_dict = new CSIMDict();
+    s_tslm = new CThreadSlm();
+    if (!s_dict->parseText(s_strDictFile)) {
+        fprintf(stderr, "fail to open Lexicon file!\n");
+        fflush(stderr);
+        exit(11);
+    }
+    if (!s_tslm->load(s_strSlmFile, true)) {
+        fprintf(stderr, "fail to open slm file!\n");
+        fflush(stderr);
+        exit(12);
+    }
+    fprintf(stderr, "done");
+    fflush(stderr);
+
+    if (argc == 0) {
+        fprintf(stderr, "\nProcessing from stdin...");
+        fflush(stderr);
+        processSingleFile(stdin, nWords, nAmbis);
+        fprintf(stderr, "%d words, %d ambiguious. Done!\n", nWords, nAmbis);
+        fflush(stderr);
+    } else {
+        for (int i = 0; i < argc; ++i) {
+            fprintf(stderr, "\nProcessing %s...", argv[i]); fflush(stderr);
+            FILE *fp = fopen(argv[i], "r");
+            if (fp != NULL) {
+                processSingleFile(fp, nWords, nAmbis);
+                fprintf(stderr, "@Offset %ld, %d words, %d ambiguious. Done!\n",
+                        ftell(fp), nWords, nAmbis);
+                fflush(stderr);
+            } else {
+                fprintf(stderr, "Can not Open!!!!!!!\n");
+                fflush(stderr);
+            }
+            fclose(fp);
+        }
+    }
+
+    s_tslm->free();
+    delete s_tslm;
+    s_tslm = NULL;
+    s_dict->close();
+    delete s_dict;
+    s_dict = NULL;
+    return 0;
+}
diff --git a/src/slm/thread/ValueCompress.cpp b/src/slm/thread/ValueCompress.cpp
new file mode 100644 (file)
index 0000000..220e619
--- /dev/null
@@ -0,0 +1,317 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright (c) 2007 Sun Microsystems, Inc. All Rights Reserved.
+ *
+ * The contents of this file are subject to the terms of either the GNU Lesser
+ * General Public License Version 2.1 only ("LGPL") or the Common Development and
+ * Distribution License ("CDDL")(collectively, the "License"). You may not use this
+ * file except in compliance with the License. You can obtain a copy of the CDDL at
+ * http://www.opensource.org/licenses/cddl1.php and a copy of the LGPLv2.1 at
+ * http://www.opensource.org/licenses/lgpl-license.php. See the License for the
+ * specific language governing permissions and limitations under the License. When
+ * distributing the software, include this License Header Notice in each file and
+ * include the full text of the License in the License file as well as the
+ * following notice:
+ *
+ * NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND DISTRIBUTION LICENSE
+ * (CDDL)
+ * For Covered Software in this distribution, this License shall be governed by the
+ * laws of the State of California (excluding conflict-of-law provisions).
+ * Any litigation relating to this License shall be subject to the jurisdiction of
+ * the Federal Courts of the Northern District of California and the state courts
+ * of the State of California, with venue lying in Santa Clara County, California.
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by only the CDDL or only
+ * the LGPL Version 2.1, indicate your decision by adding "[Contributor]" elects to
+ * include this software in this distribution under the [CDDL or LGPL Version 2.1]
+ * license." If you don't indicate a single choice of license, a recipient has the
+ * option to distribute your version of this file under either the CDDL or the LGPL
+ * Version 2.1, or to extend the choice of license to its licensees as provided
+ * above. However, if you add LGPL Version 2.1 code and therefore, elected the LGPL
+ * Version 2 license, then the option applies only if the new code is made subject
+ * to such option by the copyright holder.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdio.h>
+
+#include "ValueCompress.h"
+
+#ifdef HAVE_LIMIT_H
+#include <limit.h>
+#endif
+
+#ifndef DBL_MAX
+#define DBL_MAX (1E+300)
+#endif
+
+struct TVCArrItem {
+    float m_val;
+    unsigned m_heapIdx;
+
+    TVCArrItem(float val = 0.0, unsigned idx = 0)
+        : m_val(val), m_heapIdx(idx)
+    {
+    }
+};
+
+struct TVCHeapItem {
+    unsigned m_first;
+    unsigned m_last;
+    unsigned m_count;
+    double m_appval;
+    double m_sum;
+    double m_dist;
+
+    bool
+    operator<(const TVCHeapItem& b) const
+    {
+        return m_appval < b.m_appval;
+    }
+
+    TVCHeapItem(unsigned first = 0, unsigned last = 0, unsigned count = 0,
+                double val = 0.0, double sum = 0.0, double dist = 0.0)
+        : m_first(first), m_last(last), m_count(count),
+          m_appval(val), m_sum(sum), m_dist(dist)
+    {
+    }
+};
+
+typedef std::vector<TVCArrItem>     CVCArr;
+typedef std::vector<TVCHeapItem>    CVCHeap;
+
+
+static void
+BubbleUpVal(CVCHeap& heap, CVCArr& arr, int idx)
+{
+    while (idx > 0) {
+        int parent = (idx - 1) / 2;
+        if (heap[idx] < heap[parent])
+            break;
+        for (int h = heap[idx].m_first, t = heap[idx].m_last; h < t; ++h)
+            arr[h].m_heapIdx = parent;
+        for (int h = heap[parent].m_first, t = heap[parent].m_last; h < t; ++h)
+            arr[h].m_heapIdx = idx;
+        TVCHeapItem hitem = heap[parent];
+        heap[parent] = heap[idx];
+        heap[idx] = hitem;
+        idx = parent;
+    }
+}
+
+static void
+IronDownVal(CVCHeap& heap, CVCArr& arr, int idx, int bottom)
+{
+    int left;
+    while ((left = 2 * idx + 1) < bottom) {
+        int max = idx;
+        if (heap[max] < heap[left])
+            max = left;
+        if (left + 1 < bottom && heap[max] < heap[left + 1])
+            max = left + 1;
+        if (max == idx) break;
+
+        for (int h = heap[idx].m_first, t = heap[idx].m_last; h < t; ++h)
+            arr[h].m_heapIdx = max;
+        for (int h = heap[max].m_first, t = heap[max].m_last; h < t; ++h)
+            arr[h].m_heapIdx = idx;
+        TVCHeapItem hitem = heap[max];
+        heap[max] = heap[idx];
+        heap[idx] = hitem;
+
+        idx = max;
+    }
+}
+
+
+/**
+ * Bubble idx up according to distance
+ */
+static void
+BubbleUp(CVCHeap& heap, CVCArr& arr, int idx)
+{
+    while (idx > 0) {
+        int parent = (idx - 1) / 2;
+        if (heap[parent].m_dist <= heap[idx].m_dist)
+            break;
+        for (int h = heap[idx].m_first, t = heap[idx].m_last; h < t; ++h)
+            arr[h].m_heapIdx = parent;
+        for (int h = heap[parent].m_first, t = heap[parent].m_last; h < t; ++h)
+            arr[h].m_heapIdx = idx;
+        TVCHeapItem hitem = heap[parent];
+        heap[parent] = heap[idx];
+        heap[idx] = hitem;
+        idx = parent;
+    }
+}
+
+/**
+ * Iron idx down, but do not let it lower than bottom (< bottom)
+ */
+static void
+IronDown(CVCHeap& heap, CVCArr& arr, int idx, int bottom)
+{
+    int left;
+    while ((left = 2 * idx + 1) < bottom) {
+        int min = idx;
+        if (heap[left].m_dist < heap[min].m_dist)
+            min = left;
+        if (left + 1 < bottom && heap[left + 1].m_dist < heap[min].m_dist)
+            min = left + 1;
+        if (min == idx) break;
+
+        for (int h = heap[idx].m_first, t = heap[idx].m_last; h < t; ++h)
+            arr[h].m_heapIdx = min;
+        for (int h = heap[min].m_first, t = heap[min].m_last; h < t; ++h)
+            arr[h].m_heapIdx = idx;
+        TVCHeapItem hitem = heap[min];
+        heap[min] = heap[idx];
+        heap[idx] = hitem;
+
+        idx = min;
+    }
+}
+
+void
+CValueCompressor::operator()(std::map<float, int>& values,
+                             std::map<float, int>& map,
+                             std::vector<float>& table,
+                             unsigned N) const
+{
+    CVCArr arr;
+    CVCHeap heap;
+
+    std::map<float, int>::const_iterator itv = values.begin();
+    std::map<float, int>::const_iterator itve = values.end();
+    for (; itv != itve; ++itv) {
+        arr.push_back(TVCArrItem(itv->first, arr.size()));
+        double sum = double(itv->first);
+        if (itv->second > 0)
+            sum *= itv->second;
+        heap.push_back(TVCHeapItem(heap.size(), heap.size() + 1, itv->second,
+                                   itv->first, sum));
+    }
+
+    for (int i = 0, sz = heap.size() - 1; i < sz; ++i) {
+        if (heap[i].m_count == 0 || heap[i + 1].m_count == 0) {
+            heap[i].m_dist = DBL_MAX;
+        } else {
+            heap[i].m_dist = heap[i + 1].m_appval - heap[i].m_appval;
+        }
+        BubbleUp(heap, arr, i);
+    }
+    if (heap.size() > 0) {
+        heap[heap.size() - 1].m_dist = DBL_MAX;
+        BubbleUp(heap, arr, heap.size() - 1);
+    }
+
+    int cur, next, hiprev, hinext;
+
+    while (heap.size() > N) {
+        cur = heap[0].m_first;
+        if (cur == 0) {
+            hiprev = -1;
+        } else {
+            hiprev = arr[cur - 1].m_heapIdx;
+        }
+        next = heap[0].m_last;
+        hinext = arr[next].m_heapIdx;
+
+        for (int h = cur; h < next; ++h)
+            arr[h].m_heapIdx = hinext;
+        double newval = (heap[0].m_sum + heap[hinext].m_sum) /
+                        (heap[0].m_count + heap[hinext].m_count);
+        if (hiprev >= 0)
+            heap[hiprev].m_dist += (newval - heap[0].m_appval);
+        heap[hinext].m_first = heap[0].m_first;
+        heap[hinext].m_count += heap[0].m_count;
+        heap[hinext].m_sum += heap[0].m_sum;
+        heap[hinext].m_dist += (heap[hinext].m_appval - newval);
+        heap[hinext].m_appval = newval;
+
+        if (hiprev > hinext)
+            cur = hiprev, hiprev = hinext, hinext = cur;
+        IronDown(heap, arr, hinext, heap.size());
+        if (hiprev > 0)
+            IronDown(heap, arr, hiprev, heap.size());
+
+        heap[0] = heap[heap.size() - 1];
+        for (int h = heap[0].m_first, t = heap[0].m_last; h < t; ++h)
+            arr[h].m_heapIdx = 0;
+        heap.pop_back();
+        IronDown(heap, arr, 0, heap.size());
+    }
+
+    for (int i = 1, sz = heap.size(); i < sz; ++i)
+        BubbleUpVal(heap, arr, i);
+    for (int i = heap.size() - 1; i > 0; --i) {
+        for (int h = heap[0].m_first, t = heap[0].m_last; h < t; ++h)
+            arr[h].m_heapIdx = i;
+        for (int h = heap[i].m_first, t = heap[i].m_last; h < t; ++h)
+            arr[h].m_heapIdx = 0;
+        TVCHeapItem hitem = heap[0];
+        heap[0] = heap[i];
+        heap[i] = hitem;
+        IronDownVal(heap, arr, 0, i);
+    }
+
+    map.clear();
+    for (int i = 0, sz = arr.size(); i < sz; ++i)
+        map[arr[i].m_val] = arr[i].m_heapIdx;
+
+    table.clear();
+    table.reserve(heap.size());
+    for (int i = 0, sz = heap.size(); i < sz; ++i)
+        table.push_back(float(heap[i].m_appval));
+
+    /*
+       for (int i = 0, sz = heap.size(); i < sz; ++i) {
+        printf("%12lf:\n", heap[i].m_appval);
+        for (int h = heap[i].m_first, t = heap[i].m_last; h < t; ++h) {
+            printf("    %12f\n", arr[h].m_val);
+            if (arr[h].m_heapIdx != i) {
+                printf("error, non-consistence found\n");
+                return;
+            }
+        }
+        printf("\n");
+       }
+     */
+}
+
+
+void
+CValueCompressor::operator()(std::map<float, float>& eff2val,
+                             std::map<float, int>& values,
+                             std::map<float, int>& v2idx,
+                             std::vector<float>& table,
+                             unsigned N) const
+{
+    std::map<float, int> tmp_map;
+    this->operator()(values, tmp_map, table, N);
+
+    v2idx.clear();
+    std::map<float, int>::iterator itm = tmp_map.begin();
+    std::map<float, int>::iterator itme = tmp_map.end();
+    for (; itm != itme; ++itm) {
+        v2idx[eff2val[itm->first]] = itm->second;
+    }
+
+/* // Can not be maped back, because some value could not be in the eff2val maps
+    std::vector<float>::iterator itt = table.begin();
+    std::vector<float>::iterator itte = table.end();
+    for (; itt != itte; ++itt)
+   *itt = eff2val[*itt];
+ */
+}
+
+
+
+
+
diff --git a/src/slm/thread/ValueCompress.h b/src/slm/thread/ValueCompress.h
new file mode 100644 (file)
index 0000000..2c5621f
--- /dev/null
@@ -0,0 +1,73 @@
+// -*- mode: c++ -*-
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright (c) 2007 Sun Microsystems, Inc. All Rights Reserved.
+ *
+ * The contents of this file are subject to the terms of either the GNU Lesser
+ * General Public License Version 2.1 only ("LGPL") or the Common Development and
+ * Distribution License ("CDDL")(collectively, the "License"). You may not use this
+ * file except in compliance with the License. You can obtain a copy of the CDDL at
+ * http://www.opensource.org/licenses/cddl1.php and a copy of the LGPLv2.1 at
+ * http://www.opensource.org/licenses/lgpl-license.php. See the License for the
+ * specific language governing permissions and limitations under the License. When
+ * distributing the software, include this License Header Notice in each file and
+ * include the full text of the License in the License file as well as the
+ * following notice:
+ *
+ * NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND DISTRIBUTION LICENSE
+ * (CDDL)
+ * For Covered Software in this distribution, this License shall be governed by the
+ * laws of the State of California (excluding conflict-of-law provisions).
+ * Any litigation relating to this License shall be subject to the jurisdiction of
+ * the Federal Courts of the Northern District of California and the state courts
+ * of the State of California, with venue lying in Santa Clara County, California.
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by only the CDDL or only
+ * the LGPL Version 2.1, indicate your decision by adding "[Contributor]" elects to
+ * include this software in this distribution under the [CDDL or LGPL Version 2.1]
+ * license." If you don't indicate a single choice of license, a recipient has the
+ * option to distribute your version of this file under either the CDDL or the LGPL
+ * Version 2.1, or to extend the choice of license to its licensees as provided
+ * above. However, if you add LGPL Version 2.1 code and therefore, elected the LGPL
+ * Version 2 license, then the option applies only if the new code is made subject
+ * to such option by the copyright holder.
+ */
+
+#ifndef AGC_SUN_VALUE_COMPRESS_H
+#define AGC_SUN_VALUE_COMPRESS_H
+
+#include <map>
+#include <vector>
+
+class CValueCompressor {
+public:
+    /**
+     * N > 4
+     */
+    void
+    operator()(std::map<float, int>& values,
+               std::map<float, int>& map,
+               std::vector<float>& table,
+               unsigned N) const;
+
+/**
+ * used for using log as effective distance, vice versa.
+ * if using -log(a) as distance to compress value a, ie: a --> -log2(a),
+ * the val_rmap should be val_rmap[-log(a)] = a;
+ * values map using the effective distance value. But After this call
+ * map  using the real value, ie "a" in previous example. But table
+ * would be the weight-center for a group effective value, You should
+ * make it back to original values after this call.
+ */
+    void
+    operator()(std::map<float, float>& val_rmap,
+               std::map<float, int>& values,
+               std::map<float, int>& map,
+               std::vector<float>& table,
+               unsigned N) const;
+};
+
+#endif
diff --git a/src/slm/thread/slmthread.cpp b/src/slm/thread/slmthread.cpp
new file mode 100644 (file)
index 0000000..4aa6e38
--- /dev/null
@@ -0,0 +1,469 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright (c) 2007 Sun Microsystems, Inc. All Rights Reserved.
+ *
+ * The contents of this file are subject to the terms of either the GNU Lesser
+ * General Public License Version 2.1 only ("LGPL") or the Common Development and
+ * Distribution License ("CDDL")(collectively, the "License"). You may not use this
+ * file except in compliance with the License. You can obtain a copy of the CDDL at
+ * http://www.opensource.org/licenses/cddl1.php and a copy of the LGPLv2.1 at
+ * http://www.opensource.org/licenses/lgpl-license.php. See the License for the
+ * specific language governing permissions and limitations under the License. When
+ * distributing the software, include this License Header Notice in each file and
+ * include the full text of the License in the License file as well as the
+ * following notice:
+ *
+ * NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND DISTRIBUTION LICENSE
+ * (CDDL)
+ * For Covered Software in this distribution, this License shall be governed by the
+ * laws of the State of California (excluding conflict-of-law provisions).
+ * Any litigation relating to this License shall be subject to the jurisdiction of
+ * the Federal Courts of the Northern District of California and the state courts
+ * of the State of California, with venue lying in Santa Clara County, California.
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by only the CDDL or only
+ * the LGPL Version 2.1, indicate your decision by adding "[Contributor]" elects to
+ * include this software in this distribution under the [CDDL or LGPL Version 2.1]
+ * license." If you don't indicate a single choice of license, a recipient has the
+ * option to distribute your version of this file under either the CDDL or the LGPL
+ * Version 2.1, or to extend the choice of license to its licensees as provided
+ * above. However, if you add LGPL Version 2.1 code and therefore, elected the LGPL
+ * Version 2 license, then the option applies only if the new code is made subject
+ * to such option by the copyright holder.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifdef HAVE_ASSERT_H
+#include <assert.h>
+#endif
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+
+#include <vector>
+#include <map>
+#include <math.h>
+
+#include "../sim_slm.h"
+#include "../slm.h"
+
+#include "ValueCompress.h"
+
+class CSIMSlmWithIteration : public CSIMSlm {
+public:
+    struct TLevelIterator {
+        std::vector<int>    m_history;
+    };
+
+public:
+    int
+    getLevelSize(int lvl)
+    {
+        return sz[lvl];
+    }
+
+    int
+    getN()
+    {
+        return N;
+    }
+
+    void
+    getIdString(TLevelIterator& it, std::vector<TSIMWordId>& history);
+
+    void
+    beginLevelIteration(int lvl, TLevelIterator& it);
+
+    void
+    next(TLevelIterator& it);
+
+    bool
+    isEnd(TLevelIterator& it);
+
+    TLeaf*
+    getNodePtr(TLevelIterator& it);
+
+    int
+    findState(int n, TSIMWordId*hw);
+
+    void
+    findBackOffState(int n, TSIMWordId*hw, unsigned & bol, unsigned& bon);
+
+
+protected:
+    void
+    adjustIterator(TLevelIterator& it);
+};
+
+int
+CSIMSlmWithIteration::findState(int n, TSIMWordId*hw)
+{
+    if (n == 0) return 0;
+
+    int m = -1;
+    while (n > N) {
+        --n; ++hw;
+    }
+
+    void* pstate = ((TNode*)level[0]);
+    for (int lvl = 0; lvl < n && pstate != NULL; ++lvl) {
+        int h = ((TNode*)pstate)->child;
+        int t = (((TNode*)pstate) + 1)->child;
+        if (lvl == N - 1) {
+            TLeaf* p = (TLeaf*)level[lvl + 1];
+            pstate = (void*)binary_find_id(p + h, p + t, hw[lvl]);
+            m = (pstate != NULL) ? (((TLeaf*)pstate) - p) : (-1);
+        } else {
+            TNode* p = (TNode*)level[lvl + 1];
+            pstate = (void*)binary_find_id(p + h, p + t, hw[lvl]);
+            m = (pstate != NULL) ? (((TNode*)pstate) - p) : (-1);
+        }
+    }
+    return m;
+}
+
+void
+CSIMSlmWithIteration::findBackOffState(int n,
+                                       TSIMWordId*hw,
+                                       unsigned & bol,
+                                       unsigned& bon)
+{
+    while (n > 1) {
+        --n; ++hw;
+        int idx = findState(n, hw);
+        if (idx >= 0 && ((TNode*)(level[n]))[idx].child <
+            ((TNode*)(level[n]))[idx + 1].child) {
+            bol = n; bon = idx; return;
+        }
+    }
+    bol = bon = 0;
+    return;
+}
+
+void
+CSIMSlmWithIteration::getIdString(TLevelIterator& it,
+                                  std::vector<TSIMWordId>& history)
+{
+    history.clear();
+    for (int i = 1, tmp_sz = it.m_history.size(); i < tmp_sz; ++i) {
+        int idx = it.m_history[i];
+        if (i == N)
+            history.push_back(((TLeaf*)(level[i]))[idx].id);
+        else
+            history.push_back(((TNode*)(level[i]))[idx].id);
+    }
+}
+
+void
+CSIMSlmWithIteration::beginLevelIteration(int lvl, TLevelIterator& it)
+{
+    it.m_history.clear();
+    for (int i = 0, tmp_sz = lvl; i <= tmp_sz; ++i)
+        it.m_history.push_back(0);
+    adjustIterator(it);
+}
+
+void
+CSIMSlmWithIteration::next(TLevelIterator& it)
+{
+    ++(it.m_history.back());
+    adjustIterator(it);
+}
+
+bool
+CSIMSlmWithIteration::isEnd(TLevelIterator& it)
+{
+    return((it.m_history.back() + 1 >= sz[it.m_history.size() - 1]));
+}
+
+void
+CSIMSlmWithIteration::adjustIterator(TLevelIterator& it)
+{
+    int ch = it.m_history.back();
+    for (int i = it.m_history.size() - 2; i >= 0; --i) {
+        int len = sz[i];
+        int& parent = it.m_history[i];
+        TNode* pn = (TNode*)(level[i]);
+        while (parent < len && pn[parent + 1].child <= ch)
+            ++parent;
+        ch = parent;
+    }
+}
+
+CSIMSlm::TLeaf*
+CSIMSlmWithIteration::getNodePtr(TLevelIterator& it)
+{
+    int lvl = it.m_history.size() - 1;
+    int idx = it.m_history.back();
+    if (lvl == N)
+        return(((TLeaf*)(level[lvl])) + idx);
+    else
+        return(((TNode*)(level[lvl])) + idx);
+}
+
+
+
+void
+ShowUsage()
+{
+    printf("Usage:\n");
+    printf("    slmthread primitive_slm threaded_slm\n");
+    printf("\nDescription:\n");
+    printf(
+        "    slmthread add back-off-state for each slm node in the primitive_slm. ");
+    printf("Also it compresses 32-bit float into 16 bit representation.\n\n");
+    exit(100);
+}
+
+FILE* fp = NULL;
+CThreadSlm::TNode* levels[16];
+CThreadSlm::TLeaf* lastLevel;
+
+int
+main(int argc, char* argv[])
+{
+    CValueCompressor vc;
+    unsigned int bol, bon;
+    CSIMSlmWithIteration slm;
+    std::vector<TSIMWordId> history;
+    float real_pr, eff_pr, real_bow, eff_bow;
+
+    std::map<float, float> pr_eff, bow_eff;     // effval --> val
+    std::map<float, int> pr_values, bow_values; // effval --> freq
+    std::map<float, int> pr_map, bow_map;       // result: val --> int
+    std::vector<float>   pr_table, bow_table;   // result: val vector
+    std::vector<float>::iterator itt, itte;
+
+    if (argc != 3)
+        ShowUsage();
+
+    printf("Loading original slm..."); fflush(stdout);
+    if (slm.Load(argv[1]) == false)
+        ShowUsage();
+
+    bool usingLogPr = slm.isUseLogPr();
+
+    #define EffectivePr(a)  (float((usingLogPr) ? ((a) / log(2.0)) : (-log2((a)))))
+    #define OriginalPr(b)   (float((usingLogPr) ? ((b) * log(2.0)) : (exp2(-(b)))))
+    #define EffectiveBow(a) (float((usingLogPr) ? (exp(-(a))) : ((a))))
+    #define OriginalBow(b)  (float((usingLogPr) ? (-log((b))) : ((b))))
+
+    printf("\nfirst pass..."); fflush(stdout);
+    for (int lvl = 0; lvl <= slm.getN(); ++lvl) {
+        CSIMSlmWithIteration::TLevelIterator it;
+        slm.beginLevelIteration(lvl, it);
+        for (; !slm.isEnd(it); slm.next(it)) {
+            CSIMSlm::TLeaf* pl = slm.getNodePtr(it);
+            real_pr = pl->pr;
+            eff_pr = EffectivePr(real_pr);
+            if (pr_eff.find(eff_pr) == pr_eff.end()) {
+                pr_eff[eff_pr] = real_pr;
+            } else { // precision error cause non 1:1 mapping
+                pr_eff[eff_pr] = OriginalPr(eff_pr);
+            }
+            ++(pr_values[eff_pr]);
+            if (lvl < slm.getN()) {
+                real_bow = ((CSIMSlm::TNode*)pl)->bow;
+                eff_bow = EffectiveBow(real_bow);
+                if (bow_eff.find(eff_bow) == bow_eff.end()) {
+                    bow_eff[eff_bow] = real_bow;
+                } else { // two values map to same distance value due to precision error
+                    bow_eff[eff_bow] = OriginalBow(eff_bow);
+                }
+                ++(bow_values[eff_bow]);
+            }
+        }
+    }
+
+    // Following pr value should not be grouped, or as milestone values.
+    static float msprs[] = {
+        0.9, 0.8, 0.7, 0.6,
+        1.0 / 2, 1.0 / 4, 1.0 / 8, 1.0 / 16, 1.0 / 32, 1.0 / 64, 1.0 / 128,
+        1.0 / 256, 1.0 / 512, 1.0 / 1024, 1.0 / 2048, 1.0 / 4096, 1.0 / 8192,
+        1.0 / 16384, 1.0 / 32768, 1.0 / 65536
+    };
+
+    for (unsigned i = 0, sz = sizeof(msprs) / sizeof(float); i < sz; ++i) {
+        float real_pr = (usingLogPr) ? (-log(msprs[i])) : (msprs[i]);
+        float eff_pr = EffectivePr(real_pr);
+        if (pr_eff.find(eff_pr) == pr_eff.end()) {
+            pr_eff[eff_pr] = real_pr;
+        } else { // precision error cause non 1:1 mapping
+            pr_eff[eff_pr] = OriginalPr(eff_pr);
+        }
+        pr_values[eff_pr] = 0;
+    }
+
+    // Following bow value should not be grouped, or as milestone values.
+    static float msbows[] = {
+        1.0, 0.9, 0.8, 0.7, 0.6, 0.5, 0.4, 0.3, 0.2,
+        0.1, 0.05, 0.01, 0.005, 0.001, 0.0005, 0.0001,
+        0.00005, 0.00001, 0.000005, 0.000001, 0.0000005, 0.0000001
+    };
+
+    for (unsigned i = 0, sz = sizeof(msbows) / sizeof(float); i < sz; ++i) {
+        float real_bow = (usingLogPr) ? (-log(msbows[i])) : (msbows[i]);
+        float eff_bow = EffectiveBow(real_bow);
+        if (bow_eff.find(eff_bow) == bow_eff.end()) {
+            bow_eff[eff_bow] = real_bow;
+        } else { // two values map to same distance value due to precision error
+            bow_eff[eff_bow] = OriginalBow(eff_bow);
+        }
+        bow_values[eff_bow] = 0;
+    }
+
+    printf("\nCompressing pr values..."); fflush(stdout);
+    vc(pr_eff, pr_values, pr_map, pr_table, (1 << CThreadSlm::BITS_PR));
+    pr_values.clear();
+    itte = pr_table.end();
+    for (itt = pr_table.begin(); itt != itte; ++itt) {
+        *itt = OriginalPr(*itt);
+        assert(usingLogPr || (*itt > 0.0 && *itt < 1.0));
+        assert(!usingLogPr || *itt > 0.0);
+    }
+    printf("%lu float values ==> %lu values", pr_eff.size(), pr_table.size());
+
+    printf("\nCompressing bow values..."); fflush(stdout);
+    vc(bow_eff, bow_values, bow_map, bow_table, (1 << CThreadSlm::BITS_BOW));
+    bow_values.clear();
+    itte = bow_table.end();
+    for (itt = bow_table.begin(); itt != itte; ++itt)
+        *itt = OriginalBow(*itt);
+    printf("%lu float values ==> %lu values", bow_eff.size(), bow_table.size());
+
+
+    printf("\nThreading the new model..."); fflush(stdout);
+    for (int lvl = 0; lvl < slm.getN(); ++lvl) {
+        levels[lvl] = new CThreadSlm::TNode[slm.getLevelSize(lvl)];
+
+        CSIMSlmWithIteration::TLevelIterator it;
+        slm.beginLevelIteration(lvl, it);
+        for (; !slm.isEnd(it); slm.next(it)) {
+            slm.getIdString(it, history);
+            if (history.size() == 0) {
+                slm.findBackOffState(lvl, NULL, bol, bon);
+            } else {
+                slm.findBackOffState(lvl, &history[0], bol, bon);
+            }
+
+            CSIMSlm::TNode* pn = (CSIMSlm::TNode*)slm.getNodePtr(it);
+            CThreadSlm::TNode& nn = levels[lvl][it.m_history.back()];
+
+            std::map<float, int>::iterator prit = pr_map.find(pn->pr);
+            if (prit == pr_map.end()) { // This would be cause by precision error
+                double val = EffectivePr(pn->pr);
+                val = OriginalPr(val);
+                prit = pr_map.find(val);
+                assert(prit != pr_map.end());
+            }
+            int idx_pr = prit->second;
+            nn.set_pr(idx_pr);
+
+            nn.set_wid(pn->id);
+            nn.set_bon(bon);
+            nn.set_bol(bol);
+
+            std::map<float, int>::iterator bowit = bow_map.find(pn->bow);
+            if (bowit == bow_map.end()) { // precision error
+                double val = EffectiveBow(pn->bow);
+                val = OriginalBow(val);
+                bowit = bow_map.find(val);
+                assert(bowit != bow_map.end());
+            }
+            int idx_bow = bowit->second;
+            nn.set_bow(idx_bow);
+
+            nn.set_ch(pn->child);
+
+            assert(usingLogPr ||
+                   (pr_table[idx_pr] > 0.0 && pr_table[idx_pr] < 1.0));
+            assert(!usingLogPr || pr_table[idx_pr] > 0.0);
+        }
+        CSIMSlm::TNode* pn = (CSIMSlm::TNode*)slm.getNodePtr(it);
+        CThreadSlm::TNode& nn = levels[lvl][it.m_history.back()];
+        nn.set_ch(pn->child);
+    }
+    ;
+
+
+    lastLevel = new CThreadSlm::TLeaf [slm.getLevelSize(slm.getN())];
+    CSIMSlmWithIteration::TLevelIterator it;
+    slm.beginLevelIteration(slm.getN(), it);
+    for (int lvl = slm.getN(); !slm.isEnd(it); slm.next(it)) {
+        CSIMSlm::TLeaf* pn = slm.getNodePtr(it);
+        slm.getIdString(it, history);
+        slm.findBackOffState(lvl, &history[0], bol, bon);
+
+        CThreadSlm::TLeaf& nn = lastLevel[it.m_history.back()];
+
+        std::map<float, int>::iterator prit = pr_map.find(pn->pr);
+        if (prit == pr_map.end()) { // This would be cause by precision error
+            double val = EffectivePr(pn->pr);
+            val = OriginalPr(val);
+            prit = pr_map.find(val);
+            assert(prit != pr_map.end());
+        }
+        int idx_pr = prit->second;
+        nn.set_pr(idx_pr);
+
+        nn.set_wid(pn->id);
+        nn.set_bon(bon);
+        nn.set_bol(bol);
+    }
+
+
+    printf("\nWriting out..."); fflush(stdout);
+
+    float dummy = 0.0;
+    fp = fopen(argv[2], "wb");
+    int N = slm.getN();
+    fwrite(&N, sizeof(int), 1, fp);
+    unsigned ulp = slm.isUseLogPr();
+    fwrite(&ulp, sizeof(unsigned), 1, fp);
+
+    for (int lvl = 0; lvl <= N; ++lvl) {
+        int len = slm.getLevelSize(lvl);
+        fwrite(&len, sizeof(int), 1, fp);
+    }
+    fwrite(&pr_table[0], sizeof(float), pr_table.size(), fp);
+    for (int i = pr_table.size(), sz = (1 << CThreadSlm::BITS_PR); i < sz; ++i)
+        fwrite(&dummy, sizeof(float), 1, fp);
+
+    fwrite(&bow_table[0], sizeof(float), bow_table.size(), fp);
+    for (int i = bow_table.size(), sz = (1 << CThreadSlm::BITS_BOW);
+         i < sz;
+         ++i)
+        fwrite(&dummy, sizeof(float), 1, fp);
+
+    for (int lvl = 0; lvl < N; ++lvl)
+        fwrite(levels[lvl], sizeof(CThreadSlm::TNode), slm.getLevelSize(
+                   lvl), fp);
+    fwrite(lastLevel, sizeof(CThreadSlm::TLeaf), slm.getLevelSize(N), fp);
+    fclose(fp);
+
+    printf("done!\n"); fflush(stdout);
+
+    delete [] lastLevel;
+    for (int lvl = 0; lvl < N; ++lvl)
+        delete [] levels[lvl];
+
+    bow_values.clear();
+    bow_map.clear();
+    bow_table.clear();
+
+    pr_values.clear();
+    pr_map.clear();
+    pr_table.clear();
+
+    slm.Free();
+
+
+    return 0;
+}
diff --git a/src/slm/thread/test_vc.cpp b/src/slm/thread/test_vc.cpp
new file mode 100644 (file)
index 0000000..8475a1a
--- /dev/null
@@ -0,0 +1,97 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright (c) 2007 Sun Microsystems, Inc. All Rights Reserved.
+ *
+ * The contents of this file are subject to the terms of either the GNU Lesser
+ * General Public License Version 2.1 only ("LGPL") or the Common Development and
+ * Distribution License ("CDDL")(collectively, the "License"). You may not use this
+ * file except in compliance with the License. You can obtain a copy of the CDDL at
+ * http://www.opensource.org/licenses/cddl1.php and a copy of the LGPLv2.1 at
+ * http://www.opensource.org/licenses/lgpl-license.php. See the License for the
+ * specific language governing permissions and limitations under the License. When
+ * distributing the software, include this License Header Notice in each file and
+ * include the full text of the License in the License file as well as the
+ * following notice:
+ *
+ * NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND DISTRIBUTION LICENSE
+ * (CDDL)
+ * For Covered Software in this distribution, this License shall be governed by the
+ * laws of the State of California (excluding conflict-of-law provisions).
+ * Any litigation relating to this License shall be subject to the jurisdiction of
+ * the Federal Courts of the Northern District of California and the state courts
+ * of the State of California, with venue lying in Santa Clara County, California.
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by only the CDDL or only
+ * the LGPL Version 2.1, indicate your decision by adding "[Contributor]" elects to
+ * include this software in this distribution under the [CDDL or LGPL Version 2.1]
+ * license." If you don't indicate a single choice of license, a recipient has the
+ * option to distribute your version of this file under either the CDDL or the LGPL
+ * Version 2.1, or to extend the choice of license to its licensees as provided
+ * above. However, if you add LGPL Version 2.1 code and therefore, elected the LGPL
+ * Version 2 license, then the option applies only if the new code is made subject
+ * to such option by the copyright holder.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifdef HAVE_ASSERT_H
+#include <assert.h>
+#endif
+
+#ifdef HAVE_GETOPT_H
+#include <getopt.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "ValueCompress.h"
+
+
+std::map<float, int> values;
+std::map<float, int> mapper;
+std::vector<float>   table;
+
+int
+main(int argc, char* argv[])
+{
+    srand(1024);
+    values[0.0] = 0;
+    values[1e-10] = 0;
+    values[1e-9] = 0;
+    values[1e-8] = 0;
+    values[1e-7] = 0;
+    values[1e-6] = 0;
+    values[1e-5] = 0;
+    values[1e-4] = 0;
+    values[1e-3] = 0;
+    values[1e-2] = 0;
+    values[1e-1] = 0;
+    values[3.0] = 1;
+    values[4.0] = 1;
+    values[5.0] = 1;
+    for (int i = 4; i < 4 * 65536; ++i) {
+        unsigned int r = rand();
+        float v = 2.0 * (float)r / (float)RAND_MAX;
+        values[v] = int(1 + (1000.0 * rand()) / RAND_MAX);
+    }
+
+    CValueCompressor vc;
+    vc(values, mapper, table, 4096);
+
+    std::map<float, int>::iterator it, ite = mapper.end();
+    for (it = mapper.begin(); it != ite; ++it) {
+        printf("%d of %15.12f ---> %d ---> %15.12f\n",
+               values[it->first],
+               it->first,
+               it->second,
+               table[it->second]);
+    }
+
+    return 0;
+}
diff --git a/src/slm/tools/clean_rmrb.cpp b/src/slm/tools/clean_rmrb.cpp
new file mode 100644 (file)
index 0000000..0d7bd36
--- /dev/null
@@ -0,0 +1,94 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright (c) 2007 Sun Microsystems, Inc. All Rights Reserved.
+ *
+ * The contents of this file are subject to the terms of either the GNU Lesser
+ * General Public License Version 2.1 only ("LGPL") or the Common Development and
+ * Distribution License ("CDDL")(collectively, the "License"). You may not use this
+ * file except in compliance with the License. You can obtain a copy of the CDDL at
+ * http://www.opensource.org/licenses/cddl1.php and a copy of the LGPLv2.1 at
+ * http://www.opensource.org/licenses/lgpl-license.php. See the License for the
+ * specific language governing permissions and limitations under the License. When
+ * distributing the software, include this License Header Notice in each file and
+ * include the full text of the License in the License file as well as the
+ * following notice:
+ *
+ * NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND DISTRIBUTION LICENSE
+ * (CDDL)
+ * For Covered Software in this distribution, this License shall be governed by the
+ * laws of the State of California (excluding conflict-of-law provisions).
+ * Any litigation relating to this License shall be subject to the jurisdiction of
+ * the Federal Courts of the Northern District of California and the state courts
+ * of the State of California, with venue lying in Santa Clara County, California.
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by only the CDDL or only
+ * the LGPL Version 2.1, indicate your decision by adding "[Contributor]" elects to
+ * include this software in this distribution under the [CDDL or LGPL Version 2.1]
+ * license." If you don't indicate a single choice of license, a recipient has the
+ * option to distribute your version of this file under either the CDDL or the LGPL
+ * Version 2.1, or to extend the choice of license to its licensees as provided
+ * above. However, if you add LGPL Version 2.1 code and therefore, elected the LGPL
+ * Version 2 license, then the option applies only if the new code is made subject
+ * to such option by the copyright holder.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifdef HAVE_ASSERT_H
+#include <assert.h>
+#endif
+
+#ifdef HAVE_GETOPT_H
+#include <getopt.h>
+#endif
+
+#include <stdio.h>
+
+// erase 0xff character
+// return true for empty line(only space)
+bool
+processline(unsigned char * buf)
+{
+    bool space = true;
+    unsigned char *dst = buf;
+    while (*buf != 0) {
+        if ((unsigned int)*buf == 0xFF || (unsigned int)*buf ==
+            (unsigned int)'\n') {
+            ++buf; continue;
+        }
+        if ((unsigned int)*buf == 0x80 && (unsigned int)*(buf + 1) == 0x20) {
+            ++buf; continue;
+        }
+        if (space && (unsigned int)*buf != (unsigned int)' ' &&
+            (unsigned int)*buf != (unsigned int)'\t')
+            space = false;
+        *dst++ = *buf++;
+    }
+    *dst = *buf;
+    return space;
+}
+
+int
+main(int argc, char *argv[])
+{
+    unsigned char buf[10240];
+    for (int i = 1; i < argc; ++i) {
+        FILE *fp = fopen(argv[i], "r");
+        while (fgets((char*)buf, sizeof(buf), fp) != NULL) {
+            bool emptyline = processline(buf);
+            if ((unsigned int)buf[0] == '#' || (unsigned int)buf[0] == '0')
+                continue;
+            if (emptyline)
+                printf("\n");
+            else
+                printf("%s", buf);
+        }
+        fclose(fp);
+        printf("\n");
+    }
+}
diff --git a/src/slm/tools/dumpdict.cpp b/src/slm/tools/dumpdict.cpp
new file mode 100644 (file)
index 0000000..75b9171
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright (c) 2007 Sun Microsystems, Inc. All Rights Reserved.
+ *
+ * The contents of this file are subject to the terms of either the GNU Lesser
+ * General Public License Version 2.1 only ("LGPL") or the Common Development and
+ * Distribution License ("CDDL")(collectively, the "License"). You may not use this
+ * file except in compliance with the License. You can obtain a copy of the CDDL at
+ * http://www.opensource.org/licenses/cddl1.php and a copy of the LGPLv2.1 at
+ * http://www.opensource.org/licenses/lgpl-license.php. See the License for the
+ * specific language governing permissions and limitations under the License. When
+ * distributing the software, include this License Header Notice in each file and
+ * include the full text of the License in the License file as well as the
+ * following notice:
+ *
+ * NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND DISTRIBUTION LICENSE
+ * (CDDL)
+ * For Covered Software in this distribution, this License shall be governed by the
+ * laws of the State of California (excluding conflict-of-law provisions).
+ * Any litigation relating to this License shall be subject to the jurisdiction of
+ * the Federal Courts of the Northern District of California and the state courts
+ * of the State of California, with venue lying in Santa Clara County, California.
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by only the CDDL or only
+ * the LGPL Version 2.1, indicate your decision by adding "[Contributor]" elects to
+ * include this software in this distribution under the [CDDL or LGPL Version 2.1]
+ * license." If you don't indicate a single choice of license, a recipient has the
+ * option to distribute your version of this file under either the CDDL or the LGPL
+ * Version 2.1, or to extend the choice of license to its licensees as provided
+ * above. However, if you add LGPL Version 2.1 code and therefore, elected the LGPL
+ * Version 2 license, then the option applies only if the new code is made subject
+ * to such option by the copyright holder.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifdef HAVE_ASSERT_H
+#include <assert.h>
+#endif
+
+#ifdef HAVE_GETOPT_H
+#include <getopt.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <locale.h>
+
+#include "../sim_dict.h"
+
+void
+ShowUsage()
+{
+    fprintf(stderr, "Usage:\n    dumpdict dict_file\n");
+    fprintf(
+        stderr,
+        "Description:\n    This program read a plain text dict_file into internal binary format and print it out. For testing.\n");
+    exit(1000);
+}
+
+int
+main(int argc, char* argv[])
+{
+    setlocale(LC_ALL, "");
+    if (argc != 2) ShowUsage();
+    CSIMDict dict;
+    dict.parseText(argv[1]);
+    dict.PrintOut(stdout);
+    dict.close();
+    return 0;
+}
diff --git a/src/slm/tslmendian/slm_endian.cpp b/src/slm/tslmendian/slm_endian.cpp
new file mode 100644 (file)
index 0000000..94988d3
--- /dev/null
@@ -0,0 +1,138 @@
+/*
+ * Copyright (c) 2009 Kov Chai <tchaikov@gmail.com>
+ *
+ * The contents of this file are subject to the terms of either the GNU Lesser
+ * General Public License Version 2.1 only ("LGPL") or the Common Development and
+ * Distribution License ("CDDL")(collectively, the "License"). You may not use this
+ * file except in compliance with the License. You can obtain a copy of the CDDL at
+ * http://www.opensource.org/licenses/cddl1.php and a copy of the LGPLv2.1 at
+ * http://www.opensource.org/licenses/lgpl-license.php. See the License for the
+ * specific language governing permissions and limitations under the License. When
+ * distributing the software, include this License Header Notice in each file and
+ * include the full text of the License in the License file as well as the
+ * following notice:
+ *
+ * NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND DISTRIBUTION LICENSE
+ * (CDDL)
+ * For Covered Software in this distribution, this License shall be governed by the
+ * laws of the State of California (excluding conflict-of-law provisions).
+ * Any litigation relating to this License shall be subject to the jurisdiction of
+ * the Federal Courts of the Northern District of California and the state courts
+ * of the State of California, with venue lying in Santa Clara County, California.
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by only the CDDL or only
+ * the LGPL Version 2.1, indicate your decision by adding "[Contributor]" elects to
+ * include this software in this distribution under the [CDDL or LGPL Version 2.1]
+ * license." If you don't indicate a single choice of license, a recipient has the
+ * option to distribute your version of this file under either the CDDL or the LGPL
+ * Version 2.1, or to extend the choice of license to its licensees as provided
+ * above. However, if you add LGPL Version 2.1 code and therefore, elected the LGPL
+ * Version 2 license, then the option applies only if the new code is made subject
+ * to such option by the copyright holder.
+ */
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <assert.h>
+#include "slm_file.h"
+#include "writer.h"
+
+void
+ShowUsage(const char* progname)
+{
+    printf("Usage:\n");
+    printf(
+        "    %s [-v] [-e endian] [-i <input-lm-file>] [-o <output-lm-file>]\n",
+        progname);
+    printf("\n");
+    printf("Description:\n");
+    printf(
+        "    %s converts the binary language model files used by SunPinyin from big-endian to small-endian or vice versa.\n",
+        progname);
+    printf("\nOptions:\n");
+    printf(
+        "    -v                   # print out the endian-ness of <input-lm-file>.\n");
+    printf(
+        "    -e endian            # the endian-ness of <output-lm-file>. It can be either \"be\" or \"le\".\n");
+    printf("    -i <input-lm-file>   # input file name, e.g. lm_sc.t3g\n");
+    printf(
+        "    -o <output-lm-file>  # converted output file name. the endian-ness is of host by default.\n");
+
+    exit(100);
+}
+
+void
+showEndian(const CThreadSlmFile& slm_file)
+{
+    int endian = slm_file.getEndian();
+    printf("%s\n", endian2str(endian));
+}
+
+int
+convert(CThreadSlmFile& slm_file, const char* output, int endian)
+{
+    printf("converting from %s to %s ...",
+           endian2str(slm_file.getEndian()),
+           endian2str(endian));
+
+    size_t nwritten = slm_file.save(output, endian);
+    if (nwritten != slm_file.size()) {
+        fprintf(stderr,
+                "\nfailed to write %s. %zu/%zu bytes written.\n",
+                output,
+                nwritten,
+                slm_file.size());
+        return 1;
+    }
+    printf("done.\n");
+    return 0;
+}
+
+int
+main(int argc, char* argv[])
+{
+    int opt;
+    int endian = CThreadSlmFile::getHostEndian();
+
+    bool opt_info = false;
+    const char* input = NULL;
+    const char* output = NULL;
+    while ((opt = getopt(argc, argv, "e:i:o:v")) != -1) {
+        switch (opt) {
+        case 'e':
+            endian = parse_endian(optarg);
+            break;
+        case 'v':
+            opt_info = true;
+            break;
+        case 'i':
+            input = optarg;
+            break;
+        case 'o':
+            output = optarg;
+            break;
+        }
+    }
+
+    CThreadSlmFile slm_file;
+    if (!input) {
+        ShowUsage(argv[0]);
+    }
+    if (!slm_file.load(input)) {
+        fprintf(stderr, "failed to parse %s. corrupt file?\n", input);
+        return 1;
+    }
+    if (opt_info) {
+        showEndian(slm_file);
+    }
+    if (output) {
+        if (endian == -1) {
+            ShowUsage(argv[0]);
+        } else {
+            return convert(slm_file, output, endian);
+        }
+    }
+    return 0;
+}
diff --git a/src/slm/tslmendian/slm_file.cpp b/src/slm/tslmendian/slm_file.cpp
new file mode 100644 (file)
index 0000000..cd36264
--- /dev/null
@@ -0,0 +1,323 @@
+/*
+ * Copyright (c) 2009 Kov Chai <tchaikov@gmail.com>
+ *
+ * The contents of this file are subject to the terms of either the GNU Lesser
+ * General Public License Version 2.1 only ("LGPL") or the Common Development and
+ * Distribution License ("CDDL")(collectively, the "License"). You may not use this
+ * file except in compliance with the License. You can obtain a copy of the CDDL at
+ * http://www.opensource.org/licenses/cddl1.php and a copy of the LGPLv2.1 at
+ * http://www.opensource.org/licenses/lgpl-license.php. See the License for the
+ * specific language governing permissions and limitations under the License. When
+ * distributing the software, include this License Header Notice in each file and
+ * include the full text of the License in the License file as well as the
+ * following notice:
+ *
+ * NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND DISTRIBUTION LICENSE
+ * (CDDL)
+ * For Covered Software in this distribution, this License shall be governed by the
+ * laws of the State of California (excluding conflict-of-law provisions).
+ * Any litigation relating to this License shall be subject to the jurisdiction of
+ * the Federal Courts of the Northern District of California and the state courts
+ * of the State of California, with venue lying in Santa Clara County, California.
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by only the CDDL or only
+ * the LGPL Version 2.1, indicate your decision by adding "[Contributor]" elects to
+ * include this software in this distribution under the [CDDL or LGPL Version 2.1]
+ * license." If you don't indicate a single choice of license, a recipient has the
+ * option to distribute your version of this file under either the CDDL or the LGPL
+ * Version 2.1, or to extend the choice of license to its licensees as provided
+ * above. However, if you add LGPL Version 2.1 code and therefore, elected the LGPL
+ * Version 2 license, then the option applies only if the new code is made subject
+ * to such option by the copyright holder.
+ */
+
+/*
+ * the layout of binary file
+ * - N : uin23_t
+ * - usingLogPr : uint32_t
+ * - slm.getLevelSize(0..N) : uint32_t * N
+ * - pr_table() : float * 1<<CThreadSlm::BITS_PR    # padding with 0.0F
+ * - bow_table() : float * 1 <<CThreadSlm::BITS_BOW # padding with 0.0F
+ * - node[0][] : CThreadSlm::TNode * slm.getLevelSize(0)
+ * - node[1][] : CThreadSlm::TNode * slm.getLevelSize(1)
+ * - ...
+ * - node[N-1][] : CThreadSlm::TNode * slm.getLevelSize(N-1)
+ * - leaf[N-1][] : CThreadSlm::TLeaf * slm.getLevelSize(N)
+ */
+
+#include <arpa/inet.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <numeric>
+#include <algorithm>
+#include <iostream>
+#include <cassert>
+
+
+#include "slm_file.h"
+#include "writer.h"
+
+using namespace std;
+
+// for convenience
+typedef CThreadSlm::TNode TNode;
+typedef CThreadSlm::TLeaf TLeaf;
+
+// byte order reversed CThreadSlm::TLeaf small-endian presentation on big-endian machine
+// 5-bits padding before m_pr_lo so that m_pr_lo is 4-byte aligned
+//
+// would be easier if m_bon is 28 bits long
+struct Leaf_BE {
+    unsigned m_wid       : 18;
+    unsigned m_pr_lo     : 14;
+    unsigned padding     : 5;
+    unsigned m_bon       : 23;
+    unsigned m_bol       : 2;
+    unsigned m_pr_hi     : 2;
+};
+
+CThreadSlm::TLeaf
+leaf_betole(const CThreadSlm::TLeaf& v)
+{
+    // since the CThreadSlm::TLeaf `protects' its bits, we duplicated a `public' one
+    struct Leaf_LE_ {
+        unsigned m_wid       : 18;
+        unsigned m_pr_lo     : 14;
+        unsigned m_bon       : 23;
+        unsigned m_bol       : 2;
+        unsigned m_pr_hi     : 2;
+    };
+
+    Leaf_BE be_leaf = change_byte_order(*(Leaf_BE*)(&v));
+    be_leaf.padding = 0;
+
+    TLeaf leaf;
+    Leaf_LE_* le_leaf = (Leaf_LE_*)(&leaf);
+    le_leaf->m_wid = be_leaf.m_wid;
+    le_leaf->m_pr_lo = be_leaf.m_pr_lo;
+    le_leaf->m_bon = be_leaf.m_bon;
+    le_leaf->m_bol = be_leaf.m_bol;
+    le_leaf->m_pr_hi = be_leaf.m_pr_hi;
+    return leaf;
+}
+
+// byte order reversed little-endian presentation
+// 5-bits padding at end of struct
+struct Leaf_LE_ {
+    unsigned padding     : 5;
+    unsigned m_pr_hi     : 2;
+    unsigned m_bol       : 2;
+    unsigned m_bon       : 23;
+    unsigned m_pr_lo     : 14;
+    unsigned m_wid       : 18;
+};
+
+TLeaf
+leaf_letobe(const TLeaf& v)
+{
+    // since the TLeaf `protects' its bits, we duplicated a `public' one
+    struct Leaf_BE_ {
+        unsigned m_pr_hi     : 2;
+        unsigned m_bol       : 2;
+        unsigned m_bon       : 23;
+        unsigned m_pr_lo     : 14;
+        unsigned m_wid       : 18;
+    };
+
+
+    Leaf_LE_ le_leaf = change_byte_order(*(Leaf_LE_*)(&v));
+    le_leaf.padding = 0;
+
+    TLeaf leaf;
+    Leaf_BE_* be_leaf = (Leaf_BE_*)(&leaf);
+    be_leaf->m_wid = le_leaf.m_wid;
+    be_leaf->m_pr_lo = le_leaf.m_pr_lo;
+    be_leaf->m_bon = le_leaf.m_bon;
+    be_leaf->m_bol = le_leaf.m_bol;
+    be_leaf->m_pr_hi = le_leaf.m_pr_hi;
+    return leaf;
+}
+
+template<typename Type>
+Type
+read_value(char*& buf, bool do_swap)
+{
+    Type v = *(Type*)buf;
+    if (do_swap) {
+        v = change_byte_order(v);
+    }
+    buf += sizeof(v);
+    return v;
+}
+
+// change the byte order of all elements in the array in place
+template<typename Type>
+Type*
+read_values(char*& buf, size_t len, bool do_swap)
+{
+    Type* begin = (Type*)buf;
+    Type* end = begin + len;
+
+    if (do_swap) {
+        for (Type* p = begin; p != end; ++p) {
+            *p = change_byte_order(*p);
+        }
+    }
+    buf = (char*)end;
+    return begin;
+}
+
+
+typedef TLeaf (*convert_func_t)(const TLeaf&);
+
+template<>
+TLeaf* read_values<TLeaf
+                   >(char*& buf, size_t len, bool do_swap)
+{
+    TLeaf* begin = (TLeaf*)buf;
+    TLeaf* end = begin + len;
+    convert_func_t convert =
+        (CThreadSlmFile::getHostEndian() ==
+         BIG_ENDIAN) ? leaf_letobe : leaf_betole;
+
+    if (do_swap) {
+        for (TLeaf* p = begin; p != end; ++p) {
+            *p = convert(*p);
+        }
+    }
+    buf = (char*)end;
+    return begin;
+}
+
+template<typename Type>
+size_t
+write_value(FILE* fp, const Type& value, bool do_swap)
+{
+    Type v = value;
+    if (do_swap) {
+        v = change_byte_order(v);
+    }
+    return fwrite(&v, sizeof(v), 1, fp) * sizeof(v);
+}
+
+template<typename Type>
+size_t
+write_values(FILE* fp, Type* const begin, size_t len, bool do_swap)
+{
+    const Type* end = begin + len;
+    if (do_swap) {
+        for (Type* p = begin; p != end; ++p) {
+            *p = change_byte_order(*p);
+        }
+    }
+    return fwrite(begin, sizeof(Type), end - begin, fp) * sizeof(Type);
+}
+
+template<>
+size_t write_values<TLeaf
+                    >(FILE* fp, TLeaf* const begin, size_t len, bool do_swap)
+{
+    const TLeaf* end = begin + len;
+    convert_func_t convert =
+        (CThreadSlmFile::getHostEndian() ==
+         BIG_ENDIAN) ? leaf_betole : leaf_letobe;
+    if (do_swap) {
+        for (TLeaf* p = begin; p != end; ++p) {
+            *p = convert(*p);
+        }
+    }
+    return fwrite(begin, sizeof(TLeaf), end - begin, fp) * sizeof(TLeaf);
+}
+
+CThreadSlmFile::CThreadSlmFile()
+    : m_buf(NULL),
+      m_N(0), m_usingLogPr(0), m_levelSizes(NULL), m_prTable(NULL),
+      m_bowTable(NULL),
+      m_nnode(0), m_nodes(NULL), m_nleaf(0), m_leafs(NULL)
+{
+}
+
+// TODO: may need consolidate this class with CThreadSlm
+bool
+CThreadSlmFile::load(const char* fname)
+{
+    assert(m_buf == NULL);
+
+    int fd = open(fname, O_RDONLY);
+    ssize_t len = lseek(fd, 0, SEEK_END);
+    lseek(fd, 0, SEEK_SET);
+    m_buf = new char[len];
+    if (read(fd, m_buf, len) != len) {
+        delete [] m_buf;
+        m_buf = NULL;
+        cerr << "Failed to read from " << fname << endl;
+        return false;
+    }
+    close(fd);
+
+    char* buf = m_buf;
+    bool do_swap = (getEndian() != getHostEndian());
+
+    m_N = read_value<uint32_t>(buf, do_swap);
+    m_usingLogPr = read_value<uint32_t>(buf, do_swap);
+
+    m_levelSizes = read_values<uint32_t>(buf, m_N + 1, do_swap);
+    m_prTable = read_values<float>(buf, 1 << CThreadSlm::BITS_PR, do_swap);
+    m_bowTable = read_values<float>(buf, 1 << CThreadSlm::BITS_BOW, do_swap);
+
+    m_nnode = accumulate(m_levelSizes, m_levelSizes + m_N, 0);
+    m_nodes = read_values<TNode>(buf, m_nnode, do_swap);
+    m_nleaf = m_levelSizes[m_N];
+    m_leafs = read_values<TLeaf>(buf, m_nleaf, do_swap);
+
+    m_bufLen = len;
+    return(m_buf + len == buf);
+}
+
+size_t
+CThreadSlmFile::save(const char* fname, int endian)
+{
+    bool do_swap = (endian != getHostEndian());
+    FILE* fp = fopen(fname, "wb");
+    size_t nwrite = 0;
+    nwrite += write_value(fp, m_N, do_swap);
+    nwrite += write_value(fp, m_usingLogPr, do_swap);
+    nwrite += write_values(fp, m_levelSizes, m_N + 1, do_swap);
+    nwrite += write_values(fp, m_prTable, 1 << CThreadSlm::BITS_PR, do_swap);
+    nwrite += write_values(fp, m_bowTable, 1 << CThreadSlm::BITS_BOW, do_swap);
+    nwrite += write_values(fp, m_nodes, m_nnode, do_swap);
+    nwrite += write_values(fp, m_leafs, m_nleaf, do_swap);
+    fclose(fp);
+    return nwrite;
+}
+
+size_t
+CThreadSlmFile::size() const
+{
+    return m_bufLen;
+}
+
+CThreadSlmFile::~CThreadSlmFile()
+{
+    delete [] m_buf;
+    m_buf = NULL;
+}
+
+int
+CThreadSlmFile::getEndian() const
+{
+    assert(m_buf != NULL);
+    // assuming the N of this lm is not larger than 0x0100 0000
+    return (*(uint8_t*)m_buf) == 0 ? BIG_ENDIAN : LITTLE_ENDIAN;
+}
+
+int
+CThreadSlmFile::getHostEndian()
+{
+    return htons(0x0001) == 0x0100 ? LITTLE_ENDIAN : BIG_ENDIAN;
+}
+
diff --git a/src/slm/tslmendian/slm_file.h b/src/slm/tslmendian/slm_file.h
new file mode 100644 (file)
index 0000000..41ef1fc
--- /dev/null
@@ -0,0 +1,92 @@
+// -*- mode: c++ -*-
+/*
+ * Copyright (c) 2009 Kov Chai <tchaikov@gmail.com>
+ *
+ * The contents of this file are subject to the terms of either the GNU Lesser
+ * General Public License Version 2.1 only ("LGPL") or the Common Development and
+ * Distribution License ("CDDL")(collectively, the "License"). You may not use this
+ * file except in compliance with the License. You can obtain a copy of the CDDL at
+ * http://www.opensource.org/licenses/cddl1.php and a copy of the LGPLv2.1 at
+ * http://www.opensource.org/licenses/lgpl-license.php. See the License for the
+ * specific language governing permissions and limitations under the License. When
+ * distributing the software, include this License Header Notice in each file and
+ * include the full text of the License in the License file as well as the
+ * following notice:
+ *
+ * NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND DISTRIBUTION LICENSE
+ * (CDDL)
+ * For Covered Software in this distribution, this License shall be governed by the
+ * laws of the State of California (excluding conflict-of-law provisions).
+ * Any litigation relating to this License shall be subject to the jurisdiction of
+ * the Federal Courts of the Northern District of California and the state courts
+ * of the State of California, with venue lying in Santa Clara County, California.
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by only the CDDL or only
+ * the LGPL Version 2.1, indicate your decision by adding "[Contributor]" elects to
+ * include this software in this distribution under the [CDDL or LGPL Version 2.1]
+ * license." If you don't indicate a single choice of license, a recipient has the
+ * option to distribute your version of this file under either the CDDL or the LGPL
+ * Version 2.1, or to extend the choice of license to its licensees as provided
+ * above. However, if you add LGPL Version 2.1 code and therefore, elected the LGPL
+ * Version 2 license, then the option applies only if the new code is made subject
+ * to such option by the copyright holder.
+ */
+
+/*
+ * convert the threaded lm binary file from big-endian to small-endian or vice versa
+ */
+#ifndef SLM_FILE_H
+#define SLM_FILE_H
+
+#include <stdint.h>
+
+#include "../slm.h"
+
+// TODO: may need consolidate this class with CThreadSlm
+class CThreadSlmFile
+{
+public:
+    CThreadSlmFile();
+    ~CThreadSlmFile();
+    /**
+     * read from a lm_sc.t3g file and convert it to host byte order
+     * @param fname the filenam
+     * @return true if the given file is read successfully, false otherwise
+     */
+    bool load(const char* fname);
+    /**
+     * write the language model to a given file
+     * @param fname filenam of output file
+     * @param endian should be BIG_ENDIAN or LITTLE_ENDIAN
+     * @return the number of bytes wrote
+     */
+    size_t save(const char* fname, int endian);
+    /**
+     * return the size of the whole file
+     * @return size in byte
+     */
+    size_t size() const;
+    int getEndian() const;
+    static int getHostEndian();
+
+private:
+    CThreadSlmFile(const CThreadSlmFile&);
+
+private:
+    size_t m_bufLen;
+    char*     m_buf;
+    uint32_t m_N;
+    uint32_t m_usingLogPr;
+    uint32_t* m_levelSizes;
+    float*    m_prTable;
+    float*    m_bowTable;
+
+    size_t m_nnode;
+    CThreadSlm::TNode* m_nodes;
+    size_t m_nleaf;
+    CThreadSlm::TLeaf* m_leafs;
+};
+
+#endif //SLM_FILE_H
diff --git a/src/slm/tslmendian/writer.cpp b/src/slm/tslmendian/writer.cpp
new file mode 100644 (file)
index 0000000..c0193cd
--- /dev/null
@@ -0,0 +1,40 @@
+#include <arpa/inet.h>
+#include <cassert>
+#include <cstring>
+
+#include "writer.h"
+
+int
+get_host_endian()
+{
+    return htons(0x0001) == 0x0100 ? LITTLE_ENDIAN : BIG_ENDIAN;
+}
+
+int
+parse_endian(const char* arg)
+{
+    if (!strcmp(arg, "le")) {
+        return LITTLE_ENDIAN;
+    } else if (!strcmp(arg, "be")) {
+        return BIG_ENDIAN;
+    } else {
+        return -1;
+    }
+}
+
+const char*
+endian2str(int endian)
+{
+    static const char le[] = "little-endian";
+    static const char be[] = "big-endian";
+
+    switch (endian) {
+    case LITTLE_ENDIAN:
+        return le;
+    case BIG_ENDIAN:
+        return be;
+    default:
+        assert(0);
+    }
+    return NULL;
+}
diff --git a/src/slm/tslmendian/writer.h b/src/slm/tslmendian/writer.h
new file mode 100644 (file)
index 0000000..84439d0
--- /dev/null
@@ -0,0 +1,100 @@
+// -*- mode: c++ -*-
+#ifndef WRITER_H
+#define WRITER_H
+
+#include <stdio.h>
+#include <stdint.h>
+#include <algorithm>
+
+#ifndef LITTLE_ENDIAN
+enum {
+    BIG_ENDIAN = 4321,
+    LITTLE_ENDIAN = 1234,
+    UNKNOWN_ENDIAN = 0x0000
+};
+#else
+#define UNKNOWN_ENDIAN (0x0000)
+#endif
+int get_host_endian();
+int parse_endian(const char* arg);
+const char* endian2str(int endian);
+
+// change the byte order of given variable
+template <typename Type>
+Type change_byte_order(const Type& v){
+    Type t = v;
+    const size_t size = sizeof(v);
+    uint8_t* first = (uint8_t *) (&t);
+    uint8_t* last = first + size - 1;
+    while (first < last) {
+        std::swap(*first++, *last--);
+    }
+    return t;
+}
+
+template <typename T>
+class OtherEndian
+{
+public:
+    typedef T TargetType;
+    static TargetType create(const T& from){
+        return from;
+    }
+};
+
+#if WORDS_BIGENDIAN
+#define DEFINE_OTHER_TYPE(__T__) typedef __T__ ## _BE TargetType
+#else
+#define DEFINE_OTHER_TYPE(__T__) typedef __T__ ## _LE TargetType
+#endif
+
+//
+// we always defined a reversed layout of big-endian and little-endian
+// bit-field struct, so such kind of struct need to be reverted if host
+// arch is different from build arch.
+//
+template <typename T>
+bool revert_write(const T& t, FILE *fp){
+    T reverted = change_byte_order(t);
+    typename OtherEndian<T>::TargetType o =
+        OtherEndian<T>::create(reverted);
+    return fwrite(&o, sizeof(o), 1, fp) == 1;
+}
+
+//
+// if the struct has non-bit-field member(s), TTransUnit, among others,
+// the order of members is the same as how they are defined.
+//
+
+class Writer
+{
+public:
+    Writer(FILE *fp, bool doRevert)
+        : m_fp(fp), m_doRevert(doRevert)
+    {}
+
+    template <typename T>
+    bool write(const T& t){
+        if (m_doRevert)
+            return revert_write(t, m_fp);
+        else
+            return fwrite(&t, sizeof(t), 1, m_fp) == 1;
+    }
+
+
+    template <typename T>
+    bool write(const T* t, size_t len){
+        for (unsigned i = 0; i < len; i++) {
+            if (!write(t[i]))
+                return false;
+        }
+        return true;
+    }
+private:
+    FILE *m_fp;
+    const bool m_doRevert;
+};
+
+
+
+#endif // WRITER_H
diff --git a/src/slm/tslminfo/tslminfo.cpp b/src/slm/tslminfo/tslminfo.cpp
new file mode 100644 (file)
index 0000000..4526fad
--- /dev/null
@@ -0,0 +1,325 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright (c) 2007 Sun Microsystems, Inc. All Rights Reserved.
+ *
+ * The contents of this file are subject to the terms of either the GNU Lesser
+ * General Public License Version 2.1 only ("LGPL") or the Common Development and
+ * Distribution License ("CDDL")(collectively, the "License"). You may not use this
+ * file except in compliance with the License. You can obtain a copy of the CDDL at
+ * http://www.opensource.org/licenses/cddl1.php and a copy of the LGPLv2.1 at
+ * http://www.opensource.org/licenses/lgpl-license.php. See the License for the
+ * specific language governing permissions and limitations under the License. When
+ * distributing the software, include this License Header Notice in each file and
+ * include the full text of the License in the License file as well as the
+ * following notice:
+ *
+ * NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND DISTRIBUTION LICENSE
+ * (CDDL)
+ * For Covered Software in this distribution, this License shall be governed by the
+ * laws of the State of California (excluding conflict-of-law provisions).
+ * Any litigation relating to this License shall be subject to the jurisdiction of
+ * the Federal Courts of the Northern District of California and the state courts
+ * of the State of California, with venue lying in Santa Clara County, California.
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by only the CDDL or only
+ * the LGPL Version 2.1, indicate your decision by adding "[Contributor]" elects to
+ * include this software in this distribution under the [CDDL or LGPL Version 2.1]
+ * license." If you don't indicate a single choice of license, a recipient has the
+ * option to distribute your version of this file under either the CDDL or the LGPL
+ * Version 2.1, or to extend the choice of license to its licensees as provided
+ * above. However, if you add LGPL Version 2.1 code and therefore, elected the LGPL
+ * Version 2 license, then the option applies only if the new code is made subject
+ * to such option by the copyright holder.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifdef HAVE_ASSERT_H
+#include <assert.h>
+#endif
+
+#ifdef HAVE_GETOPT_H
+#include <getopt.h>
+#endif
+
+#include <stdio.h>
+#include <string>
+#include <math.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <vector>
+#include <map>
+
+#include "../slm.h"
+
+class CIterateThreadSlm : public CThreadSlm {
+public:
+    typedef std::vector<TState> iterator;
+
+    int
+    getLevelSize(int lvl)
+    {
+        return m_LevelSizes[lvl];
+    }
+
+    int
+    getN()
+    {
+        return m_N;
+    }
+
+    bool
+    beginLevel(int lvl, iterator& it);
+
+    void
+    next(iterator& it)
+    {
+        ++(it.back()); adjustIterator(it);
+    }
+
+    bool
+    isEnd(iterator& it)
+    {
+        return (int) ((it.back().getIdx()) + 1)
+            == getLevelSize(it.back().getLevel());
+    }
+
+    void*
+    getNodePtr(TState s);
+
+    double
+    mapPr(unsigned int pr_idx, bool log_format) const
+    {
+        double val = m_prTable[pr_idx];
+        if (log_format) {
+            return (m_UseLogPr) ? (val) : (-log(val));
+        } else {
+            return (m_UseLogPr) ? (exp(-val)) : (val);
+        }
+    }
+
+    double
+    mapBow(unsigned int bow_idx, bool log_format) const
+    {
+        double val = m_bowTable[bow_idx];
+        if (log_format) {
+            return (m_UseLogPr) ? (val) : (-log(val));
+        } else {
+            return (m_UseLogPr) ? (exp(-val)) : (val);
+        }
+    }
+
+protected:
+    void
+    adjustIterator(iterator& it);
+};
+
+bool
+CIterateThreadSlm::beginLevel(int lvl, iterator& it)
+{
+    it.clear();
+    if (lvl > (int) m_N) return false;
+    for (int i = 0; i <= lvl; ++i)
+        it.push_back(TState(i, 0));
+    adjustIterator(it);
+    return true;
+}
+
+void*
+CIterateThreadSlm::getNodePtr(TState s)
+{
+    unsigned int lvl = s.getLevel();
+    if (lvl == m_N) {
+        return(((TLeaf*)m_Levels[lvl]) + s.getIdx());
+    } else {
+        return(((TNode*)m_Levels[lvl]) + s.getIdx());
+    }
+}
+
+void
+CIterateThreadSlm::adjustIterator(iterator& it)
+{
+//    if (!isEnd(it)) {
+    for (int lvl = it.size() - 2; lvl >= 0; --lvl) {
+        int sz = getLevelSize(lvl);
+        unsigned child = (it[lvl + 1]).getIdx();
+        while ((int) it[lvl].getIdx() < (sz - 1) &&
+               (((TNode*)getNodePtr(it[lvl])) + 1)->ch() <= child) {
+            ++(it[lvl]);
+        }
+    }
+//    }
+}
+
+void
+ShowUsage()
+{
+    printf("Usage:\n");
+    printf("    tslminfo [options] threaded_slm_file\n");
+    printf("\nDescription:\n");
+    printf(
+        "    tslminfo tell information of a threaded back-off language model 'threaded_slm_file'. It can also print the model to ARPA format.");
+    printf(
+        " When no options given, slminfo will only print number of items in each level of the language model.\n");
+    printf("\nOptions:\n");
+    printf("    -v             # Verbose mode, printing arpa format.\n");
+    printf(
+        "    -p             # Prefer normal probability instead of -log(Pr) which is default. Valid under -v option.\n");
+    printf(
+        "    -l dict_file   # Lexicon. Valid under -v option. Substitute the word-id with word-text in the output.\n");
+    printf("\n");
+    exit(100);
+}
+
+static bool verbose = false;
+static char *lexicon_filename = NULL;
+static bool use_log_pr = true;
+
+static struct option long_options[] =
+{
+    { "verbose", 0, 0, 'v' },
+    { "pr", 0, 0, 'p' },
+    { "lexicon", 1, 0, 'l' },
+    { 0, 0, 0, 0 }
+};
+
+static void
+getParameters(int argc, char* argv[])
+{
+    int c, option_index = 0;
+    while ((c =
+                getopt_long(argc, argv, "vpl:", long_options,
+                            &option_index)) != -1) {
+        switch (c) {
+        case 'v':
+            verbose = true;
+            break;
+        case 'l':
+            lexicon_filename = strdup(optarg);
+            break;
+        case 'p':
+            use_log_pr = false;
+            break;
+        default:
+            ShowUsage();
+        }
+    }
+    if (use_log_pr == false && !verbose) ShowUsage();
+    if (lexicon_filename != NULL && !verbose) ShowUsage();
+    if (optind != argc - 1) ShowUsage();
+}
+
+typedef std::map<unsigned int, std::string> TReverseLexicon;
+
+
+void
+PrintARPA(CIterateThreadSlm& itslm,
+          const char* lexicon_filename,
+          bool use_log_pr)
+{
+    static unsigned int id;
+    static char word[10240];
+
+    TReverseLexicon* plexicon = NULL;
+    if (lexicon_filename != NULL) {
+        plexicon = new TReverseLexicon();
+        FILE* f_lex = fopen(lexicon_filename, "r");
+        while (fgets(word, 10240, f_lex) != NULL) {
+            if (strlen(word) > 0) {
+                char* p = word;
+                while (*p == ' ' || *p == '\t')
+                    ++p;
+                while (*p != 0 && *p != ' ' && *p != '\t')
+                    ++p;
+                if (*p == 0) continue;
+                *p++ = 0;
+                while (*p == ' ' || *p == '\t')
+                    ++p;
+                if (!(*p >= '0' && *p <= '9')) continue;
+                for (id = 0; *p >= '0' && *p <= '9'; ++p)
+                    id = 10 * id + (*p - '0');
+                (*plexicon)[id] = std::string(word);
+            }
+        }
+        fclose(f_lex);
+    }
+
+    CIterateThreadSlm::iterator it;
+    for (int lvl = 0; lvl <= itslm.getN(); ++lvl) {
+        printf("\\%d-gram\\%d\n", lvl, itslm.getLevelSize(lvl) - 1);
+        for (itslm.beginLevel(lvl, it); !itslm.isEnd(it); itslm.next(it)) {
+            for (int i = 1; i < lvl; ++i) {
+                CIterateThreadSlm::TNode*pn =
+                    (CIterateThreadSlm::TNode*)itslm.getNodePtr(it[i]);
+                if (plexicon != NULL)
+                    printf("%s ", (*plexicon)[pn->wid()].c_str());
+                else
+                    printf("%9d ", pn->wid());
+            }
+            if (lvl < itslm.getN()) {
+                CIterateThreadSlm::TNode*pn =
+                    (CIterateThreadSlm::TNode*)itslm.getNodePtr(it[lvl]);
+                if (lvl > 0) {
+                    if (plexicon != NULL)
+                        printf("%s ", ((*plexicon)[pn->wid()]).c_str());
+                    else
+                        printf("%9d ", pn->wid());
+                }
+
+                double pr = itslm.mapPr(pn->pr(), use_log_pr);
+                double bow = itslm.mapBow(pn->bow(), use_log_pr);
+                printf("%16.12lf %16.12lf ", pr, bow);
+                printf("(%1u,%u)\n", pn->bol(), pn->bon());
+            } else {
+                CIterateThreadSlm::TLeaf*pn =
+                    (CIterateThreadSlm::TLeaf*)itslm.getNodePtr(it[lvl]);
+                if (lvl > 0) {
+                    if (plexicon != NULL)
+                        printf("%s ", ((*plexicon)[pn->wid()]).c_str());
+                    else
+                        printf("%9d ", pn->wid());
+                }
+
+                double pr = itslm.mapPr(pn->pr(), use_log_pr);
+                printf("%16.12lf ", pr);
+                printf("(%1u,%u)\n", pn->bol(), pn->bon());
+            }
+        }
+    }
+
+    delete plexicon;
+}
+
+
+/**
+ * tslminfo [-v] threaded_slm_file
+ */
+int
+main(int argc, char* argv[])
+{
+    getParameters(argc, argv);
+
+    CIterateThreadSlm itslm;
+
+    if (itslm.load(argv[argc - 1], true)) {
+        if (!verbose) {
+            printf("Total %d level ngram: ", itslm.getN());
+            for (int lvl = 1; lvl <= itslm.getN(); ++lvl)
+                printf("%d ", itslm.getLevelSize(lvl) - 1);
+            printf(
+                (itslm.isUseLogPr()) ? " using -log(pr)\n" :
+                " using direct pr\n");
+        } else {
+            PrintARPA(itslm, lexicon_filename, use_log_pr);
+        }
+        itslm.free();
+        return 0;
+    }
+    return 100;
+}
diff --git a/src/slm/tslmpack/arpa_conv.cpp b/src/slm/tslmpack/arpa_conv.cpp
new file mode 100644 (file)
index 0000000..122a2ba
--- /dev/null
@@ -0,0 +1,175 @@
+/*
+ * Copyright (c) 2009 Kov Chai <tchaikov@gmail.com>
+ *
+ * The contents of this file are subject to the terms of either the GNU Lesser
+ * General Public License Version 2.1 only ("LGPL") or the Common Development and
+ * Distribution License ("CDDL")(collectively, the "License"). You may not use this
+ * file except in compliance with the License. You can obtain a copy of the CDDL at
+ * http://www.opensource.org/licenses/cddl1.php and a copy of the LGPLv2.1 at
+ * http://www.opensource.org/licenses/lgpl-license.php. See the License for the
+ * specific language governing permissions and limitations under the License. When
+ * distributing the software, include this License Header Notice in each file and
+ * include the full text of the License in the License file as well as the
+ * following notice:
+ *
+ * NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND DISTRIBUTION LICENSE
+ * (CDDL)
+ * For Covered Software in this distribution, this License shall be governed by the
+ * laws of the State of California (excluding conflict-of-law provisions).
+ * Any litigation relating to this License shall be subject to the jurisdiction of
+ * the Federal Courts of the Northern District of California and the state courts
+ * of the State of California, with venue lying in Santa Clara County, California.
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by only the CDDL or only
+ * the LGPL Version 2.1, indicate your decision by adding "[Contributor]" elects to
+ * include this software in this distribution under the [CDDL or LGPL Version 2.1]
+ * license." If you don't indicate a single choice of license, a recipient has the
+ * option to distribute your version of this file under either the CDDL or the LGPL
+ * Version 2.1, or to extend the choice of license to its licensees as provided
+ * above. However, if you add LGPL Version 2.1 code and therefore, elected the LGPL
+ * Version 2 license, then the option applies only if the new code is made subject
+ * to such option by the copyright holder.
+ */
+#include <algorithm>
+#include "common.h"
+#include "arpa_slm.h"
+#include "arpa_conv.h"
+
+
+//
+// convert CArpaSlm::TLeaf to CThreadSlm::TLeaf
+//
+class CArpaLeafConv
+{
+    const bool usingLogPr;
+    CompressedTable& m_pr_table;
+    RealIndexMap& m_pr_map;
+
+public:
+    CArpaLeafConv(bool usingLogPr_,
+                  RealIndexMap* pr_map,
+                  CompressedTable* pr_table) :
+        usingLogPr(usingLogPr_),
+        m_pr_table(*pr_table),
+        m_pr_map(*pr_map)
+    {
+    }
+
+    CThreadSlm::TLeaf
+    operator()(const CArpaSlm::TLeaf& leaf)
+    {
+        CThreadSlm::TLeaf tleaf;
+        tleaf.set_wid(leaf.wid);
+        tleaf.set_bon(leaf.bon);
+        tleaf.set_bol(leaf.bol);
+        unsigned pr_idx = get_pr_index(leaf.pr);
+        tleaf.set_pr(pr_idx);
+        return tleaf;
+    }
+
+    //
+    // lookup the Real/Effective value in the RealIndexMap for its index
+    // in the CompressedTable
+    //
+    unsigned
+    get_pr_index(float pr)
+    {
+        std::map<float, int>::iterator prit = m_pr_map.find(pr);
+        if (prit == m_pr_map.end()) { // This could be caused by precision error
+            double val = EffectivePr(pr);
+            val = OriginalPr(val);
+            prit = m_pr_map.find(val);
+            assert(prit != m_pr_map.end());
+        }
+        int idx_pr = prit->second;
+        assert(usingLogPr ||
+               (m_pr_table[idx_pr] > 0.0 && m_pr_table[idx_pr] < 1.0));
+        assert(!usingLogPr || m_pr_table[idx_pr] > 0.0);
+        return idx_pr;
+    }
+};
+
+//
+// convert CArpaSlm::TNode to CThreadSlm::TNode
+//
+class CArpaNodeConv
+{
+    const bool usingLogPr;
+    CArpaLeafConv m_leaf_conv;
+    CompressedTable& m_bow_table;
+    RealIndexMap& m_bow_map;
+
+public:
+    CArpaNodeConv(bool usingLogPr_,
+                  RealIndexMap* pr_map,
+                  CompressedTable* pr_table,
+                  RealIndexMap* bow_map,
+                  CompressedTable* bow_table) :
+        usingLogPr(usingLogPr_),
+        m_leaf_conv(usingLogPr, pr_map, pr_table),
+        m_bow_table(*bow_table),
+        m_bow_map(*bow_map)
+    {
+    }
+
+    CThreadSlm::TNode
+    operator()(const CArpaSlm::TNode& node)
+    {
+        CThreadSlm::TNode tnode;
+        tnode.set_wid(node.wid);
+        tnode.set_bon(node.bon);
+        tnode.set_bol(node.bol);
+        tnode.set_ch(node.ch);
+        unsigned pr_idx = m_leaf_conv.get_pr_index(node.pr);
+        tnode.set_pr(pr_idx);
+        unsigned bow_idx = get_bow_index(node.bow);
+        tnode.set_bow(bow_idx);
+        return tnode;
+    }
+
+    unsigned
+    get_bow_index(float bow)
+    {
+        FreqMap::iterator bowit = m_bow_map.find(bow);
+        if (bowit == m_bow_map.end()) {
+            double val = EffectiveBow(bow);
+            val = OriginalBow(val);
+            bowit = m_bow_map.find(val);
+            assert(bowit != m_bow_map.end());
+        }
+        return bowit->second;
+    }
+};
+
+void
+compress(const CArpaSlm& slm,
+         CompressedTable& pr_table, RealIndexMap& pr_map,
+         CompressedTable& bow_table, RealIndexMap& bow_map,
+         TNodeLevels& nodeLevels, CThreadSlm::TLeaf*& leafLevel)
+{
+    CArpaLeafConv leaf_conv(slm.usingLogPr(), &pr_map, &pr_table);
+    CArpaNodeConv node_conv(
+        slm.usingLogPr(), &pr_map, &pr_table, &bow_map, &bow_table);
+    const int N = slm.getN();
+    TNodeLevels node_levels(N);
+    for (int lvl = 0; lvl < N; ++lvl) {
+        const CArpaSlm::TNodeLevel& level = slm.getLevel(lvl);
+        unsigned len = level.size();
+        node_levels[lvl] = new CThreadSlm::TNode[len + 1];
+        std::transform(level.begin(), level.end(),
+                       node_levels[lvl], node_conv);
+        memset(&node_levels[lvl][len], 0, sizeof(CThreadSlm::TNode));
+        node_levels[lvl][len].set_ch(slm.getLevelSize(lvl + 1));
+    }
+
+    const CArpaSlm::TLeafLevel& level = slm.getLastLevel();
+    unsigned len = level.size();
+    CThreadSlm::TLeaf* leaf_level = new CThreadSlm::TLeaf[len + 1];
+    std::transform(level.begin(), level.end(),
+                   leaf_level, leaf_conv);
+    memset(&leaf_level[len], 0, sizeof(CThreadSlm::TLeaf));
+    nodeLevels = node_levels;
+    leafLevel = leaf_level;
+}
diff --git a/src/slm/tslmpack/arpa_conv.h b/src/slm/tslmpack/arpa_conv.h
new file mode 100644 (file)
index 0000000..6d6747b
--- /dev/null
@@ -0,0 +1,57 @@
+// -*- mode: c++ -*-
+/*
+ * Copyright (c) 2009 Kov Chai <tchaikov@gmail.com>
+ *
+ * The contents of this file are subject to the terms of either the GNU Lesser
+ * General Public License Version 2.1 only ("LGPL") or the Common Development and
+ * Distribution License ("CDDL")(collectively, the "License"). You may not use this
+ * file except in compliance with the License. You can obtain a copy of the CDDL at
+ * http://www.opensource.org/licenses/cddl1.php and a copy of the LGPLv2.1 at
+ * http://www.opensource.org/licenses/lgpl-license.php. See the License for the
+ * specific language governing permissions and limitations under the License. When
+ * distributing the software, include this License Header Notice in each file and
+ * include the full text of the License in the License file as well as the
+ * following notice:
+ *
+ * NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND DISTRIBUTION LICENSE
+ * (CDDL)
+ * For Covered Software in this distribution, this License shall be governed by the
+ * laws of the State of California (excluding conflict-of-law provisions).
+ * Any litigation relating to this License shall be subject to the jurisdiction of
+ * the Federal Courts of the Northern District of California and the state courts
+ * of the State of California, with venue lying in Santa Clara County, California.
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by only the CDDL or only
+ * the LGPL Version 2.1, indicate your decision by adding "[Contributor]" elects to
+ * include this software in this distribution under the [CDDL or LGPL Version 2.1]
+ * license." If you don't indicate a single choice of license, a recipient has the
+ * option to distribute your version of this file under either the CDDL or the LGPL
+ * Version 2.1, or to extend the choice of license to its licensees as provided
+ * above. However, if you add LGPL Version 2.1 code and therefore, elected the LGPL
+ * Version 2 license, then the option applies only if the new code is made subject
+ * to such option by the copyright holder.
+ */
+#ifndef _SLM_PACK_ARPA_CONV_H
+#define _SLM_PACK_ARPA_CONV_H
+
+#include "common.h"
+
+class CArpaSlm;
+
+//
+// slm [in]
+// pr_table [in]
+// pr_map [in]
+// bow_table [in]
+// bow_map [in]
+// nodeLevels [out]
+// leafLevel [out]
+//
+void compress(const CArpaSlm& slm,
+              CompressedTable& pr_table, RealIndexMap& pr_map,
+              CompressedTable& bow_table, RealIndexMap& bow_map,
+              TNodeLevels& nodeLevels, CThreadSlm::TLeaf*& leafLevel);
+
+#endif //_SLM_PACK_ARPA_CONV_H
diff --git a/src/slm/tslmpack/arpa_slm.cpp b/src/slm/tslmpack/arpa_slm.cpp
new file mode 100644 (file)
index 0000000..82029c6
--- /dev/null
@@ -0,0 +1,243 @@
+/*
+ * Copyright (c) 2009 Kov Chai <tchaikov@gmail.com>
+ *
+ * The contents of this file are subject to the terms of either the GNU Lesser
+ * General Public License Version 2.1 only ("LGPL") or the Common Development and
+ * Distribution License ("CDDL")(collectively, the "License"). You may not use this
+ * file except in compliance with the License. You can obtain a copy of the CDDL at
+ * http://www.opensource.org/licenses/cddl1.php and a copy of the LGPLv2.1 at
+ * http://www.opensource.org/licenses/lgpl-license.php. See the License for the
+ * specific language governing permissions and limitations under the License. When
+ * distributing the software, include this License Header Notice in each file and
+ * include the full text of the License in the License file as well as the
+ * following notice:
+ *
+ * NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND DISTRIBUTION LICENSE
+ * (CDDL)
+ * For Covered Software in this distribution, this License shall be governed by the
+ * laws of the State of California (excluding conflict-of-law provisions).
+ * Any litigation relating to this License shall be subject to the jurisdiction of
+ * the Federal Courts of the Northern District of California and the state courts
+ * of the State of California, with venue lying in Santa Clara County, California.
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by only the CDDL or only
+ * the LGPL Version 2.1, indicate your decision by adding "[Contributor]" elects to
+ * include this software in this distribution under the [CDDL or LGPL Version 2.1]
+ * license." If you don't indicate a single choice of license, a recipient has the
+ * option to distribute your version of this file under either the CDDL or the LGPL
+ * Version 2.1, or to extend the choice of license to its licensees as provided
+ * above. However, if you add LGPL Version 2.1 code and therefore, elected the LGPL
+ * Version 2 license, then the option applies only if the new code is made subject
+ * to such option by the copyright holder.
+ */
+#include <string>
+#include <iostream>
+#include <fstream>
+#include <algorithm>
+#include "arpa_slm.h"
+
+using namespace std;
+
+/**
+ * the GNU extension is not always available, so we invent another wheel.
+ */
+size_t
+getline(char *buf, size_t n, FILE* stream)
+{
+    char* p;
+    char* end = buf + n;
+    for (p = buf; p != end; ++p) {
+        int c = fgetc(stream);
+        if (c == '\n' || c == EOF)
+            break;
+        *p = c;
+        --n;
+    }
+    if (p != end)
+        *p = 0;
+    else
+        *(p - 1) = 0;
+    return p - buf;
+}
+
+char*
+getwords(char* buf, char** next)
+{
+    char* word = buf;
+    char* delim = strstr(buf, "  ");
+    if (delim == NULL) {
+        cerr << "Unknown format in: " << buf << "." << endl;
+        exit(2);
+    }
+    *delim = '\0';
+    *next = delim + 2;
+    return word;
+}
+
+unsigned
+get_wid(const char* word, const TLexicon& lexicon)
+{
+    TLexicon::const_iterator lexi = lexicon.find(word);
+    unsigned wid;
+    if (lexi != lexicon.end()) {
+        wid = lexi->second;
+    } else {
+        cerr << "Error:\"" << word << "\" not found in lexicon." << endl;
+        wid = 0;
+    }
+    return wid;
+}
+
+int
+CArpaSlm::TLeaf::load_words(char* buf, const TLexicon& lexicon)
+{
+    int nword = 0;
+    char* word, *end;
+    for (word = end = buf; *end != 0; ++end) {
+        if (*end == ' ') {
+            assert(nword < N_GRAM);
+            *end = 0;
+            hw[nword++] = get_wid(word, lexicon);
+            word = end + 1;
+        }
+    }
+    if (buf != end) {
+        wid = hw[nword++] = get_wid(word, lexicon);
+    }
+    return nword;
+}
+
+void
+CArpaSlm::TLeaf::load(istream& is, const TLexicon& lexicon)
+{
+    char buf[1024];
+    is.getline(buf, sizeof(buf));
+    char* next = 0;
+    char* words = getwords(buf, &next);
+    load_words(words, lexicon);
+    sscanf(next, "%f (%1u, %u)",
+           &pr, &bol, &bon);
+}
+
+void
+CArpaSlm::TNode::load(istream& is, const TLexicon& lexicon)
+{
+    char buf[1024];
+    is.getline(buf, sizeof(buf));
+    char* next = 0;
+    char* words = getwords(buf, &next);
+    load_words(words, lexicon);
+    sscanf(next, "%f %f (%1u, %u)",
+           &pr, &bow, &bol, &bon);
+}
+
+void
+CArpaSlm::TNode::load_level0(istream& is)
+{
+    hw[0] = 0;
+    char buf[1024];
+    is.getline(buf, sizeof(buf));
+    sscanf(buf, "%f %f (%1u, %u)",
+           &pr, &bow, &bol, &bon);
+    wid = 0;
+}
+
+void
+CArpaSlm::load(const char* filename, const TLexicon& lexicon)
+{
+    printf("Loading ARPA slm..."); fflush(stdout);
+    ifstream file(filename);
+    char buf[1024];
+    for (int i = 0; i <= N_GRAM; ++i) {
+        unsigned lvl;
+        int size;
+        file.getline(buf, sizeof(buf));
+        if (!file) {
+            cerr << "Failed to read from" << filename << endl;
+            exit(1);
+        }
+        sscanf(buf, "\\%d-gram\\%d%*[\n]", &lvl, &size);
+        assert(lvl <= N_GRAM);
+        if (lvl == 0) {
+            TNode node0;
+            node0.load_level0(file);
+            m_levels[0].push_back(node0);
+        } else if (lvl < m_N) {
+            m_levels[lvl].reserve(size);
+            for (int i = 0; i < size; ++i) {
+                TNode node;
+                node.load(file, lexicon);
+                m_levels[lvl].push_back(node);
+            }
+        } else {
+            // leaf nodes
+            m_lastLevel.reserve(size);
+            for (int i = 0; i < size; ++i) {
+                TLeaf leaf;
+                leaf.load(file, lexicon);
+                m_lastLevel.push_back(leaf);
+            }
+        }
+    }
+}
+
+template <class NodeT>
+struct CompareNode {
+    const unsigned m_lvl;
+    CompareNode(unsigned lvl) : m_lvl(lvl)
+    {
+    }
+    /**
+     * @return true if strictly less, false otherwise
+     */
+    bool
+    operator ()(const NodeT& node, const TSIMWordId hw[N_GRAM])
+    {
+        for (unsigned i = 0; i < m_lvl; ++i) {
+            if (node.hw[i] < hw[i])
+                return true;
+            if (node.hw[i] > hw[i])
+                return false;
+        }
+        // node.hw[:lvl] is the same as hw[:]
+        return false;
+    }
+};
+
+void
+CArpaSlm::threading()
+{
+    {
+        TNode& node = m_levels[0][0];
+        node.ch = 0;
+    }
+    for (unsigned lvl = 1; lvl < m_N; ++lvl) {
+        TNodeLevel& level = m_levels[lvl];
+        unsigned last_child = 0;
+        for (TNodeLevel::iterator node = level.begin();
+             node != level.end();
+             ++node) {
+            node->ch = last_child = find_1st_child(lvl, *node, last_child);
+        }
+    }
+}
+
+unsigned
+CArpaSlm::find_1st_child(unsigned lvl, const TNode& node, int last_child)
+{
+    assert(lvl < m_N);
+    if (lvl == m_N - 1) {
+        TLeafLevel::iterator found = lower_bound(
+            m_lastLevel.begin(), m_lastLevel.end(), node.hw,
+            CompareNode<TLeaf>(lvl));
+        return distance(m_lastLevel.begin(), found);
+    } else {
+        const TNodeLevel& level = m_levels[lvl + 1];
+        TNodeLevel::const_iterator found = lower_bound(level.begin(), level.end(
+                                                           ), node.hw,
+                                                       CompareNode<TNode>(lvl));
+        return distance(level.begin(), found);
+    }
+}
diff --git a/src/slm/tslmpack/arpa_slm.h b/src/slm/tslmpack/arpa_slm.h
new file mode 100644 (file)
index 0000000..3c49393
--- /dev/null
@@ -0,0 +1,111 @@
+// -*- mode: c++ -*-
+/*
+ * Copyright (c) 2009 Kov Chai <tchaikov@gmail.com>
+ *
+ * The contents of this file are subject to the terms of either the GNU Lesser
+ * General Public License Version 2.1 only ("LGPL") or the Common Development and
+ * Distribution License ("CDDL")(collectively, the "License"). You may not use this
+ * file except in compliance with the License. You can obtain a copy of the CDDL at
+ * http://www.opensource.org/licenses/cddl1.php and a copy of the LGPLv2.1 at
+ * http://www.opensource.org/licenses/lgpl-license.php. See the License for the
+ * specific language governing permissions and limitations under the License. When
+ * distributing the software, include this License Header Notice in each file and
+ * include the full text of the License in the License file as well as the
+ * following notice:
+ *
+ * NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND DISTRIBUTION LICENSE
+ * (CDDL)
+ * For Covered Software in this distribution, this License shall be governed by the
+ * laws of the State of California (excluding conflict-of-law provisions).
+ * Any litigation relating to this License shall be subject to the jurisdiction of
+ * the Federal Courts of the Northern District of California and the state courts
+ * of the State of California, with venue lying in Santa Clara County, California.
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by only the CDDL or only
+ * the LGPL Version 2.1, indicate your decision by adding "[Contributor]" elects to
+ * include this software in this distribution under the [CDDL or LGPL Version 2.1]
+ * license." If you don't indicate a single choice of license, a recipient has the
+ * option to distribute your version of this file under either the CDDL or the LGPL
+ * Version 2.1, or to extend the choice of license to its licensees as provided
+ * above. However, if you add LGPL Version 2.1 code and therefore, elected the LGPL
+ * Version 2 license, then the option applies only if the new code is made subject
+ * to such option by the copyright holder.
+ */
+#ifndef _ARPA_SLM_H
+#define _ARPA_SLM_H
+
+#include <istream>
+#include "common.h"
+
+using std::istream;
+
+#define N_GRAM (3)
+
+
+/* the ARPA style representation of sunpinyin's SLM */
+class CArpaSlm {
+public:
+    struct TLeaf {
+        TSIMWordId hw[N_GRAM];
+        TSIMWordId wid;
+        float pr;
+        unsigned ch;
+        unsigned bon;
+        unsigned bol;
+        void load(istream&, const TLexicon&);
+        int load_words(char* buf, const TLexicon& lexicon);
+        TLeaf() : wid(0), pr(.0), ch(0), bon(0), bol(0) {}
+    };
+
+    struct TNode : public TLeaf {
+        float bow;
+        void load(istream&, const TLexicon&);
+        void load_level0(istream&);
+    };
+
+    typedef std::vector<TNode> TNodeLevel;
+    typedef std::vector<TLeaf> TLeafLevel;
+
+private:
+    TNodeLevel m_levels[N_GRAM + 1]; /* [0..N_GRAM] */
+    TLeafLevel m_lastLevel;
+    const bool m_usingLogPr;
+    const unsigned m_N;
+
+public:
+    /* XXX, ARPA file does not provide these information.
+       so we assume this SLM is trigram, and does not use LogPr */
+    CArpaSlm() : m_usingLogPr(false), m_N(N_GRAM) {}
+    bool good() const { return m_levels[0].size() != 0; }
+    unsigned getN() const { return m_N; }
+    bool usingLogPr() const { return m_usingLogPr; }
+    const TNodeLevel& getLevel(unsigned lvl) const { return m_levels[lvl]; }
+    const TLeafLevel& getLastLevel() const { return m_lastLevel; }
+    unsigned getLevelSize(unsigned lvl) const {
+        assert(lvl <= m_N);
+        if (lvl < m_N) {
+            return m_levels[lvl].size();
+        } else {
+            return m_lastLevel.size();
+        }
+    }
+    /**
+     * initialize the `ch' and `wid' fields of each node in levels
+     */
+    void threading();
+    void load(const char* filename, const TLexicon& lexicon);
+
+private:
+    /**
+     * find out the first child of a given node in its next level
+     * @param lvl the level where node belongs to
+     * @param node the node
+     * @param last_child the child index of previous node
+     * @return the index of the found child
+     */
+    unsigned find_1st_child(unsigned lvl, const TNode& node, int last_child);
+};
+
+#endif //_ARPA_SLM_H
diff --git a/src/slm/tslmpack/common.h b/src/slm/tslmpack/common.h
new file mode 100644 (file)
index 0000000..06b55f0
--- /dev/null
@@ -0,0 +1,61 @@
+// -*- mode: c++ -*-
+/*
+ * Copyright (c) 2009 Kov Chai <tchaikov@gmail.com>
+ *
+ * The contents of this file are subject to the terms of either the GNU Lesser
+ * General Public License Version 2.1 only ("LGPL") or the Common Development and
+ * Distribution License ("CDDL")(collectively, the "License"). You may not use this
+ * file except in compliance with the License. You can obtain a copy of the CDDL at
+ * http://www.opensource.org/licenses/cddl1.php and a copy of the LGPLv2.1 at
+ * http://www.opensource.org/licenses/lgpl-license.php. See the License for the
+ * specific language governing permissions and limitations under the License. When
+ * distributing the software, include this License Header Notice in each file and
+ * include the full text of the License in the License file as well as the
+ * following notice:
+ *
+ * NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND DISTRIBUTION LICENSE
+ * (CDDL)
+ * For Covered Software in this distribution, this License shall be governed by the
+ * laws of the State of California (excluding conflict-of-law provisions).
+ * Any litigation relating to this License shall be subject to the jurisdiction of
+ * the Federal Courts of the Northern District of California and the state courts
+ * of the State of California, with venue lying in Santa Clara County, California.
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by only the CDDL or only
+ * the LGPL Version 2.1, indicate your decision by adding "[Contributor]" elects to
+ * include this software in this distribution under the [CDDL or LGPL Version 2.1]
+ * license." If you don't indicate a single choice of license, a recipient has the
+ * option to distribute your version of this file under either the CDDL or the LGPL
+ * Version 2.1, or to extend the choice of license to its licensees as provided
+ * above. However, if you add LGPL Version 2.1 code and therefore, elected the LGPL
+ * Version 2 license, then the option applies only if the new code is made subject
+ * to such option by the copyright holder.
+ */
+#ifndef _SLM_PACK_COMMON_H
+#define _SLM_PACK_COMMON_H
+
+#include <vector>
+#include <map>
+#include <string>
+#include <cmath>
+#include <cassert>
+
+#include "../slm.h"
+
+typedef std::vector<CThreadSlm::TNode> TNodeLevel;
+typedef std::vector<CThreadSlm::TLeaf> TLeafLevel;
+typedef std::vector<CThreadSlm::TNode*> TNodeLevels;
+typedef std::map<float, float> EffRealMap;  // map from efficient values to the real ones
+typedef std::map<float, int> FreqMap;       // how often the efficient value appears
+typedef std::vector<float> CompressedTable; // array of real values, the index is stored in RealIndexMap
+typedef std::map<float, int> RealIndexMap;  // map real values to their indices
+typedef std::map<std::string, unsigned int> TLexicon; // map word to wid
+
+#define EffectivePr(a)  (float((usingLogPr) ? ((a) / log(2.0)) : (-log2((a)))))
+#define OriginalPr(b)   (float((usingLogPr) ? ((b) * log(2.0)) : (exp2(-(b)))))
+#define EffectiveBow(a) (float((usingLogPr) ? (exp(-(a))) : ((a))))
+#define OriginalBow(b)  (float((usingLogPr) ? (-log((b))) : ((b))))
+
+#endif //_SLM_PACK_COMMON_H
diff --git a/src/slm/tslmpack/slmpack.cpp b/src/slm/tslmpack/slmpack.cpp
new file mode 100644 (file)
index 0000000..3f00d72
--- /dev/null
@@ -0,0 +1,366 @@
+/*
+ * Copyright (c) 2009 Kov Chai <tchaikov@gmail.com>
+ *
+ * The contents of this file are subject to the terms of either the GNU Lesser
+ * General Public License Version 2.1 only ("LGPL") or the Common Development and
+ * Distribution License ("CDDL")(collectively, the "License"). You may not use this
+ * file except in compliance with the License. You can obtain a copy of the CDDL at
+ * http://www.opensource.org/licenses/cddl1.php and a copy of the LGPLv2.1 at
+ * http://www.opensource.org/licenses/lgpl-license.php. See the License for the
+ * specific language governing permissions and limitations under the License. When
+ * distributing the software, include this License Header Notice in each file and
+ * include the full text of the License in the License file as well as the
+ * following notice:
+ *
+ * NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND DISTRIBUTION LICENSE
+ * (CDDL)
+ * For Covered Software in this distribution, this License shall be governed by the
+ * laws of the State of California (excluding conflict-of-law provisions).
+ * Any litigation relating to this License shall be subject to the jurisdiction of
+ * the Federal Courts of the Northern District of California and the state courts
+ * of the State of California, with venue lying in Santa Clara County, California.
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by only the CDDL or only
+ * the LGPL Version 2.1, indicate your decision by adding "[Contributor]" elects to
+ * include this software in this distribution under the [CDDL or LGPL Version 2.1]
+ * license." If you don't indicate a single choice of license, a recipient has the
+ * option to distribute your version of this file under either the CDDL or the LGPL
+ * Version 2.1, or to extend the choice of license to its licensees as provided
+ * above. However, if you add LGPL Version 2.1 code and therefore, elected the LGPL
+ * Version 2 license, then the option applies only if the new code is made subject
+ * to such option by the copyright holder.
+ */
+
+/*
+ * pack ARPA format to a binary format which can be consumed by SunPinyin
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifdef HAVE_ASSERT_H
+#include <assert.h>
+#endif
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+
+#include <vector>
+#include <map>
+#include <iostream>
+#include <cmath>
+
+//#include "../sim_slm.h"
+#include "../slm.h"
+
+#include "../thread/ValueCompress.h"
+#include "arpa_slm.h"
+#include "arpa_conv.h"
+
+
+void
+ShowUsage(const char* progname)
+{
+    printf("Usage:\n");
+    printf("    %s arpa_slm dict_file threaded_slm\n", progname);
+    printf("\n");
+    printf("Description:\n");
+    printf(
+        "    %s converts the ARPA representation of SLM to the binary format of threaded SLM. \n",
+        progname);
+    exit(100);
+}
+
+/**
+ * slm [in]
+ * pr_eff, pr_values [out]
+ * bow_eff, bow_values [out]
+ */
+
+void
+build_map(const CArpaSlm& slm,
+          EffRealMap &pr_eff,
+          FreqMap& pr_values,
+          EffRealMap &bow_eff,
+          FreqMap& bow_values)
+{
+    bool usingLogPr = slm.usingLogPr();
+
+    printf("\nfirst pass..."); fflush(stdout);
+
+    for (unsigned lvl = 0; lvl < slm.getN(); ++lvl) {
+        typedef CArpaSlm::TNodeLevel TNodeLevel;
+        const TNodeLevel& level = slm.getLevel(lvl);
+        for (TNodeLevel::const_iterator node = level.begin();
+             node != level.end();
+             ++node) {
+            float real_pr, eff_pr;
+            real_pr = node->pr;
+            eff_pr = EffectivePr(real_pr);
+            if (pr_eff.find(eff_pr) == pr_eff.end()) {
+                pr_eff[eff_pr] = real_pr;
+            } else { // precision error cause non 1:1 mapping
+                pr_eff[eff_pr] = OriginalPr(eff_pr);
+            }
+            ++(pr_values[eff_pr]);
+
+            float real_bow, eff_bow;
+            real_bow = node->bow;
+            eff_bow = EffectiveBow(real_bow);
+            if (bow_eff.find(eff_bow) == bow_eff.end()) {
+                bow_eff[eff_bow] = real_bow;
+            } else { // two values map to same distance value due to precision error
+                bow_eff[eff_bow] = OriginalBow(eff_bow);
+            }
+            ++(bow_values[eff_bow]);
+        }
+    }
+    typedef CArpaSlm::TLeafLevel TLeafLevel;
+    const TLeafLevel& level = slm.getLastLevel();
+    for (TLeafLevel::const_iterator leaf = level.begin();
+         leaf != level.end();
+         ++leaf) {
+        float real_pr, eff_pr;
+        real_pr = leaf->pr;
+        eff_pr = EffectivePr(real_pr);
+        if (pr_eff.find(eff_pr) == pr_eff.end()) {
+            pr_eff[eff_pr] = real_pr;
+        } else { // precision error cause non 1:1 mapping
+            pr_eff[eff_pr] = OriginalPr(eff_pr);
+        }
+        ++(pr_values[eff_pr]);
+    }
+    // Following pr value should not be grouped, or as milestone values.
+    static const float msprs[] = {
+        0.9, 0.8, 0.7, 0.6,
+        1.0 / 2, 1.0 / 4, 1.0 / 8, 1.0 / 16, 1.0 / 32, 1.0 / 64, 1.0 / 128,
+        1.0 / 256, 1.0 / 512, 1.0 / 1024, 1.0 / 2048, 1.0 / 4096, 1.0 / 8192,
+        1.0 / 16384, 1.0 / 32768, 1.0 / 65536
+    };
+
+    for (unsigned i = 0, sz = sizeof(msprs) / sizeof(float); i < sz; ++i) {
+        float real_pr = (usingLogPr) ? (-log(msprs[i])) : (msprs[i]);
+        float eff_pr = EffectivePr(real_pr);
+        assert(usingLogPr || (real_pr > 0.0 && real_pr < 1.0));
+        assert(!usingLogPr || real_pr > 0.0);
+
+        if (pr_eff.find(eff_pr) == pr_eff.end()) {
+            pr_eff[eff_pr] = real_pr;
+        } else { // precision error causes non 1:1 mapping
+            pr_eff[eff_pr] = OriginalPr(eff_pr);
+        }
+        pr_values[eff_pr] = 0;
+    }
+
+    // Following bow value should not be grouped, or as milestone values.
+    static const float msbows[] = {
+        1.0, 0.9, 0.8, 0.7, 0.6, 0.5, 0.4, 0.3, 0.2,
+        0.1, 0.05, 0.01, 0.005, 0.001, 0.0005, 0.0001,
+        0.00005, 0.00001, 0.000005, 0.000001, 0.0000005, 0.0000001
+    };
+
+    for (unsigned i = 0; i < sizeof(msbows) / sizeof(msbows[0]); ++i) {
+        float real_bow = (usingLogPr) ? (-log(msbows[i])) : (msbows[i]);
+        float eff_bow = EffectiveBow(real_bow);
+        if (bow_eff.find(eff_bow) == bow_eff.end()) {
+            bow_eff[eff_bow] = real_bow;
+        } else { // two values map to same distance value due to precision error
+            bow_eff[eff_bow] = OriginalBow(eff_bow);
+        }
+        bow_values[eff_bow] = 0;
+    }
+}
+
+/**
+ * group vaules into a smaller set of their approximations
+ *
+ * bow_eff [in], bow_values [in], bow_map [out], bow_table [out]
+ * pr_eff [in], pr_values [in], pr_map [out], pr_table [out]
+ *
+ */
+void
+group_values(bool usingLogPr,
+             EffRealMap& pr_eff,
+             FreqMap& pr_values,
+             CompressedTable& pr_table,
+             RealIndexMap& pr_map,
+             EffRealMap& bow_eff,
+             FreqMap& bow_values,
+             CompressedTable& bow_table,
+             RealIndexMap& bow_map)
+{
+    printf("\nCompressing pr values..."); fflush(stdout);
+    CValueCompressor vc;
+    vc(pr_eff, pr_values, pr_map, pr_table, (1 << CThreadSlm::BITS_PR));
+    CompressedTable::iterator itt, itte;
+    itte = pr_table.end();
+    for (itt = pr_table.begin(); itt != itte; ++itt) {
+        *itt = OriginalPr(*itt);
+        assert(usingLogPr || (*itt > 0.0 && *itt < 1.0));
+        assert(!usingLogPr || *itt > 0.0);
+    }
+    printf("%lu float values ==> %lu values", pr_eff.size(), pr_table.size());
+
+    printf("\nCompressing bow values..."); fflush(stdout);
+    vc(bow_eff, bow_values, bow_map, bow_table, (1 << CThreadSlm::BITS_BOW));
+    itte = bow_table.end();
+    for (itt = bow_table.begin(); itt != itte; ++itt)
+        *itt = OriginalBow(*itt);
+    printf("%lu float values ==> %lu values", bow_eff.size(), bow_table.size());
+}
+
+TLexicon
+read_lexicon(const char* filename)
+{
+    printf("Loading lexicon..."); fflush(stdout);
+    static char word[1024 * 10];
+    FILE* f_lex = fopen(filename, "r");
+    TLexicon lexicon;
+    while (fgets(word, sizeof(word), f_lex)) {
+        if (strlen(word) > 0) {
+            // skip to the first non hanzi character
+            char* p = word;
+            while (*p == ' ' || *p == '\t')
+                ++p;
+            while (*p != 0 && *p != ' ' && *p != '\t')
+                ++p;
+            if (*p == 0) continue;
+            *p++ = 0;
+            // skip to the word_id
+            while (*p == ' ' || *p == '\t')
+                ++p;
+            if (!(*p >= '0' && *p <= '9')) continue;
+
+            int id;
+            for (id = 0; *p >= '0' && *p <= '9'; ++p)
+                id = 10 * id + (*p - '0');
+            lexicon[std::string(word)] = id;
+        }
+    }
+    fclose(f_lex);
+    printf("done.\n"); fflush(stdout);
+
+    return lexicon;
+}
+
+
+
+//
+// filename [in]
+// pr_table [in]
+// bow_table [in]
+// levels[0] [in]
+// ...
+// levels[N] [in]
+// lastLevel [in]
+//
+void
+write_out(const char* filename, const CArpaSlm& slm,
+          CompressedTable& pr_table, CompressedTable& bow_table,
+          const TNodeLevels& levels, const CThreadSlm::TLeaf* lastLevel)
+{
+    printf("\nWriting out..."); fflush(stdout);
+
+    FILE* fp = fopen(filename, "wb");
+    const int N = slm.getN();
+    fwrite(&N, sizeof(int), 1, fp);
+    const unsigned usingLogPr = slm.usingLogPr();
+    fwrite(&usingLogPr, sizeof(unsigned), 1, fp);
+
+    for (int lvl = 0; lvl <= N; ++lvl) {
+        unsigned len = slm.getLevelSize(lvl) + 1;
+        fwrite(&len, sizeof(unsigned), 1, fp);
+    }
+
+    for (int i = 0, sz = pr_table.size(); i < (1 << CThreadSlm::BITS_PR);
+         ++i) {
+        if (i < sz) {
+            fwrite(&pr_table[i], sizeof(float), 1, fp);
+        } else {
+            float dummy = 0.0F;
+            fwrite(&dummy, sizeof(float), 1, fp);
+        }
+    }
+
+    for (int i = 0, sz = bow_table.size(); i < (1 << CThreadSlm::BITS_BOW);
+         ++i) {
+        if (i < sz) {
+            fwrite(&bow_table[i], sizeof(float), 1, fp);
+        } else {
+            float dummy = 0.0F;
+            fwrite(&dummy, sizeof(float), 1, fp);
+        }
+    }
+
+    for (int lvl = 0; lvl < N; ++lvl) {
+        fwrite(levels[lvl], sizeof(CThreadSlm::TNode), slm.getLevelSize(
+                   lvl) + 1, fp);
+    }
+
+    fwrite(lastLevel, sizeof(CThreadSlm::TLeaf), slm.getLevelSize(N) + 1, fp);
+
+    fclose(fp);
+
+    printf("done!\n"); fflush(stdout);
+}
+
+
+void
+cleanup(CompressedTable& pr_table, CompressedTable& bow_table,
+        TNodeLevels& levels, CThreadSlm::TLeaf* lastLevel)
+{
+    for (unsigned lvl = 0; lvl < levels.size(); ++lvl)
+        delete[] levels[lvl];
+    delete[] lastLevel;
+    bow_table.clear();
+    pr_table.clear();
+}
+
+int
+main(int argc, char* argv[])
+{
+    if (argc != 4)
+        ShowUsage(argv[0]);
+    const char* arpa_path = argv[1];
+    const char* lexicon_path = argv[2];
+    const char* threaded_path = argv[3];
+
+    CArpaSlm slm;
+    TLexicon lexicon = read_lexicon(lexicon_path);
+    slm.load(arpa_path, lexicon);
+
+    if (!slm.good()) {
+        std::cerr << "Failed to load language model from " << arpa_path <<
+        "." << std::endl;
+        exit(1);
+    }
+    slm.threading();
+
+    EffRealMap pr_eff, bow_eff;    // effval --> val
+    FreqMap pr_values, bow_values; // effval --> freq
+    build_map(slm, pr_eff, pr_values, bow_eff, bow_values);
+
+    RealIndexMap pr_map, bow_map;               // result: val --> int
+    CompressedTable pr_table, bow_table;        // result: val vector
+    group_values(slm.usingLogPr(),
+                 pr_eff, pr_values, pr_table, pr_map,
+                 bow_eff, bow_values, bow_table, bow_map);
+    pr_values.clear();
+    bow_values.clear();
+
+    TNodeLevels levels;
+    CThreadSlm::TLeaf* lastLevel;
+    compress(slm, pr_table, pr_map, bow_table, bow_map,
+             levels, lastLevel);
+
+    pr_map.clear();
+    bow_map.clear();
+    write_out(threaded_path, slm, pr_table, bow_table, levels, lastLevel);
+
+    cleanup(pr_table, bow_table, levels, lastLevel);
+    return 0;
+}
diff --git a/src/sunpinyin.h b/src/sunpinyin.h
new file mode 100644 (file)
index 0000000..c0a54eb
--- /dev/null
@@ -0,0 +1,13 @@
+// -*- mode: c++ -*-
+#ifndef ___SUNPINYIN_H___
+#define ___SUNPINYIN_H___
+
+#include <ime-core/imi_option_event.h>
+#include <ime-core/imi_view.h>
+#include <ime-core/imi_options.h>
+#include <ime-core/imi_keys.h>
+#include <ime-core/imi_option_keys.h>
+#include <ime-core/imi_winHandler.h>
+#include <ime-core/imi_uiobjects.h>
+
+#endif
diff --git a/sunpinyin-2.0.pc.in b/sunpinyin-2.0.pc.in
new file mode 100644 (file)
index 0000000..fc457fd
--- /dev/null
@@ -0,0 +1,11 @@
+prefix=@PREFIX@
+exec_prefix=${prefix}
+libdir=@LIBDIR@
+includedir=${exec_prefix}/include/sunpinyin-2.0
+
+Name: libsunpinyin
+Description: IME library based on Statistical Language Model
+Version: @VERSION@
+Requires: sqlite3
+Libs: -L${libdir} -lsunpinyin
+Cflags: @CFLAGS@
diff --git a/swap/README b/swap/README
new file mode 100644 (file)
index 0000000..83a9c56
--- /dev/null
@@ -0,0 +1 @@
+This is directory for temp result.
diff --git a/wrapper/ibus/CMakeLists.txt b/wrapper/ibus/CMakeLists.txt
new file mode 100644 (file)
index 0000000..3655ae0
--- /dev/null
@@ -0,0 +1,29 @@
+# CMakeLists.txt: cmake config file for ibus-sunpinyin
+
+set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/modules/")
+
+if(COMMAND cmake_policy)
+  cmake_policy(SET CMP0005 NEW)
+endif(COMMAND cmake_policy)
+
+cmake_minimum_required(VERSION 2.6)
+project(SUNPINYIN)
+
+set(PACKAGE             ibus-sunpinyin)
+set(GETTEXT_PACKAGE     ${PACKAGE})
+set(PACKAGE_NAME        ${PACKAGE})
+set(PACKAGE_BUGREPORT   "sunpinyin-developers@googlegroups.com")
+set(PACKAGE_TARNAME     ${PACKAGE})
+set(VERSION             "2.0.2")
+set(PACKAGE_VERSION     ${VERSION})
+set(PACKAGE_STRING      "${PACKAGE} ${VERSION}")
+
+include(Paths)
+
+install(DIRECTORY icons
+    DESTINATION "${DATA_DIR}")
+
+add_subdirectory (src)
+add_subdirectory (setup)
+add_subdirectory (data)
+add_subdirectory (po)
diff --git a/wrapper/ibus/COPYING b/wrapper/ibus/COPYING
new file mode 100644 (file)
index 0000000..a82e03e
--- /dev/null
@@ -0,0 +1 @@
+Refer to LGPL.LICENSE and OPENSOLARIS.LICENSE.
diff --git a/wrapper/ibus/LGPL.LICENSE b/wrapper/ibus/LGPL.LICENSE
new file mode 100644 (file)
index 0000000..5b9dd3b
--- /dev/null
@@ -0,0 +1,516 @@
+                 GNU LESSER GENERAL PUBLIC LICENSE
+                      Version 2.1, February 1999
+
+ Copyright (C) 1991, 1999 Free Software Foundation, Inc.
+ 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the Lesser GPL.  It also counts
+ as the successor of the GNU Library Public License, version 2, hence
+ the version number 2.1.]
+
+                           Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+  This license, the Lesser General Public License, applies to some
+specially designated software packages--typically libraries--of the
+Free Software Foundation and other authors who decide to use it.  You
+can use it too, but we suggest you first think carefully about whether
+this license or the ordinary General Public License is the better
+strategy to use in any particular case, based on the explanations below.
+
+  When we speak of free software, we are referring to freedom of use,
+not price.  Our General Public Licenses are designed to make sure that
+you have the freedom to distribute copies of free software (and charge
+for this service if you wish); that you receive source code or can get
+it if you want it; that you can change the software and use pieces of
+it in new free programs; and that you are informed that you can do
+these things.
+
+  To protect your rights, we need to make restrictions that forbid
+distributors to deny you these rights or to ask you to surrender these
+rights.  These restrictions translate to certain responsibilities for
+you if you distribute copies of the library or if you modify it.
+
+  For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you.  You must make sure that they, too, receive or can get the source
+code.  If you link other code with the library, you must provide
+complete object files to the recipients, so that they can relink them
+with the library after making changes to the library and recompiling
+it.  And you must show them these terms so they know their rights.
+
+  We protect your rights with a two-step method: (1) we copyright the
+library, and (2) we offer you this license, which gives you legal
+permission to copy, distribute and/or modify the library.
+
+  To protect each distributor, we want to make it very clear that
+there is no warranty for the free library.  Also, if the library is
+modified by someone else and passed on, the recipients should know
+that what they have is not the original version, so that the original
+author's reputation will not be affected by problems that might be
+introduced by others.
+\f
+  Finally, software patents pose a constant threat to the existence of
+any free program.  We wish to make sure that a company cannot
+effectively restrict the users of a free program by obtaining a
+restrictive license from a patent holder.  Therefore, we insist that
+any patent license obtained for a version of the library must be
+consistent with the full freedom of use specified in this license.
+
+  Most GNU software, including some libraries, is covered by the
+ordinary GNU General Public License.  This license, the GNU Lesser
+General Public License, applies to certain designated libraries, and
+is quite different from the ordinary General Public License.  We use
+this license for certain libraries in order to permit linking those
+libraries into non-free programs.
+
+  When a program is linked with a library, whether statically or using
+a shared library, the combination of the two is legally speaking a
+combined work, a derivative of the original library.  The ordinary
+General Public License therefore permits such linking only if the
+entire combination fits its criteria of freedom.  The Lesser General
+Public License permits more lax criteria for linking other code with
+the library.
+
+  We call this license the "Lesser" General Public License because it
+does Less to protect the user's freedom than the ordinary General
+Public License.  It also provides other free software developers Less
+of an advantage over competing non-free programs.  These disadvantages
+are the reason we use the ordinary General Public License for many
+libraries.  However, the Lesser license provides advantages in certain
+special circumstances.
+
+  For example, on rare occasions, there may be a special need to
+encourage the widest possible use of a certain library, so that it becomes
+a de-facto standard.  To achieve this, non-free programs must be
+allowed to use the library.  A more frequent case is that a free
+library does the same job as widely used non-free libraries.  In this
+case, there is little to gain by limiting the free library to free
+software only, so we use the Lesser General Public License.
+
+  In other cases, permission to use a particular library in non-free
+programs enables a greater number of people to use a large body of
+free software.  For example, permission to use the GNU C Library in
+non-free programs enables many more people to use the whole GNU
+operating system, as well as its variant, the GNU/Linux operating
+system.
+
+  Although the Lesser General Public License is Less protective of the
+users' freedom, it does ensure that the user of a program that is
+linked with the Library has the freedom and the wherewithal to run
+that program using a modified version of the Library.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.  Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library".  The
+former contains code derived from the library, whereas the latter must
+be combined with the library in order to run.
+\f
+                 GNU LESSER GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License Agreement applies to any software library or other
+program which contains a notice placed by the copyright holder or
+other authorized party saying it may be distributed under the terms of
+this Lesser General Public License (also called "this License").
+Each licensee is addressed as "you".
+
+  A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+  The "Library", below, refers to any such software library or work
+which has been distributed under these terms.  A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language.  (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+  "Source code" for a work means the preferred form of the work for
+making modifications to it.  For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+  Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it).  Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+  
+  1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+  You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+\f
+  2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) The modified work must itself be a software library.
+
+    b) You must cause the files modified to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    c) You must cause the whole of the work to be licensed at no
+    charge to all third parties under the terms of this License.
+
+    d) If a facility in the modified Library refers to a function or a
+    table of data to be supplied by an application program that uses
+    the facility, other than as an argument passed when the facility
+    is invoked, then you must make a good faith effort to ensure that,
+    in the event an application does not supply such function or
+    table, the facility still operates, and performs whatever part of
+    its purpose remains meaningful.
+
+    (For example, a function in a library to compute square roots has
+    a purpose that is entirely well-defined independent of the
+    application.  Therefore, Subsection 2d requires that any
+    application-supplied function or table used by this function must
+    be optional: if the application does not supply it, the square
+    root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library.  To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License.  (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.)  Do not make any other change in
+these notices.
+\f
+  Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+  This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+  4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+  If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library".  Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+  However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library".  The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+  When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library.  The
+threshold for this to be true is not precisely defined by law.
+
+  If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work.  (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+  Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+\f
+  6. As an exception to the Sections above, you may also combine or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+  You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License.  You must supply a copy of this License.  If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License.  Also, you must do one
+of these things:
+
+    a) Accompany the work with the complete corresponding
+    machine-readable source code for the Library including whatever
+    changes were used in the work (which must be distributed under
+    Sections 1 and 2 above); and, if the work is an executable linked
+    with the Library, with the complete machine-readable "work that
+    uses the Library", as object code and/or source code, so that the
+    user can modify the Library and then relink to produce a modified
+    executable containing the modified Library.  (It is understood
+    that the user who changes the contents of definitions files in the
+    Library will not necessarily be able to recompile the application
+    to use the modified definitions.)
+
+    b) Use a suitable shared library mechanism for linking with the
+    Library.  A suitable mechanism is one that (1) uses at run time a
+    copy of the library already present on the user's computer system,
+    rather than copying library functions into the executable, and (2)
+    will operate properly with a modified version of the library, if
+    the user installs one, as long as the modified version is
+    interface-compatible with the version that the work was made with.
+
+    c) Accompany the work with a written offer, valid for at
+    least three years, to give the same user the materials
+    specified in Subsection 6a, above, for a charge no more
+    than the cost of performing this distribution.
+
+    d) If distribution of the work is made by offering access to copy
+    from a designated place, offer equivalent access to copy the above
+    specified materials from the same place.
+
+    e) Verify that the user has already received a copy of these
+    materials or that you have already sent this user a copy.
+
+  For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it.  However, as a special exception,
+the materials to be distributed need not include anything that is
+normally distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+  It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system.  Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+\f
+  7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+    a) Accompany the combined library with a copy of the same work
+    based on the Library, uncombined with any other library
+    facilities.  This must be distributed under the terms of the
+    Sections above.
+
+    b) Give prominent notice with the combined library of the fact
+    that part of it is a work based on the Library, and explaining
+    where to find the accompanying uncombined form of the same work.
+
+  8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License.  Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License.  However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+  9. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Library or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+  10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties with
+this License.
+\f
+  11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded.  In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+  13. The Free Software Foundation may publish revised and/or new
+versions of the Lesser General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation.  If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+\f
+  14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission.  For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this.  Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+                           NO WARRANTY
+
+  15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU.  SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+  16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+                    END OF TERMS AND CONDITIONS
+\f
+           How to Apply These Terms to Your New Libraries
+
+  If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change.  You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+  To apply these terms, attach the following notices to the library.  It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the library's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with this library; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the
+  library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+  <signature of Ty Coon>, 1 April 1990
+  Ty Coon, President of Vice
+
+That's all there is to it!
+
+--------------------------------------------------------------------
+
+NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND
+DISTRIBUTION LICENSE (CDDL)
+
+For Covered Software in this distribution, this License shall
+be governed by the laws of the State of California (excluding
+conflict-of-law provisions).
+
+Any litigation relating to this License shall be subject to the
+jurisdiction of the Federal Courts of the Northern District of
+California and the state courts of the State of California, with
+venue lying in Santa Clara County, California.
diff --git a/wrapper/ibus/OPENSOLARIS.LICENSE b/wrapper/ibus/OPENSOLARIS.LICENSE
new file mode 100644 (file)
index 0000000..d838932
--- /dev/null
@@ -0,0 +1,377 @@
+COMMON DEVELOPMENT AND DISTRIBUTION LICENSE Version 1.0
+
+1. Definitions.
+
+    1.1. "Contributor" means each individual or entity that creates
+         or contributes to the creation of Modifications.
+
+    1.2. "Contributor Version" means the combination of the Original
+         Software, prior Modifications used by a Contributor (if any),
+         and the Modifications made by that particular Contributor.
+
+    1.3. "Covered Software" means (a) the Original Software, or (b)
+         Modifications, or (c) the combination of files containing
+         Original Software with files containing Modifications, in
+         each case including portions thereof.
+
+    1.4. "Executable" means the Covered Software in any form other
+         than Source Code.
+
+    1.5. "Initial Developer" means the individual or entity that first
+         makes Original Software available under this License.
+
+    1.6. "Larger Work" means a work which combines Covered Software or
+         portions thereof with code not governed by the terms of this
+         License.
+
+    1.7. "License" means this document.
+
+    1.8. "Licensable" means having the right to grant, to the maximum
+         extent possible, whether at the time of the initial grant or
+         subsequently acquired, any and all of the rights conveyed
+         herein.
+
+    1.9. "Modifications" means the Source Code and Executable form of
+         any of the following:
+
+        A. Any file that results from an addition to, deletion from or
+           modification of the contents of a file containing Original
+           Software or previous Modifications;
+
+        B. Any new file that contains any part of the Original
+           Software or previous Modifications; or
+
+        C. Any new file that is contributed or otherwise made
+           available under the terms of this License.
+
+    1.10. "Original Software" means the Source Code and Executable
+          form of computer software code that is originally released
+          under this License.
+
+    1.11. "Patent Claims" means any patent claim(s), now owned or
+          hereafter acquired, including without limitation, method,
+          process, and apparatus claims, in any patent Licensable by
+          grantor.
+
+    1.12. "Source Code" means (a) the common form of computer software
+          code in which modifications are made and (b) associated
+          documentation included in or with such code.
+
+    1.13. "You" (or "Your") means an individual or a legal entity
+          exercising rights under, and complying with all of the terms
+          of, this License.  For legal entities, "You" includes any
+          entity which controls, is controlled by, or is under common
+          control with You.  For purposes of this definition,
+          "control" means (a) the power, direct or indirect, to cause
+          the direction or management of such entity, whether by
+          contract or otherwise, or (b) ownership of more than fifty
+          percent (50%) of the outstanding shares or beneficial
+          ownership of such entity.
+
+2. License Grants.
+
+    2.1. The Initial Developer Grant.
+
+    Conditioned upon Your compliance with Section 3.1 below and
+    subject to third party intellectual property claims, the Initial
+    Developer hereby grants You a world-wide, royalty-free,
+    non-exclusive license:
+
+        (a) under intellectual property rights (other than patent or
+            trademark) Licensable by Initial Developer, to use,
+            reproduce, modify, display, perform, sublicense and
+            distribute the Original Software (or portions thereof),
+            with or without Modifications, and/or as part of a Larger
+            Work; and
+
+        (b) under Patent Claims infringed by the making, using or
+            selling of Original Software, to make, have made, use,
+            practice, sell, and offer for sale, and/or otherwise
+            dispose of the Original Software (or portions thereof).
+
+        (c) The licenses granted in Sections 2.1(a) and (b) are
+            effective on the date Initial Developer first distributes
+            or otherwise makes the Original Software available to a
+            third party under the terms of this License.
+
+        (d) Notwithstanding Section 2.1(b) above, no patent license is
+            granted: (1) for code that You delete from the Original
+            Software, or (2) for infringements caused by: (i) the
+            modification of the Original Software, or (ii) the
+            combination of the Original Software with other software
+            or devices.
+
+    2.2. Contributor Grant.
+
+    Conditioned upon Your compliance with Section 3.1 below and
+    subject to third party intellectual property claims, each
+    Contributor hereby grants You a world-wide, royalty-free,
+    non-exclusive license:
+
+        (a) under intellectual property rights (other than patent or
+            trademark) Licensable by Contributor to use, reproduce,
+            modify, display, perform, sublicense and distribute the
+            Modifications created by such Contributor (or portions
+            thereof), either on an unmodified basis, with other
+            Modifications, as Covered Software and/or as part of a
+            Larger Work; and
+
+        (b) under Patent Claims infringed by the making, using, or
+            selling of Modifications made by that Contributor either
+            alone and/or in combination with its Contributor Version
+            (or portions of such combination), to make, use, sell,
+            offer for sale, have made, and/or otherwise dispose of:
+            (1) Modifications made by that Contributor (or portions
+            thereof); and (2) the combination of Modifications made by
+            that Contributor with its Contributor Version (or portions
+            of such combination).
+
+        (c) The licenses granted in Sections 2.2(a) and 2.2(b) are
+            effective on the date Contributor first distributes or
+            otherwise makes the Modifications available to a third
+            party.
+
+        (d) Notwithstanding Section 2.2(b) above, no patent license is
+            granted: (1) for any code that Contributor has deleted
+            from the Contributor Version; (2) for infringements caused
+            by: (i) third party modifications of Contributor Version,
+            or (ii) the combination of Modifications made by that
+            Contributor with other software (except as part of the
+            Contributor Version) or other devices; or (3) under Patent
+            Claims infringed by Covered Software in the absence of
+            Modifications made by that Contributor.
+
+3. Distribution Obligations.
+
+    3.1. Availability of Source Code.
+
+    Any Covered Software that You distribute or otherwise make
+    available in Executable form must also be made available in Source
+    Code form and that Source Code form must be distributed only under
+    the terms of this License.  You must include a copy of this
+    License with every copy of the Source Code form of the Covered
+    Software You distribute or otherwise make available.  You must
+    inform recipients of any such Covered Software in Executable form
+    as to how they can obtain such Covered Software in Source Code
+    form in a reasonable manner on or through a medium customarily
+    used for software exchange.
+
+    3.2. Modifications.
+
+    The Modifications that You create or to which You contribute are
+    governed by the terms of this License.  You represent that You
+    believe Your Modifications are Your original creation(s) and/or
+    You have sufficient rights to grant the rights conveyed by this
+    License.
+
+    3.3. Required Notices.
+
+    You must include a notice in each of Your Modifications that
+    identifies You as the Contributor of the Modification.  You may
+    not remove or alter any copyright, patent or trademark notices
+    contained within the Covered Software, or any notices of licensing
+    or any descriptive text giving attribution to any Contributor or
+    the Initial Developer.
+
+    3.4. Application of Additional Terms.
+
+    You may not offer or impose any terms on any Covered Software in
+    Source Code form that alters or restricts the applicable version
+    of this License or the recipients' rights hereunder.  You may
+    choose to offer, and to charge a fee for, warranty, support,
+    indemnity or liability obligations to one or more recipients of
+    Covered Software.  However, you may do so only on Your own behalf,
+    and not on behalf of the Initial Developer or any Contributor.
+    You must make it absolutely clear that any such warranty, support,
+    indemnity or liability obligation is offered by You alone, and You
+    hereby agree to indemnify the Initial Developer and every
+    Contributor for any liability incurred by the Initial Developer or
+    such Contributor as a result of warranty, support, indemnity or
+    liability terms You offer.
+
+    3.5. Distribution of Executable Versions.
+
+    You may distribute the Executable form of the Covered Software
+    under the terms of this License or under the terms of a license of
+    Your choice, which may contain terms different from this License,
+    provided that You are in compliance with the terms of this License
+    and that the license for the Executable form does not attempt to
+    limit or alter the recipient's rights in the Source Code form from
+    the rights set forth in this License.  If You distribute the
+    Covered Software in Executable form under a different license, You
+    must make it absolutely clear that any terms which differ from
+    this License are offered by You alone, not by the Initial
+    Developer or Contributor.  You hereby agree to indemnify the
+    Initial Developer and every Contributor for any liability incurred
+    by the Initial Developer or such Contributor as a result of any
+    such terms You offer.
+
+    3.6. Larger Works.
+
+    You may create a Larger Work by combining Covered Software with
+    other code not governed by the terms of this License and
+    distribute the Larger Work as a single product.  In such a case,
+    You must make sure the requirements of this License are fulfilled
+    for the Covered Software.
+
+4. Versions of the License.
+
+    4.1. New Versions.
+
+    Sun Microsystems, Inc. is the initial license steward and may
+    publish revised and/or new versions of this License from time to
+    time.  Each version will be given a distinguishing version number.
+    Except as provided in Section 4.3, no one other than the license
+    steward has the right to modify this License.
+
+    4.2. Effect of New Versions.
+
+    You may always continue to use, distribute or otherwise make the
+    Covered Software available under the terms of the version of the
+    License under which You originally received the Covered Software.
+    If the Initial Developer includes a notice in the Original
+    Software prohibiting it from being distributed or otherwise made
+    available under any subsequent version of the License, You must
+    distribute and make the Covered Software available under the terms
+    of the version of the License under which You originally received
+    the Covered Software.  Otherwise, You may also choose to use,
+    distribute or otherwise make the Covered Software available under
+    the terms of any subsequent version of the License published by
+    the license steward.
+
+    4.3. Modified Versions.
+
+    When You are an Initial Developer and You want to create a new
+    license for Your Original Software, You may create and use a
+    modified version of this License if You: (a) rename the license
+    and remove any references to the name of the license steward
+    (except to note that the license differs from this License); and
+    (b) otherwise make it clear that the license contains terms which
+    differ from this License.
+
+5. DISCLAIMER OF WARRANTY.
+
+    COVERED SOFTWARE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS"
+    BASIS, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED,
+    INCLUDING, WITHOUT LIMITATION, WARRANTIES THAT THE COVERED
+    SOFTWARE IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR
+    PURPOSE OR NON-INFRINGING.  THE ENTIRE RISK AS TO THE QUALITY AND
+    PERFORMANCE OF THE COVERED SOFTWARE IS WITH YOU.  SHOULD ANY
+    COVERED SOFTWARE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT THE
+    INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE COST OF ANY
+    NECESSARY SERVICING, REPAIR OR CORRECTION.  THIS DISCLAIMER OF
+    WARRANTY CONSTITUTES AN ESSENTIAL PART OF THIS LICENSE.  NO USE OF
+    ANY COVERED SOFTWARE IS AUTHORIZED HEREUNDER EXCEPT UNDER THIS
+    DISCLAIMER.
+
+6. TERMINATION.
+
+    6.1. This License and the rights granted hereunder will terminate
+    automatically if You fail to comply with terms herein and fail to
+    cure such breach within 30 days of becoming aware of the breach.
+    Provisions which, by their nature, must remain in effect beyond
+    the termination of this License shall survive.
+
+    6.2. If You assert a patent infringement claim (excluding
+    declaratory judgment actions) against Initial Developer or a
+    Contributor (the Initial Developer or Contributor against whom You
+    assert such claim is referred to as "Participant") alleging that
+    the Participant Software (meaning the Contributor Version where
+    the Participant is a Contributor or the Original Software where
+    the Participant is the Initial Developer) directly or indirectly
+    infringes any patent, then any and all rights granted directly or
+    indirectly to You by such Participant, the Initial Developer (if
+    the Initial Developer is not the Participant) and all Contributors
+    under Sections 2.1 and/or 2.2 of this License shall, upon 60 days
+    notice from Participant terminate prospectively and automatically
+    at the expiration of such 60 day notice period, unless if within
+    such 60 day period You withdraw Your claim with respect to the
+    Participant Software against such Participant either unilaterally
+    or pursuant to a written agreement with Participant.
+
+    6.3. In the event of termination under Sections 6.1 or 6.2 above,
+    all end user licenses that have been validly granted by You or any
+    distributor hereunder prior to termination (excluding licenses
+    granted to You by any distributor) shall survive termination.
+
+7. LIMITATION OF LIABILITY.
+
+    UNDER NO CIRCUMSTANCES AND UNDER NO LEGAL THEORY, WHETHER TORT
+    (INCLUDING NEGLIGENCE), CONTRACT, OR OTHERWISE, SHALL YOU, THE
+    INITIAL DEVELOPER, ANY OTHER CONTRIBUTOR, OR ANY DISTRIBUTOR OF
+    COVERED SOFTWARE, OR ANY SUPPLIER OF ANY OF SUCH PARTIES, BE
+    LIABLE TO ANY PERSON FOR ANY INDIRECT, SPECIAL, INCIDENTAL, OR
+    CONSEQUENTIAL DAMAGES OF ANY CHARACTER INCLUDING, WITHOUT
+    LIMITATION, DAMAGES FOR LOST PROFITS, LOSS OF GOODWILL, WORK
+    STOPPAGE, COMPUTER FAILURE OR MALFUNCTION, OR ANY AND ALL OTHER
+    COMMERCIAL DAMAGES OR LOSSES, EVEN IF SUCH PARTY SHALL HAVE BEEN
+    INFORMED OF THE POSSIBILITY OF SUCH DAMAGES.  THIS LIMITATION OF
+    LIABILITY SHALL NOT APPLY TO LIABILITY FOR DEATH OR PERSONAL
+    INJURY RESULTING FROM SUCH PARTY'S NEGLIGENCE TO THE EXTENT
+    APPLICABLE LAW PROHIBITS SUCH LIMITATION.  SOME JURISDICTIONS DO
+    NOT ALLOW THE EXCLUSION OR LIMITATION OF INCIDENTAL OR
+    CONSEQUENTIAL DAMAGES, SO THIS EXCLUSION AND LIMITATION MAY NOT
+    APPLY TO YOU.
+
+8. U.S. GOVERNMENT END USERS.
+
+    The Covered Software is a "commercial item," as that term is
+    defined in 48 C.F.R. 2.101 (Oct. 1995), consisting of "commercial
+    computer software" (as that term is defined at 48
+    C.F.R. 252.227-7014(a)(1)) and "commercial computer software
+    documentation" as such terms are used in 48 C.F.R. 12.212
+    (Sept. 1995).  Consistent with 48 C.F.R. 12.212 and 48
+    C.F.R. 227.7202-1 through 227.7202-4 (June 1995), all
+    U.S. Government End Users acquire Covered Software with only those
+    rights set forth herein.  This U.S. Government Rights clause is in
+    lieu of, and supersedes, any other FAR, DFAR, or other clause or
+    provision that addresses Government rights in computer software
+    under this License.
+
+9. MISCELLANEOUS.
+
+    This License represents the complete agreement concerning subject
+    matter hereof.  If any provision of this License is held to be
+    unenforceable, such provision shall be reformed only to the extent
+    necessary to make it enforceable.  This License shall be governed
+    by the law of the jurisdiction specified in a notice contained
+    within the Original Software (except to the extent applicable law,
+    if any, provides otherwise), excluding such jurisdiction's
+    conflict-of-law provisions.  Any litigation relating to this
+    License shall be subject to the jurisdiction of the courts located
+    in the jurisdiction and venue specified in a notice contained
+    within the Original Software, with the losing party responsible
+    for costs, including, without limitation, court costs and
+    reasonable attorneys' fees and expenses.  The application of the
+    United Nations Convention on Contracts for the International Sale
+    of Goods is expressly excluded.  Any law or regulation which
+    provides that the language of a contract shall be construed
+    against the drafter shall not apply to this License.  You agree
+    that You alone are responsible for compliance with the United
+    States export administration regulations (and the export control
+    laws and regulation of any other countries) when You use,
+    distribute or otherwise make available any Covered Software.
+
+10. RESPONSIBILITY FOR CLAIMS.
+
+    As between Initial Developer and the Contributors, each party is
+    responsible for claims and damages arising, directly or
+    indirectly, out of its utilization of rights under this License
+    and You agree to work with Initial Developer and Contributors to
+    distribute such responsibility on an equitable basis.  Nothing
+    herein is intended or shall be deemed to constitute any admission
+    of liability.
+
+--------------------------------------------------------------------
+
+NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND
+DISTRIBUTION LICENSE (CDDL)
+
+For Covered Software in this distribution, this License shall
+be governed by the laws of the State of California (excluding
+conflict-of-law provisions).
+
+Any litigation relating to this License shall be subject to the
+jurisdiction of the Federal Courts of the Northern District of
+California and the state courts of the State of California, with
+venue lying in Santa Clara County, California.
diff --git a/wrapper/ibus/README b/wrapper/ibus/README
new file mode 100644 (file)
index 0000000..e1e2c26
--- /dev/null
@@ -0,0 +1,6 @@
+ibus-sunpinyin
+===
+
+ibus-sunpinyin is a wrapper around SunPinyin which enables user to use
+SunPinyin with IBus framework. 
+
diff --git a/wrapper/ibus/SConstruct b/wrapper/ibus/SConstruct
new file mode 100644 (file)
index 0000000..156c85f
--- /dev/null
@@ -0,0 +1,172 @@
+import os
+
+sources = ['src/debug.cpp',
+           'src/engine.cpp',
+           'src/ibus_portable.cpp',
+           'src/imi_ibus_win.cpp',
+           'src/main.cpp',
+           'src/sunpinyin_config.cpp',
+           'src/sunpinyin_engine.cpp',
+           'src/sunpinyin_engine_proxy.cpp',
+           'src/sunpinyin_lookup_table.cpp',
+           'src/sunpinyin_property.cpp']
+
+locales = ['zh_CN']
+
+cflags = '-O2 -g -pipe '
+version = '2.0.3'
+
+AddOption('--prefix', dest='prefix', metavar='DIR',
+          help='installation prefix')
+AddOption('--libdir', dest='libdir', metavar='DIR',
+          help='installation libdir')
+AddOption('--libexecdir', dest='libexecdir', metavar='DIR',
+          help='installation libexecdir')
+AddOption('--datadir', dest='datadir', metavar='DIR',
+          help='installation datadir')
+AddOption('--rpath', dest='rpath', metavar='DIR',
+          help='encode rpath in the executables')
+
+opts = Variables('configure.conf')
+opts.Add('PREFIX', default='/usr/local')
+opts.Add('LIBDIR', default='/usr/local/lib')
+opts.Add('LIBEXECDIR', default='/usr/local/lib')
+opts.Add('DATADIR', default='/usr/local/share')
+
+def PassVariables(envvar, env):
+    for (x, y) in envvar:
+        if x in os.environ:
+            print 'Warning: you\'ve set %s in the environmental variable!' % x
+            env[y] = os.environ[x]
+
+env = Environment(ENV=os.environ,
+                  CFLAGS=cflags, CXXFLAGS=cflags, 
+                  CPPPATH=['.'],
+                  tools=['default', 'textfile'])
+opts.Update(env)
+
+if GetOption('prefix') is not None:
+    env['PREFIX'] = GetOption('prefix')
+    env['LIBDIR'] = env['PREFIX'] + '/lib'
+    env['LIBEXECDIR'] = env['PREFIX'] + '/lib/'
+    env['DATADIR'] = env['PREFIX'] + '/share/'
+
+if GetOption('libdir') is not None:
+    env['LIBDIR'] = GetOption('libdir')
+
+if GetOption('libexecdir') is not None:
+    env['LIBEXECDIR'] = GetOption('libexecdir')
+
+if GetOption('datadir') is not None:
+    env['DATADIR'] = GetOption('datadir')
+
+opts.Save('configure.conf', env)
+
+envvar = [('CC', 'CC'),
+          ('CXX', 'CXX'),
+          ('CFLAGS', 'CFLAGS'),
+          ('CXXFLAGS', 'CXXFLAGS'),
+          ('LDFLAGS', 'LINKFLAGS')]
+PassVariables(envvar, env)
+
+data_dir = env['DATADIR'] + '/ibus-sunpinyin'
+icons_dir = env['DATADIR'] + '/ibus-sunpinyin/icons'
+bin_dir = env['LIBEXECDIR'] + '/ibus-sunpinyin'
+gettext_package = 'ibus-sunpinyin'
+
+extra_cflags = ' -DIBUS_SUNPINYIN_LOCALEDIR=\'"%s"\'' % (env['DATADIR'] + '/locale')
+extra_cflags += ' -DIBUS_SUNPINYIN_ICON_DIR=\'"%s"\'' % icons_dir
+extra_cflags += ' -DLIBEXECDIR=\'"%s"\'' % bin_dir
+extra_cflags += ' -DGETTEXT_PACKAGE=\'"%s"\'' % gettext_package
+
+env.Append(CFLAGS=extra_cflags)
+env.Append(CXXFLAGS=extra_cflags)
+
+if GetOption('rpath') is not None:
+    env.Append(LINKFLAGS=' -Wl,-R -Wl,%s' % GetOption('rpath'))
+
+#
+#==============================configure================================
+#
+def CheckPKGConfig(context, version='0.12.0'):
+    context.Message( 'Checking for pkg-config... ' )
+    ret = context.TryAction('pkg-config --atleast-pkgconfig-version=%s' % version)[0]
+    context.Result(ret)
+    return ret
+
+def CheckPKG(context, name):
+    context.Message( 'Checking for %s... ' % name )
+    ret = context.TryAction('pkg-config --exists \'%s\'' % name)[0]
+    context.Result(ret)
+    return ret
+
+conf = Configure(env, custom_tests={'CheckPKGConfig' : CheckPKGConfig,
+                                    'CheckPKG' : CheckPKG })
+
+def DoConfigure():
+    if GetOption('clean'):
+        return
+
+    if not conf.CheckPKGConfig():
+        Exit(1)
+
+    if not conf.CheckPKG('ibus-1.0'):
+        Exit(1)
+
+    if not conf.CheckPKG('sunpinyin-2.0'):
+        Exit(1)
+    env = conf.Finish()
+    env.ParseConfig('pkg-config ibus-1.0 sunpinyin-2.0 --libs --cflags')
+
+DoConfigure()
+
+env.Program('ibus-engine-sunpinyin', source=sources)
+for locale in locales:
+    mo = 'po/%s.mo' % (locale,)
+    env.Command(mo, [], 'msgfmt po/%s.po -o %s' % (locale, mo))
+
+sub = {'@LIBEXEC_DIR@': bin_dir,
+       '@DATA_DIR@' : data_dir,
+       '@ICON_DIR@': icons_dir,
+       '@VERSION@' : version,
+       '@INSTALL_PREFIX@': env['PREFIX']}
+env.Substfile('data/sunpinyin.xml.in', SUBST_DICT=sub)
+env.Substfile('setup/config.py.in', SUBST_DICT=sub)
+env.Substfile('setup/ibus-setup-sunpinyin.in', SUBST_DICT=sub)
+
+#
+#==============================install================================
+#
+def DoInstall():
+    libexec_target = env.Install(bin_dir, ['ibus-engine-sunpinyin', 
+                                           'setup/ibus-setup-sunpinyin'])
+    for exec_bin in libexec_target:
+        env.AddPostAction(exec_bin, Chmod(str(exec_bin), 0755))
+        
+    setup_target = env.Install(data_dir + '/setup',
+                               ['setup/setup.xml',
+                                'setup/main.py',
+                                'setup/config.py'])
+    icons_target = env.Install(icons_dir,
+                               ['icons/cnpunc.svg',
+                                'icons/eng.svg',
+                                'icons/enpunc.svg',
+                                'icons/fullwidth.svg',
+                                'icons/halfwidth.svg',
+                                'icons/han.svg',
+                                'icons/setup.svg',
+                                'icons/sunpinyin-logo.png'])
+    component_target = env.Install(env['DATADIR'] + '/ibus/component',
+                                   'data/sunpinyin.xml')
+    locale_targets = []
+    for locale in locales:
+        path = env['DATADIR'] + '/locale/%s/LC_MESSAGES/%s.mo' % \
+            (locale, gettext_package)
+        locale_targets.append(env.InstallAs(path, 'po/%s.mo' % (locale,)))
+
+    env.Alias('install-libexec', [libexec_target, setup_target])
+    env.Alias('install-data', [icons_target, component_target])
+    env.Alias('install-locale', locale_targets)
+
+DoInstall()
+env.Alias('install', ['install-libexec', 'install-data', 'install-locale'])
diff --git a/wrapper/ibus/cmake/modules/FindSunPinyin.cmake b/wrapper/ibus/cmake/modules/FindSunPinyin.cmake
new file mode 100644 (file)
index 0000000..ee1e59b
--- /dev/null
@@ -0,0 +1,34 @@
+# - Try to find SunPinyin
+# Once done, this will define
+#
+#  SunPinyin_FOUND - system has iBus
+#  SunPinyin_INCLUDE_DIRS - the iBus include directories
+#  SunPinyin_LIBRARIES - link these to use iBus
+
+include(LibFindMacros)
+
+# Dependencies
+
+# Use pkg-config to get hints about paths
+libfind_pkg_check_modules(SunPinyin_PKGCONF sunpinyin-2.0)
+
+# Include dir
+find_path(SunPinyin_INCLUDE_DIR
+  NAMES sunpinyin.h
+  PATHS ${SunPinyin_PKGCONF_INCLUDE_DIRS}
+)
+
+# Finally the library itself
+find_library(SunPinyin_LIBRARY
+  NAMES sunpinyin
+  PATHS ${SunPinyin_PKGCONF_LIBRARY_DIRS}
+)
+
+# Set the include dir variables and the libraries and let libfind_process do the
+# rest.
+# NOTE: Singular variables for this library, plural for libraries this this lib
+# depends on.
+set(SunPinyin_PROCESS_INCLUDES SunPinyin_INCLUDE_DIR)
+set(SunPinyin_PROCESS_LIBS SunPinyin_LIBRARY)
+libfind_process(SunPinyin)
+
diff --git a/wrapper/ibus/cmake/modules/FindiBus.cmake b/wrapper/ibus/cmake/modules/FindiBus.cmake
new file mode 100644 (file)
index 0000000..f3e9052
--- /dev/null
@@ -0,0 +1,34 @@
+# - Try to find iBus
+# Once done, this will define
+#
+#  iBus_FOUND - system has iBus
+#  iBus_INCLUDE_DIRS - the iBus include directories
+#  iBus_LIBRARIES - link these to use iBus
+
+include(LibFindMacros)
+
+# Dependencies
+
+# Use pkg-config to get hints about paths
+libfind_pkg_check_modules(iBus_PKGCONF ibus-1.0)
+
+# Include dir
+find_path(iBus_INCLUDE_DIR
+  NAMES ibus.h
+  PATHS ${iBus_PKGCONF_INCLUDE_DIRS}
+)
+
+# Finally the library itself
+find_library(iBus_LIBRARY
+  NAMES ibus
+  PATHS ${iBus_PKGCONF_LIBRARY_DIRS}
+)
+
+# Set the include dir variables and the libraries and let libfind_process do the
+# rest.
+# NOTE: Singular variables for this library, plural for libraries this this lib
+# depends on.
+set(iBus_PROCESS_INCLUDES iBus_INCLUDE_DIR)
+set(iBus_PROCESS_LIBS iBus_LIBRARY)
+libfind_process(iBus)
+
diff --git a/wrapper/ibus/cmake/modules/Gettext.cmake b/wrapper/ibus/cmake/modules/Gettext.cmake
new file mode 100644 (file)
index 0000000..3dfe68d
--- /dev/null
@@ -0,0 +1,161 @@
+# Gettext support: Create/Update pot file and
+#
+# To use: INCLUDE(Gettext)
+#
+# Most of the gettext support code is from FindGettext.cmake of cmake,
+# but it is included here because:
+#
+# 1. Some system like RHEL5 does not have FindGettext.cmake
+# 2. Bug of GETTEXT_CREATE_TRANSLATIONS make it unable to be include in 'All'
+# 3. It does not support xgettext
+#
+#===================================================================
+# Variables:
+#  XGETTEXT_OPTIONS: Options pass to xgettext
+#      Default:  --language=C --keyword=_ --keyword=N_ --keyword=C_:1c,2 --keyword=NC_:1c,2
+#  GETTEXT_MSGMERGE_EXECUTABLE: the full path to the msgmerge tool.
+#  GETTEXT_MSGFMT_EXECUTABLE: the full path to the msgfmt tool.
+#  GETTEXT_FOUND: True if gettext has been found.
+#  XGETTEXT_EXECUTABLE: the full path to the xgettext.
+#  XGETTEXT_FOUND: True if xgettext has been found.
+#
+#===================================================================
+# Macros:
+# GETTEXT_CREATE_POT(potFile
+#    [OPTION xgettext_options]
+#    SRC list_of_source_file_that_contains_msgid
+# )
+#
+# Generate .pot file.
+#    OPTION xgettext_options: Override XGETTEXT_OPTIONS
+#
+# * Produced targets: pot_file
+#
+#-------------------------------------------------------------------
+# GETTEXT_CREATE_TRANSLATIONS ( outputFile [ALL] locale1 ... localeN
+#     [COMMENT comment] )
+#
+#     This will create a target "translations" which will convert the
+#     given input po files into the binary output mo file. If the
+#     ALL option is used, the translations will also be created when
+#     building the default target.
+#
+# * Produced targets: translations
+#-------------------------------------------------------------------
+
+
+FIND_PROGRAM(GETTEXT_MSGMERGE_EXECUTABLE msgmerge)
+FIND_PROGRAM(GETTEXT_MSGFMT_EXECUTABLE msgfmt)
+FIND_PROGRAM(XGETTEXT_EXECUTABLE xgettext)
+
+IF (GETTEXT_MSGMERGE_EXECUTABLE AND GETTEXT_MSGFMT_EXECUTABLE )
+    SET(GETTEXT_FOUND TRUE)
+ELSE (GETTEXT_MSGMERGE_EXECUTABLE AND GETTEXT_MSGFMT_EXECUTABLE)
+    SET(GETTEXT_FOUND FALSE)
+    IF (GetText_REQUIRED)
+       MESSAGE(FATAL_ERROR "GetText not found")
+    ENDIF (GetText_REQUIRED)
+ENDIF (GETTEXT_MSGMERGE_EXECUTABLE AND GETTEXT_MSGFMT_EXECUTABLE )
+
+IF(XGETTEXT_EXECUTABLE)
+    SET(XGETTEXT_FOUND TRUE)
+ELSE(XGETTEXT_EXECUTABLE)
+    MESSAGE(STATUS "xgettext not found.")
+    SET(XGETTTEXT_FOUND FALSE)
+ENDIF(XGETTEXT_EXECUTABLE)
+
+IF(NOT DEFINED XGETTEXT_OPTIONS)
+    SET(XGETTEXT_OPTIONS --keyword=_ --keyword=N_ --keyword=C_:1c,2 --keyword=NC_:1c,2 -s)
+ENDIF(NOT DEFINED XGETTEXT_OPTIONS)
+
+IF(XGETTEXT_FOUND)
+    MACRO(GETTEXT_CREATE_POT _potFile _pot_options )
+       SET(_xgettext_options_list)
+       SET(_src_list)
+       SET(_src_list_abs)
+       SET(_stage "SRC")
+       FOREACH(_pot_option ${_pot_options} ${ARGN})
+           IF(_pot_option STREQUAL "OPTION")
+               SET(_stage "OPTION")
+           ELSEIF(_pot_option STREQUAL "SRC")
+               SET(_stage "SRC")
+           ELSE(_pot_option STREQUAL "OPTION")
+               IF(_stage STREQUAL "OPTION")
+                   SET(_xgettext_options_list ${_xgettext_options_list} ${_pot_option})
+               ELSE(_stage STREQUAL "OPTION")
+                   FILE(RELATIVE_PATH _relFile ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/${_pot_option})
+                   GET_FILENAME_COMPONENT(_absFile ${_pot_option} ABSOLUTE)
+                   SET(_src_list ${_src_list} ${_relFile})
+                   SET(_src_list_abs ${_src_list_abs} ${_absFile})
+               ENDIF(_stage STREQUAL "OPTION")
+           ENDIF(_pot_option STREQUAL "OPTION")
+       ENDFOREACH(_pot_option ${_pot_options} ${ARGN})
+
+       IF (_xgettext_options_list)
+           SET(_xgettext_options ${_xgettext_options_list})
+       ELSE(_xgettext_options_list)
+           SET(_xgettext_options ${XGETTEXT_OPTIONS})
+       ENDIF(_xgettext_options_list)
+
+       #MESSAGE("${XGETTEXT_EXECUTABLE} ${_xgettext_options_list} -o ${_potFile} ${_src_list}")
+       ADD_CUSTOM_COMMAND(OUTPUT ${_potFile}
+           COMMAND ${XGETTEXT_EXECUTABLE} ${_xgettext_options} -o ${_potFile} ${_src_list}
+           DEPENDS ${_src_list_abs}
+           WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
+           )
+
+       ADD_CUSTOM_TARGET(pot_file
+           COMMAND ${XGETTEXT_EXECUTABLE} ${_xgettext_options_list} -o ${_potFile} ${_src_list}
+           DEPENDS ${_src_list_abs}
+           WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
+           COMMENT "Extract translatable messages to ${_potFile}"
+           )
+    ENDMACRO(GETTEXT_CREATE_POT _potFile _pot_options)
+
+
+    MACRO(GETTEXT_CREATE_TRANSLATIONS _potFile _firstLang)
+       SET(_gmoFiles)
+       GET_FILENAME_COMPONENT(_potBasename ${_potFile} NAME_WE)
+       GET_FILENAME_COMPONENT(_absPotFile ${_potFile} ABSOLUTE)
+
+       SET(_addToAll)
+       SET(_is_comment FALSE)
+
+       FOREACH (_currentLang ${_firstLang} ${ARGN})
+           IF(_currentLang STREQUAL "ALL")
+               SET(_addToAll "ALL")
+           ELSEIF(_currentLang STREQUAL "COMMENT")
+               SET(_is_comment TRUE)
+           ELSEIF(_is_comment)
+               SET(_is_comment FALSE)
+               SET(_comment ${_currentLang})
+           ELSE()
+               SET(_lang ${_currentLang})
+               GET_FILENAME_COMPONENT(_absFile ${_currentLang}.po ABSOLUTE)
+               GET_FILENAME_COMPONENT(_abs_PATH ${_absFile} PATH)
+               SET(_gmoFile ${CMAKE_CURRENT_BINARY_DIR}/${_lang}.gmo)
+
+               #MESSAGE("_absFile=${_absFile} _abs_PATH=${_abs_PATH} _lang=${_lang} curr_bin=${CMAKE_CURRENT_BINARY_DIR}")
+               ADD_CUSTOM_COMMAND(
+                   OUTPUT ${_gmoFile}
+                   COMMAND ${GETTEXT_MSGMERGE_EXECUTABLE} --quiet --update --backup=none -s ${_absFile} ${_absPotFile}
+                   COMMAND ${GETTEXT_MSGFMT_EXECUTABLE} -o ${_gmoFile} ${_absFile}
+                   DEPENDS ${_absPotFile} ${_absFile}
+                   WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
+                   )
+
+               INSTALL(FILES ${_gmoFile} DESTINATION share/locale/${_lang}/LC_MESSAGES RENAME ${_potBasename}.mo)
+               SET(_gmoFiles ${_gmoFiles} ${_gmoFile})
+           ENDIF()
+       ENDFOREACH (_currentLang )
+
+       IF(DEFINED _comment)
+           ADD_CUSTOM_TARGET(translations ${_addToAll} DEPENDS ${_gmoFiles} COMMENT ${_comment})
+       ELSE(DEFINED _comment)
+           ADD_CUSTOM_TARGET(translations ${_addToAll} DEPENDS ${_gmoFiles})
+       ENDIF(DEFINED _comment)
+    ENDMACRO(GETTEXT_CREATE_TRANSLATIONS )
+ENDIF(XGETTEXT_FOUND)
+
+
+
diff --git a/wrapper/ibus/cmake/modules/LibFindMacros.cmake b/wrapper/ibus/cmake/modules/LibFindMacros.cmake
new file mode 100644 (file)
index 0000000..69975c5
--- /dev/null
@@ -0,0 +1,99 @@
+# Works the same as find_package, but forwards the "REQUIRED" and "QUIET" arguments
+# used for the current package. For this to work, the first parameter must be the
+# prefix of the current package, then the prefix of the new package etc, which are
+# passed to find_package.
+macro (libfind_package PREFIX)
+  set (LIBFIND_PACKAGE_ARGS ${ARGN})
+  if (${PREFIX}_FIND_QUIETLY)
+    set (LIBFIND_PACKAGE_ARGS ${LIBFIND_PACKAGE_ARGS} QUIET)
+  endif (${PREFIX}_FIND_QUIETLY)
+  if (${PREFIX}_FIND_REQUIRED)
+    set (LIBFIND_PACKAGE_ARGS ${LIBFIND_PACKAGE_ARGS} REQUIRED)
+  endif (${PREFIX}_FIND_REQUIRED)
+  find_package(${LIBFIND_PACKAGE_ARGS})
+endmacro (libfind_package)
+
+# CMake developers made the UsePkgConfig system deprecated in the same release (2.6)
+# where they added pkg_check_modules. Consequently I need to support both in my scripts
+# to avoid those deprecated warnings. Here's a helper that does just that.
+# Works identically to pkg_check_modules, except that no checks are needed prior to use.
+macro (libfind_pkg_check_modules PREFIX PKGNAME)
+  if (${CMAKE_MAJOR_VERSION} EQUAL 2 AND ${CMAKE_MINOR_VERSION} EQUAL 4)
+    include(UsePkgConfig)
+    pkgconfig(${PKGNAME} ${PREFIX}_INCLUDE_DIRS ${PREFIX}_LIBRARY_DIRS ${PREFIX}_LDFLAGS ${PREFIX}_CFLAGS)
+  else (${CMAKE_MAJOR_VERSION} EQUAL 2 AND ${CMAKE_MINOR_VERSION} EQUAL 4)
+    find_package(PkgConfig)
+    if (PKG_CONFIG_FOUND)
+      pkg_check_modules(${PREFIX} ${PKGNAME})
+    endif (PKG_CONFIG_FOUND)
+  endif (${CMAKE_MAJOR_VERSION} EQUAL 2 AND ${CMAKE_MINOR_VERSION} EQUAL 4)
+endmacro (libfind_pkg_check_modules)
+
+# Do the final processing once the paths have been detected.
+# If include dirs are needed, ${PREFIX}_PROCESS_INCLUDES should be set to contain
+# all the variables, each of which contain one include directory.
+# Ditto for ${PREFIX}_PROCESS_LIBS and library files.
+# Will set ${PREFIX}_FOUND, ${PREFIX}_INCLUDE_DIRS and ${PREFIX}_LIBRARIES.
+# Also handles errors in case library detection was required, etc.
+macro (libfind_process PREFIX)
+  # Skip processing if already processed during this run
+  if (NOT ${PREFIX}_FOUND)
+    # Start with the assumption that the library was found
+    set (${PREFIX}_FOUND TRUE)
+
+    # Process all includes and set _FOUND to false if any are missing
+    foreach (i ${${PREFIX}_PROCESS_INCLUDES})
+      if (${i})
+        set (${PREFIX}_INCLUDE_DIRS ${${PREFIX}_INCLUDE_DIRS} ${${i}})
+        mark_as_advanced(${i})
+      else (${i})
+        set (${PREFIX}_FOUND FALSE)
+      endif (${i})
+    endforeach (i)
+
+    # Process all libraries and set _FOUND to false if any are missing
+    foreach (i ${${PREFIX}_PROCESS_LIBS})
+      if (${i})
+        set (${PREFIX}_LIBRARIES ${${PREFIX}_LIBRARIES} ${${i}})
+        mark_as_advanced(${i})
+      else (${i})
+        set (${PREFIX}_FOUND FALSE)
+      endif (${i})
+    endforeach (i)
+
+    # Print message and/or exit on fatal error
+    if (${PREFIX}_FOUND)
+      if (NOT ${PREFIX}_FIND_QUIETLY)
+        message (STATUS "Found ${PREFIX} ${${PREFIX}_VERSION}")
+      endif (NOT ${PREFIX}_FIND_QUIETLY)
+    else (${PREFIX}_FOUND)
+      if (${PREFIX}_FIND_REQUIRED)
+        foreach (i ${${PREFIX}_PROCESS_INCLUDES} ${${PREFIX}_PROCESS_LIBS})
+          message("${i}=${${i}}")
+        endforeach (i)
+        message (FATAL_ERROR "Required library ${PREFIX} NOT FOUND.\nInstall the library (dev version) and try again. If the library is already installed, use ccmake to set the missing variables manually.")
+      endif (${PREFIX}_FIND_REQUIRED)
+    endif (${PREFIX}_FOUND)
+  endif (NOT ${PREFIX}_FOUND)
+endmacro (libfind_process)
+
+macro(libfind_library PREFIX basename)
+  set(TMP "")
+  if(MSVC80)
+    set(TMP -vc80)
+  endif(MSVC80)
+  if(MSVC90)
+    set(TMP -vc90)
+  endif(MSVC90)
+  set(${PREFIX}_LIBNAMES ${basename}${TMP})
+  if(${ARGC} GREATER 2)
+    set(${PREFIX}_LIBNAMES ${basename}${TMP}-${ARGV2})
+    string(REGEX REPLACE "\\." "_" TMP ${${PREFIX}_LIBNAMES})
+    set(${PREFIX}_LIBNAMES ${${PREFIX}_LIBNAMES} ${TMP})
+  endif(${ARGC} GREATER 2)
+  find_library(${PREFIX}_LIBRARY
+    NAMES ${${PREFIX}_LIBNAMES}
+    PATHS ${${PREFIX}_PKGCONF_LIBRARY_DIRS}
+  )
+endmacro(libfind_library)
+
diff --git a/wrapper/ibus/cmake/modules/Paths.cmake b/wrapper/ibus/cmake/modules/Paths.cmake
new file mode 100644 (file)
index 0000000..bc96c12
--- /dev/null
@@ -0,0 +1,12 @@
+if(NOT DEFINED LIBEXEC_DIR)
+    set(LIBEXEC_DIR "${CMAKE_INSTALL_PREFIX}/libexec")
+endif()
+add_definitions(-DLIBEXECDIR="${LIBEXEC_DIR}")
+
+set(INSTALL_PREFIX "${CMAKE_INSTALL_PREFIX}")
+set(DATA_DIR "${CMAKE_INSTALL_PREFIX}/share/${PACKAGE}")
+set(ICON_DIR "${DATA_DIR}/icons")
+
+add_definitions(-DIBUS_SUNPINYIN_ICON_DIR="${ICON_DIR}"
+                -DGETTEXT_PACKAGE="${GETTEXT_PACKAGE}"
+                -DIBUS_SUNPINYIN_LOCALEDIR="${CMAKE_INSTALL_PREFIX}/share/locale")
diff --git a/wrapper/ibus/data/CMakeLists.txt b/wrapper/ibus/data/CMakeLists.txt
new file mode 100644 (file)
index 0000000..9489bd2
--- /dev/null
@@ -0,0 +1,4 @@
+configure_file(${CMAKE_CURRENT_SOURCE_DIR}/sunpinyin.xml.in
+               ${CMAKE_CURRENT_BINARY_DIR}/sunpinyin.xml)
+install(FILES ${CMAKE_CURRENT_BINARY_DIR}/sunpinyin.xml
+    DESTINATION "${CMAKE_INSTALL_PREFIX}/share/ibus/component")
diff --git a/wrapper/ibus/data/sunpinyin.xml.in b/wrapper/ibus/data/sunpinyin.xml.in
new file mode 100644 (file)
index 0000000..1e986b5
--- /dev/null
@@ -0,0 +1,27 @@
+<?xml version=\"1.0\" encoding=\"utf-8\"?>
+<!-- filename: sunpinyin.xml -->
+<component>
+  <name>org.freedesktop.IBus.SunPinyin</name>
+  <description>SunPinyin Component</description>
+  <exec>@LIBEXEC_DIR@/ibus-engine-sunpinyin --ibus</exec>
+  <version>@VERSION@</version>
+  <author>Kov Chai &lt;tchaikov@gmail.com&gt;</author>
+  <license>LGPL</license>
+  <homepage>http://opensolaris.org/os/project/input-method/</homepage>
+  <textdomain>ibus-sunpinyin</textdomain>
+  
+  <!-- for static engines -->
+  <engines>
+    <engine>
+      <name>sunpinyin</name>
+      <language>zh_CN</language>
+      <license>LGPL</license>
+      <author>Kov Chai &lt;tchaikov@gmail.com&gt;</author>
+      <icon>@ICON_DIR@/sunpinyin-logo.png</icon>
+      <layout>us</layout>
+      <longname>SunPinyin</longname>
+      <description>SunPinyin Input Method</description>
+      <rank>99</rank>
+    </engine>
+  </engines>
+</component>
diff --git a/wrapper/ibus/icons/cnpunc.svg b/wrapper/ibus/icons/cnpunc.svg
new file mode 100644 (file)
index 0000000..3c87c8a
--- /dev/null
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   version="1.0"
+   width="64"
+   height="64"
+   id="svg2383">
+  <defs
+     id="defs2385" />
+  <g
+     id="layer1">
+    <path
+       d="M 45.959044,31.180906 C 45.794763,37.094985 42.016314,43.666204 36.595072,48.101764 L 39.387836,51.387368 C 45.959037,46.951808 52.694531,39.230622 52.694531,27.23818 C 52.694531,20.99554 49.901762,16.395688 44.15196,16.395688 C 39.387841,16.395688 35.773671,20.009858 35.773671,24.938258 C 35.773671,30.359498 39.059279,32.823707 41.852039,32.823707 C 43.166279,32.823707 45.137643,32.495145 45.794763,31.180906 L 45.959044,31.180906"
+       id="text2395"
+       style="font-size:116.15293884px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#fffcfc;fill-opacity:1;stroke:#35556b;stroke-width:2.56687784px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Adobe Kaiti Std;-inkscape-font-specification:Adobe Kaiti Std" />
+    <path
+       d="M 16,36.272728 C 16,39.335398 13.517215,41.818183 10.454545,41.818183 C 7.3918752,41.818183 4.9090905,39.335398 4.9090905,36.272728 C 4.9090905,33.210058 7.3918752,30.727273 10.454545,30.727273 C 13.517215,30.727273 16,33.210058 16,36.272728 z"
+       transform="matrix(1.7010723,0,0,1.7010723,1.4887892,-28.087496)"
+       id="path3235"
+       style="opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:#35556b;stroke-width:1.73880613;stroke-linecap:square;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
+  </g>
+</svg>
diff --git a/wrapper/ibus/icons/eng.svg b/wrapper/ibus/icons/eng.svg
new file mode 100644 (file)
index 0000000..2627d79
--- /dev/null
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   version="1.0"
+   width="48"
+   height="48"
+   id="svg2710">
+  <defs
+     id="defs2712">
+    <filter
+       id="filter4889">
+      <feGaussianBlur
+         id="feGaussianBlur4891"
+         stdDeviation="0.8789348"
+         inkscape:collect="always" />
+    </filter>
+  </defs>
+  <g
+     id="layer1">
+    <text
+       x="-2.4050589"
+       y="43"
+       id="text2720"
+       xml:space="preserve"
+       style="font-size:48px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#35556b;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Adobe Kaiti Std;-inkscape-font-specification:Adobe Kaiti Std"><tspan
+         x="-2.4050589"
+         y="43"
+         id="tspan2722">英</tspan></text>
+    <text
+       x="-0.94521457"
+       y="43.750927"
+       id="text3520"
+       xml:space="preserve"
+       style="font-size:48px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;opacity:1;fill:#36556b;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;filter:url(#filter4889);font-family:Adobe Kaiti Std;-inkscape-font-specification:Adobe Kaiti Std"><tspan
+         x="-0.94521457"
+         y="43.750927"
+         id="tspan3522">英</tspan></text>
+  </g>
+</svg>
diff --git a/wrapper/ibus/icons/enpunc.svg b/wrapper/ibus/icons/enpunc.svg
new file mode 100644 (file)
index 0000000..e320bb7
--- /dev/null
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   version="1.0"
+   width="64"
+   height="64"
+   id="svg2383">
+  <defs
+     id="defs2385" />
+  <g
+     id="layer1">
+    <text
+       x="31.421482"
+       y="37.179684"
+       transform="scale(1.0226118,0.9778882)"
+       id="text3788"
+       xml:space="preserve"
+       style="font-size:101.39350891px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#35556b;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Adobe Heiti Std;-inkscape-font-specification:Adobe Heiti Std"><tspan
+         x="31.421482"
+         y="37.179684"
+         id="tspan3790">,</tspan></text>
+    <text
+       x="7.2146564"
+       y="44.207535"
+       transform="scale(1.0206497,0.9797681)"
+       id="text3800"
+       xml:space="preserve"
+       style="font-size:85.94076538px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#35556b;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Adobe Heiti Std;-inkscape-font-specification:Adobe Heiti Std"><tspan
+         x="7.2146564"
+         y="44.207535"
+         id="tspan3802">.</tspan></text>
+  </g>
+</svg>
diff --git a/wrapper/ibus/icons/fullwidth.svg b/wrapper/ibus/icons/fullwidth.svg
new file mode 100644 (file)
index 0000000..a290d8e
--- /dev/null
@@ -0,0 +1,76 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="64px"
+   height="64px"
+   id="svg2383"
+   sodipodi:version="0.32"
+   inkscape:version="0.46"
+   sodipodi:docname="full.plain.svg"
+   inkscape:output_extension="org.inkscape.output.svg.inkscape">
+  <defs
+     id="defs2385">
+    <inkscape:perspective
+       sodipodi:type="inkscape:persp3d"
+       inkscape:vp_x="0 : 32 : 1"
+       inkscape:vp_y="0 : 1000 : 0"
+       inkscape:vp_z="64 : 32 : 1"
+       inkscape:persp3d-origin="32 : 21.333333 : 1"
+       id="perspective2391" />
+  </defs>
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     inkscape:pageopacity="0.0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="4"
+     inkscape:cx="-52.887062"
+     inkscape:cy="40.538214"
+     inkscape:current-layer="layer1"
+     showgrid="true"
+     inkscape:document-units="px"
+     inkscape:grid-bbox="true"
+     inkscape:window-width="1540"
+     inkscape:window-height="930"
+     inkscape:window-x="126"
+     inkscape:window-y="111">
+    <inkscape:grid
+       type="xygrid"
+       id="grid2662" />
+  </sodipodi:namedview>
+  <metadata
+     id="metadata2388">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     id="layer1"
+     inkscape:label="Layer 1"
+     inkscape:groupmode="layer">
+    <path
+       sodipodi:type="arc"
+       style="opacity:1;fill:#fbfbfb;fill-opacity:1;fill-rule:nonzero;stroke:#35556b;stroke-width:5;stroke-linecap:square;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+       id="path5120"
+       sodipodi:cx="29.168156"
+       sodipodi:cy="35.185398"
+       sodipodi:rx="24.925514"
+       sodipodi:ry="24.925514"
+       d="M 54.09367,35.185398 A 24.925514,24.925514 0 1 1 4.2426414,35.185398 A 24.925514,24.925514 0 1 1 54.09367,35.185398 z"
+       transform="translate(3.1003586,-3.4999123)" />
+  </g>
+</svg>
diff --git a/wrapper/ibus/icons/halfwidth.svg b/wrapper/ibus/icons/halfwidth.svg
new file mode 100644 (file)
index 0000000..defe4c3
--- /dev/null
@@ -0,0 +1,114 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:xlink="http://www.w3.org/1999/xlink"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="64px"
+   height="64px"
+   id="svg2383"
+   sodipodi:version="0.32"
+   inkscape:version="0.46"
+   sodipodi:docname="half.plain.svg"
+   inkscape:output_extension="org.inkscape.output.svg.inkscape">
+  <defs
+     id="defs2385">
+    <linearGradient
+       inkscape:collect="always"
+       id="linearGradient3720">
+      <stop
+         style="stop-color:#000000;stop-opacity:1;"
+         offset="0"
+         id="stop3722" />
+      <stop
+         style="stop-color:#000000;stop-opacity:0;"
+         offset="1"
+         id="stop3724" />
+    </linearGradient>
+    <inkscape:perspective
+       sodipodi:type="inkscape:persp3d"
+       inkscape:vp_x="0 : 32 : 1"
+       inkscape:vp_y="0 : 1000 : 0"
+       inkscape:vp_z="64 : 32 : 1"
+       inkscape:persp3d-origin="32 : 21.333333 : 1"
+       id="perspective2391" />
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3720"
+       id="radialGradient3726"
+       cx="30.727272"
+       cy="38"
+       fx="30.727272"
+       fy="38"
+       r="34.19318"
+       gradientUnits="userSpaceOnUse" />
+    <filter
+       inkscape:collect="always"
+       id="filter4052">
+      <feGaussianBlur
+         inkscape:collect="always"
+         stdDeviation="0.73699187"
+         id="feGaussianBlur4054" />
+    </filter>
+  </defs>
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     inkscape:pageopacity="0.0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="1"
+     inkscape:cx="-106.19267"
+     inkscape:cy="-30.87384"
+     inkscape:current-layer="layer1"
+     showgrid="true"
+     inkscape:document-units="px"
+     inkscape:grid-bbox="true"
+     inkscape:window-width="1392"
+     inkscape:window-height="1026"
+     inkscape:window-x="15"
+     inkscape:window-y="123"
+     inkscape:snap-global="false"
+     showguides="true"
+     inkscape:guide-bbox="true">
+    <inkscape:grid
+       type="xygrid"
+       id="grid2662" />
+  </sodipodi:namedview>
+  <metadata
+     id="metadata2388">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     id="layer1"
+     inkscape:label="Layer 1"
+     inkscape:groupmode="layer">
+    <path
+       sodipodi:type="arc"
+       style="opacity:0;fill:#e76f00;fill-opacity:1;fill-rule:nonzero;stroke:url(#radialGradient3726);stroke-width:4.02272700999999966;stroke-linecap:square;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+       id="path3510"
+       sodipodi:cx="30.727272"
+       sodipodi:cy="38"
+       sodipodi:rx="32.181816"
+       sodipodi:ry="32.181816"
+       d="M 62.909088,38 A 32.181816,32.181816 0 1 1 -1.4545441,38 A 32.181816,32.181816 0 1 1 62.909088,38 z"
+       transform="matrix(0.932937,0,0,0.9328223,3.4133581,-3.5235232)" />
+    <path
+       style="opacity:1;fill:#ffffff;fill-opacity:0.94117647000000004;fill-rule:nonzero;stroke:#35556f;stroke-width:4;stroke-linecap:square;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate;filter:url(#filter4052)"
+       d="M 32.28125 6.75 C 18.522366 6.75 7.3437501 17.928616 7.34375 31.6875 C 7.34375 45.446384 18.522368 56.625 32.28125 56.625 C 39.359772 56.625 45.74252 53.649821 50.28125 48.90625 C 48.227055 49.761823 45.987941 50.25 43.625 50.25 C 34.034 50.249999 26.25 42.466001 26.25 32.875 C 26.25 23.284 34.034 15.5 43.625 15.5 C 47.277542 15.5 50.670476 16.634772 53.46875 18.5625 C 49.072067 11.474848 41.229515 6.75 32.28125 6.75 z "
+       id="path5120" />
+  </g>
+</svg>
diff --git a/wrapper/ibus/icons/han.svg b/wrapper/ibus/icons/han.svg
new file mode 100644 (file)
index 0000000..13a4574
--- /dev/null
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   version="1.0"
+   width="48"
+   height="48"
+   id="svg2710">
+  <defs
+     id="defs2712">
+    <filter
+       id="filter4889">
+      <feGaussianBlur
+         id="feGaussianBlur4891"
+         stdDeviation="0.8789348"
+         inkscape:collect="always" />
+    </filter>
+  </defs>
+  <g
+     id="layer1">
+    <text
+       x="-2.4050589"
+       y="43"
+       id="text2720"
+       xml:space="preserve"
+       style="font-size:48px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#35556b;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:AR PL UKai CN;-inkscape-font-specification:AR PL UKai CN"><tspan
+         x="-2.4050589"
+         y="43"
+         id="tspan2722">汉</tspan></text>
+    <text
+       x="-0.94521457"
+       y="43.750927"
+       id="text3520"
+       xml:space="preserve"
+       style="font-size:48px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;opacity:1;fill:#36556b;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;filter:url(#filter4889);font-family:AR PL UKai CN;-inkscape-font-specification:AR PL UKai CN"><tspan
+         x="-0.94521457"
+         y="43.750927"
+         id="tspan3522">汉</tspan></text>
+  </g>
+</svg>
diff --git a/wrapper/ibus/icons/setup.svg b/wrapper/ibus/icons/setup.svg
new file mode 100644 (file)
index 0000000..da8c585
--- /dev/null
@@ -0,0 +1,193 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:xlink="http://www.w3.org/1999/xlink"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   inkscape:export-ydpi="90.000000"
+   inkscape:export-xdpi="90.000000"
+   inkscape:export-filename="/home/jimmac/Desktop/wi-fi.png"
+   width="48px"
+   height="48px"
+   id="svg11300"
+   sodipodi:version="0.32"
+   inkscape:version="0.46"
+   sodipodi:docbase="/home/tigert/cvs/freedesktop.org/tango-icon-theme/scalable/emblems"
+   sodipodi:docname="setup.svg"
+   inkscape:output_extension="org.inkscape.output.svg.inkscape">
+  <defs
+     id="defs3">
+    <inkscape:perspective
+       sodipodi:type="inkscape:persp3d"
+       inkscape:vp_x="0 : 24 : 1"
+       inkscape:vp_y="0 : 1000 : 0"
+       inkscape:vp_z="48 : 24 : 1"
+       inkscape:persp3d-origin="24 : 16 : 1"
+       id="perspective22" />
+    <linearGradient
+       id="linearGradient3264">
+      <stop
+         style="stop-color: rgb(201, 201, 201); stop-opacity: 1;"
+         offset="0"
+         id="stop3266" />
+      <stop
+         id="stop3276"
+         offset="0.25"
+         style="stop-color: rgb(248, 248, 248); stop-opacity: 1;" />
+      <stop
+         id="stop3272"
+         offset="0.5"
+         style="stop-color: rgb(226, 226, 226); stop-opacity: 1;" />
+      <stop
+         style="stop-color: rgb(176, 176, 176); stop-opacity: 1;"
+         offset="0.75"
+         id="stop3274" />
+      <stop
+         style="stop-color: rgb(201, 201, 201); stop-opacity: 1;"
+         offset="1"
+         id="stop3268" />
+    </linearGradient>
+    <linearGradient
+       inkscape:collect="always"
+       id="linearGradient3256">
+      <stop
+         style="stop-color: rgb(0, 0, 0); stop-opacity: 1;"
+         offset="0"
+         id="stop3258" />
+      <stop
+         style="stop-color: rgb(0, 0, 0); stop-opacity: 0;"
+         offset="1"
+         id="stop3260" />
+    </linearGradient>
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3256"
+       id="radialGradient3262"
+       cx="25.455845"
+       cy="39.161163"
+       fx="25.455845"
+       fy="39.161163"
+       r="19.622213"
+       gradientTransform="matrix(1, 0, 0, 0.315315, 0, 26.813)"
+       gradientUnits="userSpaceOnUse" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3264"
+       id="linearGradient3281"
+       gradientUnits="userSpaceOnUse"
+       x1="14.462892"
+       y1="12.284524"
+       x2="34.534348"
+       y2="39.684914"
+       gradientTransform="matrix(1.24194, 0, 0, 1.24194, -5.02751, -7.20899)" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3264"
+       id="linearGradient3291"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(1.2419415,0,0,1.241848,-5.0275463,-7.1988722)"
+       x1="14.462892"
+       y1="12.284524"
+       x2="34.534348"
+       y2="39.684914" />
+  </defs>
+  <sodipodi:namedview
+     stroke="#ef2929"
+     fill="#eeeeec"
+     id="base"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="0.25490196"
+     inkscape:pageopacity="0.0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="8"
+     inkscape:cx="40.773744"
+     inkscape:cy="23.823982"
+     inkscape:current-layer="layer1"
+     showgrid="false"
+     inkscape:grid-bbox="true"
+     inkscape:document-units="px"
+     inkscape:showpageshadow="false"
+     inkscape:window-width="1555"
+     inkscape:window-height="1025"
+     inkscape:window-x="133"
+     inkscape:window-y="104"
+     inkscape:snap-global="false">
+    <inkscape:grid
+       type="xygrid"
+       id="grid3176" />
+  </sodipodi:namedview>
+  <metadata
+     id="metadata4">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:creator>
+          <cc:Agent>
+            <dc:title>Jakub Steiner</dc:title>
+          </cc:Agent>
+        </dc:creator>
+        <dc:source>http://jimmac.musichall.cz</dc:source>
+        <cc:license
+           rdf:resource="http://creativecommons.org/licenses/by-sa/2.0/" />
+        <dc:title>Emblem System</dc:title>
+        <dc:subject>
+          <rdf:Bag>
+            <rdf:li>emblem</rdf:li>
+            <rdf:li>system</rdf:li>
+            <rdf:li>library</rdf:li>
+            <rdf:li>crucial</rdf:li>
+            <rdf:li>base</rdf:li>
+          </rdf:Bag>
+        </dc:subject>
+      </cc:Work>
+      <cc:License
+         rdf:about="http://creativecommons.org/licenses/by-sa/2.0/">
+        <cc:permits
+           rdf:resource="http://web.resource.org/cc/Reproduction" />
+        <cc:permits
+           rdf:resource="http://web.resource.org/cc/Distribution" />
+        <cc:requires
+           rdf:resource="http://web.resource.org/cc/Notice" />
+        <cc:requires
+           rdf:resource="http://web.resource.org/cc/Attribution" />
+        <cc:permits
+           rdf:resource="http://web.resource.org/cc/DerivativeWorks" />
+        <cc:requires
+           rdf:resource="http://web.resource.org/cc/ShareAlike" />
+      </cc:License>
+    </rdf:RDF>
+  </metadata>
+  <g
+     id="layer1"
+     inkscape:label="Layer 1"
+     inkscape:groupmode="layer">
+    <path
+       style="opacity:1;fill:url(#linearGradient3291);fill-opacity:1;fill-rule:nonzero;stroke:#36556b;stroke-width:1.6;stroke-linecap:butt;stroke-linejoin:miter;marker:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
+       d="M 23.249999,0.4782989 C 22.784559,0.51014282 22.332163,0.58222588 21.874997,0.63453732 L 21.843747,0.63453732 L 20.749995,6.6028448 C 18.967268,7.0088046 17.290082,7.6977551 15.781239,8.6339442 L 10.874983,5.102956 C 9.5486934,6.1325702 8.3417817,7.3333859 7.2812288,8.6339442 L 10.687483,13.602326 C 9.6532488,15.182724 8.8755125,16.987299 8.4374802,18.883184 C 8.4374052,18.892147 8.4374193,18.91287 8.4374802,18.914432 L 2.4999729,19.851862 C 2.3914194,20.73843 2.3437227,21.654668 2.3437227,22.570411 C 2.3437228,23.319655 2.3644121,24.058889 2.4374728,24.788996 L 8.3749801,25.851418 C 8.7972597,27.913157 9.5994404,29.838634 10.718733,31.538496 L 7.1874787,36.381887 C 8.198806,37.637312 9.3663731,38.780325 10.624983,39.787884 L 15.624989,36.350639 C 17.372424,37.465273 19.323077,38.246872 21.437496,38.63172 L 22.374997,44.537532 C 23.041181,44.598166 23.724348,44.600027 24.40625,44.600027 C 25.368936,44.600026 26.288489,44.563547 27.218753,44.443789 L 28.343755,38.412986 C 30.351318,37.913422 32.237229,37.046797 33.875012,35.881924 L 38.687518,39.381664 C 39.935547,38.319946 41.076798,37.099577 42.062522,35.788181 L 38.562518,30.726056 C 39.510372,29.089187 40.167149,27.28317 40.50002,25.351455 L 46.406277,24.414024 C 46.458071,23.797724 46.468777,23.200027 46.468777,22.570411 C 46.468777,21.476278 46.341595,20.403487 46.187527,19.351899 L 40.18752,18.258231 C 39.717325,16.522135 38.945842,14.902377 37.968767,13.446087 L 41.500021,8.6026965 C 40.405447,7.2641886 39.15684,6.0277062 37.781267,4.9779653 L 32.68751,8.4777058 C 31.223512,7.6119326 29.648043,6.9476371 27.937504,6.5715971 L 27.000003,0.63453732 C 26.146703,0.53416937 25.28638,0.4782989 24.40625,0.4782989 C 24.168378,0.47829891 23.923565,0.47081486 23.687499,0.4782989 C 23.572416,0.48194744 23.458533,0.4716045 23.343749,0.4782989 C 23.312661,0.48011197 23.281028,0.47617597 23.249999,0.4782989 z M 24.0625,15.664673 C 24.176666,15.65888 24.290652,15.664673 24.40625,15.664673 C 28.105382,15.664673 31.125008,18.684073 31.125008,22.382925 C 31.125009,26.081776 28.105381,29.069929 24.40625,29.069929 C 20.70712,29.06993 17.718742,26.081776 17.718742,22.382925 C 17.718743,18.799663 20.523345,15.844252 24.0625,15.664673 z"
+       id="path3243" />
+    <path
+       id="path3285"
+       d="M 22.557788,1.6501132 L 21.679599,7.4291233 C 20.008601,7.8096689 16.934874,8.9735344 15.520595,9.8511162 L 10.848562,6.3639293 C 9.6053938,7.3290873 9.5201391,7.3945394 8.5260544,8.6136804 L 11.904107,13.623634 C 10.934692,15.105095 9.7703031,17.745129 9.3522336,19.631722 C 9.3522336,19.631722 3.4328248,20.629563 3.4328248,20.629563 C 3.3310749,21.460629 3.3799751,23.239361 3.4484569,23.923761 L 9.1027005,24.942349 C 9.4985145,26.875018 10.979731,29.985937 12.028874,31.579383 L 8.4532981,36.303427 C 9.4012426,37.480259 9.5909623,37.587948 10.770691,38.532432 L 15.551859,35.029612 C 17.189777,36.074467 20.440892,37.345498 22.422794,37.706253 L 23.207481,43.412507 C 23.831913,43.469346 25.556962,43.628788 26.428924,43.516527 L 27.307112,37.576373 C 29.188855,37.108084 32.440272,35.773413 33.97541,34.681463 L 38.751465,38.132271 C 39.921276,37.13702 39.931757,36.987055 40.855703,35.757755 L 37.316505,30.727054 C 38.204954,29.192656 39.353733,26.191831 39.665742,24.381045 L 45.460384,23.419582 C 45.508931,22.841863 45.511294,21.230793 45.366882,20.245037 L 39.463105,19.226449 C 39.022378,17.599038 37.509894,14.666467 36.594056,13.301345 L 40.346408,8.5773019 C 39.320436,7.3225876 38.938964,7.150431 37.649602,6.1664065 L 32.707289,9.7056032 C 31.335043,8.8940304 28.598675,7.6568558 26.995341,7.3043568 L 26.122266,1.6501132 C 25.322445,1.5560285 23.014871,1.5978075 22.557788,1.6501132 z"
+       style="overflow:visible;marker:none;opacity:0.34659099999999998;color:rgb(0, 0, 0);fill:none;fill-opacity:1;fill-rule:nonzero;stroke:#365000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0pt;stroke-opacity:0;visibility:visible;display:inline"
+       sodipodi:nodetypes="ccccccccccccccccccccccccccccccccc" />
+    <path
+       sodipodi:type="arc"
+       style="opacity:0.64772704;fill:none;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:2.47313356;stroke-linecap:butt;stroke-linejoin:miter;marker:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
+       id="path3283"
+       sodipodi:cx="23.511301"
+       sodipodi:cy="23.781593"
+       sodipodi:rx="12.727922"
+       sodipodi:ry="12.727922"
+       d="M 36.239223,23.781593 A 12.727922,12.727922 0 1 1 10.783379,23.781593 A 12.727922,12.727922 0 1 1 36.239223,23.781593 z"
+       transform="matrix(0.6516355,0,0,0.6520284,9.0841979,6.8678522)" />
+  </g>
+</svg>
diff --git a/wrapper/ibus/icons/sunpinyin-logo.png b/wrapper/ibus/icons/sunpinyin-logo.png
new file mode 100644 (file)
index 0000000..c133e1d
Binary files /dev/null and b/wrapper/ibus/icons/sunpinyin-logo.png differ
diff --git a/wrapper/ibus/po/CMakeLists.txt b/wrapper/ibus/po/CMakeLists.txt
new file mode 100644 (file)
index 0000000..05eede5
--- /dev/null
@@ -0,0 +1,15 @@
+include(Gettext)
+
+set(POT_SRCS
+    ../src/main.cpp
+    ../src/sunpinyin_property.cpp
+    ../setup/setup.glade)
+set(LANGS zh_CN)
+set(POT_FILE ${CMAKE_CURRENT_BINARY_DIR}/${GETTEXT_PACKAGE}.pot)
+
+if (GETTEXT_FOUND)
+    GETTEXT_CREATE_POT(${POT_FILE} OPTION ${XGETTEXT_OPTIONS} SRC ${POT_SRCS})
+    GETTEXT_CREATE_TRANSLATIONS(${POT_FILE} ALL ${LANGS}
+                                COMMENT "Creating translations.")
+endif()
+
diff --git a/wrapper/ibus/po/ibus-sunpinyin.po b/wrapper/ibus/po/ibus-sunpinyin.po
new file mode 100644 (file)
index 0000000..0a8f87a
--- /dev/null
@@ -0,0 +1,192 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2010-05-09 21:02+0800\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=CHARSET\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#: ../src/main.cpp:107
+msgid "Simplified Chinese Input Method developed by SUN"
+msgstr ""
+
+#: ../src/sunpinyin_property.cpp:62
+msgid "Switch to Chinese input mode"
+msgstr ""
+
+#: ../src/sunpinyin_property.cpp:65
+msgid "Switch to English input mode"
+msgstr ""
+
+#: ../src/sunpinyin_property.cpp:77
+msgid "Switch to full-width letter input mode"
+msgstr ""
+
+#: ../src/sunpinyin_property.cpp:80
+msgid "Switch to half-width letter input mode"
+msgstr ""
+
+#: ../src/sunpinyin_property.cpp:91
+msgid "Switch to Chinese punctuation"
+msgstr ""
+
+#: ../src/sunpinyin_property.cpp:94
+msgid "Switch to English punctuation"
+msgstr ""
+
+#: ../src/sunpinyin_property.cpp:167
+msgid "Preference"
+msgstr ""
+
+#: ../setup/setup.glade:7
+msgid "SunPinyin Setup"
+msgstr ""
+
+#: ../setup/setup.glade:44
+msgid "Quan Pin"
+msgstr ""
+
+#: ../setup/setup.glade:57
+msgid "Shuang Pin"
+msgstr ""
+
+#: ../setup/setup.glade:78
+msgid ""
+"MS2003\n"
+"ZiRanMa\n"
+"ZiGuang\n"
+"ABC\n"
+"PinYinJiaJia"
+msgstr ""
+
+#: ../setup/setup.glade:102
+msgid "<b>Pinyin Mode</b>"
+msgstr ""
+
+#: ../setup/setup.glade:143
+msgid "Chinese"
+msgstr ""
+
+#: ../setup/setup.glade:156
+msgid "English"
+msgstr ""
+
+#: ../setup/setup.glade:174
+msgid "Chinese punctuation"
+msgstr ""
+
+#: ../setup/setup.glade:189
+msgid "English punctuation"
+msgstr ""
+
+#: ../setup/setup.glade:206
+msgid "Full-width Letter"
+msgstr ""
+
+#: ../setup/setup.glade:221
+msgid "Half-width Letter"
+msgstr ""
+
+#: ../setup/setup.glade:243
+msgid "<b>Initial Status</b>"
+msgstr ""
+
+#: ../setup/setup.glade:283
+msgid "Fuzzy Pinyin"
+msgstr ""
+
+#: ../setup/setup.glade:297
+msgid "Auto Correct"
+msgstr ""
+
+#: ../setup/setup.glade:312 ../setup/setup.glade:958
+msgid "Fuzzy Pinyin Setup"
+msgstr ""
+
+#: ../setup/setup.glade:327 ../setup/setup.glade:1256
+msgid "Auto Correct Setup"
+msgstr ""
+
+#: ../setup/setup.glade:348
+msgid "<b>QuanPin Setup</b>"
+msgstr ""
+
+#: ../setup/setup.glade:365
+msgid "Pinyin Mode"
+msgstr ""
+
+#: ../setup/setup.glade:424
+msgid "<b>Ch/En Switch key</b>"
+msgstr ""
+
+#: ../setup/setup.glade:488 ../setup/setup.glade:1202
+#: ../setup/setup.glade:1382 ../setup/setup.glade:2254
+msgid "None"
+msgstr ""
+
+#: ../setup/setup.glade:508
+msgid "<b>Full/Half-width Punct Switch</b>"
+msgstr ""
+
+#: ../setup/setup.glade:588
+msgid "<b>Page Flip</b>"
+msgstr ""
+
+#: ../setup/setup.glade:608
+msgid "Keyboard"
+msgstr ""
+
+#: ../setup/setup.glade:681
+msgid "<b>Character Set</b>"
+msgstr ""
+
+#: ../setup/setup.glade:723
+msgid "Candidate Num"
+msgstr ""
+
+#: ../setup/setup.glade:734
+msgid "Memory Strength"
+msgstr ""
+
+#: ../setup/setup.glade:809
+msgid "Punct mapping"
+msgstr ""
+
+#: ../setup/setup.glade:822
+msgid "Mapping Setup"
+msgstr ""
+
+#: ../setup/setup.glade:841
+msgid "<b>Symbol Mapping</b>"
+msgstr ""
+
+#: ../setup/setup.glade:861
+msgid "General"
+msgstr ""
+
+#: ../setup/setup.glade:872
+msgid "copyright (c) 2009"
+msgstr ""
+
+#: ../setup/setup.glade:881
+msgid "About"
+msgstr ""
+
+#: ../setup/setup.glade:1187 ../setup/setup.glade:1368
+#: ../setup/setup.glade:2240
+msgid "All"
+msgstr ""
+
+#: ../setup/setup.glade:1436
+msgid "Punct Mapping"
+msgstr ""
diff --git a/wrapper/ibus/po/zh_CN.po b/wrapper/ibus/po/zh_CN.po
new file mode 100644 (file)
index 0000000..0e47861
--- /dev/null
@@ -0,0 +1,215 @@
+# SunPinyin
+# Copyright (C) 2007,2009,2010 Kov Chai <tchaikov@gmail.com>
+# This file is distributed under the same license as the sunpinyin package.
+# Kov Chai <tchaikov@gmail.com>, 2007.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: sunpinyin 2.0\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2010-07-23 00:07+0800\n"
+"PO-Revision-Date: 2010-02-18 20:18+0800\n"
+"Last-Translator: Kov Chai <tchaikov@gmail.com>\n"
+"Language-Team: Kov Chai <tchaikov@gmail.com>\n"
+"Language: \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#: setup/setup.glade:461
+msgid "<b>Ch/En Switch key</b>"
+msgstr "<b>汉/英切换热键</b>"
+
+#: setup/setup.glade:764
+msgid "<b>Character Set</b>"
+msgstr "<b>字符集</b>"
+
+#: setup/setup.glade:545
+msgid "<b>Full/Half-width Punct Switch</b>"
+msgstr "<b>中/英文标点切换</b>"
+
+#: setup/setup.glade:243
+msgid "<b>Initial Status</b>"
+msgstr "<b>初始状态</b>"
+
+#: setup/setup.glade:671
+msgid "<b>Miscellaneous</b>"
+msgstr "其它"
+
+#: setup/setup.glade:625
+msgid "<b>Page Flip</b>"
+msgstr "<b>翻页</b>"
+
+#: setup/setup.glade:102
+msgid "<b>Pinyin Mode</b>"
+msgstr "拼音模式"
+
+#: setup/setup.glade:385
+msgid "<b>QuanPin Setup</b>"
+msgstr "<b>全拼设置</b>"
+
+#: setup/setup.glade:924
+msgid "<b>Symbol Mapping</b>"
+msgstr "<b>标点映射</b>"
+
+#: setup/setup.glade:964
+msgid "About"
+msgstr "关于"
+
+#: setup/setup.glade:1270 setup/setup.glade:1438
+#: setup/setup.glade:2310
+msgid "All"
+msgstr "全选"
+
+#: setup/setup.glade:297
+msgid "Auto Correct"
+msgstr "自动纠错"
+
+#: setup/setup.glade:327 setup/setup.glade:1339
+msgid "Auto Correct Setup"
+msgstr "自动纠错设置"
+
+#: setup/setup.glade:658
+msgid "Cancel with Backspace"
+msgstr "用 backspace 取消选好的候选词"
+
+#: setup/setup.glade:806
+msgid "Candidate Num"
+msgstr "候选词的个数"
+
+#: setup/setup.glade:143
+msgid "Chinese"
+msgstr "中文"
+
+#: setup/setup.glade:174
+msgid "Chinese punctuation"
+msgstr "中文标点"
+
+#: setup/setup.glade:156
+msgid "English"
+msgstr "英文"
+
+#: setup/setup.glade:189
+msgid "English punctuation"
+msgstr "英文标点"
+
+#: setup/setup.glade:206
+msgid "Full-width Letter"
+msgstr "全角字母"
+
+#: setup/setup.glade:283
+msgid "Fuzzy Pinyin"
+msgstr "模糊拼音"
+
+#: setup/setup.glade:312 setup/setup.glade:1041
+msgid "Fuzzy Pinyin Setup"
+msgstr "模糊拼音设置"
+
+#: setup/setup.glade:944
+msgid "General"
+msgstr "通用"
+
+#: setup/setup.glade:221
+msgid "Half-width Letter"
+msgstr "半角字母"
+
+#: setup/setup.glade:364
+msgid "Inner Fuzzy"
+msgstr "支持内模糊音节 (xian->xi'an)"
+
+#: setup/setup.glade:691
+msgid "Keyboard"
+msgstr "快捷键"
+
+#: setup/setup.glade:78
+msgid ""
+"MS2003\n"
+"ZiRanMa\n"
+"ZiGuang\n"
+"ABC\n"
+"PinYinJiaJia\n"
+"XiaoHe"
+msgstr ""
+"微软2003\n"
+"自然码\n"
+"紫光\n"
+"智能ABC\n"
+"拼音加加\n"
+"小鹤"
+
+#: setup/setup.glade:905
+msgid "Mapping Setup"
+msgstr "自定义标点映射配置"
+
+#: setup/setup.glade:817
+msgid "Memory Strength"
+msgstr "记忆强度"
+
+#: setup/setup.glade:525 setup/setup.glade:1285
+#: setup/setup.glade:1452 setup/setup.glade:2324
+msgid "None"
+msgstr "全不选"
+
+#: setup/setup.glade:402
+msgid "Pinyin Mode"
+msgstr "拼音模式"
+
+#: src/sunpinyin_property.cpp:167
+msgid "Preference"
+msgstr "设置"
+
+#: setup/setup.glade:1506
+msgid "Punct Mapping"
+msgstr "自定义标点映射"
+
+#: setup/setup.glade:892
+msgid "Punct mapping"
+msgstr "自定义标点映射"
+
+#: setup/setup.glade:44
+msgid "Quan Pin"
+msgstr "全拼"
+
+#: setup/setup.glade:57
+msgid "Shuang Pin"
+msgstr "双拼"
+
+#: src/main.cpp:104
+msgid "Simplified Chinese Input Method developed by SUN"
+msgstr "Sun 公司开发的简体中文输入法"
+
+#: setup/setup.glade:343
+msgid "Smart Segmentation"
+msgstr "智能切分"
+
+#: setup/setup.glade:7
+msgid "SunPinyin Setup"
+msgstr "SunPinyin 配置"
+
+#: src/sunpinyin_property.cpp:62
+msgid "Switch to Chinese input mode"
+msgstr "切换到中文输入模式"
+
+#: src/sunpinyin_property.cpp:91
+msgid "Switch to Chinese punctuation"
+msgstr "使用中文标点"
+
+#: src/sunpinyin_property.cpp:65
+msgid "Switch to English input mode"
+msgstr "切换到英文输入模式"
+
+#: src/sunpinyin_property.cpp:94
+msgid "Switch to English punctuation"
+msgstr "使用英文标点"
+
+#: src/sunpinyin_property.cpp:77
+msgid "Switch to full-width letter input mode"
+msgstr "切换到全角输入模式"
+
+#: src/sunpinyin_property.cpp:80
+msgid "Switch to half-width letter input mode"
+msgstr "切换到半角输入模式"
+
+#: setup/setup.glade:955
+msgid "copyright (c) 2009"
+msgstr "版权所有 (c) 2009"
diff --git a/wrapper/ibus/setup/CMakeLists.txt b/wrapper/ibus/setup/CMakeLists.txt
new file mode 100644 (file)
index 0000000..be1a959
--- /dev/null
@@ -0,0 +1,10 @@
+configure_file(${CMAKE_CURRENT_SOURCE_DIR}/config.py.in
+               ${CMAKE_CURRENT_BINARY_DIR}/config.py)
+configure_file(${CMAKE_CURRENT_SOURCE_DIR}/ibus-setup-sunpinyin.in
+               ${CMAKE_CURRENT_BINARY_DIR}/ibus-setup-sunpinyin
+               @ONLY)
+install(FILES setup.glade main.py
+              ${CMAKE_CURRENT_BINARY_DIR}/config.py
+    DESTINATION "${DATA_DIR}/setup")
+install(PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/ibus-setup-sunpinyin
+    DESTINATION ${LIBEXEC_DIR})
diff --git a/wrapper/ibus/setup/config.py.in b/wrapper/ibus/setup/config.py.in
new file mode 100644 (file)
index 0000000..63ab428
--- /dev/null
@@ -0,0 +1,3 @@
+prefix = "@INSTALL_PREFIX@"
+datadir = "@INSTALL_PREFIX@/share"
+localedir = "@INSTALL_PREFIX@/share/locale"
diff --git a/wrapper/ibus/setup/ibus-setup-sunpinyin.in b/wrapper/ibus/setup/ibus-setup-sunpinyin.in
new file mode 100644 (file)
index 0000000..2d32738
--- /dev/null
@@ -0,0 +1,7 @@
+#!/bin/sh
+
+prefix=@INSTALL_PREFIX@
+exec_prefix=${prefix}
+export IBUS_PREFIX=${prefix}
+export IBUS_LOCALEDIR=${prefix}/share/locale
+exec python @DATA_DIR@/setup/main.py $@
diff --git a/wrapper/ibus/setup/main.py b/wrapper/ibus/setup/main.py
new file mode 100644 (file)
index 0000000..8c1e805
--- /dev/null
@@ -0,0 +1,606 @@
+# -*- coding: utf-8 -*-
+# 
+# Copyright (c) 2009 Leo Zheng <zym361@gmail.com>, Kov Chai <tchaikov@gmail.com>
+# *
+# The contents of this file are subject to the terms of either the GNU Lesser
+# General Public License Version 2.1 only ("LGPL") or the Common Development and
+# Distribution License ("CDDL")(collectively, the "License"). You may not use this
+# file except in compliance with the License. You can obtain a copy of the CDDL at
+# http://www.opensource.org/licenses/cddl1.php and a copy of the LGPLv2.1 at
+# http://www.opensource.org/licenses/lgpl-license.php. See the License for the 
+# specific language governing permissions and limitations under the License. When
+# distributing the software, include this License Header Notice in each file and
+# include the full text of the License in the License file as well as the
+# following notice:
+# 
+# NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND DISTRIBUTION LICENSE
+# (CDDL)
+# For Covered Software in this distribution, this License shall be governed by the
+# laws of the State of California (excluding conflict-of-law provisions).
+# Any litigation relating to this License shall be subject to the jurisdiction of
+# the Federal Courts of the Northern District of California and the state courts
+# of the State of California, with venue lying in Santa Clara County, California.
+# 
+# Contributor(s):
+# 
+# If you wish your version of this file to be governed by only the CDDL or only
+# the LGPL Version 2.1, indicate your decision by adding "[Contributor]" elects to
+# include this software in this distribution under the [CDDL or LGPL Version 2.1]
+# license." If you don't indicate a single choice of license, a recipient has the
+# option to distribute your version of this file under either the CDDL or the LGPL
+# Version 2.1, or to extend the choice of license to its licensees as provided
+# above. However, if you add LGPL Version 2.1 code and therefore, elected the LGPL
+# Version 2 license, then the option applies only if the new code is made subject
+# to such option by the copyright holder. 
+#
+
+import sys
+import os
+from os import path
+import gtk
+import ibus
+import gettext
+import locale
+
+GETTEXT_PACKAGE="ibus-sunpinyin"
+_ = lambda msg: gettext.gettext(msg)
+
+XML_FILE = path.join(path.dirname(__file__), "setup.xml")
+SEPARATOR = "/"
+
+class Logger:
+    @staticmethod
+    def pr(message):
+        print >> sys.stderr, message
+        
+class Option(object):
+    """Option serves as an interface of ibus.config
+
+    it is used to synchronize the configuration with setting on user interface
+    """
+    config = ibus.Bus().get_config()
+    
+    def __init__(self, name, default):
+        self.name = name
+        self.default = default
+    
+    def read(self):
+        section, key = self.__get_config_name()
+        return self.config.get_value(section, key, self.default)
+
+    def write(self, v):
+        section, key = self.__get_config_name()
+        return self.config.set_value(section, key, type(self.default)(v))
+
+   
+    def __get_config_name(self):
+        keys = self.name.rsplit(SEPARATOR ,1)
+        if len(keys) == 2:
+            return SEPARATOR.join(("engine/SunPinyin", keys[0])), keys[1]
+        else:
+            assert len(keys) == 1
+            return "engine/SunPinyin", keys[0]
+
+class TrivalOption(Option):
+    """option represented using a simple gtk widget
+    """
+    def __init__(self, name, default, owner):
+        super(TrivalOption, self).__init__(name, default)
+        self.xml = owner
+        self.widget = owner.get_object(name)
+        assert self.widget is not None, "%s not found in gtkbuilder" % name
+
+    def init_ui(self):
+        self.init()
+        self.read_config()
+
+    def init(self):
+        pass
+    
+    def read_config(self):
+        """update user inferface with ibus.config
+        """
+        self.v = self.read()
+        self.__set_value(self.v)
+
+    def write_config(self):
+        v = self.save_ui_setting()
+        self.write(v)
+        
+    def save_ui_setting(self):
+        """save user interface settings into self.v
+        """
+        self.v = self.__get_value()
+        return self.v
+    
+    def is_changed(self):
+        return self.v != self.__get_value()
+
+    def __get_value(self):
+        try:
+            return self.widget.get_value()
+        except:
+            return self.widget.get_active()
+
+    def __set_value(self, v):
+        try:
+            self.widget.set_value(v)
+        except:
+            self.widget.set_active(v)
+            
+class CheckBoxOption(TrivalOption):
+    def __init__(self, name, default, owner):
+        super(CheckBoxOption, self).__init__(name, default, owner)
+
+class ComboBoxOption(TrivalOption):
+    def __init__(self, name, default, options, owner):
+        try:
+            default = int(default)
+        except ValueError:
+            default = options.index(default)
+        super(ComboBoxOption, self).__init__(name, default, owner)
+        self.options = options
+        
+    def init(self):
+        model = gtk.ListStore(str)
+        for v in self.options:
+            model.append([str(v)])
+        self.widget.set_model(model)
+
+    def __get_value(self):
+        active = self.widget.get_active()
+        try:
+            # if the options are numbers, save the liternal of active option as
+            # a number
+            return int(self.options[active])
+        except ValueError:
+            # otherwise save its index
+            return active
+    
+    def __set_value(self, v):
+        try:
+            # if the options are just numbers, we treat 'self.v' as the literal
+            # of option
+            dummy = int(self.options[0])
+            active = self.options.index(v)
+        except ValueError:
+            active = v
+        self.widget.set_active(active)
+        
+class RadioOption(Option):
+    """option represented using multiple Raidio buttons
+    """
+    def __init__(self, name, default, options, owner):
+        super(RadioOption, self).__init__(name, default)
+        self.options = options
+        self.xml = owner
+
+    def init_ui(self):
+        self.read_config()
+        
+    def read_config(self):
+        self.v = self.read()
+        name = SEPARATOR.join([self.name, self.v])
+        button = self.xml.get_object(name)
+        assert button is not None, "button: %r not found" % name
+        button.set_active(True)
+
+    def write_config(self):
+        active_opt = None
+        for opt in self.options:
+            radio_name = SEPARATOR.join([self.name, opt])
+            radio = self.xml.get_object(radio_name)
+            if radio.get_active():
+                active_opt = opt
+                break
+        assert active_opt is not None
+        self.write(active_opt)
+
+class MappingInfo:
+    def __init__(self, name, mapping):
+        self.name = name
+        self.mapping = mapping
+        
+class MappingOption(object):
+    """an option which presents some sort of mapping, e.g. fuzzy pinyin mapping
+
+    it is not directly related to a config option like TrivalOption does, but
+    we always have a checkbox in UI for each of it so user can change it easily.
+    """
+    def __init__(self, name, mappings, owner):
+        self.name = name
+        self.widget = owner.get_object(name)
+        self.mappings = mappings
+        
+    def get_mappings(self):
+        if self.widget.get_active():
+            return [':'.join(self.mappings)]
+        else:
+            return []
+
+    def set_active(self, enabled):
+        self.widget.set_active(enabled)
+
+    def get_active(self):
+        return self.widget.get_active()
+    
+    is_enabled = property(get_active, set_active)
+
+    def key(self):
+        return self.mappings[0]
+    
+class MultiMappingOption(Option):
+    def __init__(self, name, options, default=[]):
+        Option.__init__(self, name, default)
+        self.options = options
+        self.saved_pairs = default
+        
+    def read_config(self):
+        if not self.saved_pairs:
+            self.saved_pairs = self.read()
+        keys = set([pair.split(':')[0] for pair in self.saved_pairs])
+        for opt in self.options:
+            opt.is_enabled = (opt.key() in keys)
+            # throw away unknown pair
+    
+    def write_config(self):
+        # ignore empty settings
+        if self.saved_pairs:
+            self.write(self.saved_pairs)
+        
+    def save_ui_setting(self):
+        self.saved_pairs = sum([opt.get_mappings() for opt in self.options
+                                if opt.is_enabled], [])
+        return self.saved_pairs
+    
+    def set_active_all(self, enabled):
+        for opt in self.options:
+            opt.is_enabled = enabled
+            
+class MultiCheckDialog (object):
+    """ a modal dialog box with 'choose all' and 'choose none' button
+    
+    TODO: another option is to use radio button
+    """
+    def __init__ (self, ui_name, config_name, mappings, option_klass=MappingOption):
+        self.ui_name = ui_name
+        self.config_name = config_name
+        self.mappings = mappings
+        self.option_klass = option_klass
+        self.saved_settings = []
+        self.mapping_options = None
+        
+    def get_setup_name(self):
+        """assuming the name of dialog looks like 'dlg_fuzzy_setup'
+        """
+        return '_'.join(['dlg', self.ui_name, 'setup'])
+    
+    def __init_ui(self):
+        dlg_name = self.get_setup_name()
+        self.__xml = gtk.Builder()
+        self.__xml.add_objects_from_file(XML_FILE, dlg_name)
+        self.__dlg = self.__xml.get_object(dlg_name)
+        assert self.__dlg is not None, "dialog %s not found in %s" % (dlg_name, XML_FILE)
+        handlers = {'_'.join(["on", self.ui_name, "select_all_clicked"]) : self.on_button_check_all_clicked,
+                    '_'.join(["on", self.ui_name, "unselect_all_clicked"]) : self.on_button_uncheck_all_clicked,
+                    '_'.join(["on", self.ui_name, "ok_clicked"]) : self.on_button_ok_clicked,
+                    '_'.join(["on", self.ui_name, "cancel_clicked"]) : self.on_button_cancel_clicked}
+        self.__xml.connect_signals(handlers)
+
+        options = [self.option_klass(m.name, m.mapping, self.__xml) 
+                   for m in self.mappings]
+        self.mapping_options = MultiMappingOption(self.config_name, options, self.saved_settings)
+
+    def dummy(self):
+        """a dummy func, i don't initialize myself upon other's request.
+        instead, i will do it by myself.
+        """
+        pass
+
+    init_ui = read_config = dummy
+    
+    def run(self):
+        self.__init_ui()
+        self.__read_config()
+        self.__dlg.run()
+        
+    def __read_config(self):
+        self.mapping_options.read_config()
+        
+    def __save_ui_settings(self):
+        """save to in-memory storage, will flush to config if not canceled in main_window
+        """
+        self.saved_settings = self.mapping_options.save_ui_setting()
+
+    def write_config(self):
+        if self.mapping_options is not None:
+            self.mapping_options.write_config()
+            
+    def on_button_check_all_clicked(self, button):
+        self.mapping_options.set_active_all(True)
+        
+    def on_button_uncheck_all_clicked(self, button):
+        self.mapping_options.set_active_all(False)
+    
+    def on_button_ok_clicked(self, button):
+        """update given options with settings in UI, these settings will be
+        written to config if user push 'OK' or 'Apply' in the main window
+        """
+        self.__save_ui_settings()
+        self.__dlg.destroy()
+        
+    def on_button_cancel_clicked(self, button):
+        self.__dlg.destroy()
+
+class FuzzySetupDialog (MultiCheckDialog):
+    def __init__(self):
+        mappings = [MappingInfo('QuanPin/Fuzzy/ShiSi', ('sh','s')),
+                    MappingInfo('QuanPin/Fuzzy/ZhiZi', ('zh','z')),
+                    MappingInfo('QuanPin/Fuzzy/ChiCi', ('ch','c')),
+                    MappingInfo('QuanPin/Fuzzy/ShiSi', ('sh','s')),
+                    MappingInfo('QuanPin/Fuzzy/AnAng', ('an','ang')),
+                    MappingInfo('QuanPin/Fuzzy/OnOng', ('on','ong')),
+                    MappingInfo('QuanPin/Fuzzy/EnEng', ('en','eng')),
+                    MappingInfo('QuanPin/Fuzzy/InIng', ('in','ing')),
+                    MappingInfo('QuanPin/Fuzzy/EngOng', ('eng','ong')),
+                    MappingInfo('QuanPin/Fuzzy/IanIang', ('ian','iang')),
+                    MappingInfo('QuanPin/Fuzzy/UanUang', ('uan','uang')),
+                    MappingInfo('QuanPin/Fuzzy/NeLe', ('n','l')),
+                    MappingInfo('QuanPin/Fuzzy/FoHe', ('f','h')),
+                    MappingInfo('QuanPin/Fuzzy/LeRi', ('l','r')),
+                    MappingInfo('QuanPin/Fuzzy/KeGe', ('k','g'))]
+        MultiCheckDialog.__init__(self,
+                                  ui_name = 'fuzzy',
+                                  config_name = 'QuanPin/Fuzzy/Pinyins',
+                                  mappings = mappings)
+        
+class CorrectionSetupDialog (MultiCheckDialog):
+    def __init__(self):
+        mappings = [MappingInfo('QuanPin/AutoCorrection/GnNg', ('gn','ng')),
+                    MappingInfo('QuanPin/AutoCorrection/UenUn', ('uen','un')),
+                    MappingInfo('QuanPin/AutoCorrection/ImgIng', ('img','ing')),
+                    MappingInfo('QuanPin/AutoCorrection/IouIu', ('iou','iu')),
+                    MappingInfo('QuanPin/AutoCorrection/UeiUi', ('uei','ui'))]
+        MultiCheckDialog.__init__(self,
+                                  ui_name = 'correction',
+                                  config_name = 'QuanPin/AutoCorrection/Pinyins',
+                                  mappings = mappings)
+
+class PunctMapping(MappingOption):
+    def __init__(self, name, mappings, owner):
+        MappingOption.__init__(self, name, mappings, owner)
+        if mappings:
+            self.widget.set_sensitive(True)
+            self.init_keys_values(mappings)
+        else:
+            self.widget.set_sensitive(False)
+            
+    def init_keys_values(self, mappings):
+        self.keys = [m[0] for m in mappings]
+        values_with_closing = [v or k for k, v in mappings]
+        self.values = []
+        for v in values_with_closing:
+            try:
+                self.values.append(v[0])
+            except:
+                self.values.append(v)
+        self.keys.reverse()
+        self.values.reverse()
+
+    def get_mappings(self):
+        if self.widget.get_active():
+            pairs = []
+            for k,vs in self.mappings:
+                try:
+                    for v in vs:
+                        pairs.append(':'.join([k,v]))
+                except:
+                    v = vs
+                    if v is None:
+                        continue
+                    pairs.append(':'.join([k,v]))
+            return pairs
+        else:
+            return []
+
+    def set_active(self, enabled):
+        if not self.mappings: return
+        if enabled:
+            self.widget.set_label('\n'.join(self.values))
+        else:
+            self.widget.set_label('\n'.join(self.keys))
+        self.widget.set_active(enabled)
+
+    is_enabled = property(MappingOption.get_active, set_active)
+    
+    def key(self):
+        for k, v in self.mappings:
+            if v is not None:
+                return k
+        else:
+            return None
+
+class PunctMappingSetupDialog (MultiCheckDialog):
+    # TODO: the UI should looks like a virtual keyboard,
+    #       user are allowed to choose the mappings to all punctuation keys.
+    def __init__(self):
+        mappings = [MappingInfo('togglebutton1', [('`',None), ('~',u'~')]),
+                    MappingInfo('togglebutton2', []),
+                    MappingInfo('togglebutton3', [('2',None), ('@',u'@')]),
+                    MappingInfo('togglebutton4', [('3',None), ('#',u'#')]),
+                    MappingInfo('togglebutton5', [('4',None), ('$',u'¥' )]),
+                    MappingInfo('togglebutton6', [('5',None), ('%',u'%')]),
+                    MappingInfo('togglebutton7', [('6',None), ('^',u'…')]),
+                    MappingInfo('togglebutton8', [('7',None), ('&',u'&')]),
+                    MappingInfo('togglebutton9', [('8',None), ('*',u'*')]),
+                    MappingInfo('togglebutton10', [('9',None), ('*',u'(')]),
+                    MappingInfo('togglebutton11', [('0',None), ('*',u')')]),
+                    MappingInfo('togglebutton12', [('-',u'-'), ('_',u'——')]),
+                    MappingInfo('togglebutton13', [('=',u'='), ('+',u'+')]),
+                    MappingInfo('togglebutton14', [('\\',None), ('|',u'‖')]),
+                    MappingInfo('togglebutton27', [('[',u'〔'), ('{',u'{')]),
+                    MappingInfo('togglebutton28', [(']',u'〕'), ('}',u'}')]),
+                    MappingInfo('togglebutton39', []),
+                    MappingInfo('togglebutton40', []),
+                    MappingInfo('togglebutton50', [(',',None), ('<',u'〈')]),
+                    MappingInfo('togglebutton51', [('.',u'·'), ('>',u'〉')]),
+                    MappingInfo('togglebutton52', [('/',u'/'), ('?',None)])]
+                    #'\'',(u'‘',u'’'),
+        MultiCheckDialog.__init__(self, ui_name="punctmapping",
+                                  config_name="General/PunctMapping/Mappings",
+                                  mappings=mappings,
+                                  option_klass=PunctMapping)
+
+class MainWindow():
+    SPECIAL_OBJECTS = [
+        'pymodel', 'memory_adjustment', 'candidate_adjustment',
+        'max_best_adjustment', 'max_tail_candidate_adjustment',
+        ]
+
+    def __init__ (self):
+        self.__bus = ibus.Bus()
+        self.__config = self.__bus.get_config()
+        
+        
+    def run(self):
+        self.__init_ui("main_window")
+        self.__read_config()
+        gtk.main()
+        
+    def __init_ui(self, name):
+        self.__init_gettext()
+        xml_file = path.join(path.dirname(__file__), XML_FILE)
+        self.__xml = gtk.Builder()
+        self.__xml.add_objects_from_file(xml_file, self.SPECIAL_OBJECTS)
+        self.__xml.add_objects_from_file(xml_file, [name])
+        self.__xml.connect_signals(self)
+        self.__init_options()
+        self.window = self.__xml.get_object(name)
+        self.window.show_all()
+
+    def __init_gettext(self):
+        locale.setlocale(locale.LC_ALL, "")
+        localedir = os.getenv("IBUS_LOCALEDIR")
+        gettext.bindtextdomain(GETTEXT_PACKAGE, localedir)
+        gettext.bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8")
+
+    def __init_options(self):
+        self.__fuzzy_setup = FuzzySetupDialog()
+        self.__correction_setup = CorrectionSetupDialog()
+        self.__punctmapping_setup = PunctMappingSetupDialog()
+        
+        self.__options = [
+            TrivalOption("General/MemoryPower", 3, self.__xml),
+            TrivalOption("General/PageSize", 10, self.__xml),
+            TrivalOption("General/MaxBest", 1, self.__xml),
+            TrivalOption("General/MaxTailCandidate", 0, self.__xml),
+            
+            RadioOption("General/InitialStatus/Mode", 'Chinese', ['Chinese', 'English'], self.__xml),
+            RadioOption("General/InitialStatus/Punct", 'Full', ['Full', 'Half'], self.__xml),
+            RadioOption("General/InitialStatus/Letter", 'Half', ['Full', 'Half'], self.__xml),
+            RadioOption("General/Charset", 'GBK', ['GB2312', 'GBK', 'GB18030'], self.__xml),
+            CheckBoxOption("General/PunctMapping/Enabled", False, self.__xml),
+                                
+            RadioOption("Keyboard/ModeSwitch", 'Shift', ['Shift', 'Control'], self.__xml),
+            RadioOption("Keyboard/PunctSwitch", 'None', ['ControlComma',
+                                                         'ControlPeriod',
+                                                         'None'], self.__xml),
+            CheckBoxOption("Keyboard/Page/MinusEquals", False, self.__xml),
+            CheckBoxOption("Keyboard/Page/Brackets", False, self.__xml),
+            CheckBoxOption("Keyboard/Page/CommaPeriod", False, self.__xml),
+            CheckBoxOption("Keyboard/CancelBackspace", True, self.__xml),
+            CheckBoxOption("Keyboard/SmartPunct", True, self.__xml),
+            
+            RadioOption("Pinyin/Scheme", 'QuanPin', ['QuanPin', 'ShuangPin'], self.__xml),
+            ComboBoxOption("Pinyin/ShuangPinType", 'MS2003', ['MS2003',
+                                                              'ABC',
+                                                              'ZiRanMa',
+                                                              'Pinyin++',
+                                                              'ZiGuang',
+                                                              'XiaoHe'], self.__xml),
+            CheckBoxOption("QuanPin/Fuzzy/Enabled", False, self.__xml),
+            CheckBoxOption("QuanPin/AutoCorrection/Enabled", False, self.__xml),
+            CheckBoxOption("QuanPin/FuzzySegs/Enabled", False, self.__xml),
+            CheckBoxOption("QuanPin/InnerFuzzy/Enabled", False, self.__xml),
+            
+            self.__fuzzy_setup,
+            self.__correction_setup,
+            self.__punctmapping_setup,
+        ]
+
+    def __get_option(self, name):
+        for opt in self.__options:
+            if opt.name == name:
+                return opt
+        else:
+            return None
+        
+    def __read_config(self):
+        for opt in self.__options:
+            opt.init_ui()
+            opt.read_config()
+        self.on_chk_fuzzy_enabled_toggled(None)
+        self.on_chk_correction_enabled_toggled(None)
+        self.on_chk_punctmapping_enabled_toggled(None)
+        self.on_radio_shuangpin_toggled(None)
+        
+    def __write_config(self):
+        for opt in self.__options:
+            opt.write_config()
+
+    def __update_enabling_button(self, checkbox_name, button_name):
+        """enable a setup button when checked, disable it otherwise
+        """
+        checkbox = self.__xml.get_object(checkbox_name)
+        assert checkbox is not None, "checkbox: %s not found" % checkbox_name
+        button = self.__xml.get_object(button_name)
+        assert button is not None, "button: %s not found" % button_name
+        button_enabled = checkbox.get_active()
+        button.set_sensitive(button_enabled)
+
+    def on_radio_shuangpin_toggled(self, button):
+        radio = self.__xml.get_object("Pinyin/Scheme/ShuangPin")
+        enabled = radio.get_active()
+        combo = self.__xml.get_object("Pinyin/ShuangPinType")
+        combo.set_sensitive(enabled)
+        
+    def on_chk_fuzzy_enabled_toggled(self, button):
+        self.__update_enabling_button("QuanPin/Fuzzy/Enabled",
+                                      "button_fuzzy_setup")
+        
+    def on_button_fuzzy_setup_clicked(self, button):
+        self.__fuzzy_setup.run()
+        
+    def on_chk_correction_enabled_toggled(self, button):
+        self.__update_enabling_button("QuanPin/AutoCorrection/Enabled",
+                                      "button_correction_setup")
+
+    def on_chk_smartseg_enabled_toggled(self, button):
+        self.__update_enabling_button("QuanPin/FuzzySegs/Enabled",
+                                      "QuanPin/InnerFuzzy/Enabled")
+
+    def on_button_correction_setup_clicked(self, button):
+        self.__correction_setup.run()
+        
+    def on_chk_punctmapping_enabled_toggled(self, button):
+        self.__update_enabling_button("General/PunctMapping/Enabled",
+                                      "button_punctmapping_setup")
+    
+    def on_button_punctmapping_setup_clicked(self, button):
+        self.__punctmapping_setup.run()
+    
+    def on_main_ok_clicked(self, button):
+        self.__write_config()
+        self.__quit()
+        
+    def on_main_apply_clicked(self, button):
+        self.__write_config()
+
+    def on_main_cancel_clicked(self, button):
+        self.__quit()
+
+    def __quit(self):
+        gtk.main_quit()
+    
+if __name__ == "__main__":
+    MainWindow().run()
diff --git a/wrapper/ibus/setup/setup.xml b/wrapper/ibus/setup/setup.xml
new file mode 100644 (file)
index 0000000..246f271
--- /dev/null
@@ -0,0 +1,2884 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+  <requires lib="gtk+" version="2.16"/>
+  <object class="GtkAdjustment" id="candidate_adjustment">
+    <property name="lower">1</property>
+    <property name="upper">11</property>
+    <property name="value">9</property>
+    <property name="step_increment">1</property>
+    <property name="page_increment">1</property>
+    <property name="page_size">1</property>
+  </object>
+  <object class="GtkDialog" id="dlg_correction_setup">
+    <property name="can_focus">False</property>
+    <property name="border_width">5</property>
+    <property name="title" translatable="yes">Auto Correct Setup</property>
+    <property name="resizable">False</property>
+    <property name="modal">True</property>
+    <property name="window_position">center</property>
+    <property name="type_hint">normal</property>
+    <child internal-child="vbox">
+      <object class="GtkBox" id="dialog-vbox4">
+        <property name="visible">True</property>
+        <property name="can_focus">False</property>
+        <property name="orientation">vertical</property>
+        <property name="spacing">2</property>
+        <child internal-child="action_area">
+          <object class="GtkButtonBox" id="dialog-action_area4">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="layout_style">end</property>
+            <child>
+              <object class="GtkButton" id="correction_select_all">
+                <property name="label" translatable="yes">All</property>
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">True</property>
+                <property name="use_action_appearance">False</property>
+                <signal name="clicked" handler="on_correction_select_all_clicked" swapped="no"/>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">False</property>
+                <property name="position">0</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkButton" id="correction_unselect_all">
+                <property name="label" translatable="yes">None</property>
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">True</property>
+                <property name="use_action_appearance">False</property>
+                <signal name="clicked" handler="on_correction_uncheck_all_clicked" swapped="no"/>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">False</property>
+                <property name="position">1</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkButton" id="correction_ok">
+                <property name="label">gtk-ok</property>
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">True</property>
+                <property name="use_action_appearance">False</property>
+                <property name="use_stock">True</property>
+                <signal name="clicked" handler="on_correction_ok_clicked" swapped="no"/>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">False</property>
+                <property name="position">2</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkButton" id="correction_cancel">
+                <property name="label">gtk-cancel</property>
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">True</property>
+                <property name="use_action_appearance">False</property>
+                <property name="use_stock">True</property>
+                <signal name="clicked" handler="on_correction_cancel_clicked" swapped="no"/>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">False</property>
+                <property name="position">3</property>
+              </packing>
+            </child>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">True</property>
+            <property name="pack_type">end</property>
+            <property name="position">0</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkTable" id="table11">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="n_rows">3</property>
+            <property name="n_columns">2</property>
+            <property name="homogeneous">True</property>
+            <child>
+              <object class="GtkCheckButton" id="QuanPin/AutoCorrection/GnNg">
+                <property name="label">gn -&gt; ng</property>
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">False</property>
+                <property name="use_action_appearance">False</property>
+                <property name="active">True</property>
+                <property name="draw_indicator">True</property>
+              </object>
+            </child>
+            <child>
+              <object class="GtkCheckButton" id="QuanPin/AutoCorrection/ImgIng">
+                <property name="label">img -&gt; ing</property>
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">False</property>
+                <property name="use_action_appearance">False</property>
+                <property name="active">True</property>
+                <property name="draw_indicator">True</property>
+              </object>
+              <packing>
+                <property name="top_attach">1</property>
+                <property name="bottom_attach">2</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkCheckButton" id="QuanPin/AutoCorrection/UeiUi">
+                <property name="label">uei -&gt; ui</property>
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">False</property>
+                <property name="use_action_appearance">False</property>
+                <property name="active">True</property>
+                <property name="draw_indicator">True</property>
+              </object>
+              <packing>
+                <property name="top_attach">2</property>
+                <property name="bottom_attach">3</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkCheckButton" id="QuanPin/AutoCorrection/UenUn">
+                <property name="label">uen -&gt; un</property>
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">False</property>
+                <property name="use_action_appearance">False</property>
+                <property name="active">True</property>
+                <property name="draw_indicator">True</property>
+              </object>
+              <packing>
+                <property name="left_attach">1</property>
+                <property name="right_attach">2</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkCheckButton" id="QuanPin/AutoCorrection/IouIu">
+                <property name="label">iou -&gt; iu</property>
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">False</property>
+                <property name="use_action_appearance">False</property>
+                <property name="active">True</property>
+                <property name="draw_indicator">True</property>
+              </object>
+              <packing>
+                <property name="left_attach">1</property>
+                <property name="right_attach">2</property>
+                <property name="top_attach">1</property>
+                <property name="bottom_attach">2</property>
+              </packing>
+            </child>
+            <child>
+              <placeholder/>
+            </child>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">True</property>
+            <property name="position">1</property>
+          </packing>
+        </child>
+      </object>
+    </child>
+    <action-widgets>
+      <action-widget response="0">correction_select_all</action-widget>
+      <action-widget response="0">correction_unselect_all</action-widget>
+      <action-widget response="0">correction_ok</action-widget>
+      <action-widget response="0">correction_cancel</action-widget>
+    </action-widgets>
+  </object>
+  <object class="GtkDialog" id="dlg_fuzzy_setup">
+    <property name="can_focus">False</property>
+    <property name="border_width">5</property>
+    <property name="title" translatable="yes">Fuzzy Pinyin Setup</property>
+    <property name="resizable">False</property>
+    <property name="modal">True</property>
+    <property name="window_position">center</property>
+    <property name="type_hint">normal</property>
+    <child internal-child="vbox">
+      <object class="GtkBox" id="dialog-vbox1">
+        <property name="visible">True</property>
+        <property name="can_focus">False</property>
+        <property name="orientation">vertical</property>
+        <property name="spacing">2</property>
+        <child internal-child="action_area">
+          <object class="GtkButtonBox" id="dialog-action_area1">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="layout_style">end</property>
+            <child>
+              <object class="GtkButton" id="fuzzy_select_all">
+                <property name="label" translatable="yes">All</property>
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">True</property>
+                <property name="use_action_appearance">False</property>
+                <signal name="clicked" handler="on_fuzzy_select_all_clicked" swapped="no"/>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">False</property>
+                <property name="position">0</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkButton" id="fuzzy_unselect_all">
+                <property name="label" translatable="yes">None</property>
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">True</property>
+                <property name="use_action_appearance">False</property>
+                <signal name="clicked" handler="on_fuzzy_unselect_all_clicked" swapped="no"/>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">False</property>
+                <property name="position">1</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkButton" id="fuzzy_ok">
+                <property name="label">gtk-ok</property>
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">True</property>
+                <property name="use_action_appearance">False</property>
+                <property name="use_stock">True</property>
+                <signal name="clicked" handler="on_fuzzy_ok_clicked" swapped="no"/>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">False</property>
+                <property name="position">2</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkButton" id="fuzzy_cancel">
+                <property name="label">gtk-cancel</property>
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">True</property>
+                <property name="use_action_appearance">False</property>
+                <property name="use_stock">True</property>
+                <signal name="clicked" handler="on_fuzzy_cancel_clicked" swapped="no"/>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">False</property>
+                <property name="position">3</property>
+              </packing>
+            </child>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">True</property>
+            <property name="pack_type">end</property>
+            <property name="position">0</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkTable" id="table1">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="n_rows">7</property>
+            <property name="n_columns">2</property>
+            <property name="homogeneous">True</property>
+            <child>
+              <object class="GtkCheckButton" id="QuanPin/Fuzzy/ZhiZi">
+                <property name="label">z -&gt; zh</property>
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">False</property>
+                <property name="use_action_appearance">False</property>
+                <property name="active">True</property>
+                <property name="draw_indicator">True</property>
+              </object>
+            </child>
+            <child>
+              <object class="GtkCheckButton" id="QuanPin/Fuzzy/ChiCi">
+                <property name="label">c -&gt; ch</property>
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">False</property>
+                <property name="use_action_appearance">False</property>
+                <property name="active">True</property>
+                <property name="draw_indicator">True</property>
+              </object>
+              <packing>
+                <property name="top_attach">1</property>
+                <property name="bottom_attach">2</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkCheckButton" id="QuanPin/Fuzzy/ShiSi">
+                <property name="label">s -&gt; sh</property>
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">False</property>
+                <property name="use_action_appearance">False</property>
+                <property name="active">True</property>
+                <property name="draw_indicator">True</property>
+              </object>
+              <packing>
+                <property name="top_attach">2</property>
+                <property name="bottom_attach">3</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkCheckButton" id="QuanPin/Fuzzy/AnAng">
+                <property name="label">an -&gt; ang</property>
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">False</property>
+                <property name="use_action_appearance">False</property>
+                <property name="active">True</property>
+                <property name="draw_indicator">True</property>
+              </object>
+              <packing>
+                <property name="top_attach">3</property>
+                <property name="bottom_attach">4</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkCheckButton" id="QuanPin/Fuzzy/OnOng">
+                <property name="label">on -&gt; ong</property>
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">False</property>
+                <property name="use_action_appearance">False</property>
+                <property name="active">True</property>
+                <property name="draw_indicator">True</property>
+              </object>
+              <packing>
+                <property name="top_attach">4</property>
+                <property name="bottom_attach">5</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkCheckButton" id="QuanPin/Fuzzy/EnEng">
+                <property name="label">en -&gt; eng</property>
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">False</property>
+                <property name="use_action_appearance">False</property>
+                <property name="active">True</property>
+                <property name="draw_indicator">True</property>
+              </object>
+              <packing>
+                <property name="top_attach">5</property>
+                <property name="bottom_attach">6</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkCheckButton" id="QuanPin/Fuzzy/InIng">
+                <property name="label">in -&gt; ing</property>
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">False</property>
+                <property name="use_action_appearance">False</property>
+                <property name="active">True</property>
+                <property name="draw_indicator">True</property>
+              </object>
+              <packing>
+                <property name="top_attach">6</property>
+                <property name="bottom_attach">7</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkCheckButton" id="QuanPin/Fuzzy/EngOng">
+                <property name="label">eng -&gt; ong</property>
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">False</property>
+                <property name="use_action_appearance">False</property>
+                <property name="draw_indicator">True</property>
+              </object>
+              <packing>
+                <property name="left_attach">1</property>
+                <property name="right_attach">2</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkCheckButton" id="QuanPin/Fuzzy/IanIang">
+                <property name="label">ian -&gt; iang</property>
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">False</property>
+                <property name="use_action_appearance">False</property>
+                <property name="active">True</property>
+                <property name="draw_indicator">True</property>
+              </object>
+              <packing>
+                <property name="left_attach">1</property>
+                <property name="right_attach">2</property>
+                <property name="top_attach">1</property>
+                <property name="bottom_attach">2</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkCheckButton" id="QuanPin/Fuzzy/UanUang">
+                <property name="label">uan -&gt; uang</property>
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">False</property>
+                <property name="use_action_appearance">False</property>
+                <property name="draw_indicator">True</property>
+              </object>
+              <packing>
+                <property name="left_attach">1</property>
+                <property name="right_attach">2</property>
+                <property name="top_attach">2</property>
+                <property name="bottom_attach">3</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkCheckButton" id="QuanPin/Fuzzy/NeLe">
+                <property name="label">l -&gt; n</property>
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">False</property>
+                <property name="use_action_appearance">False</property>
+                <property name="active">True</property>
+                <property name="draw_indicator">True</property>
+              </object>
+              <packing>
+                <property name="left_attach">1</property>
+                <property name="right_attach">2</property>
+                <property name="top_attach">3</property>
+                <property name="bottom_attach">4</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkCheckButton" id="QuanPin/Fuzzy/FoHe">
+                <property name="label">f -&gt; h</property>
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">False</property>
+                <property name="use_action_appearance">False</property>
+                <property name="active">True</property>
+                <property name="draw_indicator">True</property>
+              </object>
+              <packing>
+                <property name="left_attach">1</property>
+                <property name="right_attach">2</property>
+                <property name="top_attach">4</property>
+                <property name="bottom_attach">5</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkCheckButton" id="QuanPin/Fuzzy/LeRi">
+                <property name="label">r -&gt; l</property>
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">False</property>
+                <property name="use_action_appearance">False</property>
+                <property name="active">True</property>
+                <property name="draw_indicator">True</property>
+              </object>
+              <packing>
+                <property name="left_attach">1</property>
+                <property name="right_attach">2</property>
+                <property name="top_attach">5</property>
+                <property name="bottom_attach">6</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkCheckButton" id="QuanPin/Fuzzy/KeGe">
+                <property name="label">k -&gt; g</property>
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">False</property>
+                <property name="use_action_appearance">False</property>
+                <property name="draw_indicator">True</property>
+              </object>
+              <packing>
+                <property name="left_attach">1</property>
+                <property name="right_attach">2</property>
+                <property name="top_attach">6</property>
+                <property name="bottom_attach">7</property>
+              </packing>
+            </child>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">True</property>
+            <property name="position">1</property>
+          </packing>
+        </child>
+      </object>
+    </child>
+    <action-widgets>
+      <action-widget response="-1">fuzzy_select_all</action-widget>
+      <action-widget response="0">fuzzy_unselect_all</action-widget>
+      <action-widget response="0">fuzzy_ok</action-widget>
+      <action-widget response="0">fuzzy_cancel</action-widget>
+    </action-widgets>
+  </object>
+  <object class="GtkDialog" id="dlg_punctmapping_setup">
+    <property name="can_focus">False</property>
+    <property name="border_width">5</property>
+    <property name="title" translatable="yes">Punct Mapping</property>
+    <property name="resizable">False</property>
+    <property name="modal">True</property>
+    <property name="window_position">center</property>
+    <property name="type_hint">normal</property>
+    <child internal-child="vbox">
+      <object class="GtkBox" id="dialog-vbox2">
+        <property name="visible">True</property>
+        <property name="can_focus">False</property>
+        <property name="orientation">vertical</property>
+        <property name="spacing">2</property>
+        <child internal-child="action_area">
+          <object class="GtkButtonBox" id="dialog-action_area2">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="layout_style">end</property>
+            <child>
+              <object class="GtkButton" id="punctmapping_select_all">
+                <property name="label" translatable="yes">All</property>
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">True</property>
+                <property name="use_action_appearance">False</property>
+                <signal name="clicked" handler="on_punctmapping_select_all_clicked" swapped="no"/>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">False</property>
+                <property name="position">0</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkButton" id="punctmapping_unselect_all">
+                <property name="label" translatable="yes">None</property>
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">True</property>
+                <property name="use_action_appearance">False</property>
+                <signal name="clicked" handler="on_punctmapping_unselect_all_clicked" swapped="no"/>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">False</property>
+                <property name="position">1</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkButton" id="punctmapping_ok">
+                <property name="label">gtk-ok</property>
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">True</property>
+                <property name="use_action_appearance">False</property>
+                <property name="use_stock">True</property>
+                <signal name="clicked" handler="on_punctmapping_ok_clicked" swapped="no"/>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">False</property>
+                <property name="position">2</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkButton" id="punctmapping_cancel">
+                <property name="label">gtk-cancel</property>
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">True</property>
+                <property name="use_action_appearance">False</property>
+                <property name="use_stock">True</property>
+                <signal name="clicked" handler="on_punctmapping_cancel_clicked" swapped="no"/>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">False</property>
+                <property name="position">3</property>
+              </packing>
+            </child>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">True</property>
+            <property name="pack_type">end</property>
+            <property name="position">0</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkVBox" id="vbox5">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <child>
+              <object class="GtkHBox" id="hbox1">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <child>
+                  <object class="GtkToggleButton" id="togglebutton1">
+                    <property name="label">~
+`</property>
+                    <property name="visible">True</property>
+                    <property name="can_focus">True</property>
+                    <property name="receives_default">True</property>
+                    <property name="use_action_appearance">False</property>
+                  </object>
+                  <packing>
+                    <property name="expand">True</property>
+                    <property name="fill">True</property>
+                    <property name="position">0</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkToggleButton" id="togglebutton2">
+                    <property name="label">!
+1</property>
+                    <property name="height_request">1</property>
+                    <property name="visible">True</property>
+                    <property name="can_focus">True</property>
+                    <property name="receives_default">True</property>
+                    <property name="use_action_appearance">False</property>
+                  </object>
+                  <packing>
+                    <property name="expand">True</property>
+                    <property name="fill">True</property>
+                    <property name="position">1</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkToggleButton" id="togglebutton3">
+                    <property name="label">@
+2</property>
+                    <property name="visible">True</property>
+                    <property name="can_focus">True</property>
+                    <property name="receives_default">True</property>
+                    <property name="use_action_appearance">False</property>
+                  </object>
+                  <packing>
+                    <property name="expand">True</property>
+                    <property name="fill">True</property>
+                    <property name="position">2</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkToggleButton" id="togglebutton4">
+                    <property name="label">#
+3</property>
+                    <property name="visible">True</property>
+                    <property name="can_focus">True</property>
+                    <property name="receives_default">True</property>
+                    <property name="use_action_appearance">False</property>
+                  </object>
+                  <packing>
+                    <property name="expand">True</property>
+                    <property name="fill">True</property>
+                    <property name="position">3</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkToggleButton" id="togglebutton5">
+                    <property name="label">$
+4</property>
+                    <property name="visible">True</property>
+                    <property name="can_focus">True</property>
+                    <property name="receives_default">True</property>
+                    <property name="use_action_appearance">False</property>
+                  </object>
+                  <packing>
+                    <property name="expand">True</property>
+                    <property name="fill">True</property>
+                    <property name="position">4</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkToggleButton" id="togglebutton6">
+                    <property name="label">%
+5</property>
+                    <property name="visible">True</property>
+                    <property name="can_focus">True</property>
+                    <property name="receives_default">True</property>
+                    <property name="use_action_appearance">False</property>
+                  </object>
+                  <packing>
+                    <property name="expand">True</property>
+                    <property name="fill">True</property>
+                    <property name="position">5</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkToggleButton" id="togglebutton7">
+                    <property name="label">^
+6</property>
+                    <property name="visible">True</property>
+                    <property name="can_focus">True</property>
+                    <property name="receives_default">True</property>
+                    <property name="use_action_appearance">False</property>
+                  </object>
+                  <packing>
+                    <property name="expand">True</property>
+                    <property name="fill">True</property>
+                    <property name="position">6</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkToggleButton" id="togglebutton8">
+                    <property name="label">&amp;
+7</property>
+                    <property name="visible">True</property>
+                    <property name="can_focus">True</property>
+                    <property name="receives_default">True</property>
+                    <property name="use_action_appearance">False</property>
+                  </object>
+                  <packing>
+                    <property name="expand">True</property>
+                    <property name="fill">True</property>
+                    <property name="position">7</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkToggleButton" id="togglebutton9">
+                    <property name="label">*
+8</property>
+                    <property name="visible">True</property>
+                    <property name="can_focus">True</property>
+                    <property name="receives_default">True</property>
+                    <property name="use_action_appearance">False</property>
+                  </object>
+                  <packing>
+                    <property name="expand">True</property>
+                    <property name="fill">True</property>
+                    <property name="position">8</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkToggleButton" id="togglebutton10">
+                    <property name="label">(
+9</property>
+                    <property name="visible">True</property>
+                    <property name="can_focus">True</property>
+                    <property name="receives_default">True</property>
+                    <property name="use_action_appearance">False</property>
+                  </object>
+                  <packing>
+                    <property name="expand">True</property>
+                    <property name="fill">True</property>
+                    <property name="position">9</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkToggleButton" id="togglebutton11">
+                    <property name="label">)
+0</property>
+                    <property name="visible">True</property>
+                    <property name="can_focus">True</property>
+                    <property name="receives_default">True</property>
+                    <property name="use_action_appearance">False</property>
+                  </object>
+                  <packing>
+                    <property name="expand">True</property>
+                    <property name="fill">True</property>
+                    <property name="position">10</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkToggleButton" id="togglebutton12">
+                    <property name="label">_
+-</property>
+                    <property name="visible">True</property>
+                    <property name="can_focus">True</property>
+                    <property name="receives_default">True</property>
+                    <property name="use_action_appearance">False</property>
+                  </object>
+                  <packing>
+                    <property name="expand">True</property>
+                    <property name="fill">True</property>
+                    <property name="position">11</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkToggleButton" id="togglebutton13">
+                    <property name="label">+
+=</property>
+                    <property name="visible">True</property>
+                    <property name="can_focus">True</property>
+                    <property name="receives_default">True</property>
+                    <property name="use_action_appearance">False</property>
+                  </object>
+                  <packing>
+                    <property name="expand">True</property>
+                    <property name="fill">True</property>
+                    <property name="position">12</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkToggleButton" id="togglebutton14">
+                    <property name="label">|
+\</property>
+                    <property name="visible">True</property>
+                    <property name="can_focus">True</property>
+                    <property name="receives_default">True</property>
+                    <property name="use_action_appearance">False</property>
+                  </object>
+                  <packing>
+                    <property name="expand">True</property>
+                    <property name="fill">True</property>
+                    <property name="position">13</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkToggleButton" id="togglebutton15">
+                    <property name="label">&lt;-</property>
+                    <property name="visible">True</property>
+                    <property name="sensitive">False</property>
+                    <property name="can_focus">True</property>
+                    <property name="receives_default">True</property>
+                    <property name="use_action_appearance">False</property>
+                  </object>
+                  <packing>
+                    <property name="expand">True</property>
+                    <property name="fill">True</property>
+                    <property name="position">14</property>
+                  </packing>
+                </child>
+              </object>
+              <packing>
+                <property name="expand">True</property>
+                <property name="fill">True</property>
+                <property name="position">0</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkHBox" id="hbox2">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <child>
+                  <object class="GtkToggleButton" id="togglebutton16">
+                    <property name="label">tab</property>
+                    <property name="width_request">27</property>
+                    <property name="visible">True</property>
+                    <property name="sensitive">False</property>
+                    <property name="can_focus">True</property>
+                    <property name="receives_default">True</property>
+                    <property name="use_action_appearance">False</property>
+                  </object>
+                  <packing>
+                    <property name="expand">True</property>
+                    <property name="fill">True</property>
+                    <property name="position">0</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkToggleButton" id="togglebutton17">
+                    <property name="label">Q</property>
+                    <property name="visible">True</property>
+                    <property name="sensitive">False</property>
+                    <property name="can_focus">True</property>
+                    <property name="receives_default">True</property>
+                    <property name="use_action_appearance">False</property>
+                  </object>
+                  <packing>
+                    <property name="expand">True</property>
+                    <property name="fill">True</property>
+                    <property name="position">1</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkToggleButton" id="togglebutton18">
+                    <property name="label">W</property>
+                    <property name="visible">True</property>
+                    <property name="sensitive">False</property>
+                    <property name="can_focus">True</property>
+                    <property name="receives_default">True</property>
+                    <property name="use_action_appearance">False</property>
+                  </object>
+                  <packing>
+                    <property name="expand">True</property>
+                    <property name="fill">True</property>
+                    <property name="position">2</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkToggleButton" id="togglebutton19">
+                    <property name="label">E</property>
+                    <property name="visible">True</property>
+                    <property name="sensitive">False</property>
+                    <property name="can_focus">True</property>
+                    <property name="receives_default">True</property>
+                    <property name="use_action_appearance">False</property>
+                  </object>
+                  <packing>
+                    <property name="expand">True</property>
+                    <property name="fill">True</property>
+                    <property name="position">3</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkToggleButton" id="togglebutton20">
+                    <property name="label">R</property>
+                    <property name="visible">True</property>
+                    <property name="sensitive">False</property>
+                    <property name="can_focus">True</property>
+                    <property name="receives_default">True</property>
+                    <property name="use_action_appearance">False</property>
+                  </object>
+                  <packing>
+                    <property name="expand">True</property>
+                    <property name="fill">True</property>
+                    <property name="position">4</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkToggleButton" id="togglebutton21">
+                    <property name="label">T</property>
+                    <property name="visible">True</property>
+                    <property name="sensitive">False</property>
+                    <property name="can_focus">True</property>
+                    <property name="receives_default">True</property>
+                    <property name="use_action_appearance">False</property>
+                  </object>
+                  <packing>
+                    <property name="expand">True</property>
+                    <property name="fill">True</property>
+                    <property name="position">5</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkToggleButton" id="togglebutton22">
+                    <property name="label">Y</property>
+                    <property name="visible">True</property>
+                    <property name="sensitive">False</property>
+                    <property name="can_focus">True</property>
+                    <property name="receives_default">True</property>
+                    <property name="use_action_appearance">False</property>
+                  </object>
+                  <packing>
+                    <property name="expand">True</property>
+                    <property name="fill">True</property>
+                    <property name="position">6</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkToggleButton" id="togglebutton23">
+                    <property name="label">U</property>
+                    <property name="visible">True</property>
+                    <property name="sensitive">False</property>
+                    <property name="can_focus">True</property>
+                    <property name="receives_default">True</property>
+                    <property name="use_action_appearance">False</property>
+                  </object>
+                  <packing>
+                    <property name="expand">True</property>
+                    <property name="fill">True</property>
+                    <property name="position">7</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkToggleButton" id="togglebutton24">
+                    <property name="label">I</property>
+                    <property name="visible">True</property>
+                    <property name="sensitive">False</property>
+                    <property name="can_focus">True</property>
+                    <property name="receives_default">True</property>
+                    <property name="use_action_appearance">False</property>
+                  </object>
+                  <packing>
+                    <property name="expand">True</property>
+                    <property name="fill">True</property>
+                    <property name="position">8</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkToggleButton" id="togglebutton25">
+                    <property name="label">O</property>
+                    <property name="visible">True</property>
+                    <property name="sensitive">False</property>
+                    <property name="can_focus">True</property>
+                    <property name="receives_default">True</property>
+                    <property name="use_action_appearance">False</property>
+                  </object>
+                  <packing>
+                    <property name="expand">True</property>
+                    <property name="fill">True</property>
+                    <property name="position">9</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkToggleButton" id="togglebutton26">
+                    <property name="label">P</property>
+                    <property name="visible">True</property>
+                    <property name="sensitive">False</property>
+                    <property name="can_focus">True</property>
+                    <property name="receives_default">True</property>
+                    <property name="use_action_appearance">False</property>
+                  </object>
+                  <packing>
+                    <property name="expand">True</property>
+                    <property name="fill">True</property>
+                    <property name="position">10</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkToggleButton" id="togglebutton27">
+                    <property name="label">{
+[</property>
+                    <property name="visible">True</property>
+                    <property name="can_focus">True</property>
+                    <property name="receives_default">True</property>
+                    <property name="use_action_appearance">False</property>
+                  </object>
+                  <packing>
+                    <property name="expand">True</property>
+                    <property name="fill">True</property>
+                    <property name="position">11</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkToggleButton" id="togglebutton28">
+                    <property name="label">}
+]</property>
+                    <property name="visible">True</property>
+                    <property name="can_focus">True</property>
+                    <property name="receives_default">True</property>
+                    <property name="use_action_appearance">False</property>
+                  </object>
+                  <packing>
+                    <property name="expand">True</property>
+                    <property name="fill">True</property>
+                    <property name="position">12</property>
+                  </packing>
+                </child>
+                <child>
+                  <placeholder/>
+                </child>
+              </object>
+              <packing>
+                <property name="expand">True</property>
+                <property name="fill">True</property>
+                <property name="position">1</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkHBox" id="hbox3">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <child>
+                  <object class="GtkToggleButton" id="togglebutton29">
+                    <property name="label">caps</property>
+                    <property name="visible">True</property>
+                    <property name="sensitive">False</property>
+                    <property name="can_focus">True</property>
+                    <property name="receives_default">True</property>
+                    <property name="use_action_appearance">False</property>
+                  </object>
+                  <packing>
+                    <property name="expand">True</property>
+                    <property name="fill">True</property>
+                    <property name="position">0</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkToggleButton" id="togglebutton30">
+                    <property name="label">A</property>
+                    <property name="visible">True</property>
+                    <property name="sensitive">False</property>
+                    <property name="can_focus">True</property>
+                    <property name="receives_default">True</property>
+                    <property name="use_action_appearance">False</property>
+                  </object>
+                  <packing>
+                    <property name="expand">True</property>
+                    <property name="fill">True</property>
+                    <property name="position">1</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkToggleButton" id="togglebutton31">
+                    <property name="label">S</property>
+                    <property name="visible">True</property>
+                    <property name="sensitive">False</property>
+                    <property name="can_focus">True</property>
+                    <property name="receives_default">True</property>
+                    <property name="use_action_appearance">False</property>
+                  </object>
+                  <packing>
+                    <property name="expand">True</property>
+                    <property name="fill">True</property>
+                    <property name="position">2</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkToggleButton" id="togglebutton32">
+                    <property name="label">D</property>
+                    <property name="visible">True</property>
+                    <property name="sensitive">False</property>
+                    <property name="can_focus">True</property>
+                    <property name="receives_default">True</property>
+                    <property name="use_action_appearance">False</property>
+                  </object>
+                  <packing>
+                    <property name="expand">True</property>
+                    <property name="fill">True</property>
+                    <property name="position">3</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkToggleButton" id="togglebutton33">
+                    <property name="label">F</property>
+                    <property name="visible">True</property>
+                    <property name="sensitive">False</property>
+                    <property name="can_focus">True</property>
+                    <property name="receives_default">True</property>
+                    <property name="use_action_appearance">False</property>
+                  </object>
+                  <packing>
+                    <property name="expand">True</property>
+                    <property name="fill">True</property>
+                    <property name="position">4</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkToggleButton" id="togglebutton34">
+                    <property name="label">G</property>
+                    <property name="visible">True</property>
+                    <property name="sensitive">False</property>
+                    <property name="can_focus">True</property>
+                    <property name="receives_default">True</property>
+                    <property name="use_action_appearance">False</property>
+                  </object>
+                  <packing>
+                    <property name="expand">True</property>
+                    <property name="fill">True</property>
+                    <property name="position">5</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkToggleButton" id="togglebutton35">
+                    <property name="label">H</property>
+                    <property name="visible">True</property>
+                    <property name="sensitive">False</property>
+                    <property name="can_focus">True</property>
+                    <property name="receives_default">True</property>
+                    <property name="use_action_appearance">False</property>
+                  </object>
+                  <packing>
+                    <property name="expand">True</property>
+                    <property name="fill">True</property>
+                    <property name="position">6</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkToggleButton" id="togglebutton36">
+                    <property name="label">J</property>
+                    <property name="visible">True</property>
+                    <property name="sensitive">False</property>
+                    <property name="can_focus">True</property>
+                    <property name="receives_default">True</property>
+                    <property name="use_action_appearance">False</property>
+                  </object>
+                  <packing>
+                    <property name="expand">True</property>
+                    <property name="fill">True</property>
+                    <property name="position">7</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkToggleButton" id="togglebutton37">
+                    <property name="label">K</property>
+                    <property name="visible">True</property>
+                    <property name="sensitive">False</property>
+                    <property name="can_focus">True</property>
+                    <property name="receives_default">True</property>
+                    <property name="use_action_appearance">False</property>
+                  </object>
+                  <packing>
+                    <property name="expand">True</property>
+                    <property name="fill">True</property>
+                    <property name="position">8</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkToggleButton" id="togglebutton38">
+                    <property name="label">L</property>
+                    <property name="visible">True</property>
+                    <property name="sensitive">False</property>
+                    <property name="can_focus">True</property>
+                    <property name="receives_default">True</property>
+                    <property name="use_action_appearance">False</property>
+                  </object>
+                  <packing>
+                    <property name="expand">True</property>
+                    <property name="fill">True</property>
+                    <property name="position">9</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkToggleButton" id="togglebutton39">
+                    <property name="label">:
+;</property>
+                    <property name="visible">True</property>
+                    <property name="can_focus">True</property>
+                    <property name="receives_default">True</property>
+                    <property name="use_action_appearance">False</property>
+                  </object>
+                  <packing>
+                    <property name="expand">True</property>
+                    <property name="fill">True</property>
+                    <property name="position">10</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkToggleButton" id="togglebutton40">
+                    <property name="label">"
+'</property>
+                    <property name="visible">True</property>
+                    <property name="can_focus">True</property>
+                    <property name="receives_default">True</property>
+                    <property name="use_action_appearance">False</property>
+                  </object>
+                  <packing>
+                    <property name="expand">True</property>
+                    <property name="fill">True</property>
+                    <property name="position">11</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkToggleButton" id="togglebutton41">
+                    <property name="label">Enter</property>
+                    <property name="width_request">42</property>
+                    <property name="visible">True</property>
+                    <property name="sensitive">False</property>
+                    <property name="can_focus">True</property>
+                    <property name="receives_default">True</property>
+                    <property name="use_action_appearance">False</property>
+                  </object>
+                  <packing>
+                    <property name="expand">True</property>
+                    <property name="fill">True</property>
+                    <property name="position">12</property>
+                  </packing>
+                </child>
+              </object>
+              <packing>
+                <property name="expand">True</property>
+                <property name="fill">True</property>
+                <property name="position">2</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkHBox" id="hbox4">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <child>
+                  <object class="GtkToggleButton" id="togglebutton42">
+                    <property name="label"> shift </property>
+                    <property name="visible">True</property>
+                    <property name="sensitive">False</property>
+                    <property name="can_focus">True</property>
+                    <property name="receives_default">True</property>
+                    <property name="use_action_appearance">False</property>
+                  </object>
+                  <packing>
+                    <property name="expand">True</property>
+                    <property name="fill">True</property>
+                    <property name="position">0</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkToggleButton" id="togglebutton43">
+                    <property name="label">Z</property>
+                    <property name="visible">True</property>
+                    <property name="sensitive">False</property>
+                    <property name="can_focus">True</property>
+                    <property name="receives_default">True</property>
+                    <property name="use_action_appearance">False</property>
+                  </object>
+                  <packing>
+                    <property name="expand">True</property>
+                    <property name="fill">True</property>
+                    <property name="position">1</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkToggleButton" id="togglebutton44">
+                    <property name="label">X</property>
+                    <property name="visible">True</property>
+                    <property name="sensitive">False</property>
+                    <property name="can_focus">True</property>
+                    <property name="receives_default">True</property>
+                    <property name="use_action_appearance">False</property>
+                  </object>
+                  <packing>
+                    <property name="expand">True</property>
+                    <property name="fill">True</property>
+                    <property name="position">2</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkToggleButton" id="togglebutton45">
+                    <property name="label">C</property>
+                    <property name="visible">True</property>
+                    <property name="sensitive">False</property>
+                    <property name="can_focus">True</property>
+                    <property name="receives_default">True</property>
+                    <property name="use_action_appearance">False</property>
+                  </object>
+                  <packing>
+                    <property name="expand">True</property>
+                    <property name="fill">True</property>
+                    <property name="position">3</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkToggleButton" id="togglebutton46">
+                    <property name="label">V</property>
+                    <property name="visible">True</property>
+                    <property name="sensitive">False</property>
+                    <property name="can_focus">True</property>
+                    <property name="receives_default">True</property>
+                    <property name="use_action_appearance">False</property>
+                  </object>
+                  <packing>
+                    <property name="expand">True</property>
+                    <property name="fill">True</property>
+                    <property name="position">4</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkToggleButton" id="togglebutton47">
+                    <property name="label">B</property>
+                    <property name="visible">True</property>
+                    <property name="sensitive">False</property>
+                    <property name="can_focus">True</property>
+                    <property name="receives_default">True</property>
+                    <property name="use_action_appearance">False</property>
+                  </object>
+                  <packing>
+                    <property name="expand">True</property>
+                    <property name="fill">True</property>
+                    <property name="position">5</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkToggleButton" id="togglebutton48">
+                    <property name="label">N</property>
+                    <property name="visible">True</property>
+                    <property name="sensitive">False</property>
+                    <property name="can_focus">True</property>
+                    <property name="receives_default">True</property>
+                    <property name="use_action_appearance">False</property>
+                  </object>
+                  <packing>
+                    <property name="expand">True</property>
+                    <property name="fill">True</property>
+                    <property name="position">6</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkToggleButton" id="togglebutton49">
+                    <property name="label">M</property>
+                    <property name="visible">True</property>
+                    <property name="sensitive">False</property>
+                    <property name="can_focus">True</property>
+                    <property name="receives_default">True</property>
+                    <property name="use_action_appearance">False</property>
+                  </object>
+                  <packing>
+                    <property name="expand">True</property>
+                    <property name="fill">True</property>
+                    <property name="position">7</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkToggleButton" id="togglebutton50">
+                    <property name="label">&lt;
+,</property>
+                    <property name="visible">True</property>
+                    <property name="can_focus">True</property>
+                    <property name="receives_default">True</property>
+                    <property name="use_action_appearance">False</property>
+                  </object>
+                  <packing>
+                    <property name="expand">True</property>
+                    <property name="fill">True</property>
+                    <property name="position">8</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkToggleButton" id="togglebutton51">
+                    <property name="label">&gt;
+.</property>
+                    <property name="visible">True</property>
+                    <property name="can_focus">True</property>
+                    <property name="receives_default">True</property>
+                    <property name="use_action_appearance">False</property>
+                  </object>
+                  <packing>
+                    <property name="expand">True</property>
+                    <property name="fill">True</property>
+                    <property name="position">9</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkToggleButton" id="togglebutton52">
+                    <property name="label">?
+/</property>
+                    <property name="visible">True</property>
+                    <property name="can_focus">True</property>
+                    <property name="receives_default">True</property>
+                    <property name="use_action_appearance">False</property>
+                  </object>
+                  <packing>
+                    <property name="expand">True</property>
+                    <property name="fill">True</property>
+                    <property name="position">10</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkToggleButton" id="togglebutton53">
+                    <property name="label"> shift </property>
+                    <property name="visible">True</property>
+                    <property name="sensitive">False</property>
+                    <property name="can_focus">True</property>
+                    <property name="receives_default">True</property>
+                    <property name="use_action_appearance">False</property>
+                  </object>
+                  <packing>
+                    <property name="expand">True</property>
+                    <property name="fill">True</property>
+                    <property name="position">11</property>
+                  </packing>
+                </child>
+              </object>
+              <packing>
+                <property name="expand">True</property>
+                <property name="fill">True</property>
+                <property name="position">3</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkHBox" id="hbox5">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <child>
+                  <object class="GtkToggleButton" id="togglebutton54">
+                    <property name="label">Ctrl</property>
+                    <property name="visible">True</property>
+                    <property name="sensitive">False</property>
+                    <property name="can_focus">True</property>
+                    <property name="receives_default">True</property>
+                    <property name="use_action_appearance">False</property>
+                  </object>
+                  <packing>
+                    <property name="expand">True</property>
+                    <property name="fill">True</property>
+                    <property name="position">0</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkToggleButton" id="togglebutton55">
+                    <property name="label">Win</property>
+                    <property name="visible">True</property>
+                    <property name="sensitive">False</property>
+                    <property name="can_focus">True</property>
+                    <property name="receives_default">True</property>
+                    <property name="use_action_appearance">False</property>
+                  </object>
+                  <packing>
+                    <property name="expand">True</property>
+                    <property name="fill">True</property>
+                    <property name="position">1</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkToggleButton" id="togglebutton56">
+                    <property name="label">Alt</property>
+                    <property name="visible">True</property>
+                    <property name="sensitive">False</property>
+                    <property name="can_focus">True</property>
+                    <property name="receives_default">True</property>
+                    <property name="use_action_appearance">False</property>
+                  </object>
+                  <packing>
+                    <property name="expand">True</property>
+                    <property name="fill">True</property>
+                    <property name="position">2</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkToggleButton" id="togglebutton57">
+                    <property name="label">                                                                  </property>
+                    <property name="visible">True</property>
+                    <property name="sensitive">False</property>
+                    <property name="can_focus">True</property>
+                    <property name="receives_default">True</property>
+                    <property name="use_action_appearance">False</property>
+                  </object>
+                  <packing>
+                    <property name="expand">True</property>
+                    <property name="fill">True</property>
+                    <property name="position">3</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkToggleButton" id="togglebutton58">
+                    <property name="label">Alt</property>
+                    <property name="visible">True</property>
+                    <property name="sensitive">False</property>
+                    <property name="can_focus">True</property>
+                    <property name="receives_default">True</property>
+                    <property name="use_action_appearance">False</property>
+                  </object>
+                  <packing>
+                    <property name="expand">True</property>
+                    <property name="fill">True</property>
+                    <property name="position">4</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkToggleButton" id="togglebutton59">
+                    <property name="label">Win</property>
+                    <property name="visible">True</property>
+                    <property name="sensitive">False</property>
+                    <property name="can_focus">True</property>
+                    <property name="receives_default">True</property>
+                    <property name="use_action_appearance">False</property>
+                  </object>
+                  <packing>
+                    <property name="expand">True</property>
+                    <property name="fill">True</property>
+                    <property name="position">5</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkToggleButton" id="togglebutton60">
+                    <property name="label">[]]</property>
+                    <property name="visible">True</property>
+                    <property name="sensitive">False</property>
+                    <property name="can_focus">True</property>
+                    <property name="receives_default">True</property>
+                    <property name="use_action_appearance">False</property>
+                  </object>
+                  <packing>
+                    <property name="expand">True</property>
+                    <property name="fill">True</property>
+                    <property name="position">6</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkToggleButton" id="togglebutton61">
+                    <property name="label">Ctrl</property>
+                    <property name="visible">True</property>
+                    <property name="sensitive">False</property>
+                    <property name="can_focus">True</property>
+                    <property name="receives_default">True</property>
+                    <property name="use_action_appearance">False</property>
+                  </object>
+                  <packing>
+                    <property name="expand">True</property>
+                    <property name="fill">True</property>
+                    <property name="position">7</property>
+                  </packing>
+                </child>
+              </object>
+              <packing>
+                <property name="expand">True</property>
+                <property name="fill">True</property>
+                <property name="position">4</property>
+              </packing>
+            </child>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">True</property>
+            <property name="position">1</property>
+          </packing>
+        </child>
+      </object>
+    </child>
+    <action-widgets>
+      <action-widget response="0">punctmapping_select_all</action-widget>
+      <action-widget response="0">punctmapping_unselect_all</action-widget>
+      <action-widget response="0">punctmapping_ok</action-widget>
+      <action-widget response="0">punctmapping_cancel</action-widget>
+    </action-widgets>
+  </object>
+  <object class="GtkWindow" id="main_window">
+    <property name="visible">True</property>
+    <property name="can_focus">False</property>
+    <property name="title" translatable="yes">SunPinyin Setup</property>
+    <property name="resizable">False</property>
+    <property name="window_position">center</property>
+    <signal name="destroy" handler="on_main_cancel_clicked" swapped="no"/>
+    <child>
+      <object class="GtkVBox" id="vbox1">
+        <property name="visible">True</property>
+        <property name="can_focus">False</property>
+        <child>
+          <object class="GtkNotebook" id="notebook1">
+            <property name="visible">True</property>
+            <property name="can_focus">True</property>
+            <property name="border_width">5</property>
+            <child>
+              <object class="GtkVBox" id="vbox2">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <child>
+                  <object class="GtkFrame" id="frame1">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                    <property name="border_width">5</property>
+                    <property name="label_xalign">0</property>
+                    <property name="shadow_type">none</property>
+                    <child>
+                      <object class="GtkAlignment" id="alignment1">
+                        <property name="visible">True</property>
+                        <property name="can_focus">False</property>
+                        <property name="left_padding">12</property>
+                        <child>
+                          <object class="GtkTable" id="table3">
+                            <property name="visible">True</property>
+                            <property name="can_focus">False</property>
+                            <property name="border_width">10</property>
+                            <property name="n_rows">2</property>
+                            <property name="n_columns">2</property>
+                            <property name="homogeneous">True</property>
+                            <child>
+                              <object class="GtkRadioButton" id="Pinyin/Scheme/QuanPin">
+                                <property name="label" translatable="yes">Quan Pin</property>
+                                <property name="visible">True</property>
+                                <property name="can_focus">True</property>
+                                <property name="receives_default">False</property>
+                                <property name="use_action_appearance">False</property>
+                                <property name="xalign">0</property>
+                                <property name="active">True</property>
+                                <property name="draw_indicator">True</property>
+                              </object>
+                              <packing>
+                                <property name="y_options">GTK_EXPAND</property>
+                              </packing>
+                            </child>
+                            <child>
+                              <object class="GtkRadioButton" id="Pinyin/Scheme/ShuangPin">
+                                <property name="label" translatable="yes">Shuang Pin</property>
+                                <property name="visible">True</property>
+                                <property name="can_focus">True</property>
+                                <property name="receives_default">False</property>
+                                <property name="use_action_appearance">False</property>
+                                <property name="relief">none</property>
+                                <property name="xalign">0</property>
+                                <property name="yalign">0.47999998927116394</property>
+                                <property name="draw_indicator">True</property>
+                                <property name="group">Pinyin/Scheme/QuanPin</property>
+                                <signal name="toggled" handler="on_radio_shuangpin_toggled" swapped="no"/>
+                              </object>
+                              <packing>
+                                <property name="top_attach">1</property>
+                                <property name="bottom_attach">2</property>
+                                <property name="y_options">GTK_EXPAND</property>
+                              </packing>
+                            </child>
+                            <child>
+                              <object class="GtkComboBox" id="Pinyin/ShuangPinType">
+                                <property name="visible">True</property>
+                                <property name="can_focus">False</property>
+                                <property name="model">pymodel</property>
+                                <property name="active">0</property>
+                                <property name="button_sensitivity">on</property>
+                                <child>
+                                  <object class="GtkCellRendererText" id="renderer1"/>
+                                  <attributes>
+                                    <attribute name="text">0</attribute>
+                                  </attributes>
+                                </child>
+                              </object>
+                              <packing>
+                                <property name="left_attach">1</property>
+                                <property name="right_attach">2</property>
+                                <property name="top_attach">1</property>
+                                <property name="bottom_attach">2</property>
+                                <property name="y_options">GTK_EXPAND</property>
+                              </packing>
+                            </child>
+                            <child>
+                              <placeholder/>
+                            </child>
+                          </object>
+                        </child>
+                      </object>
+                    </child>
+                    <child type="label">
+                      <object class="GtkLabel" id="label1">
+                        <property name="visible">True</property>
+                        <property name="can_focus">False</property>
+                        <property name="label" translatable="yes">&lt;b&gt;Pinyin Mode&lt;/b&gt;</property>
+                        <property name="use_markup">True</property>
+                      </object>
+                    </child>
+                  </object>
+                  <packing>
+                    <property name="expand">False</property>
+                    <property name="fill">True</property>
+                    <property name="position">0</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkHSeparator" id="hseparator1">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                  </object>
+                  <packing>
+                    <property name="expand">False</property>
+                    <property name="fill">True</property>
+                    <property name="padding">5</property>
+                    <property name="position">1</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkFrame" id="frame2">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                    <property name="border_width">5</property>
+                    <property name="label_xalign">0</property>
+                    <property name="shadow_type">none</property>
+                    <child>
+                      <object class="GtkAlignment" id="alignment2">
+                        <property name="visible">True</property>
+                        <property name="can_focus">False</property>
+                        <property name="left_padding">12</property>
+                        <child>
+                          <object class="GtkTable" id="table4">
+                            <property name="visible">True</property>
+                            <property name="can_focus">False</property>
+                            <property name="border_width">10</property>
+                            <property name="n_rows">3</property>
+                            <property name="n_columns">2</property>
+                            <property name="homogeneous">True</property>
+                            <child>
+                              <object class="GtkRadioButton" id="General/InitialStatus/Mode/Chinese">
+                                <property name="label" translatable="yes">Chinese</property>
+                                <property name="visible">True</property>
+                                <property name="can_focus">True</property>
+                                <property name="receives_default">False</property>
+                                <property name="use_action_appearance">False</property>
+                                <property name="xalign">0</property>
+                                <property name="active">True</property>
+                                <property name="draw_indicator">True</property>
+                              </object>
+                              <packing>
+                                <property name="y_options">GTK_EXPAND</property>
+                              </packing>
+                            </child>
+                            <child>
+                              <object class="GtkRadioButton" id="General/InitialStatus/Mode/English">
+                                <property name="label" translatable="yes">English</property>
+                                <property name="visible">True</property>
+                                <property name="can_focus">True</property>
+                                <property name="receives_default">False</property>
+                                <property name="use_action_appearance">False</property>
+                                <property name="relief">half</property>
+                                <property name="xalign">0</property>
+                                <property name="yalign">0.47999998927116394</property>
+                                <property name="draw_indicator">True</property>
+                                <property name="group">General/InitialStatus/Mode/Chinese</property>
+                              </object>
+                              <packing>
+                                <property name="left_attach">1</property>
+                                <property name="right_attach">2</property>
+                                <property name="y_options">GTK_EXPAND</property>
+                              </packing>
+                            </child>
+                            <child>
+                              <object class="GtkRadioButton" id="General/InitialStatus/Punct/Full">
+                                <property name="label" translatable="yes">Chinese punctuation</property>
+                                <property name="visible">True</property>
+                                <property name="can_focus">True</property>
+                                <property name="receives_default">False</property>
+                                <property name="use_action_appearance">False</property>
+                                <property name="xalign">0</property>
+                                <property name="active">True</property>
+                                <property name="draw_indicator">True</property>
+                              </object>
+                              <packing>
+                                <property name="top_attach">1</property>
+                                <property name="bottom_attach">2</property>
+                                <property name="y_options">GTK_EXPAND</property>
+                              </packing>
+                            </child>
+                            <child>
+                              <object class="GtkRadioButton" id="General/InitialStatus/Punct/Half">
+                                <property name="label" translatable="yes">English punctuation</property>
+                                <property name="visible">True</property>
+                                <property name="can_focus">True</property>
+                                <property name="receives_default">False</property>
+                                <property name="use_action_appearance">False</property>
+                                <property name="xalign">0</property>
+                                <property name="draw_indicator">True</property>
+                                <property name="group">General/InitialStatus/Punct/Full</property>
+                              </object>
+                              <packing>
+                                <property name="left_attach">1</property>
+                                <property name="right_attach">2</property>
+                                <property name="top_attach">1</property>
+                                <property name="bottom_attach">2</property>
+                                <property name="y_options">GTK_EXPAND</property>
+                              </packing>
+                            </child>
+                            <child>
+                              <object class="GtkRadioButton" id="General/InitialStatus/Letter/Full">
+                                <property name="label" translatable="yes">Full-width Letter</property>
+                                <property name="visible">True</property>
+                                <property name="can_focus">True</property>
+                                <property name="receives_default">False</property>
+                                <property name="use_action_appearance">False</property>
+                                <property name="xalign">0</property>
+                                <property name="active">True</property>
+                                <property name="draw_indicator">True</property>
+                              </object>
+                              <packing>
+                                <property name="top_attach">2</property>
+                                <property name="bottom_attach">3</property>
+                                <property name="y_options">GTK_EXPAND</property>
+                              </packing>
+                            </child>
+                            <child>
+                              <object class="GtkRadioButton" id="General/InitialStatus/Letter/Half">
+                                <property name="label" translatable="yes">Half-width Letter</property>
+                                <property name="visible">True</property>
+                                <property name="can_focus">True</property>
+                                <property name="receives_default">False</property>
+                                <property name="use_action_appearance">False</property>
+                                <property name="xalign">0</property>
+                                <property name="draw_indicator">True</property>
+                                <property name="group">General/InitialStatus/Letter/Full</property>
+                              </object>
+                              <packing>
+                                <property name="left_attach">1</property>
+                                <property name="right_attach">2</property>
+                                <property name="top_attach">2</property>
+                                <property name="bottom_attach">3</property>
+                                <property name="y_options">GTK_EXPAND</property>
+                              </packing>
+                            </child>
+                          </object>
+                        </child>
+                      </object>
+                    </child>
+                    <child type="label">
+                      <object class="GtkLabel" id="label2">
+                        <property name="visible">True</property>
+                        <property name="can_focus">False</property>
+                        <property name="label" translatable="yes">&lt;b&gt;Initial Status&lt;/b&gt;</property>
+                        <property name="use_markup">True</property>
+                      </object>
+                    </child>
+                  </object>
+                  <packing>
+                    <property name="expand">False</property>
+                    <property name="fill">True</property>
+                    <property name="position">2</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkHSeparator" id="hseparator2">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                  </object>
+                  <packing>
+                    <property name="expand">False</property>
+                    <property name="fill">True</property>
+                    <property name="padding">5</property>
+                    <property name="position">3</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkFrame" id="frame3">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                    <property name="border_width">5</property>
+                    <property name="label_xalign">0</property>
+                    <property name="shadow_type">none</property>
+                    <child>
+                      <object class="GtkAlignment" id="alignment3">
+                        <property name="visible">True</property>
+                        <property name="can_focus">False</property>
+                        <property name="left_padding">12</property>
+                        <child>
+                          <object class="GtkTable" id="table5">
+                            <property name="visible">True</property>
+                            <property name="can_focus">False</property>
+                            <property name="border_width">10</property>
+                            <property name="n_rows">4</property>
+                            <property name="n_columns">2</property>
+                            <child>
+                              <object class="GtkCheckButton" id="QuanPin/Fuzzy/Enabled">
+                                <property name="label" translatable="yes">Fuzzy Pinyin</property>
+                                <property name="visible">True</property>
+                                <property name="can_focus">True</property>
+                                <property name="receives_default">False</property>
+                                <property name="use_action_appearance">False</property>
+                                <property name="xalign">0</property>
+                                <property name="active">True</property>
+                                <property name="draw_indicator">True</property>
+                                <signal name="toggled" handler="on_chk_fuzzy_enabled_toggled" swapped="no"/>
+                              </object>
+                              <packing>
+                                <property name="y_options">GTK_EXPAND</property>
+                              </packing>
+                            </child>
+                            <child>
+                              <object class="GtkCheckButton" id="QuanPin/AutoCorrection/Enabled">
+                                <property name="label" translatable="yes">Auto Correct</property>
+                                <property name="visible">True</property>
+                                <property name="can_focus">True</property>
+                                <property name="receives_default">False</property>
+                                <property name="use_action_appearance">False</property>
+                                <property name="xalign">0</property>
+                                <property name="draw_indicator">True</property>
+                                <signal name="toggled" handler="on_chk_correction_enabled_toggled" swapped="no"/>
+                              </object>
+                              <packing>
+                                <property name="top_attach">1</property>
+                                <property name="bottom_attach">2</property>
+                                <property name="y_options">GTK_EXPAND</property>
+                              </packing>
+                            </child>
+                            <child>
+                              <object class="GtkButton" id="button_fuzzy_setup">
+                                <property name="label" translatable="yes">Fuzzy Pinyin Setup</property>
+                                <property name="visible">True</property>
+                                <property name="can_focus">True</property>
+                                <property name="receives_default">True</property>
+                                <property name="use_action_appearance">False</property>
+                                <property name="yalign">0.51999998092651367</property>
+                                <signal name="clicked" handler="on_button_fuzzy_setup_clicked" swapped="no"/>
+                              </object>
+                              <packing>
+                                <property name="left_attach">1</property>
+                                <property name="right_attach">2</property>
+                                <property name="y_options">GTK_EXPAND</property>
+                              </packing>
+                            </child>
+                            <child>
+                              <object class="GtkButton" id="button_correction_setup">
+                                <property name="label" translatable="yes">Auto Correct Setup</property>
+                                <property name="visible">True</property>
+                                <property name="can_focus">True</property>
+                                <property name="receives_default">True</property>
+                                <property name="use_action_appearance">False</property>
+                                <signal name="clicked" handler="on_button_correction_setup_clicked" swapped="no"/>
+                              </object>
+                              <packing>
+                                <property name="left_attach">1</property>
+                                <property name="right_attach">2</property>
+                                <property name="top_attach">1</property>
+                                <property name="bottom_attach">2</property>
+                                <property name="y_options">GTK_EXPAND</property>
+                              </packing>
+                            </child>
+                            <child>
+                              <object class="GtkCheckButton" id="QuanPin/FuzzySegs/Enabled">
+                                <property name="label" translatable="yes">Smart Segmentation</property>
+                                <property name="visible">True</property>
+                                <property name="can_focus">True</property>
+                                <property name="receives_default">False</property>
+                                <property name="use_action_appearance">False</property>
+                                <property name="xalign">0</property>
+                                <property name="active">True</property>
+                                <property name="draw_indicator">True</property>
+                                <signal name="toggled" handler="on_chk_smartseg_enabled_toggled" swapped="no"/>
+                              </object>
+                              <packing>
+                                <property name="top_attach">2</property>
+                                <property name="bottom_attach">3</property>
+                                <property name="y_options">GTK_EXPAND</property>
+                              </packing>
+                            </child>
+                            <child>
+                              <object class="GtkCheckButton" id="QuanPin/InnerFuzzy/Enabled">
+                                <property name="label" translatable="yes">Inner Fuzzy</property>
+                                <property name="visible">True</property>
+                                <property name="can_focus">True</property>
+                                <property name="receives_default">False</property>
+                                <property name="use_action_appearance">False</property>
+                                <property name="xalign">0</property>
+                                <property name="active">True</property>
+                                <property name="draw_indicator">True</property>
+                              </object>
+                              <packing>
+                                <property name="top_attach">3</property>
+                                <property name="bottom_attach">4</property>
+                                <property name="x_options">GTK_FILL</property>
+                                <property name="y_options">GTK_EXPAND</property>
+                                <property name="x_padding">23</property>
+                              </packing>
+                            </child>
+                            <child>
+                              <placeholder/>
+                            </child>
+                            <child>
+                              <placeholder/>
+                            </child>
+                          </object>
+                        </child>
+                      </object>
+                    </child>
+                    <child type="label">
+                      <object class="GtkLabel" id="label3">
+                        <property name="visible">True</property>
+                        <property name="can_focus">False</property>
+                        <property name="label" translatable="yes">&lt;b&gt;QuanPin Setup&lt;/b&gt;</property>
+                        <property name="use_markup">True</property>
+                      </object>
+                    </child>
+                  </object>
+                  <packing>
+                    <property name="expand">False</property>
+                    <property name="fill">True</property>
+                    <property name="position">4</property>
+                  </packing>
+                </child>
+              </object>
+            </child>
+            <child type="tab">
+              <object class="GtkLabel" id="pinyin_mode">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <property name="label" translatable="yes">Pinyin Mode</property>
+              </object>
+              <packing>
+                <property name="tab_fill">False</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkVBox" id="vbox4">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <child>
+                  <object class="GtkFrame" id="frame7">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                    <property name="border_width">5</property>
+                    <property name="label_xalign">0</property>
+                    <property name="shadow_type">none</property>
+                    <child>
+                      <object class="GtkAlignment" id="alignment7">
+                        <property name="visible">True</property>
+                        <property name="can_focus">False</property>
+                        <property name="left_padding">12</property>
+                        <child>
+                          <object class="GtkTable" id="table2">
+                            <property name="visible">True</property>
+                            <property name="can_focus">False</property>
+                            <property name="border_width">10</property>
+                            <property name="n_columns">2</property>
+                            <property name="homogeneous">True</property>
+                            <child>
+                              <object class="GtkRadioButton" id="Keyboard/ModeSwitch/Shift">
+                                <property name="label">Shift</property>
+                                <property name="visible">True</property>
+                                <property name="can_focus">True</property>
+                                <property name="receives_default">False</property>
+                                <property name="use_action_appearance">False</property>
+                                <property name="xalign">0</property>
+                                <property name="active">True</property>
+                                <property name="draw_indicator">True</property>
+                              </object>
+                              <packing>
+                                <property name="y_options">GTK_EXPAND</property>
+                              </packing>
+                            </child>
+                            <child>
+                              <object class="GtkRadioButton" id="Keyboard/ModeSwitch/Control">
+                                <property name="label">Control</property>
+                                <property name="visible">True</property>
+                                <property name="can_focus">True</property>
+                                <property name="receives_default">False</property>
+                                <property name="use_action_appearance">False</property>
+                                <property name="xalign">0</property>
+                                <property name="active">True</property>
+                                <property name="draw_indicator">True</property>
+                                <property name="group">Keyboard/ModeSwitch/Shift</property>
+                              </object>
+                              <packing>
+                                <property name="left_attach">1</property>
+                                <property name="right_attach">2</property>
+                                <property name="y_options">GTK_EXPAND</property>
+                              </packing>
+                            </child>
+                          </object>
+                        </child>
+                      </object>
+                    </child>
+                    <child type="label">
+                      <object class="GtkLabel" id="label7">
+                        <property name="visible">True</property>
+                        <property name="can_focus">False</property>
+                        <property name="label" translatable="yes">&lt;b&gt;Ch/En Switch key&lt;/b&gt;</property>
+                        <property name="use_markup">True</property>
+                      </object>
+                    </child>
+                  </object>
+                  <packing>
+                    <property name="expand">False</property>
+                    <property name="fill">True</property>
+                    <property name="position">0</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkHSeparator" id="hseparator5">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                  </object>
+                  <packing>
+                    <property name="expand">False</property>
+                    <property name="fill">True</property>
+                    <property name="position">1</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkFrame" id="frame8">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                    <property name="border_width">5</property>
+                    <property name="label_xalign">0</property>
+                    <property name="shadow_type">none</property>
+                    <child>
+                      <object class="GtkAlignment" id="alignment8">
+                        <property name="visible">True</property>
+                        <property name="can_focus">False</property>
+                        <property name="left_padding">12</property>
+                        <child>
+                          <object class="GtkTable" id="table9">
+                            <property name="visible">True</property>
+                            <property name="can_focus">False</property>
+                            <property name="border_width">10</property>
+                            <property name="n_columns">3</property>
+                            <property name="homogeneous">True</property>
+                            <child>
+                              <object class="GtkRadioButton" id="Keyboard/PunctSwitch/ControlComma">
+                                <property name="label">Ctrl + ,</property>
+                                <property name="visible">True</property>
+                                <property name="can_focus">True</property>
+                                <property name="receives_default">False</property>
+                                <property name="use_action_appearance">False</property>
+                                <property name="xalign">0</property>
+                                <property name="active">True</property>
+                                <property name="draw_indicator">True</property>
+                              </object>
+                              <packing>
+                                <property name="y_options">GTK_EXPAND</property>
+                              </packing>
+                            </child>
+                            <child>
+                              <object class="GtkRadioButton" id="Keyboard/PunctSwitch/ControlPeriod">
+                                <property name="label">Ctrl + .</property>
+                                <property name="visible">True</property>
+                                <property name="can_focus">True</property>
+                                <property name="receives_default">False</property>
+                                <property name="use_action_appearance">False</property>
+                                <property name="xalign">0</property>
+                                <property name="active">True</property>
+                                <property name="draw_indicator">True</property>
+                                <property name="group">Keyboard/PunctSwitch/ControlComma</property>
+                              </object>
+                              <packing>
+                                <property name="left_attach">1</property>
+                                <property name="right_attach">2</property>
+                                <property name="y_options">GTK_EXPAND</property>
+                              </packing>
+                            </child>
+                            <child>
+                              <object class="GtkRadioButton" id="Keyboard/PunctSwitch/None">
+                                <property name="label" translatable="yes">None</property>
+                                <property name="visible">True</property>
+                                <property name="can_focus">True</property>
+                                <property name="receives_default">False</property>
+                                <property name="use_action_appearance">False</property>
+                                <property name="xalign">0</property>
+                                <property name="active">True</property>
+                                <property name="draw_indicator">True</property>
+                                <property name="group">Keyboard/PunctSwitch/ControlComma</property>
+                              </object>
+                              <packing>
+                                <property name="left_attach">2</property>
+                                <property name="right_attach">3</property>
+                                <property name="y_options">GTK_EXPAND</property>
+                              </packing>
+                            </child>
+                          </object>
+                        </child>
+                      </object>
+                    </child>
+                    <child type="label">
+                      <object class="GtkLabel" id="label8">
+                        <property name="visible">True</property>
+                        <property name="can_focus">False</property>
+                        <property name="label" translatable="yes">&lt;b&gt;Full/Half-width Punct Switch&lt;/b&gt;</property>
+                        <property name="use_markup">True</property>
+                      </object>
+                    </child>
+                  </object>
+                  <packing>
+                    <property name="expand">False</property>
+                    <property name="fill">True</property>
+                    <property name="position">2</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkHSeparator" id="hseparator6">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                  </object>
+                  <packing>
+                    <property name="expand">False</property>
+                    <property name="fill">True</property>
+                    <property name="position">3</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkFrame" id="frame9">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                    <property name="border_width">9</property>
+                    <property name="label_xalign">0</property>
+                    <property name="shadow_type">none</property>
+                    <child>
+                      <object class="GtkAlignment" id="alignment9">
+                        <property name="visible">True</property>
+                        <property name="can_focus">False</property>
+                        <property name="left_padding">12</property>
+                        <child>
+                          <object class="GtkTable" id="table10">
+                            <property name="visible">True</property>
+                            <property name="can_focus">False</property>
+                            <property name="border_width">10</property>
+                            <property name="n_columns">3</property>
+                            <property name="homogeneous">True</property>
+                            <child>
+                              <object class="GtkCheckButton" id="Keyboard/Page/MinusEquals">
+                                <property name="label">-  /  =</property>
+                                <property name="visible">True</property>
+                                <property name="can_focus">True</property>
+                                <property name="receives_default">False</property>
+                                <property name="use_action_appearance">False</property>
+                                <property name="xalign">0</property>
+                                <property name="active">True</property>
+                                <property name="draw_indicator">True</property>
+                              </object>
+                              <packing>
+                                <property name="y_options">GTK_EXPAND</property>
+                              </packing>
+                            </child>
+                            <child>
+                              <object class="GtkCheckButton" id="Keyboard/Page/Brackets">
+                                <property name="label">[  /  ]</property>
+                                <property name="visible">True</property>
+                                <property name="can_focus">True</property>
+                                <property name="receives_default">False</property>
+                                <property name="use_action_appearance">False</property>
+                                <property name="xalign">0</property>
+                                <property name="draw_indicator">True</property>
+                              </object>
+                              <packing>
+                                <property name="left_attach">1</property>
+                                <property name="right_attach">2</property>
+                                <property name="y_options">GTK_EXPAND</property>
+                              </packing>
+                            </child>
+                            <child>
+                              <object class="GtkCheckButton" id="Keyboard/Page/CommaPeriod">
+                                <property name="label">,  /  .</property>
+                                <property name="visible">True</property>
+                                <property name="can_focus">True</property>
+                                <property name="receives_default">False</property>
+                                <property name="use_action_appearance">False</property>
+                                <property name="xalign">0</property>
+                                <property name="draw_indicator">True</property>
+                              </object>
+                              <packing>
+                                <property name="left_attach">2</property>
+                                <property name="right_attach">3</property>
+                                <property name="y_options"></property>
+                              </packing>
+                            </child>
+                          </object>
+                        </child>
+                      </object>
+                    </child>
+                    <child type="label">
+                      <object class="GtkLabel" id="label9">
+                        <property name="visible">True</property>
+                        <property name="can_focus">False</property>
+                        <property name="label" translatable="yes">&lt;b&gt;Page Flip&lt;/b&gt;</property>
+                        <property name="use_markup">True</property>
+                      </object>
+                    </child>
+                  </object>
+                  <packing>
+                    <property name="expand">False</property>
+                    <property name="fill">True</property>
+                    <property name="position">4</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkHSeparator" id="hseparator7">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                  </object>
+                  <packing>
+                    <property name="expand">False</property>
+                    <property name="fill">True</property>
+                    <property name="position">5</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkFrame" id="frame10">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                    <property name="border_width">9</property>
+                    <property name="label_xalign">0</property>
+                    <property name="shadow_type">none</property>
+                    <child>
+                      <object class="GtkAlignment" id="alignment10">
+                        <property name="visible">True</property>
+                        <property name="can_focus">False</property>
+                        <property name="left_padding">12</property>
+                        <child>
+                          <object class="GtkVBox" id="box1">
+                            <property name="visible">True</property>
+                            <property name="can_focus">False</property>
+                            <child>
+                              <object class="GtkCheckButton" id="Keyboard/CancelBackspace">
+                                <property name="label" translatable="yes">Cancel with Backspace</property>
+                                <property name="visible">True</property>
+                                <property name="can_focus">True</property>
+                                <property name="receives_default">False</property>
+                                <property name="use_action_appearance">False</property>
+                                <property name="xalign">0</property>
+                                <property name="active">True</property>
+                                <property name="draw_indicator">True</property>
+                              </object>
+                              <packing>
+                                <property name="expand">False</property>
+                                <property name="fill">True</property>
+                                <property name="position">0</property>
+                              </packing>
+                            </child>
+                            <child>
+                              <object class="GtkCheckButton" id="Keyboard/SmartPunct">
+                                <property name="label" translatable="yes">Smart Punctuation</property>
+                                <property name="visible">True</property>
+                                <property name="can_focus">True</property>
+                                <property name="receives_default">False</property>
+                                <property name="use_action_appearance">False</property>
+                                <property name="xalign">0</property>
+                                <property name="draw_indicator">True</property>
+                              </object>
+                              <packing>
+                                <property name="expand">False</property>
+                                <property name="fill">True</property>
+                                <property name="position">1</property>
+                              </packing>
+                            </child>
+                          </object>
+                        </child>
+                      </object>
+                    </child>
+                    <child type="label">
+                      <object class="GtkLabel" id="label5">
+                        <property name="visible">True</property>
+                        <property name="can_focus">False</property>
+                        <property name="label" translatable="yes">&lt;b&gt;Miscellaneous&lt;/b&gt;</property>
+                        <property name="use_markup">True</property>
+                      </object>
+                    </child>
+                  </object>
+                  <packing>
+                    <property name="expand">False</property>
+                    <property name="fill">True</property>
+                    <property name="position">6</property>
+                  </packing>
+                </child>
+              </object>
+              <packing>
+                <property name="position">1</property>
+              </packing>
+            </child>
+            <child type="tab">
+              <object class="GtkLabel" id="keyboard">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <property name="label" translatable="yes">Keyboard</property>
+              </object>
+              <packing>
+                <property name="position">1</property>
+                <property name="tab_fill">False</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkVBox" id="vbox3">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <child>
+                  <object class="GtkFrame" id="frame4">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                    <property name="border_width">5</property>
+                    <property name="label_xalign">0</property>
+                    <property name="shadow_type">none</property>
+                    <child>
+                      <object class="GtkAlignment" id="alignment4">
+                        <property name="visible">True</property>
+                        <property name="can_focus">False</property>
+                        <property name="left_padding">12</property>
+                        <child>
+                          <object class="GtkTable" id="table6">
+                            <property name="visible">True</property>
+                            <property name="can_focus">False</property>
+                            <property name="border_width">10</property>
+                            <property name="n_columns">3</property>
+                            <property name="homogeneous">True</property>
+                            <child>
+                              <object class="GtkRadioButton" id="General/Charset/GB2312">
+                                <property name="label">GB2312</property>
+                                <property name="visible">True</property>
+                                <property name="can_focus">True</property>
+                                <property name="receives_default">False</property>
+                                <property name="use_action_appearance">False</property>
+                                <property name="xalign">0</property>
+                                <property name="active">True</property>
+                                <property name="draw_indicator">True</property>
+                              </object>
+                              <packing>
+                                <property name="y_options"></property>
+                              </packing>
+                            </child>
+                            <child>
+                              <object class="GtkRadioButton" id="General/Charset/GBK">
+                                <property name="label">GBK</property>
+                                <property name="visible">True</property>
+                                <property name="can_focus">True</property>
+                                <property name="receives_default">False</property>
+                                <property name="use_action_appearance">False</property>
+                                <property name="xalign">0</property>
+                                <property name="draw_indicator">True</property>
+                                <property name="group">General/Charset/GB2312</property>
+                              </object>
+                              <packing>
+                                <property name="left_attach">1</property>
+                                <property name="right_attach">2</property>
+                                <property name="y_options"></property>
+                              </packing>
+                            </child>
+                            <child>
+                              <object class="GtkRadioButton" id="General/Charset/GB18030">
+                                <property name="label">GB18030</property>
+                                <property name="visible">True</property>
+                                <property name="can_focus">True</property>
+                                <property name="receives_default">False</property>
+                                <property name="use_action_appearance">False</property>
+                                <property name="xalign">0</property>
+                                <property name="draw_indicator">True</property>
+                                <property name="group">General/Charset/GB2312</property>
+                              </object>
+                              <packing>
+                                <property name="left_attach">2</property>
+                                <property name="right_attach">3</property>
+                                <property name="y_options"></property>
+                              </packing>
+                            </child>
+                          </object>
+                        </child>
+                      </object>
+                    </child>
+                    <child type="label">
+                      <object class="GtkLabel" id="label4">
+                        <property name="visible">True</property>
+                        <property name="can_focus">False</property>
+                        <property name="label" translatable="yes">&lt;b&gt;Character Set&lt;/b&gt;</property>
+                        <property name="use_markup">True</property>
+                      </object>
+                    </child>
+                  </object>
+                  <packing>
+                    <property name="expand">False</property>
+                    <property name="fill">True</property>
+                    <property name="position">0</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkHSeparator" id="hseparator3">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                  </object>
+                  <packing>
+                    <property name="expand">False</property>
+                    <property name="fill">True</property>
+                    <property name="position">1</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkFrame" id="frame5">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                    <property name="border_width">5</property>
+                    <property name="label_xalign">0</property>
+                    <property name="shadow_type">none</property>
+                    <child>
+                      <object class="GtkAlignment" id="alignment5">
+                        <property name="visible">True</property>
+                        <property name="can_focus">False</property>
+                        <property name="left_padding">12</property>
+                        <child>
+                          <object class="GtkTable" id="table7">
+                            <property name="visible">True</property>
+                            <property name="can_focus">False</property>
+                            <property name="border_width">10</property>
+                            <property name="n_rows">4</property>
+                            <property name="n_columns">2</property>
+                            <property name="homogeneous">True</property>
+                            <child>
+                              <object class="GtkLabel" id="candidate_num">
+                                <property name="visible">True</property>
+                                <property name="can_focus">False</property>
+                                <property name="xalign">0</property>
+                                <property name="label" translatable="yes">Candidate Num</property>
+                                <property name="ellipsize">end</property>
+                              </object>
+                              <packing>
+                                <property name="y_options"></property>
+                              </packing>
+                            </child>
+                            <child>
+                              <object class="GtkLabel" id="mem_strength">
+                                <property name="visible">True</property>
+                                <property name="can_focus">False</property>
+                                <property name="xalign">0</property>
+                                <property name="label" translatable="yes">Memory Strength</property>
+                                <property name="ellipsize">end</property>
+                              </object>
+                              <packing>
+                                <property name="top_attach">1</property>
+                                <property name="bottom_attach">2</property>
+                                <property name="y_options"></property>
+                              </packing>
+                            </child>
+                            <child>
+                              <object class="GtkHScale" id="General/PageSize">
+                                <property name="visible">True</property>
+                                <property name="can_focus">True</property>
+                                <property name="adjustment">candidate_adjustment</property>
+                                <property name="digits">0</property>
+                                <property name="value_pos">right</property>
+                              </object>
+                              <packing>
+                                <property name="left_attach">1</property>
+                                <property name="right_attach">2</property>
+                                <property name="y_options"></property>
+                              </packing>
+                            </child>
+                            <child>
+                              <object class="GtkHScale" id="General/MemoryPower">
+                                <property name="visible">True</property>
+                                <property name="can_focus">True</property>
+                                <property name="adjustment">memory_adjustment</property>
+                                <property name="digits">0</property>
+                                <property name="value_pos">right</property>
+                              </object>
+                              <packing>
+                                <property name="left_attach">1</property>
+                                <property name="right_attach">2</property>
+                                <property name="top_attach">1</property>
+                                <property name="bottom_attach">2</property>
+                                <property name="y_options"></property>
+                              </packing>
+                            </child>
+                            <child>
+                              <object class="GtkLabel" id="max_best">
+                                <property name="visible">True</property>
+                                <property name="can_focus">False</property>
+                                <property name="xalign">0</property>
+                                <property name="label" translatable="yes">Number of Best Sentence</property>
+                              </object>
+                              <packing>
+                                <property name="top_attach">2</property>
+                                <property name="bottom_attach">3</property>
+                              </packing>
+                            </child>
+                            <child>
+                              <object class="GtkLabel" id="max_tail_candidate">
+                                <property name="visible">True</property>
+                                <property name="can_focus">False</property>
+                                <property name="xalign">0</property>
+                                <property name="label" translatable="yes">Number of Best Tail Candidate</property>
+                              </object>
+                              <packing>
+                                <property name="top_attach">3</property>
+                                <property name="bottom_attach">4</property>
+                              </packing>
+                            </child>
+                            <child>
+                              <object class="GtkHScale" id="General/MaxBest">
+                                <property name="visible">True</property>
+                                <property name="can_focus">True</property>
+                                <property name="adjustment">max_best_adjustment</property>
+                                <property name="round_digits">0</property>
+                                <property name="digits">0</property>
+                                <property name="value_pos">right</property>
+                              </object>
+                              <packing>
+                                <property name="left_attach">1</property>
+                                <property name="right_attach">2</property>
+                                <property name="top_attach">2</property>
+                                <property name="bottom_attach">3</property>
+                                <property name="y_options"></property>
+                              </packing>
+                            </child>
+                            <child>
+                              <object class="GtkHScale" id="General/MaxTailCandidate">
+                                <property name="visible">True</property>
+                                <property name="can_focus">True</property>
+                                <property name="adjustment">max_tail_candidate_adjustment</property>
+                                <property name="round_digits">0</property>
+                                <property name="digits">0</property>
+                                <property name="value_pos">right</property>
+                              </object>
+                              <packing>
+                                <property name="left_attach">1</property>
+                                <property name="right_attach">2</property>
+                                <property name="top_attach">3</property>
+                                <property name="bottom_attach">4</property>
+                                <property name="y_options"></property>
+                              </packing>
+                            </child>
+                          </object>
+                        </child>
+                      </object>
+                    </child>
+                  </object>
+                  <packing>
+                    <property name="expand">False</property>
+                    <property name="fill">True</property>
+                    <property name="position">2</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkHSeparator" id="hseparator4">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                  </object>
+                  <packing>
+                    <property name="expand">False</property>
+                    <property name="fill">True</property>
+                    <property name="position">3</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkFrame" id="frame6">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                    <property name="border_width">5</property>
+                    <property name="label_xalign">0</property>
+                    <property name="shadow_type">none</property>
+                    <child>
+                      <object class="GtkAlignment" id="alignment6">
+                        <property name="visible">True</property>
+                        <property name="can_focus">False</property>
+                        <property name="left_padding">12</property>
+                        <child>
+                          <object class="GtkTable" id="table8">
+                            <property name="visible">True</property>
+                            <property name="can_focus">False</property>
+                            <property name="border_width">10</property>
+                            <property name="n_columns">2</property>
+                            <property name="homogeneous">True</property>
+                            <child>
+                              <object class="GtkCheckButton" id="General/PunctMapping/Enabled">
+                                <property name="label" translatable="yes">Punct mapping</property>
+                                <property name="visible">True</property>
+                                <property name="can_focus">True</property>
+                                <property name="receives_default">False</property>
+                                <property name="use_action_appearance">False</property>
+                                <property name="xalign">0</property>
+                                <property name="draw_indicator">True</property>
+                                <signal name="toggled" handler="on_chk_punctmapping_enabled_toggled" swapped="no"/>
+                              </object>
+                              <packing>
+                                <property name="y_options"></property>
+                              </packing>
+                            </child>
+                            <child>
+                              <object class="GtkButton" id="button_punctmapping_setup">
+                                <property name="label" translatable="yes">Mapping Setup</property>
+                                <property name="visible">True</property>
+                                <property name="can_focus">True</property>
+                                <property name="receives_default">True</property>
+                                <property name="use_action_appearance">False</property>
+                                <signal name="clicked" handler="on_button_punctmapping_setup_clicked" swapped="no"/>
+                              </object>
+                              <packing>
+                                <property name="left_attach">1</property>
+                                <property name="right_attach">2</property>
+                                <property name="y_options"></property>
+                              </packing>
+                            </child>
+                          </object>
+                        </child>
+                      </object>
+                    </child>
+                    <child type="label">
+                      <object class="GtkLabel" id="label6">
+                        <property name="visible">True</property>
+                        <property name="can_focus">False</property>
+                        <property name="label" translatable="yes">&lt;b&gt;Symbol Mapping&lt;/b&gt;</property>
+                        <property name="use_markup">True</property>
+                      </object>
+                    </child>
+                  </object>
+                  <packing>
+                    <property name="expand">False</property>
+                    <property name="fill">True</property>
+                    <property name="position">4</property>
+                  </packing>
+                </child>
+              </object>
+              <packing>
+                <property name="position">2</property>
+              </packing>
+            </child>
+            <child type="tab">
+              <object class="GtkLabel" id="general">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <property name="label" translatable="yes">General</property>
+              </object>
+              <packing>
+                <property name="position">2</property>
+                <property name="tab_fill">False</property>
+              </packing>
+            </child>
+          </object>
+          <packing>
+            <property name="expand">True</property>
+            <property name="fill">True</property>
+            <property name="position">0</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkHButtonBox" id="hbuttonbox1">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="border_width">10</property>
+            <property name="spacing">10</property>
+            <property name="homogeneous">True</property>
+            <property name="layout_style">end</property>
+            <child>
+              <object class="GtkButton" id="main_ok">
+                <property name="label">gtk-ok</property>
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">True</property>
+                <property name="use_action_appearance">False</property>
+                <property name="use_stock">True</property>
+                <signal name="clicked" handler="on_main_ok_clicked" swapped="no"/>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">False</property>
+                <property name="position">0</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkButton" id="main_cancel">
+                <property name="label">gtk-cancel</property>
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">True</property>
+                <property name="use_action_appearance">False</property>
+                <property name="use_stock">True</property>
+                <signal name="clicked" handler="on_main_cancel_clicked" swapped="no"/>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">False</property>
+                <property name="position">1</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkButton" id="main_apply">
+                <property name="label">gtk-apply</property>
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">True</property>
+                <property name="use_action_appearance">False</property>
+                <property name="use_stock">True</property>
+                <signal name="clicked" handler="on_main_apply_clicked" swapped="no"/>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">False</property>
+                <property name="position">2</property>
+              </packing>
+            </child>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">False</property>
+            <property name="position">1</property>
+          </packing>
+        </child>
+      </object>
+    </child>
+  </object>
+  <object class="GtkAdjustment" id="max_best_adjustment">
+    <property name="upper">10</property>
+    <property name="value">1</property>
+    <property name="step_increment">1</property>
+    <property name="page_increment">10</property>
+  </object>
+  <object class="GtkAdjustment" id="max_tail_candidate_adjustment">
+    <property name="upper">10</property>
+    <property name="step_increment">1</property>
+    <property name="page_increment">10</property>
+  </object>
+  <object class="GtkAdjustment" id="memory_adjustment">
+    <property name="upper">11</property>
+    <property name="value">3</property>
+    <property name="step_increment">1</property>
+    <property name="page_increment">1</property>
+    <property name="page_size">1</property>
+  </object>
+  <object class="GtkListStore" id="pymodel">
+    <columns>
+      <!-- column-name gchararray -->
+      <column type="gchararray"/>
+    </columns>
+    <data>
+      <row>
+        <col id="0" translatable="yes">MS2003</col>
+      </row>
+      <row>
+        <col id="0" translatable="yes">ZiRanMa</col>
+      </row>
+      <row>
+        <col id="0" translatable="yes">ZiGuang</col>
+      </row>
+      <row>
+        <col id="0" translatable="yes">ABC</col>
+      </row>
+      <row>
+        <col id="0" translatable="yes">PinYinJiaJia</col>
+      </row>
+      <row>
+        <col id="0" translatable="yes">XiaoHe</col>
+      </row>
+    </data>
+  </object>
+</interface>
diff --git a/wrapper/ibus/src/CMakeLists.txt b/wrapper/ibus/src/CMakeLists.txt
new file mode 100644 (file)
index 0000000..bbe8d64
--- /dev/null
@@ -0,0 +1,26 @@
+# CMakeLists.txt: cmake config file for ibus-sunpinyin
+
+find_package(GTK2 REQUIRED gtk)
+find_package(iBus 1.2 REQUIRED)
+find_package(SunPinyin 2.0 REQUIRED)
+
+include_directories(${GTK2_INCLUDE_DIRS} ${iBus_INCLUDE_DIRS} ${SunPinyin_INCLUDE_DIRS})
+set(LIBS ${LIBS} ${GTK2_LIBRARIES} ${iBus_LIBRARIES} ${SunPinyin_LIBRARIES})
+set(ENGINE_SRCS
+    main.cpp
+    engine.cpp 
+    pointer.h ibus_common.h
+    imi_ibus_win.cpp imi_ibus_win.h
+    sunpinyin_config_keys.h
+    sunpinyin_config.cpp sunpinyin_config.h
+    sunpinyin_engine.cpp sunpinyin_engine.h
+    sunpinyin_engine_proxy.cpp sunpinyin_engine_proxy.h
+    sunpinyin_lookup_table.cpp sunpinyin_lookup_table.h
+    sunpinyin_property.cpp sunpinyin_property.h)
+
+set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE)
+add_executable(ibus-engine-sunpinyin ${ENGINE_SRCS})
+target_link_libraries(ibus-engine-sunpinyin ${LIBS})
+
+install(TARGETS ibus-engine-sunpinyin
+    RUNTIME DESTINATION ${LIBEXEC_DIR})
diff --git a/wrapper/ibus/src/debug.cpp b/wrapper/ibus/src/debug.cpp
new file mode 100644 (file)
index 0000000..90b0c40
--- /dev/null
@@ -0,0 +1,13 @@
+#include "debug.h"
+
+#include <iostream>
+#include <iomanip>
+#include <fstream>
+
+
+namespace ibus
+{
+    using namespace std;
+    
+    std::fstream log("/tmp/ibus.log", fstream::app|fstream::out);
+}
diff --git a/wrapper/ibus/src/debug.h b/wrapper/ibus/src/debug.h
new file mode 100644 (file)
index 0000000..e78ac58
--- /dev/null
@@ -0,0 +1,23 @@
+#ifndef SUNPINYIN_DEBUG_H
+#define SUNPINYIN_DEBUG_H
+
+#include <iostream>
+#include <iomanip>
+#include <fstream>
+#include <cerrno>
+
+namespace ibus
+{
+    extern std::fstream log;
+}
+
+using std::cout;
+using std::hex;
+using std::endl;
+
+#define PRINT_VAL(val)                          \
+    do {                                        \
+        cout << "  "#val" = " << val << endl;   \
+    } while (0)
+#endif // SUNPINYIN_DEBUG_H
diff --git a/wrapper/ibus/src/engine.cpp b/wrapper/ibus/src/engine.cpp
new file mode 100644 (file)
index 0000000..df4524e
--- /dev/null
@@ -0,0 +1,109 @@
+/*
+ * Copyright (c) 2009 Kov Chai <tchaikov@gmail.com>
+ *
+ * The contents of this file are subject to the terms of either the GNU Lesser
+ * General Public License Version 2.1 only ("LGPL") or the Common Development and
+ * Distribution License ("CDDL")(collectively, the "License"). You may not use this
+ * file except in compliance with the License. You can obtain a copy of the CDDL at
+ * http://www.opensource.org/licenses/cddl1.php and a copy of the LGPLv2.1 at
+ * http://www.opensource.org/licenses/lgpl-license.php. See the License for the 
+ * specific language governing permissions and limitations under the License. When
+ * distributing the software, include this License Header Notice in each file and
+ * include the full text of the License in the License file as well as the
+ * following notice:
+ * 
+ * NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND DISTRIBUTION LICENSE
+ * (CDDL)
+ * For Covered Software in this distribution, this License shall be governed by the
+ * laws of the State of California (excluding conflict-of-law provisions).
+ * Any litigation relating to this License shall be subject to the jurisdiction of
+ * the Federal Courts of the Northern District of California and the state courts
+ * of the State of California, with venue lying in Santa Clara County, California.
+ * 
+ * Contributor(s):
+ * 
+ * If you wish your version of this file to be governed by only the CDDL or only
+ * the LGPL Version 2.1, indicate your decision by adding "[Contributor]" elects to
+ * include this software in this distribution under the [CDDL or LGPL Version 2.1]
+ * license." If you don't indicate a single choice of license, a recipient has the
+ * option to distribute your version of this file under either the CDDL or the LGPL
+ * Version 2.1, or to extend the choice of license to its licensees as provided
+ * above. However, if you add LGPL Version 2.1 code and therefore, elected the LGPL
+ * Version 2 license, then the option applies only if the new code is made subject
+ * to such option by the copyright holder. 
+ */
+
+#include "sunpinyin_engine_proxy.h"
+#include "sunpinyin_engine.h"
+#include "sunpinyin_config.h"
+#include "engine.h"
+
+
+#define IBUS_SUNPINYIN_ENGINE_CLASS(klass)     \
+    (G_TYPE_CHECK_CLASS_CAST ((klass), IBUS_TYPE_SUNPINYIN_ENGINE, IBusSunPinyinEngineClass))
+#define IBUS_SUNPINYIN_ENGINE_GET_CLASS(obj)   \
+    (G_TYPE_INSTANCE_GET_CLASS ((obj), IBUS_TYPE_SUNPINYIN_ENGINE, IBusSunPinyinEngineClass))
+
+struct IBusSunPinyinEngineClass {
+    IBusEngineClass parent;
+};
+
+typedef SunPinyinEngine IBusSunPinyinEngine;
+
+/* functions prototype */
+static void ibus_sunpinyin_engine_class_init (IBusSunPinyinEngineClass *);
+
+IBusEngineClass *parent_class = NULL;
+
+GType
+ibus_sunpinyin_engine_get_type (void)
+{
+    static GType type = 0;
+
+    static const GTypeInfo type_info = {
+        sizeof (IBusSunPinyinEngineClass),
+        (GBaseInitFunc)     NULL,
+        (GBaseFinalizeFunc) NULL,
+        (GClassInitFunc)    ibus_sunpinyin_engine_class_init,
+        NULL,
+        NULL,
+        sizeof (IBusSunPinyinEngine),
+        0,
+        (GInstanceInitFunc) ibus_sunpinyin_engine_init,
+    };
+
+    if (type == 0) {
+        type = g_type_register_static (IBUS_TYPE_ENGINE,
+                                       "IBusSunPinyinEngine",
+                                       &type_info,
+                                       (GTypeFlags) 0);
+    }
+
+    return type;
+}
+
+// initialize the meta class object
+void
+ibus_sunpinyin_engine_class_init (IBusSunPinyinEngineClass *klass)
+{
+    IBusObjectClass *ibus_object_class = IBUS_OBJECT_CLASS (klass);
+    IBusEngineClass *engine_class = IBUS_ENGINE_CLASS (klass);
+    
+    parent_class = (IBusEngineClass *) g_type_class_peek_parent (klass);
+    
+    ibus_object_class->destroy = (IBusObjectDestroyFunc) ibus_sunpinyin_engine_destroy;
+    
+    engine_class->process_key_event = ibus_sunpinyin_engine_process_key_event;
+    engine_class->focus_in          = ibus_sunpinyin_engine_focus_in;
+    engine_class->focus_out         = ibus_sunpinyin_engine_focus_out;
+    engine_class->reset             = ibus_sunpinyin_engine_reset;
+    engine_class->enable            = ibus_sunpinyin_engine_enable;
+    engine_class->disable           = ibus_sunpinyin_engine_disable;
+    engine_class->page_up           = ibus_sunpinyin_engine_page_up;
+    engine_class->page_down         = ibus_sunpinyin_engine_page_down;
+    engine_class->cursor_up         = ibus_sunpinyin_engine_cursor_up;
+    engine_class->cursor_down       = ibus_sunpinyin_engine_cursor_down;
+    engine_class->property_activate = ibus_sunpinyin_engine_property_activate;
+    engine_class->candidate_clicked = ibus_sunpinyin_engine_candidate_clicked;
+}
+
diff --git a/wrapper/ibus/src/engine.h b/wrapper/ibus/src/engine.h
new file mode 100644 (file)
index 0000000..482422c
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2009 Kov Chai <tchaikov@gmail.com>
+ *
+ * The contents of this file are subject to the terms of either the GNU Lesser
+ * General Public License Version 2.1 only ("LGPL") or the Common Development and
+ * Distribution License ("CDDL")(collectively, the "License"). You may not use this
+ * file except in compliance with the License. You can obtain a copy of the CDDL at
+ * http://www.opensource.org/licenses/cddl1.php and a copy of the LGPLv2.1 at
+ * http://www.opensource.org/licenses/lgpl-license.php. See the License for the 
+ * specific language governing permissions and limitations under the License. When
+ * distributing the software, include this License Header Notice in each file and
+ * include the full text of the License in the License file as well as the
+ * following notice:
+ * 
+ * NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND DISTRIBUTION LICENSE
+ * (CDDL)
+ * For Covered Software in this distribution, this License shall be governed by the
+ * laws of the State of California (excluding conflict-of-law provisions).
+ * Any litigation relating to this License shall be subject to the jurisdiction of
+ * the Federal Courts of the Northern District of California and the state courts
+ * of the State of California, with venue lying in Santa Clara County, California.
+ * 
+ * Contributor(s):
+ * 
+ * If you wish your version of this file to be governed by only the CDDL or only
+ * the LGPL Version 2.1, indicate your decision by adding "[Contributor]" elects to
+ * include this software in this distribution under the [CDDL or LGPL Version 2.1]
+ * license." If you don't indicate a single choice of license, a recipient has the
+ * option to distribute your version of this file under either the CDDL or the LGPL
+ * Version 2.1, or to extend the choice of license to its licensees as provided
+ * above. However, if you add LGPL Version 2.1 code and therefore, elected the LGPL
+ * Version 2 license, then the option applies only if the new code is made subject
+ * to such option by the copyright holder. 
+ */
+
+#ifndef __ENGINE_H__
+#define __ENGINE_H__
+
+#include <ibus.h>
+
+#define IBUS_TYPE_SUNPINYIN_ENGINE \
+    (ibus_sunpinyin_engine_get_type ())
+
+GType   ibus_sunpinyin_engine_get_type    (void);
+
+void ibus_sunpinyin_init(IBusBus *bus);
+void ibus_sunpinyin_exit();
+
+#endif  /* __ENGINE_H__ */
diff --git a/wrapper/ibus/src/ibus_common.h b/wrapper/ibus/src/ibus_common.h
new file mode 100644 (file)
index 0000000..0837877
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2010 Kov Chai <tchaikov@gmail.com>
+ *
+ * The contents of this file are subject to the terms of either the GNU Lesser
+ * General Public License Version 2.1 only ("LGPL") or the Common Development and
+ * Distribution License ("CDDL")(collectively, the "License"). You may not use this
+ * file except in compliance with the License. You can obtain a copy of the CDDL at
+ * http://www.opensource.org/licenses/cddl1.php and a copy of the LGPLv2.1 at
+ * http://www.opensource.org/licenses/lgpl-license.php. See the License for the 
+ * specific language governing permissions and limitations under the License. When
+ * distributing the software, include this License Header Notice in each file and
+ * include the full text of the License in the License file as well as the
+ * following notice:
+ * 
+ * NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND DISTRIBUTION LICENSE
+ * (CDDL)
+ * For Covered Software in this distribution, this License shall be governed by the
+ * laws of the State of California (excluding conflict-of-law provisions).
+ * Any litigation relating to this License shall be subject to the jurisdiction of
+ * the Federal Courts of the Northern District of California and the state courts
+ * of the State of California, with venue lying in Santa Clara County, California.
+ * 
+ * Contributor(s):
+ * 
+ * If you wish your version of this file to be governed by only the CDDL or only
+ * the LGPL Version 2.1, indicate your decision by adding "[Contributor]" elects to
+ * include this software in this distribution under the [CDDL or LGPL Version 2.1]
+ * license." If you don't indicate a single choice of license, a recipient has the
+ * option to distribute your version of this file under either the CDDL or the LGPL
+ * Version 2.1, or to extend the choice of license to its licensees as provided
+ * above. However, if you add LGPL Version 2.1 code and therefore, elected the LGPL
+ * Version 2 license, then the option applies only if the new code is made subject
+ * to such option by the copyright holder. 
+ */
+
+#include <ibus.h>
+#include "pointer.h"
+
+
+namespace ibus {
+    typedef Pointer<IBusText> Text;
+    typedef Pointer<IBusProperty> Property;
+    typedef Pointer<IBusPropList> PropList;
+    typedef Pointer<IBusEngine> Engine;
+    typedef Pointer<IBusLookupTable> LookupTable;
+    typedef Pointer<IBusBus> Bus;
+    typedef Pointer<IBusConfig> Config;
+    typedef Pointer<IBusComponent> Component;
+    typedef Pointer<IBusFactory> Factory;
+}
diff --git a/wrapper/ibus/src/ibus_portable.cpp b/wrapper/ibus/src/ibus_portable.cpp
new file mode 100644 (file)
index 0000000..b9cf7ff
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2009 Kov Chai <tchaikov@gmail.com>
+ *
+ * The contents of this file are subject to the terms of either the GNU Lesser
+ * General Public License Version 2.1 only ("LGPL") or the Common Development and
+ * Distribution License ("CDDL")(collectively, the "License"). You may not use this
+ * file except in compliance with the License. You can obtain a copy of the CDDL at
+ * http://www.opensource.org/licenses/cddl1.php and a copy of the LGPLv2.1 at
+ * http://www.opensource.org/licenses/lgpl-license.php. See the License for the 
+ * specific language governing permissions and limitations under the License. When
+ * distributing the software, include this License Header Notice in each file and
+ * include the full text of the License in the License file as well as the
+ * following notice:
+ * 
+ * NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND DISTRIBUTION LICENSE
+ * (CDDL)
+ * For Covered Software in this distribution, this License shall be governed by the
+ * laws of the State of California (excluding conflict-of-law provisions).
+ * Any litigation relating to this License shall be subject to the jurisdiction of
+ * the Federal Courts of the Northern District of California and the state courts
+ * of the State of California, with venue lying in Santa Clara County, California.
+ * 
+ * Contributor(s):
+ * 
+ * If you wish your version of this file to be governed by only the CDDL or only
+ * the LGPL Version 2.1, indicate your decision by adding "[Contributor]" elects to
+ * include this software in this distribution under the [CDDL or LGPL Version 2.1]
+ * license." If you don't indicate a single choice of license, a recipient has the
+ * option to distribute your version of this file under either the CDDL or the LGPL
+ * Version 2.1, or to extend the choice of license to its licensees as provided
+ * above. However, if you add LGPL Version 2.1 code and therefore, elected the LGPL
+ * Version 2 license, then the option applies only if the new code is made subject
+ * to such option by the copyright holder. 
+ */
+
+#include "ibus_portable.h"
+
+#if defined(WITH_IBUS_1_1_0)
+
+void
+ibus_property_set_icon (IBusProperty *prop,
+                        const gchar  *icon)
+{
+    g_assert (IBUS_IS_PROPERTY (prop));
+
+    g_free (prop->icon);
+    prop->icon = NULL;
+    prop->icon = g_strdup (icon != NULL ? icon : "");
+}
+
+void
+ibus_property_set_state (IBusProperty  *prop,
+                         IBusPropState  state)
+{
+    g_assert (IBUS_IS_PROPERTY (prop));
+    g_return_if_fail (state == PROP_STATE_UNCHECKED ||
+                      state == PROP_STATE_CHECKED ||
+                      state == PROP_STATE_INCONSISTENT);
+
+    prop->state = state;
+}
+
+void
+ibus_property_set_tooltip (IBusProperty *prop,
+                           IBusText     *tooltip)
+{
+    g_assert (IBUS_IS_PROPERTY (prop));
+    g_return_if_fail (tooltip == NULL || IBUS_IS_TEXT (tooltip));
+
+    UNREF (prop->tooltip);
+
+    if (tooltip == NULL) {
+        prop->tooltip = ibus_text_new_from_static_string ("");
+    }
+    else {
+        prop->tooltip = (IBusText *)g_object_ref (tooltip);
+    }
+}
+
+#endif // WITH_IBUS_1_1_0
diff --git a/wrapper/ibus/src/ibus_portable.h b/wrapper/ibus/src/ibus_portable.h
new file mode 100644 (file)
index 0000000..144ce0f
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2009 Kov Chai <tchaikov@gmail.com>
+ *
+ * The contents of this file are subject to the terms of either the GNU Lesser
+ * General Public License Version 2.1 only ("LGPL") or the Common Development and
+ * Distribution License ("CDDL")(collectively, the "License"). You may not use this
+ * file except in compliance with the License. You can obtain a copy of the CDDL at
+ * http://www.opensource.org/licenses/cddl1.php and a copy of the LGPLv2.1 at
+ * http://www.opensource.org/licenses/lgpl-license.php. See the License for the 
+ * specific language governing permissions and limitations under the License. When
+ * distributing the software, include this License Header Notice in each file and
+ * include the full text of the License in the License file as well as the
+ * following notice:
+ * 
+ * NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND DISTRIBUTION LICENSE
+ * (CDDL)
+ * For Covered Software in this distribution, this License shall be governed by the
+ * laws of the State of California (excluding conflict-of-law provisions).
+ * Any litigation relating to this License shall be subject to the jurisdiction of
+ * the Federal Courts of the Northern District of California and the state courts
+ * of the State of California, with venue lying in Santa Clara County, California.
+ * 
+ * Contributor(s):
+ * 
+ * If you wish your version of this file to be governed by only the CDDL or only
+ * the LGPL Version 2.1, indicate your decision by adding "[Contributor]" elects to
+ * include this software in this distribution under the [CDDL or LGPL Version 2.1]
+ * license." If you don't indicate a single choice of license, a recipient has the
+ * option to distribute your version of this file under either the CDDL or the LGPL
+ * Version 2.1, or to extend the choice of license to its licensees as provided
+ * above. However, if you add LGPL Version 2.1 code and therefore, elected the LGPL
+ * Version 2 license, then the option applies only if the new code is made subject
+ * to such option by the copyright holder. 
+ */
+
+#ifndef IBUS_COMPABILITY_H
+#define  IBUS_COMPABILITY_H
+
+
+#if defined(WITH_IBUS_1_1_0)
+
+#include <ibus.h>
+
+void ibus_property_set_icon (IBusProperty *prop,
+                             const gchar  *icon);
+void ibus_property_set_state (IBusProperty  *prop,
+                              IBusPropState state);
+void ibus_property_set_tooltip (IBusProperty  *prop,
+                              IBusText    *tooltip);
+#endif // WITH_IBUS_1_1_0
+
+#endif // IBUS_COMPABILITY_H
diff --git a/wrapper/ibus/src/imi_ibus_win.cpp b/wrapper/ibus/src/imi_ibus_win.cpp
new file mode 100644 (file)
index 0000000..e511a30
--- /dev/null
@@ -0,0 +1,105 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright (c) 2007, 2009 Kov Chai <tchaikov@gmail.com>
+ *
+ * The contents of this file are subject to the terms of either the GNU Lesser
+ * General Public License Version 2.1 only ("LGPL") or the Common Development and
+ * Distribution License ("CDDL")(collectively, the "License"). You may not use this
+ * file except in compliance with the License. You can obtain a copy of the CDDL at
+ * http://www.opensource.org/licenses/cddl1.php and a copy of the LGPLv2.1 at
+ * http://www.opensource.org/licenses/lgpl-license.php. See the License for the 
+ * specific language governing permissions and limitations under the License. When
+ * distributing the software, include this License Header Notice in each file and
+ * include the full text of the License in the License file as well as the
+ * following notice:
+ * 
+ * NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND DISTRIBUTION LICENSE
+ * (CDDL)
+ * For Covered Software in this distribution, this License shall be governed by the
+ * laws of the State of California (excluding conflict-of-law provisions).
+ * Any litigation relating to this License shall be subject to the jurisdiction of
+ * the Federal Courts of the Northern District of California and the state courts
+ * of the State of California, with venue lying in Santa Clara County, California.
+ * 
+ * Contributor(s):
+ * 
+ * If you wish your version of this file to be governed by only the CDDL or only
+ * the LGPL Version 2.1, indicate your decision by adding "[Contributor]" elects to
+ * include this software in this distribution under the [CDDL or LGPL Version 2.1]
+ * license." If you don't indicate a single choice of license, a recipient has the
+ * option to distribute your version of this file under either the CDDL or the LGPL
+ * Version 2.1, or to extend the choice of license to its licensees as provided
+ * above. However, if you add LGPL Version 2.1 code and therefore, elected the LGPL
+ * Version 2 license, then the option applies only if the new code is made subject
+ * to such option by the copyright holder. 
+ */
+#include <string>
+#include <algorithm>
+#include <ime-core/imi_uiobjects.h>
+
+#include "sunpinyin_engine.h"
+#include "imi_ibus_win.h"
+
+
+
+CIBusWinHandler::CIBusWinHandler(SunPinyinEngine* engine)
+  : m_engine(engine)
+{
+    //
+}
+
+CIBusWinHandler::~CIBusWinHandler()
+{
+}
+
+void
+CIBusWinHandler::commit(const TWCHAR* wstr)
+{
+    if (wstr) {
+        std::wstring str;
+        copy(wstr, wstr+WCSLEN(wstr)+1, back_inserter(str));
+        m_engine->commit_string(str);
+    }
+}
+
+void
+CIBusWinHandler::updatePreedit(const IPreeditString* ppd)
+{
+    if (ppd)
+        m_engine->update_preedit_string(*ppd);
+}
+
+void
+CIBusWinHandler::updateCandidates(const ICandidateList* pcl)
+{
+    if (pcl)
+        m_engine->update_candidates(*pcl);
+}
+
+void
+CIBusWinHandler::throwBackKey(unsigned keycode, unsigned keyvalue, unsigned modifier)
+{
+    if (keyvalue > 0x0 && keyvalue < 0x7f) {
+        printf("%c", keyvalue);
+        fflush(stdout);
+    }
+}
+
+void
+CIBusWinHandler::updateStatus(int key, int value)
+{
+    switch (key) {
+    case STATUS_ID_CN:
+        m_engine->update_status_property(value != 0);
+        break;
+    case STATUS_ID_FULLPUNC:
+        m_engine->update_punct_property(value != 0);
+        break;
+    case STATUS_ID_FULLSYMBOL:
+        m_engine->update_letter_property(value != 0);
+        break;
+    default:
+        break;
+    }
+}
diff --git a/wrapper/ibus/src/imi_ibus_win.h b/wrapper/ibus/src/imi_ibus_win.h
new file mode 100644 (file)
index 0000000..c43d6af
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2007,2009 Kov Chai <tchaikov@gmail.com>
+ *
+ * The contents of this file are subject to the terms of either the GNU Lesser
+ * General Public License Version 2.1 only ("LGPL") or the Common Development and
+ * Distribution License ("CDDL")(collectively, the "License"). You may not use this
+ * file except in compliance with the License. You can obtain a copy of the CDDL at
+ * http://www.opensource.org/licenses/cddl1.php and a copy of the LGPLv2.1 at
+ * http://www.opensource.org/licenses/lgpl-license.php. See the License for the 
+ * specific language governing permissions and limitations under the License. When
+ * distributing the software, include this License Header Notice in each file and
+ * include the full text of the License in the License file as well as the
+ * following notice:
+ * 
+ * NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND DISTRIBUTION LICENSE
+ * (CDDL)
+ * For Covered Software in this distribution, this License shall be governed by the
+ * laws of the State of California (excluding conflict-of-law provisions).
+ * Any litigation relating to this License shall be subject to the jurisdiction of
+ * the Federal Courts of the Northern District of California and the state courts
+ * of the State of California, with venue lying in Santa Clara County, California.
+ * 
+ * Contributor(s):
+ * 
+ * If you wish your version of this file to be governed by only the CDDL or only
+ * the LGPL Version 2.1, indicate your decision by adding "[Contributor]" elects to
+ * include this software in this distribution under the [CDDL or LGPL Version 2.1]
+ * license." If you don't indicate a single choice of license, a recipient has the
+ * option to distribute your version of this file under either the CDDL or the LGPL
+ * Version 2.1, or to extend the choice of license to its licensees as provided
+ * above. However, if you add LGPL Version 2.1 code and therefore, elected the LGPL
+ * Version 2 license, then the option applies only if the new code is made subject
+ * to such option by the copyright holder. 
+ */
+
+#ifndef IMI_IBUS_WIN_H
+#define IMI_IBUS_WIN_H
+
+#include <ime-core/imi_glibHandler.h>
+
+class SunPinyinEngine;
+
+class CIBusWinHandler : public CIMIGlibHandler
+{
+public:
+    CIBusWinHandler(SunPinyinEngine *);
+
+    /* inherited methods implementation */
+    /*@{*/
+    virtual ~CIBusWinHandler();
+
+    /** commit a string, normally the converted result */
+    virtual void commit(const TWCHAR* wstr);
+    
+    /** when a key is not processed */
+    virtual void throwBackKey(unsigned keycode, unsigned keyvalue, unsigned modifier);
+
+    /** Update window's preedit area using a GTK widget. */
+    virtual void updatePreedit(const IPreeditString* ppd);
+
+    /** Update window's candidates area using a GTK widget. */
+    virtual void updateCandidates(const ICandidateList* pcl);
+
+    /** Update status of current session using a GTK buttons. */
+    virtual void  updateStatus(int key, int value);
+
+    /*@}*/
+
+private:
+    SunPinyinEngine *m_engine;
+};
+
+#endif // IMI_IBUS_WIN_H
diff --git a/wrapper/ibus/src/main.cpp b/wrapper/ibus/src/main.cpp
new file mode 100644 (file)
index 0000000..6fe7365
--- /dev/null
@@ -0,0 +1,141 @@
+/*
+ * Copyright (c) 2009 Kov Chai <tchaikov@gmail.com>
+ *
+ * The contents of this file are subject to the terms of either the GNU Lesser
+ * General Public License Version 2.1 only ("LGPL") or the Common Development and
+ * Distribution License ("CDDL")(collectively, the "License"). You may not use this
+ * file except in compliance with the License. You can obtain a copy of the CDDL at
+ * http://www.opensource.org/licenses/cddl1.php and a copy of the LGPLv2.1 at
+ * http://www.opensource.org/licenses/lgpl-license.php. See the License for the 
+ * specific language governing permissions and limitations under the License. When
+ * distributing the software, include this License Header Notice in each file and
+ * include the full text of the License in the License file as well as the
+ * following notice:
+ * 
+ * NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND DISTRIBUTION LICENSE
+ * (CDDL)
+ * For Covered Software in this distribution, this License shall be governed by the
+ * laws of the State of California (excluding conflict-of-law provisions).
+ * Any litigation relating to this License shall be subject to the jurisdiction of
+ * the Federal Courts of the Northern District of California and the state courts
+ * of the State of California, with venue lying in Santa Clara County, California.
+ * 
+ * Contributor(s):
+ * 
+ * If you wish your version of this file to be governed by only the CDDL or only
+ * the LGPL Version 2.1, indicate your decision by adding "[Contributor]" elects to
+ * include this software in this distribution under the [CDDL or LGPL Version 2.1]
+ * license." If you don't indicate a single choice of license, a recipient has the
+ * option to distribute your version of this file under either the CDDL or the LGPL
+ * Version 2.1, or to extend the choice of license to its licensees as provided
+ * above. However, if you add LGPL Version 2.1 code and therefore, elected the LGPL
+ * Version 2 license, then the option applies only if the new code is made subject
+ * to such option by the copyright holder. 
+ */
+
+#include <locale.h>
+#include <libintl.h>
+#include <unistd.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <ibus.h>
+#include "engine.h"
+#include "ibus_common.h"
+#include "sunpinyin_config.h"
+
+#define N_(String) (String)
+#define _(String)  gettext(String)
+
+static ibus::Factory factory;
+
+// options
+static gboolean by_ibus = FALSE;
+static gboolean verbose = FALSE;
+
+static const GOptionEntry entries[] = 
+{
+    { "ibus",    'i', 0, G_OPTION_ARG_NONE, &by_ibus, "component is executed by ibus", NULL },
+    { "verbose", 'v', 0, G_OPTION_ARG_NONE, &verbose, "verbose", NULL },
+    { NULL },
+};
+
+
+static void
+ibus_disconnected_cb (IBusBus  *bus,
+                      gpointer  user_data)
+{
+    ibus_quit ();
+}
+
+IBusBus *bus = NULL;
+ibus::Component component;
+
+static void
+init ()
+{
+    ibus_init ();
+    bus = ibus_bus_new ();
+    g_object_ref_sink(bus);
+    
+    if (!ibus_bus_is_connected (bus)) {
+        g_warning("Can not connect to ibus");
+        exit (0);
+    }
+    
+    g_signal_connect (bus, "disconnected", G_CALLBACK (ibus_disconnected_cb), NULL);
+       
+    IBusConfig* config = ibus_bus_get_config(bus);
+    g_object_ref_sink(config);
+    
+    SunPinyinConfig::set_config(config);
+
+    
+    component = ibus_component_new ("org.freedesktop.IBus.SunPinyin",
+                                    "SunPinyin2",
+                                    "0.1.0",
+                                    "LGPL/CDDL",
+                                    "Kov Chai <tchaikov@gmail.com>",
+                                    "http://code.google.com/p/sunpinyin/",
+                                    "",
+                                    "ibus-sunpinyin");
+    ibus_component_add_engine (component,
+                               ibus_engine_desc_new ("sunpinyin",
+                                                     "SunPinyin",
+                                                     _("Simplified Chinese Input Method developed by SUN"),
+                                                     "zh_CN",
+                                                     "LGPL/CDDL",
+                                                     "Kov Chai <tchaikov@gmail.com>",
+                                                     IBUS_SUNPINYIN_ICON_DIR"/sunpinyin-logo.png",
+                                                     "en"));
+    
+    factory = ibus_factory_new (ibus_bus_get_connection (bus));
+    ibus_factory_add_engine (factory, "sunpinyin", IBUS_TYPE_SUNPINYIN_ENGINE);
+
+    if (by_ibus) {
+        ibus_bus_request_name (bus, "org.freedesktop.IBus.SunPinyin", 0);
+    } else {
+        ibus_bus_register_component (bus, component);
+    }
+    ibus_main ();
+}
+
+int main(int argc, char *argv[])
+{
+
+    setlocale (LC_ALL, "");
+    bindtextdomain (GETTEXT_PACKAGE, IBUS_SUNPINYIN_LOCALEDIR);
+    textdomain (GETTEXT_PACKAGE);
+    
+    GOptionContext* context;
+    context = g_option_context_new ("- ibus sunpinyin engine component");
+    g_option_context_add_main_entries (context, entries, "ibus-sunpinyin");
+    GError *error = NULL;
+    if (!g_option_context_parse (context, &argc, &argv, &error)) {
+        g_print ("Option parsing failed: %s\n", error->message);
+        return -1;
+    }
+    // mask SIGTERM so that the destroy() method has the chance to be called
+    // in case user quits X session.
+    sighold(SIGTERM);
+    init ();
+}
diff --git a/wrapper/ibus/src/pointer.h b/wrapper/ibus/src/pointer.h
new file mode 100644 (file)
index 0000000..204b858
--- /dev/null
@@ -0,0 +1,109 @@
+/*
+ * Copyright (c) 2010 Kov Chai <tchaikov@gmail.com>
+ *
+ * The contents of this file are subject to the terms of either the GNU Lesser
+ * General Public License Version 2.1 only ("LGPL") or the Common Development and
+ * Distribution License ("CDDL")(collectively, the "License"). You may not use this
+ * file except in compliance with the License. You can obtain a copy of the CDDL at
+ * http://www.opensource.org/licenses/cddl1.php and a copy of the LGPLv2.1 at
+ * http://www.opensource.org/licenses/lgpl-license.php. See the License for the 
+ * specific language governing permissions and limitations under the License. When
+ * distributing the software, include this License Header Notice in each file and
+ * include the full text of the License in the License file as well as the
+ * following notice:
+ * 
+ * NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND DISTRIBUTION LICENSE
+ * (CDDL)
+ * For Covered Software in this distribution, this License shall be governed by the
+ * laws of the State of California (excluding conflict-of-law provisions).
+ * Any litigation relating to this License shall be subject to the jurisdiction of
+ * the Federal Courts of the Northern District of California and the state courts
+ * of the State of California, with venue lying in Santa Clara County, California.
+ * 
+ * Contributor(s):
+ * 
+ * If you wish your version of this file to be governed by only the CDDL or only
+ * the LGPL Version 2.1, indicate your decision by adding "[Contributor]" elects to
+ * include this software in this distribution under the [CDDL or LGPL Version 2.1]
+ * license." If you don't indicate a single choice of license, a recipient has the
+ * option to distribute your version of this file under either the CDDL or the LGPL
+ * Version 2.1, or to extend the choice of license to its licensees as provided
+ * above. However, if you add LGPL Version 2.1 code and therefore, elected the LGPL
+ * Version 2 license, then the option applies only if the new code is made subject
+ * to such option by the copyright holder. 
+ */
+
+#ifndef POINTER_H
+#define POINTER_H
+
+template <typename T>
+class Pointer
+{
+public:
+    Pointer(T *p = 0) 
+        : m_p(0)
+    {
+        set(p);
+    }
+
+    ~Pointer()
+    {
+        set(0);
+    }
+    
+    Pointer(const Pointer& p)
+        : m_p(0)
+    {
+        set(p.m_p);
+    }
+
+    Pointer& operator=(T *object)
+    {
+        set(object);
+        return *this;
+    }
+
+    Pointer& operator=(const Pointer<T>& src)
+    {
+        set(src.m_p);
+        return *this;
+    }
+
+    const T* operator->() const
+    {
+        return m_p;
+    }
+
+    T* operator->()
+    {
+        return m_p;
+    }
+
+    operator T* () const 
+    {
+        return m_p;
+    }
+
+    operator bool () const
+    {
+        return m_p != 0;
+    }
+    
+private:
+    
+    T *m_p;
+
+    void set(T *p)
+    {
+        if (m_p) {
+            g_object_unref(m_p);
+        }
+        m_p = p;
+        
+        if (p) {
+            g_object_ref_sink(p);
+        }
+    }
+};
+
+#endif// POINTER_H
diff --git a/wrapper/ibus/src/sunpinyin_config.cpp b/wrapper/ibus/src/sunpinyin_config.cpp
new file mode 100644 (file)
index 0000000..04dc5c5
--- /dev/null
@@ -0,0 +1,448 @@
+/*
+ * Copyright (c) 2009 Kov Chai <tchaikov@gmail.com>
+ *
+ * The contents of this file are subject to the terms of either the GNU Lesser
+ * General Public License Version 2.1 only ("LGPL") or the Common Development and
+ * Distribution License ("CDDL")(collectively, the "License"). You may not use this
+ * file except in compliance with the License. You can obtain a copy of the CDDL at
+ * http://www.opensource.org/licenses/cddl1.php and a copy of the LGPLv2.1 at
+ * http://www.opensource.org/licenses/lgpl-license.php. See the License for the 
+ * specific language governing permissions and limitations under the License. When
+ * distributing the software, include this License Header Notice in each file and
+ * include the full text of the License in the License file as well as the
+ * following notice:
+ * 
+ * NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND DISTRIBUTION LICENSE
+ * (CDDL)
+ * For Covered Software in this distribution, this License shall be governed by the
+ * laws of the State of California (excluding conflict-of-law provisions).
+ * Any litigation relating to this License shall be subject to the jurisdiction of
+ * the Federal Courts of the Northern District of California and the state courts
+ * of the State of California, with venue lying in Santa Clara County, California.
+ * 
+ * Contributor(s):
+ * 
+ * If you wish your version of this file to be governed by only the CDDL or only
+ * the LGPL Version 2.1, indicate your decision by adding "[Contributor]" elects to
+ * include this software in this distribution under the [CDDL or LGPL Version 2.1]
+ * license." If you don't indicate a single choice of license, a recipient has the
+ * option to distribute your version of this file under either the CDDL or the LGPL
+ * Version 2.1, or to extend the choice of license to its licensees as provided
+ * above. However, if you add LGPL Version 2.1 code and therefore, elected the LGPL
+ * Version 2 license, then the option applies only if the new code is made subject
+ * to such option by the copyright holder. 
+ */
+
+#include <cassert>
+#include <sunpinyin.h>
+#include "sunpinyin_config_keys.h"
+#include "sunpinyin_config.h"
+
+using namespace std;
+
+struct ConfigItem
+{
+    string section;
+    string name;
+    ConfigItem(const string& key)
+    {
+        section = "engine/SunPinyin/";
+        size_t pos = key.rfind('/');
+        if (pos != key.npos) {
+            section += key.substr(0, pos);
+            pos += 1;
+        } else {
+            pos = 0;
+        }
+        name = key.substr(pos);
+    }
+};
+
+IBusConfig* SunPinyinConfig::m_config;
+
+SunPinyinConfig::SunPinyinConfig()
+{
+    m_scheme_names["QuanPin"]    = CSunpinyinSessionFactory::QUANPIN;
+    m_scheme_names["ShuangPin"]  = CSunpinyinSessionFactory::SHUANGPIN;
+}
+
+SunPinyinConfig::~SunPinyinConfig()
+{}
+
+void
+SunPinyinConfig::set_config(IBusConfig* config)
+{
+    assert(config);
+    m_config = config;
+    listen_on_changed();
+}
+
+CSunpinyinSessionFactory::EPyScheme
+SunPinyinConfig::get_py_scheme(CSunpinyinSessionFactory::EPyScheme scheme)
+{
+    string default_name =
+        get_scheme_name(scheme);
+    string name = get(PINYIN_SCHEME, default_name);
+    return get_scheme(name);
+}
+
+bool
+SunPinyinConfig::is_initial_mode_cn()
+{
+    string init_mode("Chinese");
+    init_mode = get(CONFIG_GENERAL_INITIAL_MODE, init_mode);
+    return (init_mode == "Chinese");
+}
+
+bool
+SunPinyinConfig::is_initial_punct_full()
+{
+    string init_punct("Full");
+    init_punct = get(CONFIG_GENERAL_INITIAL_PUNCT, init_punct);
+    return (init_punct == "Full");
+}
+
+bool
+SunPinyinConfig::is_initial_letter_full()
+{
+    string init_letter("Half");
+    init_letter = get(CONFIG_GENERAL_INITIAL_LETTER, init_letter);
+    return (init_letter == "Full");
+}
+
+void
+SunPinyinConfig::listen_on_changed()
+{
+    assert(m_config != NULL);
+    g_signal_connect(m_config, "value-changed",
+                     G_CALLBACK(on_config_value_changed), 0);
+}
+
+std::string
+SunPinyinConfig::get_scheme_name(CSunpinyinSessionFactory::EPyScheme scheme)
+{
+    string val = "ShuangPin";
+    for (SchemeNames::iterator it = m_scheme_names.begin();
+         it != m_scheme_names.end(); ++it) {
+        if (it->second == scheme)
+            val = it->first;
+    }
+    return val;
+}
+
+CSunpinyinSessionFactory::EPyScheme
+SunPinyinConfig::get_scheme(const std::string& name)
+{
+    CSunpinyinSessionFactory::EPyScheme val = CSunpinyinSessionFactory::SHUANGPIN;
+    SchemeNames::iterator it = m_scheme_names.find(name);
+    if (it != m_scheme_names.end()) {
+        val = it->second;
+    }
+    return val;
+}
+
+#if IBUS_CHECK_VERSION (1, 3, 99)
+static vector<string> get_strings_from_gvariant(GVariant *value);
+
+bool
+SunPinyinConfig::get(const char* key, bool val)
+{
+    assert(m_config != NULL);
+    
+    ConfigItem item(key);
+    GVariant* value = ibus_config_get_value(m_config, item.section.c_str(), item.name.c_str());
+    bool result = val;
+    if (g_variant_classify(value) == G_VARIANT_CLASS_BOOLEAN) {
+        result = (g_variant_get_boolean(value) == TRUE);
+    }
+    return result;
+}
+
+void
+SunPinyinConfig::set(const char* key, bool val)
+{
+    assert(m_config != NULL);
+    
+    GVariant * value = g_variant_new_boolean(val);
+    ConfigItem item(key);
+    ibus_config_set_value(m_config, item.section.c_str(), item.name.c_str(), value);
+}
+
+std::string
+SunPinyinConfig::get(const char* key, const std::string& val)
+{
+    assert(m_config != NULL);
+    
+    ConfigItem item(key);
+    GVariant* value = ibus_config_get_value(m_config, item.section.c_str(), item.name.c_str());
+    string result = val;
+    if (g_variant_classify(value) == G_VARIANT_CLASS_STRING) {
+      result = string(g_variant_get_string(value, NULL));
+    }
+    return result;
+}
+
+void
+SunPinyinConfig::set(const char* key, const std::string& val)
+{
+    assert(m_config != NULL);
+    
+    GVariant* value = g_variant_new_string(val.c_str());
+    ConfigItem item(key);
+    ibus_config_set_value(m_config, item.section.c_str(), item.name.c_str(), value);
+}
+
+int
+SunPinyinConfig::get(const char* key, int val)
+{
+    assert(m_config != NULL);
+    
+    ConfigItem item(key);
+    GVariant* value = ibus_config_get_value(m_config, item.section.c_str(), item.name.c_str());
+    int result = val;
+    if (g_variant_classify(value) == G_VARIANT_CLASS_INT32) {
+        result =  g_variant_get_int32(value);
+    }
+    return result;
+}
+
+void 
+SunPinyinConfig::set(const char* key, int val)
+{
+    assert(m_config != NULL);
+    
+    GVariant* value = g_variant_new_int32(val);
+    ConfigItem item(key);
+    ibus_config_set_value(m_config, item.section.c_str(), item.name.c_str(), value);
+}
+
+std::vector<std::string>
+SunPinyinConfig::get(const char* key, const std::vector<std::string>& val)
+{
+    assert(m_config != NULL);
+    
+    ConfigItem item(key);
+    GVariant* value = ibus_config_get_value(m_config, item.section.c_str(), item.name.c_str());
+    vector<string> result(val);
+    if (g_variant_classify(value) == G_VARIANT_CLASS_ARRAY) {
+        result =  get_strings_from_gvariant(value);
+    }
+    return result;
+}
+
+vector<string>
+get_strings_from_gvariant(GVariant *value)
+{
+    const gchar **array = g_variant_get_strv(value, NULL);
+    assert(array != NULL);
+    vector<string> strings;
+    for (unsigned i = 0; array[i]; ++i) {
+        strings.push_back(array[i]);
+    }
+    return strings;
+}
+
+static COptionEvent
+g_value_to_event(const gchar *section, const gchar *name, GVariant *value)
+{
+    string event_name;
+    
+    if (strlen(section) == 0) {
+        event_name = name;
+    } else {
+        event_name = string(section) + "/" + string(name);
+    }
+    
+    switch (g_variant_classify(value)) {
+    case G_VARIANT_CLASS_INT32:
+        return COptionEvent(event_name, g_variant_get_int32(value));
+    case G_VARIANT_CLASS_STRING:
+      return COptionEvent(event_name, g_variant_get_string(value, NULL));
+    case G_VARIANT_CLASS_BOOLEAN:
+        return COptionEvent(event_name,
+                            g_variant_get_boolean(value)?true:false);
+    default:
+        // G_TYPE_VALUE_ARRAY() not a constant
+        if (G_VARIANT_CLASS_ARRAY ==  g_variant_classify(value))
+            return COptionEvent(event_name, get_strings_from_gvariant(value));
+        assert(false && "unknown gvalue");
+        return COptionEvent(event_name, 0);
+    }   
+}
+
+void
+SunPinyinConfig::on_config_value_changed(IBusConfig *config,
+                                         const gchar *section,
+                                         const gchar *name,
+                                         GVariant *value,
+                                         SunPinyinConfig* thiz)
+{
+    static const char* prefix = "engine/SunPinyin/";
+    if (!strstr(section, prefix))
+        return;
+    const char *sub_section = section + strlen(prefix);
+    COptionEvent event = g_value_to_event(sub_section, name, value);
+    AOptionEventBus::instance().publishEvent(event);
+}
+
+#else /* for versions lower than 1.3.99 (or 1.4) */
+
+static vector<string> get_strings_from_gvalue(GValue* value);
+
+bool
+SunPinyinConfig::get(const char* key, bool val)
+{
+    assert(m_config != NULL);
+    
+    GValue v = {0};
+    gboolean got;
+    ConfigItem item(key);
+    got = ibus_config_get_value(m_config, item.section.c_str(), item.name.c_str(), &v);
+    bool result = val;
+    if (got && G_VALUE_TYPE(&v) == G_TYPE_BOOLEAN) {
+        result = (g_value_get_boolean(&v) == TRUE);
+    }
+    return result;
+}
+
+void
+SunPinyinConfig::set(const char* key, bool value)
+{
+    assert(m_config != NULL);
+    
+    GValue v = {0};
+    g_value_init(&v, G_TYPE_BOOLEAN);
+    g_value_set_boolean(&v, value?TRUE:FALSE);
+    ConfigItem item(key);
+    ibus_config_set_value(m_config, item.section.c_str(), item.name.c_str(), &v);
+}
+
+std::string
+SunPinyinConfig::get(const char* key, const std::string& val)
+{
+    assert(m_config != NULL);
+    
+    GValue v = {0};
+    gboolean got;
+    ConfigItem item(key);
+    got = ibus_config_get_value(m_config, item.section.c_str(), item.name.c_str(), &v);
+    string result = val;
+    if (got && G_VALUE_TYPE(&v) == G_TYPE_STRING) {
+        result = string(g_value_get_string(&v));
+    }
+    return result;
+}
+
+void
+SunPinyinConfig::set(const char* key, const std::string& val)
+{
+    assert(m_config != NULL);
+    
+    GValue v = {0};
+    g_value_init(&v, G_TYPE_STRING);
+    g_value_set_string(&v, val.c_str());
+    ConfigItem item(key);
+    ibus_config_set_value(m_config, item.section.c_str(), item.name.c_str(), &v);
+}
+
+int
+SunPinyinConfig::get(const char* key, int val)
+{
+    assert(m_config != NULL);
+    
+    GValue v = {0};
+    gboolean got;
+    ConfigItem item(key);
+    got = ibus_config_get_value(m_config, item.section.c_str(), item.name.c_str(), &v);
+    int result = val;
+    if (got && G_VALUE_TYPE(&v) == G_TYPE_INT) {
+        result =  g_value_get_int(&v);
+    }
+    return result;
+}
+
+void 
+SunPinyinConfig::set(const char* key, int value)
+{
+    assert(m_config != NULL);
+    
+    GValue v = {0};
+    g_value_init(&v, G_TYPE_INT);
+    g_value_set_int(&v, value);
+    ConfigItem item(key);
+    ibus_config_set_value(m_config, item.section.c_str(), item.name.c_str(), &v);
+}
+
+std::vector<std::string>
+SunPinyinConfig::get(const char *key, const std::vector<std::string>& val)
+{
+    assert(m_config != NULL);
+    
+    GValue v = {0};
+    gboolean got;
+    ConfigItem item(key);
+    got = ibus_config_get_value(m_config, item.section.c_str(), item.name.c_str(), &v);
+    vector<string> result(val);
+    if (got && G_VALUE_TYPE(&v) == G_TYPE_VALUE_ARRAY) {
+        result =  get_strings_from_gvalue(&v);
+    }
+    return result;
+}
+
+vector<string>
+get_strings_from_gvalue(GValue *value)
+{
+    GValueArray *array = (GValueArray *)g_value_get_boxed(value);
+    assert(array != NULL);
+    vector<string> strings;
+    for (unsigned i = 0; i < array->n_values; ++i) {
+        GValue *element = &(array->values[i]);
+        assert (G_VALUE_TYPE(element) == G_TYPE_STRING && "only array of string is supported");
+        strings.push_back(g_value_get_string(element));
+    }
+    return strings;
+}
+
+static COptionEvent
+g_value_to_event(const gchar *section, const gchar *name, GValue *value)
+{
+    string event_name;
+    
+    if (strlen(section) == 0) {
+        event_name = name;
+    } else {
+        event_name = string(section) + "/" + string(name);
+    }
+    
+    switch (G_VALUE_TYPE(value)) {
+    case G_TYPE_INT:
+        return COptionEvent(event_name, g_value_get_int(value));
+    case G_TYPE_STRING:
+        return COptionEvent(event_name, g_value_get_string(value));
+    case G_TYPE_BOOLEAN:
+        return COptionEvent(event_name,
+                            g_value_get_boolean(value)?true:false);
+    default:
+        // G_TYPE_VALUE_ARRAY() not a constant
+        if (G_TYPE_VALUE_ARRAY == G_VALUE_TYPE(value))
+            return COptionEvent(event_name, get_strings_from_gvalue(value));
+        assert(false && "unknown gvalue");
+        return COptionEvent(event_name, 0);
+    }   
+}
+
+void
+SunPinyinConfig::on_config_value_changed(IBusConfig *config,
+                                         const gchar *section,
+                                         const gchar *name,
+                                         GValue *value,
+                                         SunPinyinConfig* thiz)
+{
+    static const char* prefix = "engine/SunPinyin/";
+    if (!strstr(section, prefix))
+        return;
+    const char *sub_section = section + strlen(prefix);
+    COptionEvent event = g_value_to_event(sub_section, name, value);
+    AOptionEventBus::instance().publishEvent(event);
+}
+#endif
diff --git a/wrapper/ibus/src/sunpinyin_config.h b/wrapper/ibus/src/sunpinyin_config.h
new file mode 100644 (file)
index 0000000..5c8b029
--- /dev/null
@@ -0,0 +1,120 @@
+/*
+ * Copyright (c) 2009 Kov Chai <tchaikov@gmail.com>
+ *
+ * The contents of this file are subject to the terms of either the GNU Lesser
+ * General Public License Version 2.1 only ("LGPL") or the Common Development and
+ * Distribution License ("CDDL")(collectively, the "License"). You may not use this
+ * file except in compliance with the License. You can obtain a copy of the CDDL at
+ * http://www.opensource.org/licenses/cddl1.php and a copy of the LGPLv2.1 at
+ * http://www.opensource.org/licenses/lgpl-license.php. See the License for the
+ * specific language governing permissions and limitations under the License. When
+ * distributing the software, include this License Header Notice in each file and
+ * include the full text of the License in the License file as well as the
+ * following notice:
+ *
+ * NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND DISTRIBUTION LICENSE
+ * (CDDL)
+ * For Covered Software in this distribution, this License shall be governed by the
+ * laws of the State of California (excluding conflict-of-law provisions).
+ * Any litigation relating to this License shall be subject to the jurisdiction of
+ * the Federal Courts of the Northern District of California and the state courts
+ * of the State of California, with venue lying in Santa Clara County, California.
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by only the CDDL or only
+ * the LGPL Version 2.1, indicate your decision by adding "[Contributor]" elects to
+ * include this software in this distribution under the [CDDL or LGPL Version 2.1]
+ * license." If you don't indicate a single choice of license, a recipient has the
+ * option to distribute your version of this file under either the CDDL or the LGPL
+ * Version 2.1, or to extend the choice of license to its licensees as provided
+ * above. However, if you add LGPL Version 2.1 code and therefore, elected the LGPL
+ * Version 2 license, then the option applies only if the new code is made subject
+ * to such option by the copyright holder.
+ */
+
+#ifndef SUNPINYIN_CONFIG_H
+#define SUNPINYIN_CONFIG_H
+
+#include <map>
+#include <vector>
+#include <string>
+#include <ibus.h>
+#include <sunpinyin.h>
+
+class EngineImpl;
+
+enum CharsetLevel
+{
+    GB2312,
+    GBK,
+    GB18030
+};
+
+class SunPinyinConfig
+{
+    typedef std::map<std::string,
+        CSunpinyinSessionFactory::EPyScheme> SchemeNames;
+    typedef std::map<std::string,
+        EShuangpinType> TypeNames;
+
+    SchemeNames        m_scheme_names;
+    TypeNames          m_type_names;
+
+    static IBusConfig* m_config;
+
+
+public:
+    SunPinyinConfig();
+    virtual ~SunPinyinConfig();
+
+    static void set_config(IBusConfig *config);
+
+
+    bool get(const char* key, bool val);
+    void set(const char* key, bool val);
+
+    int get(const char* key, int val);
+    void set(const char* key, int val);
+
+    std::string get(const char *key, const std::string& default_val);
+    void set(const char* key, const std::string& val);
+
+    std::vector<std::string> get(const char *key, const std::vector<std::string>& val);
+
+    CSunpinyinSessionFactory::EPyScheme get_py_scheme(CSunpinyinSessionFactory::EPyScheme);
+    void set_py_scheme(CSunpinyinSessionFactory::EPyScheme);
+
+    bool is_initial_mode_cn();
+    bool is_initial_punct_full();
+    bool is_initial_letter_full();
+
+    /**
+     * register on_config_value_changed() as the signal handler of value-changed,
+     */
+    static void listen_on_changed();
+
+private:
+
+    /**
+     * called by ibus when a value changed in config
+     */
+#if IBUS_CHECK_VERSION(1, 3, 99)
+    static void on_config_value_changed(IBusConfig *config,
+                                        const gchar *section,
+                                        const gchar *name,
+                                        GVariant *value,
+                                        SunPinyinConfig *user_data);
+#else
+    static void on_config_value_changed(IBusConfig *config,
+                                        const gchar *section,
+                                        const gchar *name,
+                                        GValue *value,
+                                        SunPinyinConfig *user_data);
+#endif
+
+    std::string get_scheme_name(CSunpinyinSessionFactory::EPyScheme scheme);
+    CSunpinyinSessionFactory::EPyScheme get_scheme(const std::string& name);
+};
+
+#endif // SUNPINYIN_CONFIG_H
diff --git a/wrapper/ibus/src/sunpinyin_config_keys.h b/wrapper/ibus/src/sunpinyin_config_keys.h
new file mode 100644 (file)
index 0000000..d04a4c0
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2009 Kov Chai <tchaikov@gmail.com>
+ *
+ * The contents of this file are subject to the terms of either the GNU Lesser
+ * General Public License Version 2.1 only ("LGPL") or the Common Development and
+ * Distribution License ("CDDL")(collectively, the "License"). You may not use this
+ * file except in compliance with the License. You can obtain a copy of the CDDL at
+ * http://www.opensource.org/licenses/cddl1.php and a copy of the LGPLv2.1 at
+ * http://www.opensource.org/licenses/lgpl-license.php. See the License for the
+ * specific language governing permissions and limitations under the License. When
+ * distributing the software, include this License Header Notice in each file and
+ * include the full text of the License in the License file as well as the
+ * following notice:
+ *
+ * NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND DISTRIBUTION LICENSE
+ * (CDDL)
+ * For Covered Software in this distribution, this License shall be governed by the
+ * laws of the State of California (excluding conflict-of-law provisions).
+ * Any litigation relating to this License shall be subject to the jurisdiction of
+ * the Federal Courts of the Northern District of California and the state courts
+ * of the State of California, with venue lying in Santa Clara County, California.
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by only the CDDL or only
+ * the LGPL Version 2.1, indicate your decision by adding "[Contributor]" elects to
+ * include this software in this distribution under the [CDDL or LGPL Version 2.1]
+ * license." If you don't indicate a single choice of license, a recipient has the
+ * option to distribute your version of this file under either the CDDL or the LGPL
+ * Version 2.1, or to extend the choice of license to its licensees as provided
+ * above. However, if you add LGPL Version 2.1 code and therefore, elected the LGPL
+ * Version 2 license, then the option applies only if the new code is made subject
+ * to such option by the copyright holder.
+ */
+
+#ifndef SUNPINYIN_CONFIG_KEYS_H
+#define SUNPINYIN_CONFIG_KEYS_H
+
+#define CONFIG_GENERAL_PAGE_SIZE            "General/PageSize"
+#define CONFIG_GENERAL_MEMORY_POWER         "General/MemoryPower"
+#define CONFIG_GENERAL_CHARSET_LEVEL        "General/Charset"
+#define CONFIG_GENERAL_MAX_BEST             "General/MaxBest"
+#define CONFIG_GENERAL_MAX_TAIL_CANDIDATE   "General/MaxTailCandidate"
+#define CONFIG_GENERAL_INITIAL_MODE         "General/InitialStatus/Mode"
+#define CONFIG_GENERAL_INITIAL_PUNCT        "General/InitialStatus/Punct"
+#define CONFIG_GENERAL_INITIAL_LETTER       "General/InitialStatus/Letter"
+
+#define CONFIG_QUANPIN_FUZZY_ANY         "QuanPin/Fuzzy/Any"
+#define CONFIG_QUANPIN_FUZZY_ZhiZi       "QuanPin/Fuzzy/ZhiZi"
+#define CONFIG_QUANPIN_FUZZY_ChiCi       "QuanPin/Fuzzy/ChiCi"
+#define CONFIG_QUANPIN_FUZZY_ShiSi       "QuanPin/Fuzzy/ShiSi"
+#define CONFIG_QUANPIN_FUZZY_AnAng       "QuanPin/Fuzzy/AnAng"
+#define CONFIG_QUANPIN_FUZZY_OnOng       "QuanPin/Fuzzy/OnOng"
+#define CONFIG_QUANPIN_FUZZY_EnEng       "QuanPin/Fuzzy/EnEng"
+#define CONFIG_QUANPIN_FUZZY_InIng       "QuanPin/Fuzzy/InIng"
+#define CONFIG_QUANPIN_FUZZY_EngOng      "QuanPin/Fuzzy/EngOng"
+#define CONFIG_QUANPIN_FUZZY_IanIang     "QuanPin/Fuzzy/IanIang"
+#define CONFIG_QUANPIN_FUZZY_UanUang     "QuanPin/Fuzzy/UanUang"
+#define CONFIG_QUANPIN_FUZZY_NeLe        "QuanPin/Fuzzy/NeLe"
+#define CONFIG_QUANPIN_FUZZY_FoHe        "QuanPin/Fuzzy/FoHe"
+#define CONFIG_QUANPIN_FUZZY_LeRi        "QuanPin/Fuzzy/LeRi"
+#define CONFIG_QUANPIN_FUZZY_KeGe        "QuanPin/Fuzzy/KeGe"
+
+#define CONFIG_QUANPIN_FUZZYSEGS_ENABLED  "QuanPin/FuzzySegs/Enabled"
+#define CONFIG_QUANPIN_INNERFUZZY_ENABLED "QuanPin/InnerFuzzy/Enabled"
+
+#define CONFIG_QUANPIN_CORRECTION_IgnIng "QuanPin/AutoCorrecting/IgnIng"
+#define CONFIG_QUANPIN_CORRECTION_OgnOng "QuanPin/AutoCorrecting/OgnOng"
+#define CONFIG_QUANPIN_CORRECTION_UenUn  "QuanPin/AutoCorrecting/UenUn"
+#define CONFIG_QUANPIN_CORRECTION_ImgIng "QuanPin/AutoCorrecting/ImgIng"
+#define CONFIG_QUANPIN_CORRECTION_IouIu  "QuanPin/AutoCorrecting/IouIu"
+#define CONFIG_QUANPIN_CORRECTION_UeiUi  "QuanPin/AutoCorrecting/UeiUi"
+
+#define CONFIG_KEYBOARD_MODE_SWITCH      "Keyboard/ModeSwitch"
+#define CONFIG_KEYBOARD_PUNCT_SWITCH     "Keyboard/PunctSwitch"
+#define CONFIG_KEYBOARD_PAGE_COMMA       "Keyboard/Page/CommaPeriod"
+#define CONFIG_KEYBOARD_PAGE_MINUS       "Keyboard/Page/MinusEquals"
+#define CONFIG_KEYBOARD_PAGE_BRACKET     "Keyboard/Page/Brackets"
+#define CONFIG_KEYBOARD_CANCEL_BACKSPACE "Keyboard/CancelBackspace"
+#define CONFIG_KEYBOARD_SMARK_PUNCT      "Keyboard/SmartPunct"
+
+#endif // SUNPINYIN_CONFIG_KEYS_H
diff --git a/wrapper/ibus/src/sunpinyin_engine.cpp b/wrapper/ibus/src/sunpinyin_engine.cpp
new file mode 100644 (file)
index 0000000..136f4cc
--- /dev/null
@@ -0,0 +1,640 @@
+/*
+ * Copyright (c) 2009 Kov Chai <tchaikov@gmail.com>
+ *
+ * The contents of this file are subject to the terms of either the GNU Lesser
+ * General Public License Version 2.1 only ("LGPL") or the Common Development and
+ * Distribution License ("CDDL")(collectively, the "License"). You may not use this
+ * file except in compliance with the License. You can obtain a copy of the CDDL at
+ * http://www.opensource.org/licenses/cddl1.php and a copy of the LGPLv2.1 at
+ * http://www.opensource.org/licenses/lgpl-license.php. See the License for the
+ * specific language governing permissions and limitations under the License. When
+ * distributing the software, include this License Header Notice in each file and
+ * include the full text of the License in the License file as well as the
+ * following notice:
+ *
+ * NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND DISTRIBUTION LICENSE
+ * (CDDL)
+ * For Covered Software in this distribution, this License shall be governed by the
+ * laws of the State of California (excluding conflict-of-law provisions).
+ * Any litigation relating to this License shall be subject to the jurisdiction of
+ * the Federal Courts of the Northern District of California and the state courts
+ * of the State of California, with venue lying in Santa Clara County, California.
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by only the CDDL or only
+ * the LGPL Version 2.1, indicate your decision by adding "[Contributor]" elects to
+ * include this software in this distribution under the [CDDL or LGPL Version 2.1]
+ * license." If you don't indicate a single choice of license, a recipient has the
+ * option to distribute your version of this file under either the CDDL or the LGPL
+ * Version 2.1, or to extend the choice of license to its licensees as provided
+ * above. However, if you add LGPL Version 2.1 code and therefore, elected the LGPL
+ * Version 2 license, then the option applies only if the new code is made subject
+ * to such option by the copyright holder.
+ */
+
+#include <cassert>
+#include <algorithm>
+#include <sstream>
+
+#include <sunpinyin.h>
+
+#include "sunpinyin_property.h"
+#include "sunpinyin_lookup_table.h"
+#include "sunpinyin_config.h"
+#include "sunpinyin_config_keys.h"
+#include "imi_ibus_win.h"
+#include "ibus_portable.h"
+#include "sunpinyin_engine.h"
+
+extern ibus::Config config;
+
+SunPinyinEngine::SunPinyinEngine(IBusEngine *engine)
+    : m_engine(engine),
+      m_status_prop(SunPinyinProperty::create_status_prop(engine)),
+      m_letter_prop(SunPinyinProperty::create_letter_prop(engine)),
+      m_punct_prop(SunPinyinProperty::create_punct_prop(engine)),
+      m_wh(NULL),
+      m_pv(NULL),
+      m_hotkey_profile(NULL)
+{
+    CSunpinyinSessionFactory& factory = CSunpinyinSessionFactory::getFactory();
+
+    CSunpinyinSessionFactory::EPyScheme pinyin_scheme =
+        m_config.get_py_scheme(CSunpinyinSessionFactory::QUANPIN);
+    factory.setPinyinScheme(pinyin_scheme);
+    if (pinyin_scheme == CSunpinyinSessionFactory::QUANPIN) {
+        update_fuzzy_pinyins();
+        update_correction_pinyins();
+        update_fuzzy_segs();
+    } else {
+        update_shuangpin_type();
+    }
+    update_user_data_dir();
+    update_punct_mappings();
+
+    factory.setCandiWindowSize(m_config.get(CONFIG_GENERAL_PAGE_SIZE, 10));
+
+    m_pv = factory.createSession();
+    if (!m_pv)
+        return;
+
+    m_hotkey_profile = new CHotkeyProfile();
+    m_pv->setHotkeyProfile(m_hotkey_profile);
+
+    m_wh = new CIBusWinHandler(this);
+    m_pv->attachWinHandler(m_wh);
+
+    m_prop_list = ibus_prop_list_new();
+
+    ibus_prop_list_append(m_prop_list, m_status_prop);
+    ibus_prop_list_append(m_prop_list, m_letter_prop);
+    ibus_prop_list_append(m_prop_list, m_punct_prop);
+    ibus_prop_list_append(m_prop_list, m_setup_prop);
+
+    update_config();
+}
+
+SunPinyinEngine::~SunPinyinEngine()
+{
+    if (m_pv) {
+        CSunpinyinSessionFactory& factory =
+            CSunpinyinSessionFactory::getFactory();
+        factory.destroySession(m_pv);
+    }
+
+    delete m_wh;
+    delete m_hotkey_profile;
+}
+
+static CKeyEvent
+translate_key(guint key_val, guint /*key_code*/, guint modifiers)
+{
+    // XXX: may need to move this logic into CKeyEvent
+    if (key_val > 0x20 && key_val < 0x7f // isprint(key_val) && !isspace(key_val)
+       && !(modifiers & IM_CTRL_MASK)) {
+        // we only care about key_val here
+        return CKeyEvent(key_val, key_val, modifiers);
+    } else {
+        // what matters is key_code, but ibus sents me key_code as key_val
+        return CKeyEvent(key_val, 0, modifiers);
+    }
+}
+
+gboolean
+SunPinyinEngine::process_key_event (guint key_val,
+                                    guint key_code,
+                                    guint modifiers)
+{
+    CKeyEvent key = translate_key(key_val, key_code, modifiers);
+
+    if (!m_pv->getStatusAttrValue(CIBusWinHandler::STATUS_ID_CN)) {
+        // we are in English input mode
+        if (!m_hotkey_profile->isModeSwitchKey(key)) {
+            m_hotkey_profile->rememberLastKey(key);
+            return FALSE;
+        }
+    } else if (m_hotkey_profile->isModeSwitchKey(key)) {
+        m_pv->onKeyEvent(CKeyEvent(IM_VK_ENTER, 0, 0));
+        m_pv->setStatusAttrValue(CIMIWinHandler::STATUS_ID_CN, false);
+        return TRUE;
+    }
+
+    return m_pv->onKeyEvent(key);
+}
+
+void
+SunPinyinEngine::focus_in ()
+{
+    ibus_engine_register_properties(m_engine, m_prop_list);
+    m_pv->updateWindows(CIMIView::PREEDIT_MASK | CIMIView::CANDIDATE_MASK);
+}
+
+void
+SunPinyinEngine::focus_out ()
+{
+    reset();
+}
+
+void
+SunPinyinEngine::reset ()
+{
+    m_pv->updateWindows(m_pv->clearIC());
+}
+
+void
+SunPinyinEngine::enable ()
+{
+    bool is_cn = m_config.is_initial_mode_cn();
+    m_status_prop.update(is_cn);
+    m_pv->setStatusAttrValue(CIMIWinHandler::STATUS_ID_CN, is_cn);
+
+    bool is_letter_full = m_config.is_initial_letter_full();
+    m_letter_prop.update(is_letter_full);
+    m_pv->setStatusAttrValue(CIMIWinHandler::STATUS_ID_FULLSYMBOL, is_letter_full);
+
+    bool is_punct_full = m_config.is_initial_punct_full();
+    m_punct_prop.update(is_punct_full);
+    m_pv->setStatusAttrValue(CIMIWinHandler::STATUS_ID_FULLPUNC, is_punct_full);
+}
+
+void
+SunPinyinEngine::disable ()
+{
+}
+
+void
+SunPinyinEngine::page_up ()
+{
+    m_pv->onCandidatePageRequest(-1, true /* relative */);
+}
+
+void
+SunPinyinEngine::page_down ()
+{
+    m_pv->onCandidatePageRequest(1, true /* relative */);
+}
+
+void
+SunPinyinEngine::property_activate (const std::string& property, unsigned /*state*/)
+{
+    if (m_status_prop.toggle(property)) {
+        m_pv->setStatusAttrValue(CIMIWinHandler::STATUS_ID_CN,
+                                 m_status_prop.state());
+    } else if (m_letter_prop.toggle(property)) {
+        m_pv->setStatusAttrValue(CIMIWinHandler::STATUS_ID_FULLSYMBOL,
+                                 m_letter_prop.state());
+    } else if (m_punct_prop.toggle(property)) {
+        m_pv->setStatusAttrValue(CIMIWinHandler::STATUS_ID_FULLPUNC,
+                                 m_punct_prop.state());
+    } else {
+        // try to launch the setup UI
+        m_setup_prop.launch(property);
+    }
+}
+
+void
+SunPinyinEngine::candidate_clicked (guint index)
+{
+    m_pv->onCandidateSelectRequest(index);
+}
+
+void
+SunPinyinEngine::cursor_up ()
+{
+    if (m_lookup_table.cursor_up()) {
+        update_lookup_table();
+    }
+}
+
+void
+SunPinyinEngine::cursor_down ()
+{
+    if (m_lookup_table.cursor_down()) {
+        update_lookup_table();
+    }
+}
+
+bool
+SunPinyinEngine::onConfigChanged(const COptionEvent& event)
+{
+    if (event.name == CONFIG_GENERAL_MEMORY_POWER) {
+        update_history_power();
+    } else if (event.name == CONFIG_GENERAL_PAGE_SIZE) {
+        update_cand_window_size();
+    } else if (event.name == CONFIG_GENERAL_CHARSET_LEVEL) {
+        update_charset_level();
+    } else if (event.name == CONFIG_GENERAL_MAX_BEST) {
+        update_max_best();
+    } else if (event.name == CONFIG_GENERAL_MAX_TAIL_CANDIDATE) {
+        update_max_tail_candidate();
+    } else if (event.name == CONFIG_KEYBOARD_MODE_SWITCH) {
+        update_mode_key();
+    } else if (event.name == CONFIG_KEYBOARD_PUNCT_SWITCH) {
+        update_punct_key();
+    } else if (event.name == CONFIG_KEYBOARD_PAGE_COMMA) {
+        update_page_key_comma();
+    } else if (event.name == CONFIG_KEYBOARD_PAGE_MINUS) {
+        update_page_key_minus();
+    } else if (event.name == CONFIG_KEYBOARD_PAGE_BRACKET) {
+        update_page_key_bracket();
+    } else if (event.name == CONFIG_QUANPIN_FUZZYSEGS_ENABLED) {
+        update_fuzzy_segs();
+    } else if (event.name == CONFIG_KEYBOARD_CANCEL_BACKSPACE) {
+        update_cancel_with_backspace();
+    } else if (event.name == CONFIG_KEYBOARD_SMARK_PUNCT) {
+        update_smart_punc();
+    }
+
+    return false;
+}
+
+void
+SunPinyinEngine::update_config()
+{
+    update_history_power();
+    update_cand_window_size();
+    update_max_best();
+    update_max_tail_candidate();
+    update_charset_level();
+    update_page_key_minus();
+    update_page_key_comma();
+    update_page_key_bracket();
+    update_mode_key();
+    update_punct_key();
+    update_cancel_with_backspace();
+    update_smart_punc();
+    update_punct_mappings();
+    update_candi_delete_key();
+    // update_quanpin_config();
+    // update_shuangpin_config();
+}
+
+void
+SunPinyinEngine::commit_string (const std::wstring& str)
+{
+    IBusText *text;
+    text = ibus_text_new_from_ucs4((const gunichar*) str.c_str());
+    ibus_engine_commit_text(m_engine, text);
+}
+
+void
+SunPinyinEngine::update_candidates(const ICandidateList& cl)
+{
+    if (m_lookup_table.update_candidates(cl) > 0)
+        update_lookup_table();
+    else
+        ibus_engine_hide_lookup_table (m_engine);
+}
+
+void
+SunPinyinEngine::update_lookup_table()
+{
+    ibus_engine_update_lookup_table(m_engine, m_lookup_table, TRUE);
+}
+
+bool
+SunPinyinEngine::is_valid() const
+{
+    return m_pv != NULL;
+}
+
+static int
+find_embed_preedit_pos(const IPreeditString& preedit)
+{
+    int mask = IPreeditString::USER_CHOICE & IPreeditString::HANZI_CHAR;
+    for (size_t i = 0; i < preedit.charTypeSize(); i++) {
+        if ((preedit.charTypeAt(i) & mask) == 0) {
+            return i;
+        }
+    }
+    return preedit.charTypeSize();
+}
+
+enum {ORANGE = 0xE76F00, GRAY_BLUE = 0x35556B, WHITE = 0xFFFFFF,
+      BLACK = 0x000000};
+
+void
+SunPinyinEngine::update_preedit_string(const IPreeditString& preedit)
+{
+    if (preedit.size() > 0) {
+        wstring wstr(preedit.string());
+        int embed_pos = find_embed_preedit_pos(preedit);
+        wstring embed_wstr = wstr.substr(0, embed_pos);
+        wstring preedit_wstr = wstr.substr(embed_pos);
+        const gunichar* embed_cstr = (const gunichar*) embed_wstr.c_str();
+        const gunichar* preedit_cstr = (const gunichar*) preedit_wstr.c_str();
+        IBusText* preedit_text = ibus_text_new_from_ucs4(preedit_cstr);
+        int caret = preedit.caret() - embed_pos;
+
+        if (preedit.caret() < preedit.size()) {
+            ibus_text_append_attribute(preedit_text, IBUS_ATTR_TYPE_FOREGROUND,
+                                       WHITE, caret, preedit_wstr.size());
+            ibus_text_append_attribute(preedit_text, IBUS_ATTR_TYPE_BACKGROUND,
+                                       GRAY_BLUE, caret, preedit_wstr.size());
+        }
+        ibus_engine_update_auxiliary_text(m_engine, preedit_text, TRUE);
+
+        ibus_engine_update_preedit_text(m_engine,
+                                        ibus_text_new_from_ucs4(embed_cstr),
+                                        preedit.caret(), TRUE);
+
+    } else {
+        ibus_engine_hide_auxiliary_text(m_engine);
+        ibus_engine_hide_preedit_text(m_engine);
+    }
+}
+
+void
+SunPinyinEngine::update_status_property(bool cn)
+{
+    m_status_prop.update(cn);
+}
+
+void
+SunPinyinEngine::update_punct_property(bool full)
+{
+    m_punct_prop.update(full);
+}
+
+void
+SunPinyinEngine::update_letter_property(bool full)
+{
+    m_letter_prop.update(full);
+}
+
+void
+SunPinyinEngine::update_history_power()
+{
+    unsigned power = m_config.get(CONFIG_GENERAL_MEMORY_POWER, 3);
+    CIMIContext* ic = m_pv->getIC();
+    assert(ic);
+    ic->setHistoryPower(power);
+}
+
+void
+SunPinyinEngine::update_charset_level()
+{
+    unsigned charset = m_config.get(CONFIG_GENERAL_CHARSET_LEVEL, GBK);
+    CIMIContext* ic = m_pv->getIC();
+    assert(ic);
+    charset &= 3;               // charset can only be 0,1,2 or 3
+    ic->setCharsetLevel(charset);
+}
+
+void
+SunPinyinEngine::update_cand_window_size()
+{
+    unsigned size = m_config.get(CONFIG_GENERAL_PAGE_SIZE, 10);
+    m_pv->setCandiWindowSize(size);
+}
+
+void
+SunPinyinEngine::update_mode_key()
+{
+    std::string mode_switch("Shift");
+    mode_switch = m_config.get(CONFIG_KEYBOARD_MODE_SWITCH, mode_switch);
+
+    CKeyEvent shift_l  (IM_VK_SHIFT_L, 0, IM_SHIFT_MASK|IM_RELEASE_MASK);
+    CKeyEvent shift_r  (IM_VK_SHIFT_R, 0, IM_SHIFT_MASK|IM_RELEASE_MASK);
+    CKeyEvent control_l(IM_VK_CONTROL_L, 0, IM_CTRL_MASK|IM_RELEASE_MASK);
+    CKeyEvent control_r(IM_VK_CONTROL_R, 0, IM_CTRL_MASK|IM_RELEASE_MASK);
+
+    if (mode_switch == "Shift") {
+        m_hotkey_profile->removeModeSwitchKey(control_l);
+        m_hotkey_profile->removeModeSwitchKey(control_r);
+        m_hotkey_profile->addModeSwitchKey(shift_l);
+        m_hotkey_profile->addModeSwitchKey(shift_r);
+    } else if (mode_switch == "Control") {
+        m_hotkey_profile->removeModeSwitchKey(shift_l);
+        m_hotkey_profile->removeModeSwitchKey(shift_r);
+        m_hotkey_profile->addModeSwitchKey(control_l);
+        m_hotkey_profile->addModeSwitchKey(control_r);
+    }
+}
+
+void
+SunPinyinEngine::update_punct_key()
+{
+    std::string punct_switch("ControlComma");
+    punct_switch = m_config.get(CONFIG_KEYBOARD_PUNCT_SWITCH, punct_switch);
+    if (punct_switch == "ControlComma") {
+        m_hotkey_profile->setPunctSwitchKey(CKeyEvent(IM_VK_COMMA, 0, IM_CTRL_MASK));
+    } else if (punct_switch == "ControlPeriod") {
+        m_hotkey_profile->setPunctSwitchKey(CKeyEvent(IM_VK_PERIOD, 0, IM_CTRL_MASK));
+    }
+}
+
+void
+SunPinyinEngine::update_page_key_minus()
+{
+    update_page_key(CONFIG_KEYBOARD_PAGE_MINUS, false,
+                    IM_VK_MINUS, IM_VK_EQUALS);
+}
+
+void
+SunPinyinEngine::update_page_key_comma()
+{
+    update_page_key(CONFIG_KEYBOARD_PAGE_COMMA, false,
+                    IM_VK_COMMA, IM_VK_PERIOD);
+}
+
+void
+SunPinyinEngine::update_page_key_bracket()
+{
+    update_page_key(CONFIG_KEYBOARD_PAGE_BRACKET, false,
+                    IM_VK_OPEN_BRACKET, IM_VK_CLOSE_BRACKET);
+}
+
+void
+SunPinyinEngine::update_page_key(const char* conf_key, bool default_val,
+                            unsigned page_up, unsigned page_down)
+{
+    bool enabled = m_config.get(conf_key, default_val);
+
+    if (enabled) {
+        m_hotkey_profile->addPageUpKey(CKeyEvent(page_up, 0));
+        m_hotkey_profile->addPageDownKey(CKeyEvent(page_down, 0));
+    } else {
+        m_hotkey_profile->removePageUpKey(CKeyEvent(page_up, 0));
+        m_hotkey_profile->removePageDownKey(CKeyEvent(page_down, 0));
+    }
+}
+
+void
+SunPinyinEngine::update_cancel_with_backspace()
+{
+    bool enabled = m_config.get(CONFIG_KEYBOARD_CANCEL_BACKSPACE, true);
+    m_pv->setCancelOnBackspace(enabled);
+}
+
+void
+SunPinyinEngine::update_smart_punc()
+{
+    m_pv->setSmartPunct(m_config.get(CONFIG_KEYBOARD_SMARK_PUNCT, true));
+}
+
+void
+SunPinyinEngine::update_max_best()
+{
+    if (m_pv->getIC() == NULL) {
+        return;
+    }
+    int oldval = (int) m_pv->getIC()->getMaxBest();
+    m_pv->getIC()->setMaxBest(m_config.get(CONFIG_GENERAL_MAX_BEST, oldval));
+}
+
+void
+SunPinyinEngine::update_max_tail_candidate()
+{
+    if (m_pv->getIC() == NULL) {
+        return;
+    }
+    int oldval = (int) m_pv->getIC()->getMaxTailCandidateNum();
+    m_pv->getIC()->setMaxTailCandidateNum(
+        m_config.get(CONFIG_GENERAL_MAX_TAIL_CANDIDATE, oldval));
+}
+
+string_pairs parse_pairs(const std::vector<std::string>& strings)
+{
+    string_pairs pairs;
+    for (std::vector<std::string>::const_iterator pair = strings.begin();
+         pair != strings.end(); ++pair) {
+
+        std::string::size_type found = pair->find(':');
+        if (found == pair->npos || pair->length() < 3)
+            continue;
+        if (found == 0 && (*pair)[0] == ':')
+            found = 1;
+
+        pairs.push_back(make_pair(pair->substr(0, found),
+                                  pair->substr(found+1)));
+    }
+    return pairs;
+}
+
+// the mappings in default_pairs will override the ones in user_pairs
+string_pairs merge_pairs(const string_pairs& default_pairs,
+                         const string_pairs& user_pairs)
+{
+    typedef std::map<std::string, int> Indexes;
+    Indexes indexes;
+    int index = 0;
+    for (string_pairs::const_iterator it = default_pairs.begin();
+         it != default_pairs.end(); ++it, ++index) {
+        Indexes::iterator found = indexes.find(it->first);
+        if (found == indexes.end()) {
+            indexes[it->first] = index;
+        } else {
+            // it is a paired punct.
+            indexes[it->first] = -found->second;
+        }
+    }
+    string_pairs result(default_pairs);
+    for (string_pairs::const_iterator it = user_pairs.begin();
+         it != user_pairs.end(); ++it) {
+        Indexes::iterator found = indexes.find(it->first);
+        if (found == indexes.end()) {
+            result.push_back(*it);
+        } else if (found->second >= 0) {
+            result[found->second] = *it;
+        } else {
+            // it is a paired punct,
+            // but we don't support this kind of mapping yet,
+            // so quietly ignore it.
+        }
+    }
+    return result;
+}
+
+void
+SunPinyinEngine::update_punct_mappings()
+{
+    CSimplifiedChinesePolicy& policy = ASimplifiedChinesePolicy::instance();
+    if (m_config.get(PINYIN_PUNCTMAPPING_ENABLED, false)) {
+        std::vector<std::string> mappings;
+        mappings = m_config.get(PINYIN_PUNCTMAPPING_MAPPINGS, mappings);
+        string_pairs pairs(merge_pairs(policy.getDefaultPunctMapping(),
+                                       parse_pairs(mappings)));
+        policy.setPunctMapping(pairs);
+    }
+}
+
+void
+SunPinyinEngine::update_user_data_dir()
+{
+    std::stringstream user_data_dir;
+    user_data_dir << g_get_home_dir()
+                  << G_DIR_SEPARATOR_S << ".sunpinyin";
+    ASimplifiedChinesePolicy::instance().setUserDataDir(user_data_dir.str());
+}
+
+void
+SunPinyinEngine::update_fuzzy_pinyins()
+{
+    bool enabled = m_config.get(QUANPIN_FUZZY_ENABLED, false);
+    AQuanpinSchemePolicy::instance().setFuzzyForwarding(enabled);
+    AShuangpinSchemePolicy::instance().setFuzzyForwarding(enabled);
+    if (!enabled)
+        return;
+    std::vector<std::string> fuzzy_pinyins;
+    fuzzy_pinyins = m_config.get(QUANPIN_FUZZY_PINYINS, fuzzy_pinyins);
+    AQuanpinSchemePolicy::instance().setFuzzyPinyinPairs(parse_pairs(fuzzy_pinyins));
+    AShuangpinSchemePolicy::instance().setFuzzyPinyinPairs(parse_pairs(fuzzy_pinyins));
+}
+
+void
+SunPinyinEngine::update_correction_pinyins()
+{
+    bool enabled = m_config.get(QUANPIN_AUTOCORRECTION_ENABLED, false);
+    AQuanpinSchemePolicy::instance().setAutoCorrecting(enabled);
+    if (!enabled)
+        return;
+    std::vector<std::string> correction_pinyins;
+    correction_pinyins = m_config.get(QUANPIN_AUTOCORRECTION_PINYINS, correction_pinyins);
+    AQuanpinSchemePolicy::instance().setAutoCorrectionPairs(parse_pairs(correction_pinyins));
+}
+
+void
+SunPinyinEngine::update_fuzzy_segs()
+{
+    bool enable_fuzzy_segs = m_config.get(CONFIG_QUANPIN_FUZZYSEGS_ENABLED, false);
+    AQuanpinSchemePolicy::instance().setFuzzySegmentation(enable_fuzzy_segs);
+    bool enable_inner_fuzzy = m_config.get(CONFIG_QUANPIN_INNERFUZZY_ENABLED, false);
+    AQuanpinSchemePolicy::instance().setInnerFuzzySegmentation(CONFIG_QUANPIN_INNERFUZZY_ENABLED);
+}
+
+void
+SunPinyinEngine::update_shuangpin_type()
+{
+    EShuangpinType shuangpin_type = MS2003;
+    shuangpin_type = (EShuangpinType) m_config.get(SHUANGPIN_TYPE, (int) shuangpin_type);
+    AShuangpinSchemePolicy::instance().setShuangpinType(shuangpin_type);
+}
+
+void
+SunPinyinEngine::update_candi_delete_key()
+{
+    /* FIXME: need to get candi_delete_key from user's configuration */
+    m_hotkey_profile->setCandiDeleteKey(CKeyEvent(0, 0, IM_ALT_MASK));
+}
diff --git a/wrapper/ibus/src/sunpinyin_engine.h b/wrapper/ibus/src/sunpinyin_engine.h
new file mode 100644 (file)
index 0000000..9bfb4cb
--- /dev/null
@@ -0,0 +1,135 @@
+/*
+ * Copyright (c) 2009 Kov Chai <tchaikov@gmail.com>
+ *
+ * The contents of this file are subject to the terms of either the GNU Lesser
+ * General Public License Version 2.1 only ("LGPL") or the Common Development and
+ * Distribution License ("CDDL")(collectively, the "License"). You may not use this
+ * file except in compliance with the License. You can obtain a copy of the CDDL at
+ * http://www.opensource.org/licenses/cddl1.php and a copy of the LGPLv2.1 at
+ * http://www.opensource.org/licenses/lgpl-license.php. See the License for the
+ * specific language governing permissions and limitations under the License. When
+ * distributing the software, include this License Header Notice in each file and
+ * include the full text of the License in the License file as well as the
+ * following notice:
+ *
+ * NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND DISTRIBUTION LICENSE
+ * (CDDL)
+ * For Covered Software in this distribution, this License shall be governed by the
+ * laws of the State of California (excluding conflict-of-law provisions).
+ * Any litigation relating to this License shall be subject to the jurisdiction of
+ * the Federal Courts of the Northern District of California and the state courts
+ * of the State of California, with venue lying in Santa Clara County, California.
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by only the CDDL or only
+ * the LGPL Version 2.1, indicate your decision by adding "[Contributor]" elects to
+ * include this software in this distribution under the [CDDL or LGPL Version 2.1]
+ * license." If you don't indicate a single choice of license, a recipient has the
+ * option to distribute your version of this file under either the CDDL or the LGPL
+ * Version 2.1, or to extend the choice of license to its licensees as provided
+ * above. However, if you add LGPL Version 2.1 code and therefore, elected the LGPL
+ * Version 2 license, then the option applies only if the new code is made subject
+ * to such option by the copyright holder.
+ */
+
+#ifndef SUNPINYIN_ENGINE_H
+#define SUNPINYIN_ENGINE_H
+
+#include <string>
+#include <ibus.h>
+#include <ime-core/imi_option_event.h>
+#include "sunpinyin_config.h"
+#include "sunpinyin_property.h"
+#include "sunpinyin_lookup_table.h"
+
+class ICandidateList;
+class IPreeditString;
+class CIBusWinHandler;
+class CIMIView;
+class CHotkeyProfile;
+
+class SunPinyinEngine : public IConfigurable
+{
+public:
+    SunPinyinEngine(IBusEngine *);
+    virtual ~SunPinyinEngine();
+
+    void init ();
+    void destroy ();
+    /* @{ */
+    gboolean process_key_event (guint key_val, guint key_code, guint modifiers);
+    void focus_in ();
+    void focus_out ();
+    void reset ();
+    void enable ();
+    void disable ();
+    void page_up ();
+    void page_down ();
+    void cursor_up ();
+    void cursor_down ();
+    void commit_string (const std::wstring&);
+    void property_activate (const std::string& name, unsigned state = PROP_STATE_UNCHECKED);
+    void candidate_clicked (guint index);
+    /* @} */
+
+    /* helpers for @ref CIBusWinHandler */
+    /* @{ */
+    void update_candidates(const ICandidateList&);
+    void update_preedit_string(const IPreeditString&);
+    void update_status_property(bool);
+    void update_punct_property(bool);
+    void update_letter_property(bool);
+    /* @} */
+
+    /* for implemented class */
+    bool is_valid() const;
+
+    virtual bool onConfigChanged(const COptionEvent& event);
+
+private:
+    void update_config();
+    void update_history_power();
+    void update_cand_window_size();
+    void update_mode_key();
+    void update_punct_key();
+    void update_page_key_minus();
+    void update_page_key_comma();
+    void update_page_key_bracket();
+    void update_page_key(const char* conf_key, bool default_val,
+                         unsigned page_up, unsigned page_down);
+    void update_candi_delete_key();
+    void update_cancel_with_backspace();
+    void update_smart_punc();
+    void update_max_best();
+    void update_max_tail_candidate();
+
+    void update_charset_level();
+    void update_user_data_dir();
+    void update_punct_mappings();
+    void update_fuzzy_pinyins();
+    void update_correction_pinyins();
+    void update_fuzzy_segs();
+    void update_shuangpin_type();
+
+    void update_lookup_table();
+
+private:
+    ibus::Engine           m_engine;
+    ibus::PropList         m_prop_list;
+
+    SunPinyinProperty m_status_prop;
+    SunPinyinProperty m_letter_prop;
+    SunPinyinProperty m_punct_prop;
+    SetupLauncher     m_setup_prop;
+
+    SunPinyinLookupTable m_lookup_table;
+
+    CIBusWinHandler *m_wh;
+    CIMIView        *m_pv;
+    CHotkeyProfile  *m_hotkey_profile;
+
+    SunPinyinConfig  m_config;
+};
+
+#endif // SUNPINYIN_ENGINE_H
diff --git a/wrapper/ibus/src/sunpinyin_engine_proxy.cpp b/wrapper/ibus/src/sunpinyin_engine_proxy.cpp
new file mode 100644 (file)
index 0000000..9774bd3
--- /dev/null
@@ -0,0 +1,131 @@
+/*
+ * Copyright (c) 2009 Kov Chai <tchaikov@gmail.com>
+ *
+ * The contents of this file are subject to the terms of either the GNU Lesser
+ * General Public License Version 2.1 only ("LGPL") or the Common Development and
+ * Distribution License ("CDDL")(collectively, the "License"). You may not use this
+ * file except in compliance with the License. You can obtain a copy of the CDDL at
+ * http://www.opensource.org/licenses/cddl1.php and a copy of the LGPLv2.1 at
+ * http://www.opensource.org/licenses/lgpl-license.php. See the License for the 
+ * specific language governing permissions and limitations under the License. When
+ * distributing the software, include this License Header Notice in each file and
+ * include the full text of the License in the License file as well as the
+ * following notice:
+ * 
+ * NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND DISTRIBUTION LICENSE
+ * (CDDL)
+ * For Covered Software in this distribution, this License shall be governed by the
+ * laws of the State of California (excluding conflict-of-law provisions).
+ * Any litigation relating to this License shall be subject to the jurisdiction of
+ * the Federal Courts of the Northern District of California and the state courts
+ * of the State of California, with venue lying in Santa Clara County, California.
+ * 
+ * Contributor(s):
+ * 
+ * If you wish your version of this file to be governed by only the CDDL or only
+ * the LGPL Version 2.1, indicate your decision by adding "[Contributor]" elects to
+ * include this software in this distribution under the [CDDL or LGPL Version 2.1]
+ * license." If you don't indicate a single choice of license, a recipient has the
+ * option to distribute your version of this file under either the CDDL or the LGPL
+ * Version 2.1, or to extend the choice of license to its licensees as provided
+ * above. However, if you add LGPL Version 2.1 code and therefore, elected the LGPL
+ * Version 2 license, then the option applies only if the new code is made subject
+ * to such option by the copyright holder. 
+ */
+
+#include "sunpinyin_engine_proxy.h"
+#include "sunpinyin_engine.h"
+
+#define IBUS_SUNPINYIN_ENGINE(obj) \
+    (G_TYPE_CHECK_INSTANCE_CAST ((obj), IBUS_TYPE_SUNPINYIN_ENGINE, IBusSunPinyinEngine))
+
+#define IBUS_IS_SUNPINYIN_ENGINE(obj) \
+    (G_TYPE_CHECK_INSTANCE_TYPE ((obj), IBUS_TYPE_SUNPINYIN_ENGINE))
+
+#define IBUS_SUNPINYIN_ENGINE_GET_CLASS(obj) \
+    (G_TYPE_INSTANCE_GET_CLASS ((obj), IBUS_TYPE_SUNPINYIN_ENGINE, IBusSunPinyinEngineClass))
+
+extern IBusEngineClass *parent_class;
+
+struct IBusSunPinyinEngine {
+    IBusEngine parent;
+
+    /* members */
+    SunPinyinEngine *engine;
+};
+
+#define GET_PY_ENGINE(__engine__)               \
+    (((IBusSunPinyinEngine *)(__engine__))->engine)
+
+
+void
+ibus_sunpinyin_engine_init(IBusEngine *py_engine)
+{
+    if (g_object_is_floating (py_engine))
+        g_object_ref_sink (py_engine);
+    GET_PY_ENGINE(py_engine) = new SunPinyinEngine(IBUS_ENGINE(py_engine));
+}
+
+void
+ibus_sunpinyin_engine_destroy(IBusEngine *py_engine)
+{
+    
+    delete GET_PY_ENGINE(py_engine);
+    GET_PY_ENGINE(py_engine) = NULL;
+    IBUS_OBJECT_CLASS (parent_class)->destroy( IBUS_OBJECT(py_engine));
+}
+
+gboolean
+ibus_sunpinyin_engine_process_key_event(IBusEngine *engine,
+                                        guint keyval,
+                                        guint keycode,
+                                        guint modifiers)
+{
+    if (GET_PY_ENGINE(engine)->is_valid()) {
+        return GET_PY_ENGINE(engine)->process_key_event(keyval, keycode, modifiers) ?
+            TRUE : FALSE;
+    } else {
+        return FALSE;
+    }
+}
+
+void
+ibus_sunpinyin_engine_property_activate (IBusEngine *engine,
+                                         const gchar *prop_name,
+                                         guint prop_state)
+{
+    if (GET_PY_ENGINE(engine)->is_valid()) {
+        GET_PY_ENGINE(engine)->property_activate(prop_name, prop_state);
+    }
+}
+
+void ibus_sunpinyin_engine_candidate_clicked (IBusEngine *engine,
+                                              guint index,
+                                              guint button,
+                                              guint state)
+{
+    GET_PY_ENGINE(engine)->candidate_clicked(index);
+}
+
+#define IMPL_WITH(name)                                   \
+    void                                                  \
+    ibus_sunpinyin_engine_##name (IBusEngine *engine)     \
+    {                                                     \
+        IBusSunPinyinEngine *py_engine =                  \
+            (IBusSunPinyinEngine *) engine;               \
+        if (py_engine->engine->is_valid()) {              \
+            py_engine->engine->name();                    \
+        }                                                 \
+        parent_class->name (engine);                      \
+    }
+
+IMPL_WITH(focus_in)
+IMPL_WITH(focus_out)
+IMPL_WITH(reset)
+IMPL_WITH(enable)
+IMPL_WITH(disable)
+IMPL_WITH(page_up)
+IMPL_WITH(page_down)
+IMPL_WITH(cursor_up)
+IMPL_WITH(cursor_down)
+
diff --git a/wrapper/ibus/src/sunpinyin_engine_proxy.h b/wrapper/ibus/src/sunpinyin_engine_proxy.h
new file mode 100644 (file)
index 0000000..feb1258
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2009 Kov Chai <tchaikov@gmail.com>
+ *
+ * The contents of this file are subject to the terms of either the GNU Lesser
+ * General Public License Version 2.1 only ("LGPL") or the Common Development and
+ * Distribution License ("CDDL")(collectively, the "License"). You may not use this
+ * file except in compliance with the License. You can obtain a copy of the CDDL at
+ * http://www.opensource.org/licenses/cddl1.php and a copy of the LGPLv2.1 at
+ * http://www.opensource.org/licenses/lgpl-license.php. See the License for the 
+ * specific language governing permissions and limitations under the License. When
+ * distributing the software, include this License Header Notice in each file and
+ * include the full text of the License in the License file as well as the
+ * following notice:
+ * 
+ * NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND DISTRIBUTION LICENSE
+ * (CDDL)
+ * For Covered Software in this distribution, this License shall be governed by the
+ * laws of the State of California (excluding conflict-of-law provisions).
+ * Any litigation relating to this License shall be subject to the jurisdiction of
+ * the Federal Courts of the Northern District of California and the state courts
+ * of the State of California, with venue lying in Santa Clara County, California.
+ * 
+ * Contributor(s):
+ * 
+ * If you wish your version of this file to be governed by only the CDDL or only
+ * the LGPL Version 2.1, indicate your decision by adding "[Contributor]" elects to
+ * include this software in this distribution under the [CDDL or LGPL Version 2.1]
+ * license." If you don't indicate a single choice of license, a recipient has the
+ * option to distribute your version of this file under either the CDDL or the LGPL
+ * Version 2.1, or to extend the choice of license to its licensees as provided
+ * above. However, if you add LGPL Version 2.1 code and therefore, elected the LGPL
+ * Version 2 license, then the option applies only if the new code is made subject
+ * to such option by the copyright holder. 
+ */
+
+#ifndef SUNPINYIN_ENGINE_PROXY_H
+#define SUNPINYIN_ENGINE_PROXY_H
+
+#include <ibus.h>
+
+extern "C" {
+
+void ibus_sunpinyin_engine_init(IBusEngine *engine);
+void ibus_sunpinyin_engine_destroy(IBusEngine *engine);
+gboolean ibus_sunpinyin_engine_process_key_event(IBusEngine *engine,
+                                                 guint keyval,
+                                                 guint keycode,
+                                                 guint modifiers);
+void ibus_sunpinyin_engine_focus_in(IBusEngine *engine);
+void ibus_sunpinyin_engine_focus_out(IBusEngine *engine);
+void ibus_sunpinyin_engine_reset(IBusEngine *engine);
+void ibus_sunpinyin_engine_enable(IBusEngine *engine);
+void ibus_sunpinyin_engine_disable(IBusEngine *engine);
+void ibus_sunpinyin_engine_focus_in(IBusEngine *engine);
+void ibus_sunpinyin_engine_focus_out(IBusEngine *engine);
+void ibus_sunpinyin_engine_page_up(IBusEngine *engine);
+void ibus_sunpinyin_engine_page_down(IBusEngine *engine);
+void ibus_sunpinyin_engine_cursor_up(IBusEngine *engine);
+void ibus_sunpinyin_engine_cursor_down(IBusEngine *engine);
+void ibus_sunpinyin_engine_property_activate (IBusEngine *engine,
+                                              const gchar *prop_name,
+                                              guint prop_state);
+void ibus_sunpinyin_engine_candidate_clicked(IBusEngine *engine,
+                                             guint index,
+                                             guint button,
+                                             guint state);
+};
+
+#endif // SUNPINYIN_ENGINE_PROXY_H
diff --git a/wrapper/ibus/src/sunpinyin_lookup_table.cpp b/wrapper/ibus/src/sunpinyin_lookup_table.cpp
new file mode 100644 (file)
index 0000000..89a68e1
--- /dev/null
@@ -0,0 +1,125 @@
+/*
+ * Copyright (c) 2009 Kov Chai <tchaikov@gmail.com>
+ *
+ * The contents of this file are subject to the terms of either the GNU Lesser
+ * General Public License Version 2.1 only ("LGPL") or the Common Development and
+ * Distribution License ("CDDL")(collectively, the "License"). You may not use this
+ * file except in compliance with the License. You can obtain a copy of the CDDL at
+ * http://www.opensource.org/licenses/cddl1.php and a copy of the LGPLv2.1 at
+ * http://www.opensource.org/licenses/lgpl-license.php. See the License for the 
+ * specific language governing permissions and limitations under the License. When
+ * distributing the software, include this License Header Notice in each file and
+ * include the full text of the License in the License file as well as the
+ * following notice:
+ * 
+ * NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND DISTRIBUTION LICENSE
+ * (CDDL)
+ * For Covered Software in this distribution, this License shall be governed by the
+ * laws of the State of California (excluding conflict-of-law provisions).
+ * Any litigation relating to this License shall be subject to the jurisdiction of
+ * the Federal Courts of the Northern District of California and the state courts
+ * of the State of California, with venue lying in Santa Clara County, California.
+ * 
+ * Contributor(s):
+ * 
+ * If you wish your version of this file to be governed by only the CDDL or only
+ * the LGPL Version 2.1, indicate your decision by adding "[Contributor]" elects to
+ * include this software in this distribution under the [CDDL or LGPL Version 2.1]
+ * license." If you don't indicate a single choice of license, a recipient has the
+ * option to distribute your version of this file under either the CDDL or the LGPL
+ * Version 2.1, or to extend the choice of license to its licensees as provided
+ * above. However, if you add LGPL Version 2.1 code and therefore, elected the LGPL
+ * Version 2 license, then the option applies only if the new code is made subject
+ * to such option by the copyright holder. 
+ */
+
+#include <sunpinyin.h>
+#include "ibus_portable.h"
+#include "sunpinyin_lookup_table.h"
+
+SunPinyinLookupTable::SunPinyinLookupTable() 
+    : Pointer<IBusLookupTable>(ibus_lookup_table_new (9, 0, TRUE, TRUE))
+{}
+
+SunPinyinLookupTable::~SunPinyinLookupTable()
+{
+}
+
+int
+SunPinyinLookupTable::update_candidates(const ICandidateList& cl)
+{
+    const int size = cl.size();
+    if (size <= 0)
+        return size;
+    
+    const int total = cl.total();
+    // total is the number of items in all pages, while size is the number of items in the current
+    // page (only these items are included in the candidate list).
+    ibus_lookup_table_set_page_size(*this, size);
+    // We are updating the current page only, thus some ugly hacks are needed...
+    ibus_lookup_table_clear(*this);
+    int page_start = get_current_page_start(), cur_total = 0;
+    // Dummy candidates are inserted when they are not in the current page.
+    // Maybe we can share these candidates (but what if someone else changes the attributes?)
+    for (; cur_total < page_start; ++cur_total)
+       ibus_lookup_table_append_candidate(*this, ibus_text_new_from_static_string(""));
+    for (int i = 0; i < size; ++i) {
+       const TWCHAR* cand = cl.candiString(i);
+       if (cand && cl.candiSize(i)) {
+           ibus::Text text(ibus_text_new_from_ucs4(cand));
+           decorate_candidate(text, cl.candiType(i));
+           ibus_lookup_table_append_candidate(*this, text);
+           ++cur_total;
+       } else break; // I think this shouldn't happen...
+    }
+    for (; cur_total < total; ++cur_total)
+       ibus_lookup_table_append_candidate(*this, ibus_text_new_from_static_string(""));
+
+    return size;
+    //ibus_lookup_table_set_cursor_pos (m_lookup_table, index);
+}
+
+bool
+SunPinyinLookupTable::cursor_up()
+{
+    ibus_lookup_table_cursor_down(*this);
+    return true;
+}
+
+bool
+SunPinyinLookupTable::cursor_down()
+{
+    ibus_lookup_table_cursor_down(*this);
+    return true;
+}
+
+size_t
+SunPinyinLookupTable::get_cursor_pos() const
+{
+    return ibus_lookup_table_get_cursor_pos(*this);
+}
+
+void
+SunPinyinLookupTable::decorate_candidate(ibus::Text text, int type)
+{
+    switch (type) {
+    case ICandidateList::BEST_WORD:
+        ibus_text_append_attribute (text, IBUS_ATTR_TYPE_FOREGROUND,
+                                    0x003E6B8A, 0, -1);
+        ibus_text_append_attribute (text, IBUS_ATTR_TYPE_UNDERLINE,
+                                    IBUS_ATTR_UNDERLINE_SINGLE, 0, -1);
+        break;
+    case ICandidateList::USER_SELECTED_WORD:
+        break;
+    case ICandidateList::NORMAL_WORD:
+        break;
+    }
+}
+
+int
+SunPinyinLookupTable::get_current_page_start() const
+{
+    guint cursor = ibus_lookup_table_get_cursor_pos(*this);
+    guint cursor_in_page = ibus_lookup_table_get_cursor_in_page(*this);
+    return cursor - cursor_in_page;
+}
diff --git a/wrapper/ibus/src/sunpinyin_lookup_table.h b/wrapper/ibus/src/sunpinyin_lookup_table.h
new file mode 100644 (file)
index 0000000..9c8f5a9
--- /dev/null
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2009 Kov Chai <tchaikov@gmail.com>
+ *
+ * The contents of this file are subject to the terms of either the GNU Lesser
+ * General Public License Version 2.1 only ("LGPL") or the Common Development and
+ * Distribution License ("CDDL")(collectively, the "License"). You may not use this
+ * file except in compliance with the License. You can obtain a copy of the CDDL at
+ * http://www.opensource.org/licenses/cddl1.php and a copy of the LGPLv2.1 at
+ * http://www.opensource.org/licenses/lgpl-license.php. See the License for the
+ * specific language governing permissions and limitations under the License. When
+ * distributing the software, include this License Header Notice in each file and
+ * include the full text of the License in the License file as well as the
+ * following notice:
+ *
+ * NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND DISTRIBUTION LICENSE
+ * (CDDL)
+ * For Covered Software in this distribution, this License shall be governed by the
+ * laws of the State of California (excluding conflict-of-law provisions).
+ * Any litigation relating to this License shall be subject to the jurisdiction of
+ * the Federal Courts of the Northern District of California and the state courts
+ * of the State of California, with venue lying in Santa Clara County, California.
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by only the CDDL or only
+ * the LGPL Version 2.1, indicate your decision by adding "[Contributor]" elects to
+ * include this software in this distribution under the [CDDL or LGPL Version 2.1]
+ * license." If you don't indicate a single choice of license, a recipient has the
+ * option to distribute your version of this file under either the CDDL or the LGPL
+ * Version 2.1, or to extend the choice of license to its licensees as provided
+ * above. However, if you add LGPL Version 2.1 code and therefore, elected the LGPL
+ * Version 2 license, then the option applies only if the new code is made subject
+ * to such option by the copyright holder.
+ */
+
+#ifndef SUNPINYIN_LOOKUP_TABLE_H
+#define SUNPINYIN_LOOKUP_TABLE_H
+
+#include <ibus.h>
+#include "ibus_common.h"
+
+class ICandidateList;
+
+/**
+ * a helper class to maintain the IBusLookupTable
+ */
+class SunPinyinLookupTable : public ibus::LookupTable
+{
+public:
+    SunPinyinLookupTable();
+    virtual ~SunPinyinLookupTable();
+    /**
+     * update lookup table with given candidate list
+     * @param cl candidate list
+     * @return the number of candidates updated
+     */
+    int update_candidates(const ICandidateList& cl);
+    bool cursor_up();
+    bool cursor_down();
+    size_t get_cursor_pos() const;
+
+private:
+    /**
+     * set the candidate in lookup table
+     * @param cl the candidate list including all available candidates in current page
+     * @param index the candidate's index in page
+     * @param begin the begin position in candidates
+     * @return the length of candidate string
+     */
+    int append_candidate(const ICandidateList& cl, int index, int begin);
+
+    /**
+     * get the index of current page's start point
+     * @return the index where current page starts
+     */
+    int get_current_page_start() const;
+
+    /**
+     * update text's attributes according to the type of candidate
+     * @param text
+     * @param type
+     */
+    void decorate_candidate(ibus::Text text, int type);
+};
+
+#endif // SUNPINYIN_LOOKUP_TABLE_H
diff --git a/wrapper/ibus/src/sunpinyin_property.cpp b/wrapper/ibus/src/sunpinyin_property.cpp
new file mode 100644 (file)
index 0000000..2616463
--- /dev/null
@@ -0,0 +1,206 @@
+/*
+ * Copyright (c) 2009 Kov Chai <tchaikov@gmail.com>
+ *
+ * The contents of this file are subject to the terms of either the GNU Lesser
+ * General Public License Version 2.1 only ("LGPL") or the Common Development and
+ * Distribution License ("CDDL")(collectively, the "License"). You may not use this
+ * file except in compliance with the License. You can obtain a copy of the CDDL at
+ * http://www.opensource.org/licenses/cddl1.php and a copy of the LGPLv2.1 at
+ * http://www.opensource.org/licenses/lgpl-license.php. See the License for the 
+ * specific language governing permissions and limitations under the License. When
+ * distributing the software, include this License Header Notice in each file and
+ * include the full text of the License in the License file as well as the
+ * following notice:
+ * 
+ * NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND DISTRIBUTION LICENSE
+ * (CDDL)
+ * For Covered Software in this distribution, this License shall be governed by the
+ * laws of the State of California (excluding conflict-of-law provisions).
+ * Any litigation relating to this License shall be subject to the jurisdiction of
+ * the Federal Courts of the Northern District of California and the state courts
+ * of the State of California, with venue lying in Santa Clara County, California.
+ * 
+ * Contributor(s):
+ * 
+ * If you wish your version of this file to be governed by only the CDDL or only
+ * the LGPL Version 2.1, indicate your decision by adding "[Contributor]" elects to
+ * include this software in this distribution under the [CDDL or LGPL Version 2.1]
+ * license." If you don't indicate a single choice of license, a recipient has the
+ * option to distribute your version of this file under either the CDDL or the LGPL
+ * Version 2.1, or to extend the choice of license to its licensees as provided
+ * above. However, if you add LGPL Version 2.1 code and therefore, elected the LGPL
+ * Version 2 license, then the option applies only if the new code is made subject
+ * to such option by the copyright holder. 
+ */
+
+#include <libintl.h>
+#include <ibus.h>
+#include "ibus_portable.h"
+#include "sunpinyin_property.h"
+
+#define N_(String) (String)
+#define _(String)  gettext(String)
+
+static const char *PROP_STATUS = "status";
+static const char *PROP_LETTER = "full_letter";
+static const char *PROP_PUNCT  = "full_punct";
+
+PropertyInfo::PropertyInfo()
+    : label(NULL), tooltip(NULL)
+{}
+
+PropertyInfo::~PropertyInfo()
+{}
+
+
+SunPinyinProperty 
+SunPinyinProperty::create_status_prop(ibus::Engine engine, bool state)
+{
+    SunPinyinProperty prop(engine, PROP_STATUS);
+    prop.m_info[0].label = ibus_text_new_from_static_string("EN");
+    prop.m_info[0].icon  = IBUS_SUNPINYIN_ICON_DIR"/eng.svg";
+    prop.m_info[0].tooltip = ibus_text_new_from_static_string(_("Switch to Chinese input mode"));
+    prop.m_info[1].label = ibus_text_new_from_static_string("CN");
+    prop.m_info[1].icon  = IBUS_SUNPINYIN_ICON_DIR"/han.svg";
+    prop.m_info[1].tooltip = ibus_text_new_from_static_string(_("Switch to English input mode"));
+    prop.init(state);
+    
+    return prop;
+}
+
+SunPinyinProperty
+SunPinyinProperty::create_letter_prop(ibus::Engine engine, bool state)
+{
+    SunPinyinProperty prop(engine, PROP_LETTER);
+    prop.m_info[0].label = ibus_text_new_from_static_string("Aa");
+    prop.m_info[0].icon  = IBUS_SUNPINYIN_ICON_DIR"/halfwidth.svg";
+    prop.m_info[0].tooltip = ibus_text_new_from_static_string(_("Switch to full-width letter input mode"));
+    prop.m_info[1].label = ibus_text_new_from_static_string("Aa");
+    prop.m_info[1].icon  = IBUS_SUNPINYIN_ICON_DIR"/fullwidth.svg";
+    prop.m_info[1].tooltip = ibus_text_new_from_static_string(_("Switch to half-width letter input mode"));
+    prop.init(state);
+    return prop;
+}
+
+SunPinyinProperty 
+SunPinyinProperty::create_punct_prop(ibus::Engine engine, bool state)
+{
+    SunPinyinProperty prop(engine, PROP_PUNCT);
+    prop.m_info[0].label = ibus_text_new_from_static_string(",.");
+    prop.m_info[0].icon  = IBUS_SUNPINYIN_ICON_DIR"/enpunc.svg";
+    prop.m_info[0].tooltip = ibus_text_new_from_static_string(_("Switch to Chinese punctuation"));
+    prop.m_info[1].label = ibus_text_new_from_static_string(",。");
+    prop.m_info[1].icon  = IBUS_SUNPINYIN_ICON_DIR"/cnpunc.svg";
+    prop.m_info[1].tooltip = ibus_text_new_from_static_string(_("Switch to English punctuation"));
+    prop.init(state);
+    return prop;
+
+}
+
+SunPinyinProperty::SunPinyinProperty(ibus::Engine engine, const std::string& name)
+    : ibus::Property(
+        ibus_property_new(name.c_str(),
+                          PROP_TYPE_NORMAL,
+                          NULL, /* label */ NULL, /* icon */
+                          NULL, /* tooltip */ TRUE, /* sensitive */
+                          TRUE, /* visible */ PROP_STATE_UNCHECKED, /* state */
+                          NULL)),
+      m_engine(engine),
+      m_name(name),
+      m_state(false)
+{}
+
+SunPinyinProperty::~SunPinyinProperty()
+{
+}
+
+bool
+SunPinyinProperty::toggle(const std::string& name)
+{
+    if (name == m_name) {
+        // called by ibus, simple toggle current state
+        update(!m_state);
+        return true;
+    }
+    return false;
+}
+
+void
+SunPinyinProperty::update(bool state)
+{
+    if (state == m_state)
+        return;
+    init(state);
+    ibus_engine_update_property(m_engine, *this);
+}
+
+void
+SunPinyinProperty::init(bool state)
+{
+    m_state = state;
+    int which = m_state ? 1 : 0;
+    PropertyInfo& info = m_info[which];
+    ibus_property_set_label(*this, info.label);
+    ibus_property_set_icon(*this, info.icon.c_str());
+    ibus_property_set_tooltip(*this, info.tooltip);
+    ibus_property_set_visible(*this, TRUE);
+    ibus_property_set_state(*this, state ? PROP_STATE_CHECKED : PROP_STATE_UNCHECKED);
+}
+
+bool
+SunPinyinProperty::state() const
+{
+    return m_state;
+}
+
+SetupLauncher::SetupLauncher()
+    : ibus::Property(
+        ibus_property_new("setup",
+                          PROP_TYPE_NORMAL,
+                          NULL, /* label */ NULL, /* icon */
+                          NULL, /* tooltip */ TRUE, /* sensitive */
+                          TRUE, /* visible */ PROP_STATE_UNCHECKED, /* state */
+                          NULL)),
+      m_name("setup")
+{
+    m_info.label   = ibus_text_new_from_static_string(_("Preference"));
+    m_info.tooltip = ibus_text_new_from_static_string(_("Preference"));
+    m_info.icon    = IBUS_SUNPINYIN_ICON_DIR"/setup.svg";
+    init();
+}
+
+void
+SetupLauncher::launch(const std::string& name)
+{
+    if (m_name != name) return;
+    
+    GError *error = NULL;
+    gchar *argv[2] = { NULL, };
+       gchar *path;
+       const char* libexecdir;
+    
+       libexecdir = g_getenv("LIBEXECDIR");
+       if (libexecdir == NULL)
+           libexecdir = LIBEXECDIR;
+    
+       path = g_build_filename(libexecdir, "ibus-setup-sunpinyin", NULL);
+       argv[0] = path;
+       argv[1] = NULL;
+    gboolean success;
+    success = g_spawn_async (NULL, argv, NULL,
+                             G_SPAWN_SEARCH_PATH,
+                             NULL, NULL, NULL, &error);
+    if (!success) {
+        g_message("Unabled to launch \"%s\"", path);
+    }
+    g_free(path);
+}
+
+void
+SetupLauncher::init()
+{
+    ibus_property_set_label (*this, m_info.label);
+    ibus_property_set_icon (*this, m_info.icon.c_str());
+    ibus_property_set_tooltip (*this, m_info.tooltip);
+    ibus_property_set_visible (*this, TRUE);
+}
diff --git a/wrapper/ibus/src/sunpinyin_property.h b/wrapper/ibus/src/sunpinyin_property.h
new file mode 100644 (file)
index 0000000..a129cc2
--- /dev/null
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 2009 Kov Chai <tchaikov@gmail.com>
+ *
+ * The contents of this file are subject to the terms of either the GNU Lesser
+ * General Public License Version 2.1 only ("LGPL") or the Common Development and
+ * Distribution License ("CDDL")(collectively, the "License"). You may not use this
+ * file except in compliance with the License. You can obtain a copy of the CDDL at
+ * http://www.opensource.org/licenses/cddl1.php and a copy of the LGPLv2.1 at
+ * http://www.opensource.org/licenses/lgpl-license.php. See the License for the
+ * specific language governing permissions and limitations under the License. When
+ * distributing the software, include this License Header Notice in each file and
+ * include the full text of the License in the License file as well as the
+ * following notice:
+ *
+ * NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND DISTRIBUTION LICENSE
+ * (CDDL)
+ * For Covered Software in this distribution, this License shall be governed by the
+ * laws of the State of California (excluding conflict-of-law provisions).
+ * Any litigation relating to this License shall be subject to the jurisdiction of
+ * the Federal Courts of the Northern District of California and the state courts
+ * of the State of California, with venue lying in Santa Clara County, California.
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by only the CDDL or only
+ * the LGPL Version 2.1, indicate your decision by adding "[Contributor]" elects to
+ * include this software in this distribution under the [CDDL or LGPL Version 2.1]
+ * license." If you don't indicate a single choice of license, a recipient has the
+ * option to distribute your version of this file under either the CDDL or the LGPL
+ * Version 2.1, or to extend the choice of license to its licensees as provided
+ * above. However, if you add LGPL Version 2.1 code and therefore, elected the LGPL
+ * Version 2 license, then the option applies only if the new code is made subject
+ * to such option by the copyright holder.
+ */
+
+#ifndef SUNPINYIN_PROPERTY_H
+#define SUNPINYIN_PROPERTY_H
+
+#include <string>
+#include "ibus_common.h"
+
+struct PropertyInfo
+{
+    PropertyInfo();
+    ~PropertyInfo();
+
+    std::string icon;
+    ibus::Text  label;
+    ibus::Text  tooltip;
+};
+
+class SunPinyinProperty : public ibus::Property
+{
+    ibus::Engine      m_engine;
+    const std::string m_name;
+    PropertyInfo      m_info[2];
+    bool              m_state;
+
+public:
+    static SunPinyinProperty create_status_prop(ibus::Engine engine,
+                                                bool state = true);
+    static SunPinyinProperty create_letter_prop(ibus::Engine engine,
+                                                bool state = false);
+    static SunPinyinProperty create_punct_prop(ibus::Engine engine,
+                                                bool state = false);
+    virtual ~SunPinyinProperty();
+    bool toggle(const std::string& name);
+    void update(bool state);
+    bool state() const;
+
+private:
+    void init(bool state);
+    SunPinyinProperty(ibus::Engine engine, const std::string& name);
+};
+
+class SetupLauncher : public ibus::Property
+{
+    const std::string m_name;
+    PropertyInfo      m_info;
+
+public:
+    SetupLauncher();
+    void launch(const std::string& name);
+    void init();
+};
+
+
+#endif // SUNPINYIN_PROPERTY_H
diff --git a/wrapper/scim/COPYING b/wrapper/scim/COPYING
new file mode 100644 (file)
index 0000000..a82e03e
--- /dev/null
@@ -0,0 +1 @@
+Refer to LGPL.LICENSE and OPENSOLARIS.LICENSE.
diff --git a/wrapper/scim/LGPL.LICENSE b/wrapper/scim/LGPL.LICENSE
new file mode 100644 (file)
index 0000000..5b9dd3b
--- /dev/null
@@ -0,0 +1,516 @@
+                 GNU LESSER GENERAL PUBLIC LICENSE
+                      Version 2.1, February 1999
+
+ Copyright (C) 1991, 1999 Free Software Foundation, Inc.
+ 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the Lesser GPL.  It also counts
+ as the successor of the GNU Library Public License, version 2, hence
+ the version number 2.1.]
+
+                           Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+  This license, the Lesser General Public License, applies to some
+specially designated software packages--typically libraries--of the
+Free Software Foundation and other authors who decide to use it.  You
+can use it too, but we suggest you first think carefully about whether
+this license or the ordinary General Public License is the better
+strategy to use in any particular case, based on the explanations below.
+
+  When we speak of free software, we are referring to freedom of use,
+not price.  Our General Public Licenses are designed to make sure that
+you have the freedom to distribute copies of free software (and charge
+for this service if you wish); that you receive source code or can get
+it if you want it; that you can change the software and use pieces of
+it in new free programs; and that you are informed that you can do
+these things.
+
+  To protect your rights, we need to make restrictions that forbid
+distributors to deny you these rights or to ask you to surrender these
+rights.  These restrictions translate to certain responsibilities for
+you if you distribute copies of the library or if you modify it.
+
+  For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you.  You must make sure that they, too, receive or can get the source
+code.  If you link other code with the library, you must provide
+complete object files to the recipients, so that they can relink them
+with the library after making changes to the library and recompiling
+it.  And you must show them these terms so they know their rights.
+
+  We protect your rights with a two-step method: (1) we copyright the
+library, and (2) we offer you this license, which gives you legal
+permission to copy, distribute and/or modify the library.
+
+  To protect each distributor, we want to make it very clear that
+there is no warranty for the free library.  Also, if the library is
+modified by someone else and passed on, the recipients should know
+that what they have is not the original version, so that the original
+author's reputation will not be affected by problems that might be
+introduced by others.
+\f
+  Finally, software patents pose a constant threat to the existence of
+any free program.  We wish to make sure that a company cannot
+effectively restrict the users of a free program by obtaining a
+restrictive license from a patent holder.  Therefore, we insist that
+any patent license obtained for a version of the library must be
+consistent with the full freedom of use specified in this license.
+
+  Most GNU software, including some libraries, is covered by the
+ordinary GNU General Public License.  This license, the GNU Lesser
+General Public License, applies to certain designated libraries, and
+is quite different from the ordinary General Public License.  We use
+this license for certain libraries in order to permit linking those
+libraries into non-free programs.
+
+  When a program is linked with a library, whether statically or using
+a shared library, the combination of the two is legally speaking a
+combined work, a derivative of the original library.  The ordinary
+General Public License therefore permits such linking only if the
+entire combination fits its criteria of freedom.  The Lesser General
+Public License permits more lax criteria for linking other code with
+the library.
+
+  We call this license the "Lesser" General Public License because it
+does Less to protect the user's freedom than the ordinary General
+Public License.  It also provides other free software developers Less
+of an advantage over competing non-free programs.  These disadvantages
+are the reason we use the ordinary General Public License for many
+libraries.  However, the Lesser license provides advantages in certain
+special circumstances.
+
+  For example, on rare occasions, there may be a special need to
+encourage the widest possible use of a certain library, so that it becomes
+a de-facto standard.  To achieve this, non-free programs must be
+allowed to use the library.  A more frequent case is that a free
+library does the same job as widely used non-free libraries.  In this
+case, there is little to gain by limiting the free library to free
+software only, so we use the Lesser General Public License.
+
+  In other cases, permission to use a particular library in non-free
+programs enables a greater number of people to use a large body of
+free software.  For example, permission to use the GNU C Library in
+non-free programs enables many more people to use the whole GNU
+operating system, as well as its variant, the GNU/Linux operating
+system.
+
+  Although the Lesser General Public License is Less protective of the
+users' freedom, it does ensure that the user of a program that is
+linked with the Library has the freedom and the wherewithal to run
+that program using a modified version of the Library.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.  Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library".  The
+former contains code derived from the library, whereas the latter must
+be combined with the library in order to run.
+\f
+                 GNU LESSER GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License Agreement applies to any software library or other
+program which contains a notice placed by the copyright holder or
+other authorized party saying it may be distributed under the terms of
+this Lesser General Public License (also called "this License").
+Each licensee is addressed as "you".
+
+  A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+  The "Library", below, refers to any such software library or work
+which has been distributed under these terms.  A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language.  (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+  "Source code" for a work means the preferred form of the work for
+making modifications to it.  For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+  Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it).  Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+  
+  1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+  You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+\f
+  2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) The modified work must itself be a software library.
+
+    b) You must cause the files modified to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    c) You must cause the whole of the work to be licensed at no
+    charge to all third parties under the terms of this License.
+
+    d) If a facility in the modified Library refers to a function or a
+    table of data to be supplied by an application program that uses
+    the facility, other than as an argument passed when the facility
+    is invoked, then you must make a good faith effort to ensure that,
+    in the event an application does not supply such function or
+    table, the facility still operates, and performs whatever part of
+    its purpose remains meaningful.
+
+    (For example, a function in a library to compute square roots has
+    a purpose that is entirely well-defined independent of the
+    application.  Therefore, Subsection 2d requires that any
+    application-supplied function or table used by this function must
+    be optional: if the application does not supply it, the square
+    root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library.  To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License.  (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.)  Do not make any other change in
+these notices.
+\f
+  Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+  This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+  4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+  If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library".  Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+  However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library".  The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+  When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library.  The
+threshold for this to be true is not precisely defined by law.
+
+  If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work.  (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+  Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+\f
+  6. As an exception to the Sections above, you may also combine or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+  You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License.  You must supply a copy of this License.  If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License.  Also, you must do one
+of these things:
+
+    a) Accompany the work with the complete corresponding
+    machine-readable source code for the Library including whatever
+    changes were used in the work (which must be distributed under
+    Sections 1 and 2 above); and, if the work is an executable linked
+    with the Library, with the complete machine-readable "work that
+    uses the Library", as object code and/or source code, so that the
+    user can modify the Library and then relink to produce a modified
+    executable containing the modified Library.  (It is understood
+    that the user who changes the contents of definitions files in the
+    Library will not necessarily be able to recompile the application
+    to use the modified definitions.)
+
+    b) Use a suitable shared library mechanism for linking with the
+    Library.  A suitable mechanism is one that (1) uses at run time a
+    copy of the library already present on the user's computer system,
+    rather than copying library functions into the executable, and (2)
+    will operate properly with a modified version of the library, if
+    the user installs one, as long as the modified version is
+    interface-compatible with the version that the work was made with.
+
+    c) Accompany the work with a written offer, valid for at
+    least three years, to give the same user the materials
+    specified in Subsection 6a, above, for a charge no more
+    than the cost of performing this distribution.
+
+    d) If distribution of the work is made by offering access to copy
+    from a designated place, offer equivalent access to copy the above
+    specified materials from the same place.
+
+    e) Verify that the user has already received a copy of these
+    materials or that you have already sent this user a copy.
+
+  For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it.  However, as a special exception,
+the materials to be distributed need not include anything that is
+normally distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+  It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system.  Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+\f
+  7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+    a) Accompany the combined library with a copy of the same work
+    based on the Library, uncombined with any other library
+    facilities.  This must be distributed under the terms of the
+    Sections above.
+
+    b) Give prominent notice with the combined library of the fact
+    that part of it is a work based on the Library, and explaining
+    where to find the accompanying uncombined form of the same work.
+
+  8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License.  Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License.  However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+  9. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Library or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+  10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties with
+this License.
+\f
+  11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded.  In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+  13. The Free Software Foundation may publish revised and/or new
+versions of the Lesser General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation.  If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+\f
+  14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission.  For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this.  Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+                           NO WARRANTY
+
+  15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU.  SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+  16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+                    END OF TERMS AND CONDITIONS
+\f
+           How to Apply These Terms to Your New Libraries
+
+  If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change.  You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+  To apply these terms, attach the following notices to the library.  It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the library's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with this library; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the
+  library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+  <signature of Ty Coon>, 1 April 1990
+  Ty Coon, President of Vice
+
+That's all there is to it!
+
+--------------------------------------------------------------------
+
+NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND
+DISTRIBUTION LICENSE (CDDL)
+
+For Covered Software in this distribution, this License shall
+be governed by the laws of the State of California (excluding
+conflict-of-law provisions).
+
+Any litigation relating to this License shall be subject to the
+jurisdiction of the Federal Courts of the Northern District of
+California and the state courts of the State of California, with
+venue lying in Santa Clara County, California.
diff --git a/wrapper/scim/Makefile.am b/wrapper/scim/Makefile.am
new file mode 100755 (executable)
index 0000000..4611492
--- /dev/null
@@ -0,0 +1,24 @@
+## Makefile.am -- Process this file with automake to produce Makefile.in
+## Copyright (C) 2002 James Su
+##
+## This program is free software; you can redistribute it and/or modify
+## it under the terms of the GNU General Public License as published by
+## the Free Software Foundation; either version 2, or (at your option)
+## any later version.
+##
+## This program is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+## GNU General Public License for more details.
+##
+## You should have received a copy of the GNU General Public License
+## along with this program; if not, write to the Free Software
+## Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+SUBDIRS                = data src
+
+MAINTAINERCLEANFILES   = Makefile.in
+
+CLEANFILES             = *.bak src/*.bak
+
+
diff --git a/wrapper/scim/OPENSOLARIS.LICENSE b/wrapper/scim/OPENSOLARIS.LICENSE
new file mode 100644 (file)
index 0000000..d838932
--- /dev/null
@@ -0,0 +1,377 @@
+COMMON DEVELOPMENT AND DISTRIBUTION LICENSE Version 1.0
+
+1. Definitions.
+
+    1.1. "Contributor" means each individual or entity that creates
+         or contributes to the creation of Modifications.
+
+    1.2. "Contributor Version" means the combination of the Original
+         Software, prior Modifications used by a Contributor (if any),
+         and the Modifications made by that particular Contributor.
+
+    1.3. "Covered Software" means (a) the Original Software, or (b)
+         Modifications, or (c) the combination of files containing
+         Original Software with files containing Modifications, in
+         each case including portions thereof.
+
+    1.4. "Executable" means the Covered Software in any form other
+         than Source Code.
+
+    1.5. "Initial Developer" means the individual or entity that first
+         makes Original Software available under this License.
+
+    1.6. "Larger Work" means a work which combines Covered Software or
+         portions thereof with code not governed by the terms of this
+         License.
+
+    1.7. "License" means this document.
+
+    1.8. "Licensable" means having the right to grant, to the maximum
+         extent possible, whether at the time of the initial grant or
+         subsequently acquired, any and all of the rights conveyed
+         herein.
+
+    1.9. "Modifications" means the Source Code and Executable form of
+         any of the following:
+
+        A. Any file that results from an addition to, deletion from or
+           modification of the contents of a file containing Original
+           Software or previous Modifications;
+
+        B. Any new file that contains any part of the Original
+           Software or previous Modifications; or
+
+        C. Any new file that is contributed or otherwise made
+           available under the terms of this License.
+
+    1.10. "Original Software" means the Source Code and Executable
+          form of computer software code that is originally released
+          under this License.
+
+    1.11. "Patent Claims" means any patent claim(s), now owned or
+          hereafter acquired, including without limitation, method,
+          process, and apparatus claims, in any patent Licensable by
+          grantor.
+
+    1.12. "Source Code" means (a) the common form of computer software
+          code in which modifications are made and (b) associated
+          documentation included in or with such code.
+
+    1.13. "You" (or "Your") means an individual or a legal entity
+          exercising rights under, and complying with all of the terms
+          of, this License.  For legal entities, "You" includes any
+          entity which controls, is controlled by, or is under common
+          control with You.  For purposes of this definition,
+          "control" means (a) the power, direct or indirect, to cause
+          the direction or management of such entity, whether by
+          contract or otherwise, or (b) ownership of more than fifty
+          percent (50%) of the outstanding shares or beneficial
+          ownership of such entity.
+
+2. License Grants.
+
+    2.1. The Initial Developer Grant.
+
+    Conditioned upon Your compliance with Section 3.1 below and
+    subject to third party intellectual property claims, the Initial
+    Developer hereby grants You a world-wide, royalty-free,
+    non-exclusive license:
+
+        (a) under intellectual property rights (other than patent or
+            trademark) Licensable by Initial Developer, to use,
+            reproduce, modify, display, perform, sublicense and
+            distribute the Original Software (or portions thereof),
+            with or without Modifications, and/or as part of a Larger
+            Work; and
+
+        (b) under Patent Claims infringed by the making, using or
+            selling of Original Software, to make, have made, use,
+            practice, sell, and offer for sale, and/or otherwise
+            dispose of the Original Software (or portions thereof).
+
+        (c) The licenses granted in Sections 2.1(a) and (b) are
+            effective on the date Initial Developer first distributes
+            or otherwise makes the Original Software available to a
+            third party under the terms of this License.
+
+        (d) Notwithstanding Section 2.1(b) above, no patent license is
+            granted: (1) for code that You delete from the Original
+            Software, or (2) for infringements caused by: (i) the
+            modification of the Original Software, or (ii) the
+            combination of the Original Software with other software
+            or devices.
+
+    2.2. Contributor Grant.
+
+    Conditioned upon Your compliance with Section 3.1 below and
+    subject to third party intellectual property claims, each
+    Contributor hereby grants You a world-wide, royalty-free,
+    non-exclusive license:
+
+        (a) under intellectual property rights (other than patent or
+            trademark) Licensable by Contributor to use, reproduce,
+            modify, display, perform, sublicense and distribute the
+            Modifications created by such Contributor (or portions
+            thereof), either on an unmodified basis, with other
+            Modifications, as Covered Software and/or as part of a
+            Larger Work; and
+
+        (b) under Patent Claims infringed by the making, using, or
+            selling of Modifications made by that Contributor either
+            alone and/or in combination with its Contributor Version
+            (or portions of such combination), to make, use, sell,
+            offer for sale, have made, and/or otherwise dispose of:
+            (1) Modifications made by that Contributor (or portions
+            thereof); and (2) the combination of Modifications made by
+            that Contributor with its Contributor Version (or portions
+            of such combination).
+
+        (c) The licenses granted in Sections 2.2(a) and 2.2(b) are
+            effective on the date Contributor first distributes or
+            otherwise makes the Modifications available to a third
+            party.
+
+        (d) Notwithstanding Section 2.2(b) above, no patent license is
+            granted: (1) for any code that Contributor has deleted
+            from the Contributor Version; (2) for infringements caused
+            by: (i) third party modifications of Contributor Version,
+            or (ii) the combination of Modifications made by that
+            Contributor with other software (except as part of the
+            Contributor Version) or other devices; or (3) under Patent
+            Claims infringed by Covered Software in the absence of
+            Modifications made by that Contributor.
+
+3. Distribution Obligations.
+
+    3.1. Availability of Source Code.
+
+    Any Covered Software that You distribute or otherwise make
+    available in Executable form must also be made available in Source
+    Code form and that Source Code form must be distributed only under
+    the terms of this License.  You must include a copy of this
+    License with every copy of the Source Code form of the Covered
+    Software You distribute or otherwise make available.  You must
+    inform recipients of any such Covered Software in Executable form
+    as to how they can obtain such Covered Software in Source Code
+    form in a reasonable manner on or through a medium customarily
+    used for software exchange.
+
+    3.2. Modifications.
+
+    The Modifications that You create or to which You contribute are
+    governed by the terms of this License.  You represent that You
+    believe Your Modifications are Your original creation(s) and/or
+    You have sufficient rights to grant the rights conveyed by this
+    License.
+
+    3.3. Required Notices.
+
+    You must include a notice in each of Your Modifications that
+    identifies You as the Contributor of the Modification.  You may
+    not remove or alter any copyright, patent or trademark notices
+    contained within the Covered Software, or any notices of licensing
+    or any descriptive text giving attribution to any Contributor or
+    the Initial Developer.
+
+    3.4. Application of Additional Terms.
+
+    You may not offer or impose any terms on any Covered Software in
+    Source Code form that alters or restricts the applicable version
+    of this License or the recipients' rights hereunder.  You may
+    choose to offer, and to charge a fee for, warranty, support,
+    indemnity or liability obligations to one or more recipients of
+    Covered Software.  However, you may do so only on Your own behalf,
+    and not on behalf of the Initial Developer or any Contributor.
+    You must make it absolutely clear that any such warranty, support,
+    indemnity or liability obligation is offered by You alone, and You
+    hereby agree to indemnify the Initial Developer and every
+    Contributor for any liability incurred by the Initial Developer or
+    such Contributor as a result of warranty, support, indemnity or
+    liability terms You offer.
+
+    3.5. Distribution of Executable Versions.
+
+    You may distribute the Executable form of the Covered Software
+    under the terms of this License or under the terms of a license of
+    Your choice, which may contain terms different from this License,
+    provided that You are in compliance with the terms of this License
+    and that the license for the Executable form does not attempt to
+    limit or alter the recipient's rights in the Source Code form from
+    the rights set forth in this License.  If You distribute the
+    Covered Software in Executable form under a different license, You
+    must make it absolutely clear that any terms which differ from
+    this License are offered by You alone, not by the Initial
+    Developer or Contributor.  You hereby agree to indemnify the
+    Initial Developer and every Contributor for any liability incurred
+    by the Initial Developer or such Contributor as a result of any
+    such terms You offer.
+
+    3.6. Larger Works.
+
+    You may create a Larger Work by combining Covered Software with
+    other code not governed by the terms of this License and
+    distribute the Larger Work as a single product.  In such a case,
+    You must make sure the requirements of this License are fulfilled
+    for the Covered Software.
+
+4. Versions of the License.
+
+    4.1. New Versions.
+
+    Sun Microsystems, Inc. is the initial license steward and may
+    publish revised and/or new versions of this License from time to
+    time.  Each version will be given a distinguishing version number.
+    Except as provided in Section 4.3, no one other than the license
+    steward has the right to modify this License.
+
+    4.2. Effect of New Versions.
+
+    You may always continue to use, distribute or otherwise make the
+    Covered Software available under the terms of the version of the
+    License under which You originally received the Covered Software.
+    If the Initial Developer includes a notice in the Original
+    Software prohibiting it from being distributed or otherwise made
+    available under any subsequent version of the License, You must
+    distribute and make the Covered Software available under the terms
+    of the version of the License under which You originally received
+    the Covered Software.  Otherwise, You may also choose to use,
+    distribute or otherwise make the Covered Software available under
+    the terms of any subsequent version of the License published by
+    the license steward.
+
+    4.3. Modified Versions.
+
+    When You are an Initial Developer and You want to create a new
+    license for Your Original Software, You may create and use a
+    modified version of this License if You: (a) rename the license
+    and remove any references to the name of the license steward
+    (except to note that the license differs from this License); and
+    (b) otherwise make it clear that the license contains terms which
+    differ from this License.
+
+5. DISCLAIMER OF WARRANTY.
+
+    COVERED SOFTWARE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS"
+    BASIS, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED,
+    INCLUDING, WITHOUT LIMITATION, WARRANTIES THAT THE COVERED
+    SOFTWARE IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR
+    PURPOSE OR NON-INFRINGING.  THE ENTIRE RISK AS TO THE QUALITY AND
+    PERFORMANCE OF THE COVERED SOFTWARE IS WITH YOU.  SHOULD ANY
+    COVERED SOFTWARE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT THE
+    INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE COST OF ANY
+    NECESSARY SERVICING, REPAIR OR CORRECTION.  THIS DISCLAIMER OF
+    WARRANTY CONSTITUTES AN ESSENTIAL PART OF THIS LICENSE.  NO USE OF
+    ANY COVERED SOFTWARE IS AUTHORIZED HEREUNDER EXCEPT UNDER THIS
+    DISCLAIMER.
+
+6. TERMINATION.
+
+    6.1. This License and the rights granted hereunder will terminate
+    automatically if You fail to comply with terms herein and fail to
+    cure such breach within 30 days of becoming aware of the breach.
+    Provisions which, by their nature, must remain in effect beyond
+    the termination of this License shall survive.
+
+    6.2. If You assert a patent infringement claim (excluding
+    declaratory judgment actions) against Initial Developer or a
+    Contributor (the Initial Developer or Contributor against whom You
+    assert such claim is referred to as "Participant") alleging that
+    the Participant Software (meaning the Contributor Version where
+    the Participant is a Contributor or the Original Software where
+    the Participant is the Initial Developer) directly or indirectly
+    infringes any patent, then any and all rights granted directly or
+    indirectly to You by such Participant, the Initial Developer (if
+    the Initial Developer is not the Participant) and all Contributors
+    under Sections 2.1 and/or 2.2 of this License shall, upon 60 days
+    notice from Participant terminate prospectively and automatically
+    at the expiration of such 60 day notice period, unless if within
+    such 60 day period You withdraw Your claim with respect to the
+    Participant Software against such Participant either unilaterally
+    or pursuant to a written agreement with Participant.
+
+    6.3. In the event of termination under Sections 6.1 or 6.2 above,
+    all end user licenses that have been validly granted by You or any
+    distributor hereunder prior to termination (excluding licenses
+    granted to You by any distributor) shall survive termination.
+
+7. LIMITATION OF LIABILITY.
+
+    UNDER NO CIRCUMSTANCES AND UNDER NO LEGAL THEORY, WHETHER TORT
+    (INCLUDING NEGLIGENCE), CONTRACT, OR OTHERWISE, SHALL YOU, THE
+    INITIAL DEVELOPER, ANY OTHER CONTRIBUTOR, OR ANY DISTRIBUTOR OF
+    COVERED SOFTWARE, OR ANY SUPPLIER OF ANY OF SUCH PARTIES, BE
+    LIABLE TO ANY PERSON FOR ANY INDIRECT, SPECIAL, INCIDENTAL, OR
+    CONSEQUENTIAL DAMAGES OF ANY CHARACTER INCLUDING, WITHOUT
+    LIMITATION, DAMAGES FOR LOST PROFITS, LOSS OF GOODWILL, WORK
+    STOPPAGE, COMPUTER FAILURE OR MALFUNCTION, OR ANY AND ALL OTHER
+    COMMERCIAL DAMAGES OR LOSSES, EVEN IF SUCH PARTY SHALL HAVE BEEN
+    INFORMED OF THE POSSIBILITY OF SUCH DAMAGES.  THIS LIMITATION OF
+    LIABILITY SHALL NOT APPLY TO LIABILITY FOR DEATH OR PERSONAL
+    INJURY RESULTING FROM SUCH PARTY'S NEGLIGENCE TO THE EXTENT
+    APPLICABLE LAW PROHIBITS SUCH LIMITATION.  SOME JURISDICTIONS DO
+    NOT ALLOW THE EXCLUSION OR LIMITATION OF INCIDENTAL OR
+    CONSEQUENTIAL DAMAGES, SO THIS EXCLUSION AND LIMITATION MAY NOT
+    APPLY TO YOU.
+
+8. U.S. GOVERNMENT END USERS.
+
+    The Covered Software is a "commercial item," as that term is
+    defined in 48 C.F.R. 2.101 (Oct. 1995), consisting of "commercial
+    computer software" (as that term is defined at 48
+    C.F.R. 252.227-7014(a)(1)) and "commercial computer software
+    documentation" as such terms are used in 48 C.F.R. 12.212
+    (Sept. 1995).  Consistent with 48 C.F.R. 12.212 and 48
+    C.F.R. 227.7202-1 through 227.7202-4 (June 1995), all
+    U.S. Government End Users acquire Covered Software with only those
+    rights set forth herein.  This U.S. Government Rights clause is in
+    lieu of, and supersedes, any other FAR, DFAR, or other clause or
+    provision that addresses Government rights in computer software
+    under this License.
+
+9. MISCELLANEOUS.
+
+    This License represents the complete agreement concerning subject
+    matter hereof.  If any provision of this License is held to be
+    unenforceable, such provision shall be reformed only to the extent
+    necessary to make it enforceable.  This License shall be governed
+    by the law of the jurisdiction specified in a notice contained
+    within the Original Software (except to the extent applicable law,
+    if any, provides otherwise), excluding such jurisdiction's
+    conflict-of-law provisions.  Any litigation relating to this
+    License shall be subject to the jurisdiction of the courts located
+    in the jurisdiction and venue specified in a notice contained
+    within the Original Software, with the losing party responsible
+    for costs, including, without limitation, court costs and
+    reasonable attorneys' fees and expenses.  The application of the
+    United Nations Convention on Contracts for the International Sale
+    of Goods is expressly excluded.  Any law or regulation which
+    provides that the language of a contract shall be construed
+    against the drafter shall not apply to this License.  You agree
+    that You alone are responsible for compliance with the United
+    States export administration regulations (and the export control
+    laws and regulation of any other countries) when You use,
+    distribute or otherwise make available any Covered Software.
+
+10. RESPONSIBILITY FOR CLAIMS.
+
+    As between Initial Developer and the Contributors, each party is
+    responsible for claims and damages arising, directly or
+    indirectly, out of its utilization of rights under this License
+    and You agree to work with Initial Developer and Contributors to
+    distribute such responsibility on an equitable basis.  Nothing
+    herein is intended or shall be deemed to constitute any admission
+    of liability.
+
+--------------------------------------------------------------------
+
+NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND
+DISTRIBUTION LICENSE (CDDL)
+
+For Covered Software in this distribution, this License shall
+be governed by the laws of the State of California (excluding
+conflict-of-law provisions).
+
+Any litigation relating to this License shall be subject to the
+jurisdiction of the Federal Courts of the Northern District of
+California and the state courts of the State of California, with
+venue lying in Santa Clara County, California.
diff --git a/wrapper/scim/README b/wrapper/scim/README
new file mode 100644 (file)
index 0000000..c8ef0ec
--- /dev/null
@@ -0,0 +1,6 @@
+scim-sunpinyin
+===
+
+scim-sunpinyin is a wrapper around SunPinyin which enables user to use
+SunPinyin with SCIM(Smart Common Input Method).
+
diff --git a/wrapper/scim/SConstruct b/wrapper/scim/SConstruct
new file mode 100644 (file)
index 0000000..efb5535
--- /dev/null
@@ -0,0 +1,165 @@
+import os
+import SCons.Tool.textfile
+
+locales = []
+
+cflags = '-O2 -g -pipe '
+version = '2.0.3'
+
+AddOption('--prefix', dest='prefix', metavar='DIR',
+          help='installation prefix')
+AddOption('--libdir', dest='libdir', metavar='DIR',
+          help='installation libdir')
+AddOption('--libexecdir', dest='libexecdir', metavar='DIR',
+          help='installation libexecdir')
+AddOption('--datadir', dest='datadir', metavar='DIR',
+          help='installation datadir')
+AddOption('--rpath', dest='rpath', metavar='DIR',
+          help='encode rpath in the executables')
+
+opts = Variables('configure.conf')
+opts.Add('PREFIX', default='/usr/local')
+opts.Add('LIBDIR', default='/usr/local/lib')
+opts.Add('LIBEXECDIR', default='/usr/local/lib')
+opts.Add('DATADIR', default='/usr/local/share')
+
+def PassVariables(envvar, env):
+    for (x, y) in envvar:
+        if x in os.environ:
+            print 'Warning: you\'ve set %s in the environmental variable!' % x
+            env[y] = os.environ[x]
+
+env = Environment(ENV=os.environ,
+                  CFLAGS=cflags, CXXFLAGS=cflags, 
+                  CPPPATH=['.'], SUBSTFILESUFFIX='.in')
+opts.Update(env)
+
+if GetOption('prefix') is not None:
+    env['PREFIX'] = GetOption('prefix')
+    env['LIBDIR'] = env['PREFIX'] + '/lib'
+    env['LIBEXECDIR'] = env['PREFIX'] + '/lib/'
+    env['DATADIR'] = env['PREFIX'] + '/share/'
+
+if GetOption('libdir') is not None:
+    env['LIBDIR'] = GetOption('libdir')
+
+if GetOption('libexecdir') is not None:
+    env['LIBEXECDIR'] = GetOption('libexecdir')
+
+if GetOption('datadir') is not None:
+    env['DATADIR'] = GetOption('datadir')
+
+opts.Save('configure.conf', env)
+
+envvar = [('CC', 'CC'),
+          ('CXX', 'CXX'),
+          ('CFLAGS', 'CFLAGS'),
+          ('CXXFLAGS', 'CXXFLAGS'),
+          ('LDFLAGS', 'LINKFLAGS')]
+PassVariables(envvar, env)
+
+data_dir = env['DATADIR'] + '/scim-sunpinyin'
+icons_dir = env['DATADIR'] + '/scim-sunpinyin/icons'
+bin_dir = env['LIBEXECDIR'] + '/scim-sunpinyin'
+gettext_package = 'scim-sunpinyin'
+
+extra_cflags  = ' -DSCIM_SUNPINYIN_LOCALEDIR=\'"%s"\'' % (env['DATADIR'] + '/locale')
+extra_cflags += ' -DSCIM_SUNPINYIN_ICON_DIR=\'"%s"\'' % icons_dir
+extra_cflags += ' -DLIBEXECDIR=\'"%s"\'' % bin_dir
+extra_cflags += ' -DGETTEXT_PACKAGE=\'"%s"\'' % gettext_package
+extra_cflags += ' -Isrc'
+
+env.Append(CFLAGS=extra_cflags)
+env.Append(CXXFLAGS=extra_cflags)
+env.Replace(SHLIBPREFIX = '')
+
+if GetOption('rpath') is not None:
+    env.Append(LINKFLAGS=' -Wl,-R -Wl,%s' % GetOption('rpath'))
+
+#
+#==============================configure================================
+#
+def CheckPKGConfig(context, version='0.12.0'):
+    context.Message( 'Checking for pkg-config... ' )
+    ret = context.TryAction('pkg-config --atleast-pkgconfig-version=%s' % version)[0]
+    context.Result(ret)
+    return ret
+
+def CheckPKG(context, name):
+    context.Message( 'Checking for %s... ' % name )
+    ret = context.TryAction('pkg-config --exists \'%s\'' % name)[0]
+    context.Result(ret)
+    return ret
+
+conf = Configure(env, custom_tests={'CheckPKGConfig' : CheckPKGConfig,
+                                    'CheckPKG' : CheckPKG })
+
+def DoConfigure():
+    if GetOption('clean'):
+        return
+
+    if not conf.CheckPKGConfig():
+        Exit(1)
+
+    if not conf.CheckPKG('scim'):
+        Exit(1)
+
+    if not conf.CheckPKG('sunpinyin-2.0'):
+        Exit(1)
+
+    if not conf.CheckPKG('scim-gtkutils'):
+        Exit(1)
+    
+    env = conf.Finish()
+    env.ParseConfig('pkg-config scim sunpinyin-2.0 scim-gtkutils --libs --cflags')
+
+DoConfigure()
+
+scim_icondir = os.popen('pkg-config scim   --variable=icondir').readlines()[0].rstrip()
+scim_moduledir =os.popen('pkg-config scim   --variable=moduledir').readlines()[0].rstrip()
+
+lib_sunpinyin_imengine_setup_target  = "sunpinyin_imengine_setup"
+lib_sunpinyin_imengine_setup_sources = ["src/sunpinyin_imengine_setup.cpp"]
+env.SharedLibrary(target = lib_sunpinyin_imengine_setup_target, source = lib_sunpinyin_imengine_setup_sources)
+
+lib_sunpinyin_imengine_target  = "sunpinyin_imengine"
+lib_sunpinyin_imengine_sources = ['src/imi_scimwin.cpp',
+                                  'src/sunpinyin_imengine.cpp',
+                                  'src/sunpinyin_lookup_table.cpp',
+                                  'src/sunpinyin_utils.cpp']
+env.SharedLibrary(target = lib_sunpinyin_imengine_target, source = lib_sunpinyin_imengine_sources)
+os.system('chmod 0644 ' + lib_sunpinyin_imengine_setup_target + '.so')
+os.system('chmod 0644 ' + lib_sunpinyin_imengine_target + '.so')
+for locale in locales:
+    mo = 'po/%s.mo' % (locale,)
+    env.Command(mo, [], 'msgfmt po/%s.po -o %s' % (locale, mo))
+
+#
+#==============================install================================
+#
+def DoInstall():
+
+    os.system('chmod 0644 ' + lib_sunpinyin_imengine_setup_target + '.so')
+    os.system('chmod 0644 ' + lib_sunpinyin_imengine_target + '.so')
+        
+    icons_target = env.Install(scim_icondir,
+                               ['data/sunpinyin_logo.png'])
+
+    imengine_target = env.Install(scim_moduledir + '/IMEngine',
+                                   'sunpinyin_imengine.so')
+
+    imsetup_target = env.Install(scim_moduledir + '/SetupUI',
+                                   'sunpinyin_imengine_setup.so')
+
+    locale_targets = []
+    for locale in locales:
+        path = env['DATADIR'] + '/locale/%s/LC_MESSAGES/%s.mo' % \
+            (locale, gettext_package)
+        locale_targets.append(env.InstallAs(path, 'po/%s.mo' % (locale,)))
+
+    env.Alias('install-libexec', [imengine_target, imsetup_target])
+    env.Alias('install-data', [icons_target])
+    env.Alias('install-locale', locale_targets)
+
+DoInstall()
+env.Alias('install', ['install-libexec', 'install-data', 'install-locale'])
diff --git a/wrapper/scim/config.log b/wrapper/scim/config.log
new file mode 100644 (file)
index 0000000..e2459e1
--- /dev/null
@@ -0,0 +1,31 @@
+file /home/zeus/workspace/sunpinyin-git/wrapper/scim/SConstruct,line 95:
+       Configure(confdir = .sconf_temp)
+scons: Configure: Checking for pkg-config... 
+scons: Configure: ".sconf_temp/conftest_0" is up to date.
+scons: Configure: The original builder output was:
+  |pkg-config --atleast-pkgconfig-version=0.12.0
+  |
+scons: Configure: (cached) yes
+
+scons: Configure: Checking for scim... 
+scons: Configure: ".sconf_temp/conftest_1" is up to date.
+scons: Configure: The original builder output was:
+  |pkg-config --exists 'scim'
+  |
+scons: Configure: (cached) yes
+
+scons: Configure: Checking for sunpinyin-2.0... 
+scons: Configure: ".sconf_temp/conftest_2" is up to date.
+scons: Configure: The original builder output was:
+  |pkg-config --exists 'sunpinyin-2.0'
+  |
+scons: Configure: (cached) yes
+
+scons: Configure: Checking for scim-gtkutils... 
+scons: Configure: ".sconf_temp/conftest_3" is up to date.
+scons: Configure: The original builder output was:
+  |pkg-config --exists 'scim-gtkutils'
+  |
+scons: Configure: (cached) yes
+
+
diff --git a/wrapper/scim/configure.conf b/wrapper/scim/configure.conf
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/wrapper/scim/data/Makefile.am b/wrapper/scim/data/Makefile.am
new file mode 100755 (executable)
index 0000000..6f1cac4
--- /dev/null
@@ -0,0 +1,12 @@
+## Makefile.am -- Process this file with automake to produce Makefile.in
+## Copyright (C) 2009 SAMSUNG
+##
+
+MAINTAINERCLEANFILES  = Makefile.in
+CLEANFILES      = *.bak
+
+icondir                        = $(SUNPINYIN_ICON_DIR)
+icon_DATA              = sunpinyin_logo.png
+
+EXTRA_DIST            = $(icon_DATA)
+
diff --git a/wrapper/scim/data/sunpinyin_logo.png b/wrapper/scim/data/sunpinyin_logo.png
new file mode 100644 (file)
index 0000000..1f2eab1
Binary files /dev/null and b/wrapper/scim/data/sunpinyin_logo.png differ
diff --git a/wrapper/scim/src/Makefile.am b/wrapper/scim/src/Makefile.am
new file mode 100755 (executable)
index 0000000..5c295a1
--- /dev/null
@@ -0,0 +1,50 @@
+## Makefile.am -- Process this file with automake to produce Makefile.in
+## Copyright (C) 2002 James Su
+##
+## This program is free software; you can redistribute it and/or modify
+## it under the terms of the GNU General Public License as published by
+## the Free Software Foundation; either version 2, or (at your option)
+## any later version.
+##
+## This program is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+## GNU General Public License for more details.
+##
+## You should have received a copy of the GNU General Public License
+## along with this program; if not, write to the Free Software
+## Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+MAINTAINERCLEANFILES   = Makefile.in
+
+ise_engine_sunpinyin_DEFINES   = -DSCIM_ICONDIR=\"@SUNPINYIN_ICON_DIR@\"\
+                -DSCIM_SUNPINYIN_LOCALEDIR=\"$(localedir)\"
+
+INCLUDES = -I./ -I../../../ -I../../../src/ -I../../../src/ime-core
+noinst_HEADERS = imi_scimwin.h\
+                       sunpinyin_imengine.h\
+                       sunpinyin_imengine_config_keys.h\
+                       sunpinyin_keycode.h\
+                       sunpinyin_lookup_table.h\
+                       sunpinyin_private.h\
+                       sunpinyin_utils.h
+
+
+############### ise-engine-xt9.la ###################
+moduledir = @SUNPINYIN_MODULE_DIR@/IMEngine
+module_LTLIBRARIES = ise-engine-sunpinyin.la
+
+ise_engine_sunpinyin_la_SOURCES =imi_scimwin.cpp\
+                                  sunpinyin_imengine.cpp\
+                                  sunpinyin_lookup_table.cpp\
+                                  sunpinyin_utils.cpp
+
+ise_engine_sunpinyin_la_CXXFLAGS = @ISF_CFLAGS@ ${ise_engine_sunpinyin_DEFINES}
+
+ise_engine_sunpinyin_la_LDFLAGS = -avoid-version \
+                                       -module \
+                                       -export-dynamic\
+                                       @ISF_LIBS@\
+                                        -lstdc++
+
+ise_engine_sunpinyin_la_LIBADD = $(top_builddir)/src/libsunpinyin.la
diff --git a/wrapper/scim/src/imi_scimwin.cpp b/wrapper/scim/src/imi_scimwin.cpp
new file mode 100644 (file)
index 0000000..180b412
--- /dev/null
@@ -0,0 +1,127 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright (c) 2007 Kov Chai <tchaikov@gmail.com>
+ *
+ * The contents of this file are subject to the terms of either the GNU Lesser
+ * General Public License Version 2.1 only ("LGPL") or the Common Development and
+ * Distribution License ("CDDL")(collectively, the "License"). You may not use this
+ * file except in compliance with the License. You can obtain a copy of the CDDL at
+ * http://www.opensource.org/licenses/cddl1.php and a copy of the LGPLv2.1 at
+ * http://www.opensource.org/licenses/lgpl-license.php. See the License for the 
+ * specific language governing permissions and limitations under the License. When
+ * distributing the software, include this License Header Notice in each file and
+ * include the full text of the License in the License file as well as the
+ * following notice:
+ * 
+ * NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND DISTRIBUTION LICENSE
+ * (CDDL)
+ * For Covered Software in this distribution, this License shall be governed by the
+ * laws of the State of California (excluding conflict-of-law provisions).
+ * Any litigation relating to this License shall be subject to the jurisdiction of
+ * the Federal Courts of the Northern District of California and the state courts
+ * of the State of California, with venue lying in Santa Clara County, California.
+ * 
+ * Contributor(s):
+ * 
+ * If you wish your version of this file to be governed by only the CDDL or only
+ * the LGPL Version 2.1, indicate your decision by adding "[Contributor]" elects to
+ * include this software in this distribution under the [CDDL or LGPL Version 2.1]
+ * license." If you don't indicate a single choice of license, a recipient has the
+ * option to distribute your version of this file under either the CDDL or the LGPL
+ * Version 2.1, or to extend the choice of license to its licensees as provided
+ * above. However, if you add LGPL Version 2.1 code and therefore, elected the LGPL
+ * Version 2 license, then the option applies only if the new code is made subject
+ * to such option by the copyright holder. 
+ */
+#define Uses_STL_AUTOPTR
+#define Uses_STL_FUNCTIONAL
+#define Uses_STL_VECTOR
+#define Uses_STL_IOSTREAM
+#define Uses_STL_FSTREAM
+#define Uses_STL_ALGORITHM
+#define Uses_STL_MAP
+#define Uses_STL_UTILITY
+#define Uses_STL_IOMANIP
+#define Uses_C_STDIO
+#define Uses_SCIM_UTILITY
+#define Uses_SCIM_IMENGINE
+#define Uses_SCIM_ICONV
+#define Uses_SCIM_CONFIG_BASE
+#define Uses_SCIM_CONFIG_PATH
+#define Uses_SCIM_LOOKUP_TABLE
+#define Uses_SCIM_DEBUG
+
+#include "portability.h"
+
+#include <imi_scimwin.h>
+#include <imi_winHandler.h>
+#include <imi_uiobjects.h>
+
+#include <scim.h>
+#include "sunpinyin_utils.h"
+#include "sunpinyin_lookup_table.h"
+#include "sunpinyin_imengine.h"
+
+using namespace scim;
+
+CScimWinHandler::CScimWinHandler(SunPyInstance* ime, SunLookupTable* lookup_table)
+    : CIMIWinHandler(), m_ime(ime), m_lookup_table(lookup_table)
+{
+    //
+}
+
+CScimWinHandler::~CScimWinHandler()
+{
+}
+
+void
+CScimWinHandler::commit(const TWCHAR* wstr)
+{
+    if (wstr) {
+        SCIM_DEBUG_IMENGINE (3) << "commit(" << wstr << ")\n";
+        m_ime->commit_string(wstr_to_widestr(wstr));
+    }
+}
+
+void
+CScimWinHandler::updatePreedit(const IPreeditString* ppd)
+{
+    if (ppd)
+        m_ime->redraw_preedit_string(ppd);
+}
+
+void
+CScimWinHandler::updateCandidates(const ICandidateList* pcl)
+{
+    if (pcl)
+        m_ime->redraw_lookup_table(pcl);
+}
+
+void
+CScimWinHandler::throwBackKey(unsigned keycode, unsigned keyvalue, unsigned modifier)
+{
+    if (keyvalue > 0x0 && keyvalue < 0x7f) {
+        printf("%c", keyvalue);
+        fflush(stdout);
+    }
+}
+
+void
+CScimWinHandler::updateStatus(int key, int value)
+{
+    switch (key) {
+    case STATUS_ID_CN:
+        m_ime->refresh_status_property(value != 0);
+        break;
+    case STATUS_ID_FULLPUNC:
+        m_ime->refresh_fullpunc_property(value != 0);
+        break;
+    case STATUS_ID_FULLSYMBOL:
+        m_ime->refresh_fullsymbol_property(value != 0);
+        break;
+    default:
+        SCIM_DEBUG_IMENGINE (2) << "Should not happen: updateStatus(" << key << ", " << value << ")\n";
+        break;
+    }
+}
diff --git a/wrapper/scim/src/imi_scimwin.h b/wrapper/scim/src/imi_scimwin.h
new file mode 100644 (file)
index 0000000..5e27def
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2007 Kov Chai <tchaikov@gmail.com>
+ *
+ * The contents of this file are subject to the terms of either the GNU Lesser
+ * General Public License Version 2.1 only ("LGPL") or the Common Development and
+ * Distribution License ("CDDL")(collectively, the "License"). You may not use this
+ * file except in compliance with the License. You can obtain a copy of the CDDL at
+ * http://www.opensource.org/licenses/cddl1.php and a copy of the LGPLv2.1 at
+ * http://www.opensource.org/licenses/lgpl-license.php. See the License for the 
+ * specific language governing permissions and limitations under the License. When
+ * distributing the software, include this License Header Notice in each file and
+ * include the full text of the License in the License file as well as the
+ * following notice:
+ * 
+ * NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND DISTRIBUTION LICENSE
+ * (CDDL)
+ * For Covered Software in this distribution, this License shall be governed by the
+ * laws of the State of California (excluding conflict-of-law provisions).
+ * Any litigation relating to this License shall be subject to the jurisdiction of
+ * the Federal Courts of the Northern District of California and the state courts
+ * of the State of California, with venue lying in Santa Clara County, California.
+ * 
+ * Contributor(s):
+ * 
+ * If you wish your version of this file to be governed by only the CDDL or only
+ * the LGPL Version 2.1, indicate your decision by adding "[Contributor]" elects to
+ * include this software in this distribution under the [CDDL or LGPL Version 2.1]
+ * license." If you don't indicate a single choice of license, a recipient has the
+ * option to distribute your version of this file under either the CDDL or the LGPL
+ * Version 2.1, or to extend the choice of license to its licensees as provided
+ * above. However, if you add LGPL Version 2.1 code and therefore, elected the LGPL
+ * Version 2 license, then the option applies only if the new code is made subject
+ * to such option by the copyright holder. 
+ */
+
+#ifndef IMI_SCIMWIN_H
+#define IMI_SCIMWIN_H
+
+#include "sunpinyin_lookup_table.h"
+#include "imi_winHandler.h"
+
+class SunPyInstance;
+
+class CScimWinHandler : public CIMIWinHandler
+{
+public:
+    CScimWinHandler(SunPyInstance* ime, SunLookupTable* lookup_table);
+
+    /* inherited methods implementation */
+    /*@{*/
+    virtual ~CScimWinHandler();
+
+    /** commit a string, normally the converted result */
+    virtual void commit(const TWCHAR* wstr);
+    
+    /** when a key is not processed */
+    virtual void throwBackKey(unsigned keycode, unsigned keyvalue, unsigned modifier);
+
+    /** Update window's preedit area using a GTK widget. */
+    virtual void updatePreedit(const IPreeditString* ppd);
+
+    /** Update window's candidates area using a GTK widget. */
+    virtual void updateCandidates(const ICandidateList* pcl);
+
+    /** Update status of current session using a GTK buttons. */
+    virtual void  updateStatus(int key, int value);
+
+    /*@}*/
+
+private:
+    /** load the images representing CN/EN, FULL/HALF PUNC|Simbol Simbol STATE*/
+    void load_images();
+
+private:
+    char m_buf[512];
+    SunPyInstance      *m_ime;
+    SunLookupTable     *m_lookup_table;
+};
+
+#endif//IMI_SCIMWIN_H
diff --git a/wrapper/scim/src/sunpinyin_imengine.cpp b/wrapper/scim/src/sunpinyin_imengine.cpp
new file mode 100644 (file)
index 0000000..aa40557
--- /dev/null
@@ -0,0 +1,626 @@
+/*
+ * Copyright (c) 2007 Kov Chai <tchaikov@gmail.com>
+ * Copyright (c) 2012-2013 Samsung Electronics Co., Ltd.
+ *
+ * The contents of this file are subject to the terms of either the GNU Lesser
+ * General Public License Version 2.1 only ("LGPL") or the Common Development and
+ * Distribution License ("CDDL")(collectively, the "License"). You may not use this
+ * file except in compliance with the License. You can obtain a copy of the CDDL at
+ * http://www.opensource.org/licenses/cddl1.php and a copy of the LGPLv2.1 at
+ * http://www.opensource.org/licenses/lgpl-license.php. See the License for the 
+ * specific language governing permissions and limitations under the License. When
+ * distributing the software, include this License Header Notice in each file and
+ * include the full text of the License in the License file as well as the
+ * following notice:
+ * 
+ * NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND DISTRIBUTION LICENSE
+ * (CDDL)
+ * For Covered Software in this distribution, this License shall be governed by the
+ * laws of the State of California (excluding conflict-of-law provisions).
+ * Any litigation relating to this License shall be subject to the jurisdiction of
+ * the Federal Courts of the Northern District of California and the state courts
+ * of the State of California, with venue lying in Santa Clara County, California.
+ * 
+ * Contributor(s):
+ * 
+ * If you wish your version of this file to be governed by only the CDDL or only
+ * the LGPL Version 2.1, indicate your decision by adding "[Contributor]" elects to
+ * include this software in this distribution under the [CDDL or LGPL Version 2.1]
+ * license." If you don't indicate a single choice of license, a recipient has the
+ * option to distribute your version of this file under either the CDDL or the LGPL
+ * Version 2.1, or to extend the choice of license to its licensees as provided
+ * above. However, if you add LGPL Version 2.1 code and therefore, elected the LGPL
+ * Version 2 license, then the option applies only if the new code is made subject
+ * to such option by the copyright holder. 
+ *
+ * Modifications by Samsung Electronics Co., Ltd.
+ *
+ * 1.Added always candidate show feature
+ * 2.Added auto commit feature for mobile user
+ */
+
+#define Uses_STL_AUTOPTR
+#define Uses_STL_FUNCTIONAL
+#define Uses_STL_VECTOR
+#define Uses_STL_IOSTREAM
+#define Uses_STL_FSTREAM
+#define Uses_STL_ALGORITHM
+#define Uses_STL_MAP
+#define Uses_STL_UTILITY
+#define Uses_STL_IOMANIP
+#define Uses_C_STDIO
+#define Uses_SCIM_UTILITY
+#define Uses_SCIM_IMENGINE
+#define Uses_SCIM_ICONV
+#define Uses_SCIM_CONFIG_BASE
+#define Uses_SCIM_CONFIG_PATH
+#define Uses_SCIM_LOOKUP_TABLE
+#define Uses_SCIM_DEBUG
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include <imi_options.h>
+#include <imi_view.h>
+#include <ic_history.h>
+
+#include <scim.h>
+
+#include "imi_scimwin.h"
+#include "sunpinyin_utils.h"
+#include "sunpinyin_keycode.h"
+#include "sunpinyin_lookup_table.h"
+#include "sunpinyin_imengine.h"
+#include "sunpinyin_imengine_config_keys.h"
+#include "sunpinyin_private.h"
+
+#define SCIM_PROP_STATUS                  "/IMEngine/SunPinyin/Status"
+#define SCIM_PROP_LETTER                  "/IMEngine/SunPinyin/Letter"
+#define SCIM_PROP_PUNCT                   "/IMEngine/SunPinyin/Punct"
+
+#ifndef SCIM_SUNPINYIN_DATADIR
+    #define SCIM_SUNPINYIN_DATADIR            "/usr/share/scim/sunpinyin"
+#endif
+
+#ifndef SCIM_ICONDIR
+    #define SCIM_ICONDIR                      "/usr/share/scim/icons"
+#endif
+
+#ifndef SCIM_SUNPINYIN_ICON_FILE
+    #define SCIM_SUNPINYIN_ICON_FILE       (SCIM_ICONDIR "/sunpinyin_logo.png")
+#endif
+
+#define SCIM_FULL_LETTER_ICON              (SCIM_ICONDIR "/full-letter.png")
+#define SCIM_HALF_LETTER_ICON              (SCIM_ICONDIR "/half-letter.png")
+#define SCIM_FULL_PUNCT_ICON               (SCIM_ICONDIR "/full-punct.png")
+#define SCIM_HALF_PUNCT_ICON               (SCIM_ICONDIR "/half-punct.png")
+
+using namespace scim;
+
+static IMEngineFactoryPointer _scim_pinyin_factory (0); 
+
+static ConfigPointer _scim_config (0);
+
+static Property _status_property   (SCIM_PROP_STATUS, "");
+static Property _letter_property   (SCIM_PROP_LETTER, "");
+static Property _punct_property    (SCIM_PROP_PUNCT, "");
+
+static char g_common_symbol[]={'#','$','%','^','&','*','@'};
+
+extern "C" {
+    void scim_module_init (void)
+    {
+        SCIM_DEBUG_IMENGINE (3) << "scim_module_init\n";
+        bindtextdomain (GETTEXT_PACKAGE, SCIM_SUNPINYIN_LOCALEDIR);
+        bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8");
+    }
+
+    void scim_module_exit (void)
+    {
+        _scim_pinyin_factory.reset ();
+        _scim_config.reset ();
+    }
+
+    uint32 scim_imengine_module_init (const ConfigPointer &config)
+    {
+        SCIM_DEBUG_IMENGINE (3) << "module_init\n";
+        _status_property.set_tip (_("The status of the current input method. Click to change it."));
+        _status_property.set_label ("英");
+        
+        _letter_property.set_icon (SCIM_HALF_LETTER_ICON);
+        _letter_property.set_tip (_("The input mode of the letters. Click to toggle between half and full."));
+        _letter_property.set_label (_("Full/Half Letter"));
+
+        _punct_property.set_icon (SCIM_HALF_PUNCT_ICON);
+        _punct_property.set_tip (_("The input mode of the puncutations. Click to toggle between half and full."));
+        _punct_property.set_label (_("Full/Half Punct"));
+
+        _scim_config = config;
+        return 1;
+    }
+
+    IMEngineFactoryPointer scim_imengine_module_create_factory (uint32 engine)
+    {
+        SCIM_DEBUG_IMENGINE (3) << "entering scim_imengine_module_create_factory()\n";
+        if (engine != 0) return IMEngineFactoryPointer (0);
+        if (_scim_pinyin_factory.null ()) {
+            SunPyFactory *factory = new SunPyFactory (_scim_config); 
+            if (factory->valid ())
+                _scim_pinyin_factory = factory;
+            else
+                delete factory;
+        }
+        return _scim_pinyin_factory;
+    }
+}
+
+// implementation of SunPyFactory
+SunPyFactory::SunPyFactory (const ConfigPointer &config)
+    : m_config (config),
+      m_valid (false)
+{
+    SCIM_DEBUG_IMENGINE (3) << "SunPyFactory()\n";
+    set_languages ("zh_CN");
+    m_name = utf8_mbstowcs ("SunPinyin");
+    m_valid = init ();
+    m_reload_signal_connection = m_config->signal_connect_reload (slot (this, &SunPyFactory::reload_config));
+    m_hotkey_profile = new CHotkeyProfile();
+}
+
+bool
+SunPyFactory::init ()
+{
+    bool valid = true;
+    
+    if (m_config) {
+        valid = load_user_config();
+    }
+    
+    // postpone the load_user_data() to the ctor of SunPyInstance
+    return valid;
+}
+
+bool
+SunPyFactory::load_user_config()
+{
+    // Load configurations.
+
+    return true;
+}
+
+SunPyFactory::~SunPyFactory ()
+{
+    SCIM_DEBUG_IMENGINE (3) << "~SunPyFactory()\n";
+    m_reload_signal_connection.disconnect ();
+    delete m_hotkey_profile;
+}
+
+WideString
+SunPyFactory::get_name () const
+{
+    return m_name;
+}
+
+WideString
+SunPyFactory::get_authors () const
+{
+    return utf8_mbstowcs (
+                String (_("Lei Zhang, <Phill.Zhang@sun.com>; Shuguagn Yan, <Ervin.Yan@sun.com>")));
+}
+
+WideString
+SunPyFactory::get_credits () const
+{
+    return utf8_mbstowcs (
+        String (_("Ported by Kov Chai, <tchaikov@gmail.com>")));
+}
+
+WideString
+SunPyFactory::get_help () const
+{
+    String help =
+        String (_("Hot Keys:"
+                  "\n\n  Shift+Alt:\n"
+                  "    Switch between English/Chinese mode."
+                  "\n\n  Control+period:\n"
+                  "    Switch between full/half width punctuation mode."
+                  "\n\n  Shift+space:\n"
+                  "    Switch between full/half width letter mode."
+                  "\n\n  PageUp:\n"
+                  "    Page up in lookup table."
+                  "\n\n  PageDown:\n"
+                  "    Page down in lookup table."
+                  "\n\n  Esc:\n"
+                  "    Cancel current syllable.\n"));
+    return utf8_mbstowcs (help);
+}
+
+String
+SunPyFactory::get_uuid () const
+{
+    return String ("3240fe82-585a-4f4a-96b3-0cad779c3b51");
+}
+
+String
+SunPyFactory::get_icon_file () const
+{
+    return String (SCIM_SUNPINYIN_ICON_FILE);
+}
+
+IMEngineInstancePointer
+SunPyFactory::create_instance (const String& encoding, int id)
+{
+    SCIM_DEBUG_IMENGINE (3) <<  "SunPyFactory::create_instance(" << id << ")\n";    
+    return new SunPyInstance (this, m_hotkey_profile, encoding, id);
+}
+
+void
+SunPyFactory::reload_config (const ConfigPointer &config)
+{
+    m_config = config;
+    m_valid = init ();
+}
+
+// implementation of SunPyInstance
+SunPyInstance::SunPyInstance (SunPyFactory *factory,
+                              CHotkeyProfile *hotkey_profile,
+                              const String& encoding,
+                              int id)
+    : IMEngineInstanceBase (factory, encoding, id),
+      m_factory (factory),
+      m_pv (0),
+      m_wh (0),
+      m_hotkey_profile (hotkey_profile),
+      m_lookup_table (0),
+      m_common_lookup_table(0),
+      m_focused (false)
+{
+    SCIM_DEBUG_IMENGINE (3) << get_id() << ": SunPyInstance()\n";
+    create_session(hotkey_profile);
+    if (!m_pv) return;
+    m_reload_signal_connection = factory->m_config->signal_connect_reload (slot (this, &SunPyInstance::reload_config));
+    init_lookup_table_labels ();
+}
+
+SunPyInstance::~SunPyInstance ()
+{
+    SCIM_DEBUG_IMENGINE (3) <<  get_id() << ": ~SunPyInstance()\n";
+    m_reload_signal_connection.disconnect ();
+    destroy_session();
+}
+
+static CKeyEvent
+translate_key(const KeyEvent& key)
+{
+    // XXX: may need to move this logic into CKeyEvent
+    if (!(key.code & 0xff00) && isprint(key.code) && !isspace(key.code) && !(key.mask & IM_CTRL_MASK)) {
+        // we only care about key_val here
+        return CKeyEvent(0, key.code, key.mask);
+    } else {
+        // what matters is key_code, but ibus sents me key_code as key_val
+        return CKeyEvent(key.code, 0, key.mask);
+    }
+}
+
+bool
+SunPyInstance::process_key_event (const KeyEvent& key)
+{
+    SCIM_DEBUG_IMENGINE (3) <<  get_id() << ": process_key_event(" << m_focused << ", "  <<
+        key.code << ", " <<
+        key.mask << ", " <<
+        key.layout << ")\n";
+        
+    if (!m_focused) return false;
+
+    CKeyEvent ev = translate_key(key);
+    
+    if ( !m_pv->getStatusAttrValue(CScimWinHandler::STATUS_ID_CN) ) {
+        // we are in English input mode
+        if ( !m_hotkey_profile->isModeSwitchKey(ev) ) {
+            m_hotkey_profile->rememberLastKey(ev);
+            return false;
+        }
+    }
+    return ( key.is_key_release() ||
+             m_pv->onKeyEvent(ev) );
+}
+
+void
+SunPyInstance::select_candidate (unsigned int item)
+{
+    if(m_lookup_table->number_of_candidates() == 0 && item < sizeof(g_common_symbol)/sizeof(char)) {
+        char _str[2]={g_common_symbol[item],0};
+        commit_string(utf8_mbstowcs(_str));
+        return;
+    }
+    m_pv->onCandidateSelectRequest(item);
+//  m_pv->makeSelection(item);
+}
+
+void
+SunPyInstance::update_lookup_table_page_size (unsigned int page_size)
+{
+    if (page_size > 0) {
+        SCIM_DEBUG_IMENGINE (3) << ": update_lookup_table_page_size(" << page_size << ")\n";
+        m_pv->setCandiWindowSize(page_size);
+        m_lookup_table->set_page_size(page_size);
+    }
+}
+
+void
+SunPyInstance::lookup_table_page_up ()
+{
+    lookup_page_up();
+    m_pv->onCandidatePageRequest(-1, true);
+}
+
+void
+SunPyInstance::lookup_page_up()
+{
+    m_lookup_table->page_up();
+    //    m_lookup_table->set_page_size(m_pv->s_CandiWindowSize);
+}
+
+void
+SunPyInstance::lookup_page_down()
+{
+    m_lookup_table->page_down();
+    //    m_lookup_table->set_page_size(m_pv->s_CandiWindowSize);
+}
+
+void
+SunPyInstance::lookup_table_page_down ()
+{
+    // XXX, it would be great, if View class expose a page_up() method
+    //    m_pv->onKeyEvent(IM_VK_PAGE_DOWN, 0, 0);
+    // classic View overrides this method
+    // but modern View uses the default dummy implementation
+    lookup_page_down ();
+    m_pv->onCandidatePageRequest(1, true);
+}
+
+void
+SunPyInstance::move_preedit_caret (unsigned int /*pos*/)
+{
+}
+
+void
+SunPyInstance::reset ()
+{
+    SCIM_DEBUG_IMENGINE (3) << get_id() << ": reset()\n";
+    flush();
+    m_lookup_table->clear ();
+    hide_preedit_string ();
+    //hide_aux_string ();
+    //m_pv->updateWindows(m_pv->clearIC());
+    //refresh_all_properties ();
+    show_lookup_table ();
+    m_pv->updateWindows(CIMIView::PREEDIT_MASK | CIMIView::CANDIDATE_MASK);
+}
+
+void
+SunPyInstance::focus_in ()
+{
+    SCIM_DEBUG_IMENGINE(3) << get_id() << ": focus_in ()\n";
+    m_focused = true;
+    show_lookup_table ();
+    initialize_all_properties ();
+    
+    hide_preedit_string ();
+    //hide_aux_string ();
+    
+    init_lookup_table_labels ();
+    
+    //hide_aux_string ();
+
+    m_pv->updateWindows(CIMIView::PREEDIT_MASK | CIMIView::CANDIDATE_MASK);
+}
+
+void
+SunPyInstance::focus_out ()
+{
+    SCIM_DEBUG_IMENGINE(3) << get_id() << ": focus_out ()\n";
+    m_focused = false;
+}
+
+void
+SunPyInstance::flush ()
+{
+    SCIM_DEBUG_IMENGINE(3) << get_id() << ": flush ()\n";
+    m_pv->onCandidateSelectRequest(0);
+}
+
+void
+SunPyInstance::trigger_property (const String &property)
+{
+    SCIM_DEBUG_IMENGINE (3) << get_id() << ": trigger_property(" << property << ")\n";
+    
+    if (property == SCIM_PROP_STATUS) {
+        const int is_CN = m_pv->getStatusAttrValue(CIMIWinHandler::STATUS_ID_CN);
+        m_pv->setStatusAttrValue(CIMIWinHandler::STATUS_ID_CN, is_CN?0:1);
+    } else if (property == SCIM_PROP_LETTER) {
+        const int is_fullsymbol = m_pv->getStatusAttrValue(CIMIWinHandler::STATUS_ID_FULLSYMBOL);
+        m_pv->setStatusAttrValue(CIMIWinHandler::STATUS_ID_FULLSYMBOL, is_fullsymbol?0:1);
+    } else if (property == SCIM_PROP_PUNCT) {
+        const int is_fullpunc = m_pv->getStatusAttrValue(CIMIWinHandler::STATUS_ID_FULLPUNC);
+        m_pv->setStatusAttrValue(CIMIWinHandler::STATUS_ID_FULLPUNC, is_fullpunc?0:1);
+    }
+}
+
+
+void
+SunPyInstance::init_lookup_table_labels ()
+{
+    m_pv->setCandiWindowSize(10);
+    m_lookup_table->set_page_size (10);
+    m_lookup_table->show_cursor ();
+}
+
+void
+SunPyInstance::initialize_all_properties ()
+{
+    PropertyList proplist;
+
+    proplist.push_back (_status_property);
+    proplist.push_back (_letter_property);
+    proplist.push_back (_punct_property);
+
+    register_properties (proplist);
+    refresh_all_properties ();
+}
+
+void
+SunPyInstance::refresh_all_properties ()
+{
+    SCIM_DEBUG_IMENGINE (3) << get_id() << ": refresh_all_properties()\n";
+    m_wh->updateStatus(CIMIWinHandler::STATUS_ID_CN,
+                       m_pv->getStatusAttrValue(CIMIWinHandler::STATUS_ID_CN));
+    m_wh->updateStatus(CIMIWinHandler::STATUS_ID_FULLPUNC,
+                       m_pv->getStatusAttrValue(CIMIWinHandler::STATUS_ID_FULLPUNC));
+    m_wh->updateStatus(CIMIWinHandler::STATUS_ID_FULLSYMBOL, 
+                       m_pv->getStatusAttrValue(CIMIWinHandler::STATUS_ID_FULLSYMBOL));
+}
+
+
+void
+SunPyInstance::refresh_status_property(bool cn)
+{
+    SCIM_DEBUG_IMENGINE (3) << get_id() << ": refresh_status_property(" << cn << ")\n";
+    if (!cn) {
+        reset();
+    }
+    _status_property.set_label(cn ? "中" : "英");
+    update_property(_status_property);
+}
+
+void
+SunPyInstance::refresh_fullsymbol_property(bool full)
+{
+    SCIM_DEBUG_IMENGINE (3) << get_id() << ": refresh_fullsimbol_property(" << full << ")\n";
+    _letter_property.set_icon(
+        full ? SCIM_FULL_LETTER_ICON : SCIM_HALF_LETTER_ICON);
+    update_property(_letter_property);
+}
+
+void
+SunPyInstance::refresh_fullpunc_property(bool full)
+{
+    _punct_property.set_icon(
+        full ? SCIM_FULL_PUNCT_ICON : SCIM_HALF_PUNCT_ICON);
+    update_property(_punct_property);
+}
+
+void
+SunPyInstance::create_session(CHotkeyProfile *hotkey_profile)
+{
+    SCIM_DEBUG_IMENGINE (3) << get_id() <<  ": create_session()\n";
+    AttributeList attrs;
+    CSunpinyinSessionFactory& factory = CSunpinyinSessionFactory::getFactory();
+    factory.setPinyinScheme(CSunpinyinSessionFactory::QUANPIN);
+    factory.setCandiWindowSize(10);
+    m_pv = factory.createSession();
+    if (!m_pv) {
+        SCIM_DEBUG_IMENGINE (3) << get_id() <<  " factory.createSession() failed\n";
+        return;
+    }
+    
+    m_pv->setHotkeyProfile(hotkey_profile);
+
+    m_lookup_table = new SunLookupTable();
+    m_common_lookup_table = new CommonLookupTable();
+    for(int i = 0;i < sizeof(g_common_symbol)/sizeof(char);i++) {
+        char _str[2]={g_common_symbol[i],0};
+        m_common_lookup_table->append_candidate (utf8_mbstowcs ((const char*)_str),attrs);
+    }
+    m_wh = new CScimWinHandler(this, m_lookup_table);
+    m_pv->attachWinHandler(m_wh);
+}
+
+void
+SunPyInstance::destroy_session()
+{
+    SCIM_DEBUG_IMENGINE (3) << get_id() <<  ": destroy_session()\n";
+    
+    // wh and ic are not pointers, I don't think it's necessary to delete them
+    // either
+    delete m_pv;
+    delete m_wh;
+    delete m_lookup_table;
+    delete m_common_lookup_table;
+    
+    m_pv = 0;
+    m_wh = 0;
+    m_lookup_table = 0;
+}
+
+AttributeList
+SunPyInstance::build_preedit_attribs (const IPreeditString* ppd)
+{
+    AttributeList attrs;
+    const int sz = ppd->charTypeSize();
+    for (int i = 0; i < sz; ) {
+        const int ct = ppd->charTypeAt(i);
+        if (ct & IPreeditString::ILLEGAL) {
+            const int start = i;
+            for (++i; (i<sz) && (ppd->charTypeAt(i) & IPreeditString::ILLEGAL); ++i) ;
+            attrs.push_back( Attribute(start, i-start,
+                                       SCIM_ATTR_DECORATE, SCIM_ATTR_DECORATE_REVERSE));
+        } else if (ct & IPreeditString::NORMAL_CHAR) {
+            if (ct & IPreeditString::USER_CHOICE) {
+                const int start = i;
+                for (++i; (i<sz) && (ppd->charTypeAt(i) & IPreeditString::USER_CHOICE); ++i) ;
+                attrs.push_back( Attribute(start, i-start,
+                                           SCIM_ATTR_DECORATE, SCIM_ATTR_DECORATE_UNDERLINE));
+            } else {
+                ++i;
+            }
+        } else {
+            ++i;
+        }
+    }
+    return attrs;
+}
+
+void
+SunPyInstance::redraw_preedit_string (const IPreeditString* ppd)
+{
+    SCIM_DEBUG_IMENGINE (3) << get_id() <<  ": redraw_preedit_string()\n";
+    if (ppd->size() != 0) {
+        AttributeList attrs;
+        const int caret = ppd->caret();
+        if (caret > 0 && caret <= ppd->size()) {
+            attrs.push_back( Attribute(ppd->candi_start(),
+                                       ppd->charTypeSize(),
+                                       SCIM_ATTR_DECORATE, SCIM_ATTR_DECORATE_REVERSE));
+        }
+        update_preedit_string( wstr_to_widestr(ppd->string(), ppd->size()) );
+        show_preedit_string ();
+        update_preedit_caret (caret);
+    } else {
+        hide_preedit_string ();
+    }
+}
+
+void
+SunPyInstance::redraw_lookup_table(const ICandidateList* pcl)
+{
+    SCIM_DEBUG_IMENGINE (3) << get_id() << ": redraw_lookup_table()\n";
+    
+    m_lookup_table->update(*pcl);
+    if (m_lookup_table->number_of_candidates()) {
+        update_lookup_table(*m_lookup_table);
+    } else {
+        update_lookup_table(*m_common_lookup_table);
+    }
+}
+
+void
+SunPyInstance::reload_config(const ConfigPointer &config)
+{
+    SCIM_DEBUG_IMENGINE (3) << get_id() << ": reload_config()\n";
+    reset();
+    if (m_factory->valid()) {
+        m_factory->load_user_config();
+    }
+}
diff --git a/wrapper/scim/src/sunpinyin_imengine.h b/wrapper/scim/src/sunpinyin_imengine.h
new file mode 100755 (executable)
index 0000000..9024a53
--- /dev/null
@@ -0,0 +1,152 @@
+/*
+ * Copyright (c) 2007 Kov Chai <tchaikov@gmail.com>
+ * Copyright (c) 2012-2013 Samsung Electronics Co., Ltd.
+ *
+ * The contents of this file are subject to the terms of either the GNU Lesser
+ * General Public License Version 2.1 only ("LGPL") or the Common Development and
+ * Distribution License ("CDDL")(collectively, the "License"). You may not use this
+ * file except in compliance with the License. You can obtain a copy of the CDDL at
+ * http://www.opensource.org/licenses/cddl1.php and a copy of the LGPLv2.1 at
+ * http://www.opensource.org/licenses/lgpl-license.php. See the License for the 
+ * specific language governing permissions and limitations under the License. When
+ * distributing the software, include this License Header Notice in each file and
+ * include the full text of the License in the License file as well as the
+ * following notice:
+ * 
+ * NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND DISTRIBUTION LICENSE
+ * (CDDL)
+ * For Covered Software in this distribution, this License shall be governed by the
+ * laws of the State of California (excluding conflict-of-law provisions).
+ * Any litigation relating to this License shall be subject to the jurisdiction of
+ * the Federal Courts of the Northern District of California and the state courts
+ * of the State of California, with venue lying in Santa Clara County, California.
+ * 
+ * Contributor(s):
+ * 
+ * If you wish your version of this file to be governed by only the CDDL or only
+ * the LGPL Version 2.1, indicate your decision by adding "[Contributor]" elects to
+ * include this software in this distribution under the [CDDL or LGPL Version 2.1]
+ * license." If you don't indicate a single choice of license, a recipient has the
+ * option to distribute your version of this file under either the CDDL or the LGPL
+ * Version 2.1, or to extend the choice of license to its licensees as provided
+ * above. However, if you add LGPL Version 2.1 code and therefore, elected the LGPL
+ * Version 2 license, then the option applies only if the new code is made subject
+ * to such option by the copyright holder. 
+ *
+ * Modifications by Samsung Electronics Co., Ltd.
+ *
+ * 1.Added always candidate show feature
+ * 2.Added auto commit feature for mobile user
+ */
+
+#ifndef SUNPINYIN_IMENGINE_H
+#define SUNPINYIN_IMENGINE_H
+
+using namespace scim;
+
+class CHotkeyProfile;
+
+class SunPyFactory : public IMEngineFactoryBase
+{
+    ConfigPointer       m_config;
+    bool                m_valid;
+    WideString          m_name;
+    Connection          m_reload_signal_connection;
+    CHotkeyProfile     *m_hotkey_profile;
+
+    friend class SunPyInstance;
+    
+public:
+    SunPyFactory (const ConfigPointer &config);
+
+    virtual ~SunPyFactory ();
+
+    virtual WideString  get_name () const;
+    virtual WideString  get_authors () const;
+    virtual WideString  get_credits () const;
+    virtual WideString  get_help () const;
+    virtual String      get_uuid () const;
+    virtual String      get_icon_file () const;
+
+    virtual IMEngineInstancePointer create_instance (const String& encoding, int id = -1);
+    
+public:
+    bool valid () const { return m_valid; }
+    void reload_config(const ConfigPointer& config);
+    
+private:
+    bool init ();
+    bool load_user_config ();
+};
+
+class SunPyInstance : public IMEngineInstanceBase
+{
+    SunPyFactory        *m_factory;
+    CIMIView            *m_pv;
+    CScimWinHandler     *m_wh;
+    CHotkeyProfile      *m_hotkey_profile;
+    SunLookupTable      *m_lookup_table;
+    CommonLookupTable   *m_common_lookup_table;
+    Connection           m_reload_signal_connection;
+    bool                 m_focused;
+    
+  public:
+    SunPyInstance(SunPyFactory *factory,
+                  CHotkeyProfile *hotkey_profile,
+                  const String& encoding, int id);
+    virtual ~SunPyInstance();
+    /**
+     * - mode switch key
+     * - toggle full width punctuation mode
+     * - toggle full width letter mode
+     * - chinese/english switch
+     * - caret left/right/home/end
+     * - candidate table cursor_up/cursor_down/page_up/page_down/number_select
+     * - backspace/delete
+     * - space/enter
+     */
+    virtual bool process_key_event (const KeyEvent& key);
+    virtual void move_preedit_caret (unsigned int pos);
+    virtual void select_candidate (unsigned int item);
+    virtual void update_lookup_table_page_size (unsigned int page_size);
+    virtual void lookup_table_page_up ();
+    virtual void lookup_table_page_down ();
+    virtual void reset ();
+    virtual void focus_in ();
+    virtual void focus_out ();
+    virtual void flush ();
+    /**
+     * update the configuration of the input method
+     */
+    virtual void trigger_property (const String &property);
+
+public:
+    /**
+     * expose this inherited protected method
+     * so that CScimWinHandler can call it
+     */
+    using IMEngineInstanceBase::commit_string;
+    
+    void refresh_status_property(bool cn);
+    void refresh_fullsymbol_property(bool full);
+    void refresh_fullpunc_property(bool full);
+    void redraw_preedit_string(const IPreeditString* ppd);
+    void redraw_lookup_table(const ICandidateList* pcl);
+
+private:
+    void create_session(CHotkeyProfile*);
+    void destroy_session();
+    
+    void init_lookup_table_labels ();
+    void reload_config (const ConfigPointer &config);
+    void refresh_all_properties ();
+    void initialize_all_properties();
+    
+    AttributeList build_preedit_attribs(const IPreeditString* ppd);
+
+    void lookup_page_up();
+    void lookup_page_down();
+};
+
+// emacs: -*- c++-mode -*-
+#endif//SUNPINYIN_IMENGINE_H
diff --git a/wrapper/scim/src/sunpinyin_imengine_config_keys.h b/wrapper/scim/src/sunpinyin_imengine_config_keys.h
new file mode 100644 (file)
index 0000000..d3a150a
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2007 Kov Chai <tchaikov@gmail.com>
+ *
+ * The contents of this file are subject to the terms of either the GNU Lesser
+ * General Public License Version 2.1 only ("LGPL") or the Common Development and
+ * Distribution License ("CDDL")(collectively, the "License"). You may not use this
+ * file except in compliance with the License. You can obtain a copy of the CDDL at
+ * http://www.opensource.org/licenses/cddl1.php and a copy of the LGPLv2.1 at
+ * http://www.opensource.org/licenses/lgpl-license.php. See the License for the 
+ * specific language governing permissions and limitations under the License. When
+ * distributing the software, include this License Header Notice in each file and
+ * include the full text of the License in the License file as well as the
+ * following notice:
+ * 
+ * NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND DISTRIBUTION LICENSE
+ * (CDDL)
+ * For Covered Software in this distribution, this License shall be governed by the
+ * laws of the State of California (excluding conflict-of-law provisions).
+ * Any litigation relating to this License shall be subject to the jurisdiction of
+ * the Federal Courts of the Northern District of California and the state courts
+ * of the State of California, with venue lying in Santa Clara County, California.
+ * 
+ * Contributor(s):
+ * 
+ * If you wish your version of this file to be governed by only the CDDL or only
+ * the LGPL Version 2.1, indicate your decision by adding "[Contributor]" elects to
+ * include this software in this distribution under the [CDDL or LGPL Version 2.1]
+ * license." If you don't indicate a single choice of license, a recipient has the
+ * option to distribute your version of this file under either the CDDL or the LGPL
+ * Version 2.1, or to extend the choice of license to its licensees as provided
+ * above. However, if you add LGPL Version 2.1 code and therefore, elected the LGPL
+ * Version 2 license, then the option applies only if the new code is made subject
+ * to such option by the copyright holder. 
+ */
+
+
+#ifndef SUNPINYIN_IMENGINE_CONFIG_KEYS_H
+#define SUNPINYIN_IMENGINE_CONFIG_KEYS_H
+
+#define SCIM_CONFIG_IMENGINE_SUNPINYIN_SYSTEM_LANGUAGE_MODEL            "/IMEngine/SunPinyin/System/LanguageModel"
+#define SCIM_CONFIG_IMENGINE_SUNPINYIN_SYSTEM_DICTIONARY                "/IMEngine/SunPinyin/System/Dictionary"
+
+#define SCIM_CONFIG_IMENGINE_SUNPINYIN_USER_HISTORY                     "/IMEngine/SunPinyin/User/History"
+
+#define SCIM_CONFIG_IMENGINE_SUNPINYIN_USER_VIEW_TYPE                   "/IMEngine/SunPinyin/InputStyle"
+#define SCIM_CONFIG_IMENGINE_SUNPINYIN_USER_CHARHSET                    "/IMEngine/SunPinyin/Charset"
+#define SCIM_CONFIG_IMENGINE_SUNPINYIN_USER_PAGE_MINUS                  "/IMEngine/SunPinyin/PageKey/Minus"
+#define SCIM_CONFIG_IMENGINE_SUNPINYIN_USER_PAGE_BRACKET                "/IMEngine/SunPinyin/PageKey/Bracket"
+#define SCIM_CONFIG_IMENGINE_SUNPINYIN_USER_PAGE_COMMA                  "/IMEngine/SunPinyin/PageKey/Comma"
+#define SCIM_CONFIG_IMENGINE_SUNPINYIN_USER_MEMORY_POWER                "/IMEngine/SunPinyin/HistoryMemory"
+#define SCIM_CONFIG_IMENGINE_SUNPINYIN_USER_CONTEXT_METHOD              "/IMEngine/SunPinyin/RankingMethod"
+#define SCIM_CONFIG_IMENGINE_SUNPINYIN_USER_LAYOUT_VERTICAL             "/IMEngine/SunPinyin/Layout"
+#define SCIM_CONFIG_IMENGINE_SUNPINYIN_AMBIGUITY                        "/IMEngine/SunPinyin/Ambiguity"
+#define SCIM_CONFIG_IMENGINE_SUNPINYIN_AMBIGUITY_ANY                    "/IMEngine/SunPinyin/Ambiguity/Any"
+#define SCIM_CONFIG_IMENGINE_SUNPINYIN_AMBIGUITY_ZhiZi                  "/IMEngine/SunPinyin/Ambiguity/ZhiZi"
+#define SCIM_CONFIG_IMENGINE_SUNPINYIN_AMBIGUITY_ChiCi                  "/IMEngine/SunPinyin/Ambiguity/ChiCi"
+#define SCIM_CONFIG_IMENGINE_SUNPINYIN_AMBIGUITY_ShiSi                  "/IMEngine/SunPinyin/Ambiguity/ShiSi"
+#define SCIM_CONFIG_IMENGINE_SUNPINYIN_AMBIGUITY_NeLe                   "/IMEngine/SunPinyin/Ambiguity/NeLe"
+#define SCIM_CONFIG_IMENGINE_SUNPINYIN_AMBIGUITY_LeRi                   "/IMEngine/SunPinyin/Ambiguity/LeRi"
+#define SCIM_CONFIG_IMENGINE_SUNPINYIN_AMBIGUITY_FoHe                   "/IMEngine/SunPinyin/Ambiguity/FoHe"
+#define SCIM_CONFIG_IMENGINE_SUNPINYIN_AMBIGUITY_AnAng                  "/IMEngine/SunPinyin/Ambiguity/AnAng"
+#define SCIM_CONFIG_IMENGINE_SUNPINYIN_AMBIGUITY_EnEng                  "/IMEngine/SunPinyin/Ambiguity/EnEng"
+#define SCIM_CONFIG_IMENGINE_SUNPINYIN_AMBIGUITY_InIng                  "/IMEngine/SunPinyin/Ambiguity/InIng"
+
+#endif//SUNPINYIN_IMENGINE_CONFIG_KEYS_H
diff --git a/wrapper/scim/src/sunpinyin_imengine_setup.cpp b/wrapper/scim/src/sunpinyin_imengine_setup.cpp
new file mode 100644 (file)
index 0000000..9e69098
--- /dev/null
@@ -0,0 +1,394 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ * 
+ * Copyright (c) 2007 Sun Microsystems, Inc. All Rights Reserved.
+ * 
+ * The contents of this file are subject to the terms of either the GNU Lesser
+ * General Public License Version 2.1 only ("LGPL") or the Common Development and
+ * Distribution License ("CDDL")(collectively, the "License"). You may not use this
+ * file except in compliance with the License. You can obtain a copy of the CDDL at
+ * http://www.opensource.org/licenses/cddl1.php and a copy of the LGPLv2.1 at
+ * http://www.opensource.org/licenses/lgpl-license.php. See the License for the 
+ * specific language governing permissions and limitations under the License. When
+ * distributing the software, include this License Header Notice in each file and
+ * include the full text of the License in the License file as well as the
+ * following notice:
+ * 
+ * NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND DISTRIBUTION LICENSE
+ * (CDDL)
+ * For Covered Software in this distribution, this License shall be governed by the
+ * laws of the State of California (excluding conflict-of-law provisions).
+ * Any litigation relating to this License shall be subject to the jurisdiction of
+ * the Federal Courts of the Northern District of California and the state courts
+ * of the State of California, with venue lying in Santa Clara County, California.
+ * 
+ * Contributor(s):
+ * 
+ * If you wish your version of this file to be governed by only the CDDL or only
+ * the LGPL Version 2.1, indicate your decision by adding "[Contributor]" elects to
+ * include this software in this distribution under the [CDDL or LGPL Version 2.1]
+ * license." If you don't indicate a single choice of license, a recipient has the
+ * option to distribute your version of this file under either the CDDL or the LGPL
+ * Version 2.1, or to extend the choice of license to its licensees as provided
+ * above. However, if you add LGPL Version 2.1 code and therefore, elected the LGPL
+ * Version 2 license, then the option applies only if the new code is made subject
+ * to such option by the copyright holder. 
+ */
+#define Uses_SCIM_CONFIG_BASE
+
+#include <gtk/gtk.h>
+
+#include <scim.h>
+#include <gtk/scimkeyselection.h>
+
+#include "sunpinyin_private.h"
+#include "sunpinyin_imengine_config_keys.h"
+
+using namespace scim;
+
+#if !GTK_CHECK_VERSION(2, 12, 0)
+    #define SUNPINYIN_USE_GTK_TOOLTIPS
+#endif
+
+#if GTK_CHECK_VERSION(2, 24, 0)
+    #define SUNPINYIN_USE_GTK_COMBO_BOX_TEXT
+#endif
+
+#if GTK_CHECK_VERSION(3, 0, 0)
+    #define SUNPINYIN_USE_GTK_BOX
+#endif
+
+#define scim_module_init sunpinyin_imengine_setup_LTX_scim_module_init
+#define scim_module_exit sunpinyin_imengine_setup_LTX_scim_module_exit
+
+#define scim_setup_module_create_ui       sunpinyin_imengine_setup_LTX_scim_setup_module_create_ui
+#define scim_setup_module_get_category    sunpinyin_imengine_setup_LTX_scim_setup_module_get_category
+#define scim_setup_module_get_name        sunpinyin_imengine_setup_LTX_scim_setup_module_get_name
+#define scim_setup_module_get_description sunpinyin_imengine_setup_LTX_scim_setup_module_get_description
+#define scim_setup_module_load_config     sunpinyin_imengine_setup_LTX_scim_setup_module_load_config
+#define scim_setup_module_save_config     sunpinyin_imengine_setup_LTX_scim_setup_module_save_config
+#define scim_setup_module_query_changed   sunpinyin_imengine_setup_LTX_scim_setup_module_query_changed
+
+static GtkWidget * input_style_combo = NULL;
+static GtkWidget * charset_combo = NULL;
+static GtkWidget * minus_pageup_button = NULL;
+static GtkWidget * bracket_pageup_button = NULL;
+static GtkWidget * comma_pageup_button = NULL;
+static GtkWidget * memory_power_button = NULL;
+
+static GtkWidget * create_setup_window ();
+static void        load_config (const ConfigPointer &config);
+static void        save_config (const ConfigPointer &config);
+static bool        query_changed ();
+
+// Module Interface.
+extern "C" {
+    void scim_module_init (void)
+    {
+        bindtextdomain (GETTEXT_PACKAGE, SCIM_SUNPINYIN_LOCALEDIR);
+        bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8");
+    }
+
+    void scim_module_exit (void)
+    {
+    }
+
+    GtkWidget * scim_setup_module_create_ui (void)
+    {
+        static GtkWidget *setup_ui = NULL;
+        if (setup_ui == NULL)
+            setup_ui = create_setup_window ();
+        return setup_ui;
+    }
+
+    String scim_setup_module_get_category (void)
+    {
+        return String ("IMEngine");
+    }
+
+    String scim_setup_module_get_name (void)
+    {
+        return String (_("SunPinyin"));
+    }
+
+    String scim_setup_module_get_description (void)
+    {
+        return String (_("A Statistical Language Model Based Intelligent IMEngine Module for Simplified Chinese."));
+    }
+
+    void scim_setup_module_load_config (const ConfigPointer &config)
+    {
+        load_config (config);
+    }
+
+    void scim_setup_module_save_config (const ConfigPointer &config)
+    {
+        save_config (config);
+    }
+
+    bool scim_setup_module_query_changed ()
+    {
+        return query_changed ();
+    }
+} // extern "C"
+
+static bool __have_changed                 = false;
+
+static void
+on_value_changed(GtkWidget *  widget,
+                 gpointer     user_data)
+{
+    __have_changed = true;
+}
+
+static GtkWidget *
+#ifdef SUNPINYIN_USE_GTK_TOOLTIPS
+create_options_page(GtkTooltips *tooltips)
+#else
+create_options_page()
+#endif
+{
+    GtkWidget *vbox;
+    GtkWidget *label;
+    GtkWidget *button;
+
+#ifdef SUNPINYIN_USE_GTK_BOX
+    vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 12);
+#else
+    vbox = gtk_vbox_new (FALSE, 12);
+#endif
+
+    gtk_container_set_border_width(GTK_CONTAINER(vbox), 12);
+
+    GtkWidget *table = gtk_table_new (2, 2, FALSE);
+    gtk_box_pack_start(GTK_BOX(vbox), table, FALSE, TRUE, 0);
+
+    label = gtk_label_new (_("Input Style:"));
+    gtk_misc_set_alignment (GTK_MISC (label), 1.0, 0.5);
+    gtk_table_attach (GTK_TABLE (table), label, 0, 1, 0, 1,
+                      (GtkAttachOptions) (GTK_FILL),
+                      (GtkAttachOptions) (GTK_FILL), 4, 4);
+
+
+#ifdef SUNPINYIN_USE_GTK_COMBO_BOX_TEXT
+    GtkWidget *combo_box = gtk_combo_box_text_new();
+#else
+    GtkWidget *combo_box = gtk_combo_box_new_text();
+#endif
+
+    gtk_table_attach (GTK_TABLE (table), combo_box, 1, 2, 0, 1,
+                      (GtkAttachOptions) (GTK_FILL),
+                      (GtkAttachOptions) (GTK_FILL), 4, 4);
+
+#ifdef SUNPINYIN_USE_GTK_COMBO_BOX_TEXT
+    gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo_box), _("Classic Style"));
+    gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo_box), _("Instant Style"));
+#else
+    gtk_combo_box_append_text(GTK_COMBO_BOX(combo_box), _("Classic Style"));
+    gtk_combo_box_append_text(GTK_COMBO_BOX(combo_box), _("Instant Style"));
+#endif
+
+    const gchar *input_style_tooltip = _("You may feel more comfortable in classic style, "
+                                         "if you are used to input methods like scim-pinyin."
+                                         " In instant style, the most possible candidate "
+                                         "word will show up in the preedit area right after "
+                                         "its pinyin is input.");
+#ifdef SUNPINYIN_USE_GTK_TOOLTIPS
+    gtk_tooltips_set_tip(tooltips, combo_box, input_style_tooltip, NULL);
+#else
+    gtk_widget_set_tooltip_text(combo_box, input_style_tooltip);
+#endif
+
+    g_signal_connect(G_OBJECT(combo_box), "changed",
+                     G_CALLBACK(on_value_changed), NULL);
+    input_style_combo = combo_box;
+
+    label = gtk_label_new (_("Character Set:"));
+    gtk_misc_set_alignment (GTK_MISC (label), 1.0, 0.5);
+    gtk_table_attach (GTK_TABLE (table), label, 0, 1, 1, 2,
+                      (GtkAttachOptions) (GTK_FILL),
+                      (GtkAttachOptions) (GTK_FILL), 4, 4);
+
+#ifdef SUNPINYIN_USE_GTK_COMBO_BOX_TEXT
+    combo_box = gtk_combo_box_text_new();
+#else
+    combo_box = gtk_combo_box_new_text();
+#endif
+
+    gtk_table_attach (GTK_TABLE (table), combo_box, 1, 2, 1, 2,
+                      (GtkAttachOptions) (GTK_FILL),
+                      (GtkAttachOptions) (GTK_FILL), 4, 4);
+
+#ifdef SUNPINYIN_USE_GTK_COMBO_BOX_TEXT
+    gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo_box), _("GB2312"));
+    gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo_box), _("GBK"));
+#else
+    gtk_combo_box_append_text(GTK_COMBO_BOX(combo_box), _("GB2312"));
+    gtk_combo_box_append_text(GTK_COMBO_BOX(combo_box), _("GBK"));
+#endif
+
+    const gchar *charset_tooltip = _("Choosing GBK over GB2312 will trade some speed "
+                                     "with a larger charset in which I search candidate "
+                                     "words/characters for you.");
+#ifdef SUNPINYIN_USE_GTK_TOOLTIPS
+    gtk_tooltips_set_tip(tooltips, combo_box, charset_tooltip, NULL);
+#else
+    gtk_widget_set_tooltip_text(combo_box, charset_tooltip);
+#endif
+
+    g_signal_connect(G_OBJECT(combo_box), "changed",
+                     G_CALLBACK(on_value_changed), NULL);
+    charset_combo = combo_box;
+
+    button = gtk_check_button_new_with_mnemonic (_("Use -/= for paging down/up"));
+    gtk_box_pack_start(GTK_BOX(vbox), button, FALSE, FALSE, 0);
+    g_signal_connect(G_OBJECT(button), "toggled",
+                     G_CALLBACK(on_value_changed), NULL);
+    minus_pageup_button = button;
+
+    button = gtk_check_button_new_with_mnemonic (_("Use [/] for paging down/up"));
+    gtk_box_pack_start(GTK_BOX(vbox), button, FALSE, FALSE, 0);
+    g_signal_connect(G_OBJECT(button), "toggled",
+                     G_CALLBACK(on_value_changed), NULL);
+    bracket_pageup_button = button;
+
+    button = gtk_check_button_new_with_mnemonic (_("Use ,/. for paging down/up"));
+    gtk_box_pack_start(GTK_BOX(vbox), button, FALSE, FALSE, 0);
+    g_signal_connect(G_OBJECT(button), "toggled",
+                     G_CALLBACK(on_value_changed), NULL);
+    comma_pageup_button = button;
+
+    // MemoryPower
+    GtkWidget *hbox;
+
+#ifdef SUNPINYIN_USE_GTK_BOX
+    hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
+#else
+    hbox = gtk_hbox_new (FALSE, 0);
+#endif
+
+    gtk_widget_show (hbox);
+    gtk_box_pack_start (GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
+
+    label = gtk_label_new (NULL);
+    gtk_label_set_text_with_mnemonic (GTK_LABEL (label), _("M_emory power:"));
+    gtk_widget_show (label);
+    gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 2);
+    gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);
+    gtk_misc_set_padding (GTK_MISC (label), 2, 0);
+
+    button = gtk_spin_button_new_with_range (0, 10, 1);
+
+    const gchar *memory_power_tooltip =  _("The larger this number is, the faster I "
+                                           "memorize/forget new words.");
+#ifdef SUNPINYIN_USE_GTK_TOOLTIPS
+    gtk_tooltips_set_tip(tooltips, button, memory_power_tooltip, NULL);
+#else
+    gtk_widget_set_tooltip_text(button, memory_power_tooltip);
+#endif
+
+    g_signal_connect (G_OBJECT(button), "value_changed",
+                      G_CALLBACK(on_value_changed), NULL);
+    gtk_widget_show (button);
+    gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, FALSE, 0);
+    gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (button), TRUE);
+    gtk_spin_button_set_snap_to_ticks (GTK_SPIN_BUTTON (button), TRUE);
+    gtk_spin_button_set_digits (GTK_SPIN_BUTTON (button), 0);
+    gtk_label_set_mnemonic_widget (GTK_LABEL (label), button);
+    memory_power_button = button;
+    
+    return vbox;
+}
+
+static GtkWidget *
+create_setup_window ()
+{
+    GtkWidget *notebook;
+    GtkWidget *label;
+    GtkWidget *page;
+#ifdef SUNPINYIN_USE_GTK_TOOLTIPS
+    GtkTooltips *tooltips;
+
+    // Create the shared tooltips.
+    tooltips = gtk_tooltips_new ();
+#endif
+
+    notebook = gtk_notebook_new ();
+
+    // Create the option page. 
+#ifdef SUNPINYIN_USE_GTK_TOOLTIPS
+    page = create_options_page(tooltips);
+#else
+    page = create_options_page();
+#endif
+    label = gtk_label_new (_("Options"));
+    gtk_notebook_append_page (GTK_NOTEBOOK (notebook), page, label);
+
+    gtk_notebook_set_current_page(GTK_NOTEBOOK (notebook), 0);
+
+    gtk_widget_show_all(notebook);
+    return notebook;
+}
+
+static void
+load_config (const ConfigPointer &config)
+{
+    if (config.null())
+        return;
+
+    int viewtype = config->read (String (SCIM_CONFIG_IMENGINE_SUNPINYIN_USER_VIEW_TYPE), 0);
+    gtk_combo_box_set_active (GTK_COMBO_BOX(input_style_combo), viewtype);
+
+    int charset  = config->read (String (SCIM_CONFIG_IMENGINE_SUNPINYIN_USER_CHARHSET), 1);
+    gtk_combo_box_set_active (GTK_COMBO_BOX(charset_combo), charset);
+
+    bool stat;
+    stat = config->read (String (SCIM_CONFIG_IMENGINE_SUNPINYIN_USER_PAGE_MINUS), true);
+    gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(minus_pageup_button), stat);
+
+    stat = config->read (String (SCIM_CONFIG_IMENGINE_SUNPINYIN_USER_PAGE_BRACKET), true);
+    gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(bracket_pageup_button), stat);
+
+    stat = config->read (String (SCIM_CONFIG_IMENGINE_SUNPINYIN_USER_PAGE_COMMA), false);
+    gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(comma_pageup_button), stat);
+
+    gint value;
+    value = config->read (String (SCIM_CONFIG_IMENGINE_SUNPINYIN_USER_MEMORY_POWER), 5);
+    gtk_spin_button_set_value(GTK_SPIN_BUTTON(memory_power_button), value);
+
+    __have_changed = false;
+}
+
+static void
+save_config (const ConfigPointer &config)
+{
+    if (config.null())
+        return;
+
+    int no = gtk_combo_box_get_active(GTK_COMBO_BOX(input_style_combo));
+    config->write (String (SCIM_CONFIG_IMENGINE_SUNPINYIN_USER_VIEW_TYPE), no);
+
+    no = gtk_combo_box_get_active(GTK_COMBO_BOX(charset_combo));
+    config->write (String (SCIM_CONFIG_IMENGINE_SUNPINYIN_USER_CHARHSET), no);
+
+    gboolean stat;
+    stat = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(minus_pageup_button));
+    config->write (String (SCIM_CONFIG_IMENGINE_SUNPINYIN_USER_PAGE_MINUS), (bool)stat);
+
+    stat = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(bracket_pageup_button));
+    config->write (String (SCIM_CONFIG_IMENGINE_SUNPINYIN_USER_PAGE_BRACKET), (bool)stat);
+
+    stat = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(comma_pageup_button));
+    config->write (String (SCIM_CONFIG_IMENGINE_SUNPINYIN_USER_PAGE_COMMA), (bool)stat);
+
+    gint value;
+    value = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(memory_power_button));
+    config->write (String (SCIM_CONFIG_IMENGINE_SUNPINYIN_USER_MEMORY_POWER), value);
+    __have_changed = false;
+}
+
+bool
+query_changed ()
+{
+    return __have_changed;
+}
diff --git a/wrapper/scim/src/sunpinyin_keycode.h b/wrapper/scim/src/sunpinyin_keycode.h
new file mode 100644 (file)
index 0000000..fb8efef
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2007 Kov Chai <tchaikov@gmail.com>
+ *
+ * The contents of this file are subject to the terms of either the GNU Lesser
+ * General Public License Version 2.1 only ("LGPL") or the Common Development and
+ * Distribution License ("CDDL")(collectively, the "License"). You may not use this
+ * file except in compliance with the License. You can obtain a copy of the CDDL at
+ * http://www.opensource.org/licenses/cddl1.php and a copy of the LGPLv2.1 at
+ * http://www.opensource.org/licenses/lgpl-license.php. See the License for the 
+ * specific language governing permissions and limitations under the License. When
+ * distributing the software, include this License Header Notice in each file and
+ * include the full text of the License in the License file as well as the
+ * following notice:
+ * 
+ * NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND DISTRIBUTION LICENSE
+ * (CDDL)
+ * For Covered Software in this distribution, this License shall be governed by the
+ * laws of the State of California (excluding conflict-of-law provisions).
+ * Any litigation relating to this License shall be subject to the jurisdiction of
+ * the Federal Courts of the Northern District of California and the state courts
+ * of the State of California, with venue lying in Santa Clara County, California.
+ * 
+ * Contributor(s):
+ * 
+ * If you wish your version of this file to be governed by only the CDDL or only
+ * the LGPL Version 2.1, indicate your decision by adding "[Contributor]" elects to
+ * include this software in this distribution under the [CDDL or LGPL Version 2.1]
+ * license." If you don't indicate a single choice of license, a recipient has the
+ * option to distribute your version of this file under either the CDDL or the LGPL
+ * Version 2.1, or to extend the choice of license to its licensees as provided
+ * above. However, if you add LGPL Version 2.1 code and therefore, elected the LGPL
+ * Version 2 license, then the option applies only if the new code is made subject
+ * to such option by the copyright holder. 
+ */
+
+#ifndef SUNPINYIN_KEYCODE_H
+#define SUNPINYIN_KEYCODE_H
+
+#define Uses_SCIM_TYPES
+#define Uses_SCIM_EVENT
+#include <scim.h>
+
+using namespace scim;
+
+#define IM_VK_TAB            SCIM_KEY_Tab
+#define IM_VK_SHIFT          SCIM_KEY_Shift_L
+#define IM_VK_CONTROL        SCIM_KEY_Control_L
+#define IM_VK_CAPS_LOCK      SCIM_KEY_Caps_Lock
+
+#define IM_VK_SLASH          SCIM_KEY_slash
+#define IM_VK_QUOTE          SCIM_KEY_apostrophe
+#define IM_VK_QUOTEDBL       SCIM_KEY_quotedbl
+
+#define IM_VK_0              SCIM_KEY_0
+#define IM_VK_1              SCIM_KEY_1
+#define IM_VK_2              SCIM_KEY_2
+#define IM_VK_3              SCIM_KEY_3
+#define IM_VK_4              SCIM_KEY_4
+#define IM_VK_5              SCIM_KEY_5
+#define IM_VK_6              SCIM_KEY_6
+#define IM_VK_7              SCIM_KEY_7
+#define IM_VK_8              SCIM_KEY_8
+#define IM_VK_9              SCIM_KEY_9
+
+#define IM_VK_K              SCIM_KEY_k
+
+#endif//SUNPINYIN_KEYCODE_H
diff --git a/wrapper/scim/src/sunpinyin_lookup_table.cpp b/wrapper/scim/src/sunpinyin_lookup_table.cpp
new file mode 100644 (file)
index 0000000..5dde215
--- /dev/null
@@ -0,0 +1,213 @@
+/*
+ * Copyright (c) 2007 Kov Chai <tchaikov@gmail.com>
+ *
+ * The contents of this file are subject to the terms of either the GNU Lesser
+ * General Public License Version 2.1 only ("LGPL") or the Common Development and
+ * Distribution License ("CDDL")(collectively, the "License"). You may not use this
+ * file except in compliance with the License. You can obtain a copy of the CDDL at
+ * http://www.opensource.org/licenses/cddl1.php and a copy of the LGPLv2.1 at
+ * http://www.opensource.org/licenses/lgpl-license.php. See the License for the 
+ * specific language governing permissions and limitations under the License. When
+ * distributing the software, include this License Header Notice in each file and
+ * include the full text of the License in the License file as well as the
+ * following notice:
+ * 
+ * NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND DISTRIBUTION LICENSE
+ * (CDDL)
+ * For Covered Software in this distribution, this License shall be governed by the
+ * laws of the State of California (excluding conflict-of-law provisions).
+ * Any litigation relating to this License shall be subject to the jurisdiction of
+ * the Federal Courts of the Northern District of California and the state courts
+ * of the State of California, with venue lying in Santa Clara County, California.
+ * 
+ * Contributor(s):
+ * 
+ * If you wish your version of this file to be governed by only the CDDL or only
+ * the LGPL Version 2.1, indicate your decision by adding "[Contributor]" elects to
+ * include this software in this distribution under the [CDDL or LGPL Version 2.1]
+ * license." If you don't indicate a single choice of license, a recipient has the
+ * option to distribute your version of this file under either the CDDL or the LGPL
+ * Version 2.1, or to extend the choice of license to its licensees as provided
+ * above. However, if you add LGPL Version 2.1 code and therefore, elected the LGPL
+ * Version 2 license, then the option applies only if the new code is made subject
+ * to such option by the copyright holder. 
+ */
+
+#include <cassert>
+#include <vector>
+
+#include "portability.h"
+
+#include "sunpinyin_lookup_table.h"
+#include "sunpinyin_utils.h"
+
+#include <imi_uiobjects.h>
+
+using namespace scim;
+
+template <class Seg>
+class SegVector
+{
+    typedef typename Seg::value_type T;
+    std::vector<T>      m_buffer;
+    std::vector<uint32> m_index;
+public:
+    uint32 length() const {
+        return m_index.size();
+    }
+    
+    void push_back(const Seg& s) {
+        m_index.push_back(m_buffer.size());
+        m_buffer.insert(m_buffer.end(), s.begin(), s.end());
+    }
+    
+    void push_back(const T& t) {
+        m_index.push_back(m_buffer.size());
+        m_buffer.push_back(t);
+    }
+    
+    Seg operator [] (uint32 index) const {
+        const uint32 len = length();
+        if (index >= len)
+            return Seg();
+        typename std::vector<T>::const_iterator begin, end;
+        begin = m_buffer.begin() + m_index[index];
+        if (index < len - 1)
+            end = m_buffer.begin() + m_index[index+1];
+        else
+            end = m_buffer.end();
+        return Seg(begin, end);
+    }
+    
+    void clear() {
+        std::vector<T>     ().swap(m_buffer);
+        std::vector<uint32>().swap(m_index);
+    }
+};
+
+class SunLookupTable::SunLookupTableImpl
+{
+public:
+    SegVector<WideString>     m_candidates;
+    SegVector<AttributeList>  m_attributes;
+};
+
+SunLookupTable::SunLookupTable(int page_size)
+    : LookupTable(page_size),
+      m_impl( new SunLookupTableImpl ())
+{
+    std::vector <WideString> labels;
+    char buf [2] = { 0, 0 };
+    for (int i = 0; i < 9; ++i) {
+        buf [0] = '1' + i;
+        labels.push_back (utf8_mbstowcs (buf));
+    }
+
+    labels.push_back (utf8_mbstowcs ("0"));
+    fix_page_size(false);
+    set_candidate_labels (labels);
+}
+
+SunLookupTable::~SunLookupTable()
+{
+    delete m_impl;
+}
+
+WideString
+SunLookupTable::get_candidate (int index) const
+{
+    // the start point should be synced
+    SCIM_DEBUG_IMENGINE  (3) <<  "get_candidate(" << index << ")\n";
+    
+    index = translate_index(index);
+    
+    if (index < 0) {
+        SCIM_DEBUG_IMENGINE (2) << "index out of bound: " << index << "!\n";
+        return WideString();
+    }
+    else
+        return m_impl->m_candidates[index];
+}
+
+AttributeList
+SunLookupTable::get_attributes (int index) const
+{
+    index = translate_index(index);
+    
+    if (index < 0) {
+        SCIM_DEBUG_IMENGINE (2) << "index out of bound: " << index << "!\n";
+        return AttributeList();
+    }
+    else
+        return m_impl->m_attributes[index];
+}
+
+uint32
+SunLookupTable::number_of_candidates () const
+{
+    return m_total;
+}
+
+void
+SunLookupTable::clear()
+{
+    LookupTable::clear();
+    m_impl->m_candidates.clear();
+    m_impl->m_attributes.clear();
+}
+
+void
+SunLookupTable::update(const ICandidateList& cl)
+{
+    clear();
+
+    const int sz = cl.size();
+    m_total = cl.total();
+    
+    for (int i = 0, begin = 0; i < sz; ++i) {
+        const int len = append_candidate(cl, i, begin);
+        if (len)
+            begin += len;
+        else
+            break;
+    }
+    LookupTable::set_page_size(sz);
+    SCIM_DEBUG_IMENGINE (3) << "update() " << sz << "/" << m_total << " candidates updated\n";
+}
+
+int
+SunLookupTable::translate_index(int index) const
+{
+    // SunLookupTable *only* provides access to candidates in current page
+    assert(index >= get_current_page_start());
+    assert(index < (get_current_page_start() + get_current_page_size()));
+    return index - get_current_page_start();
+}
+
+int
+SunLookupTable::append_candidate(const ICandidateList& cl, int i, int begin)
+{
+    const TWCHAR* cand = 0;
+    int len = 0;
+    
+    if ( (cand = cl.candiString(i)) ) {
+        len = cl.candiSize(i);
+        m_impl->m_candidates.push_back( wstr_to_widestr(cand, len) );
+        // XXX, a better looking decoration should be used
+        // to disable this, simply s/push_back(attr)/push_back(AttributeList())/
+        Attribute attr(begin, len, SCIM_ATTR_DECORATE);
+        switch (cl.candiType(i)) {
+        case ICandidateList::BEST_TAIL:
+            attr.set_value(SCIM_ATTR_DECORATE_REVERSE);
+            break;
+        case ICandidateList::BEST_WORD:
+            attr.set_value(SCIM_ATTR_DECORATE_UNDERLINE);
+            break;
+        default:
+            // NORMAL_WORD, USER_SELECTED_WORD, ...
+            break;
+        }
+        m_impl->m_attributes.push_back(attr);
+    }
+    return len;
+}
diff --git a/wrapper/scim/src/sunpinyin_lookup_table.h b/wrapper/scim/src/sunpinyin_lookup_table.h
new file mode 100644 (file)
index 0000000..ec8862b
--- /dev/null
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2007 Kov Chai <tchaikov@gmail.com>
+ *
+ * The contents of this file are subject to the terms of either the GNU Lesser
+ * General Public License Version 2.1 only ("LGPL") or the Common Development and
+ * Distribution License ("CDDL")(collectively, the "License"). You may not use this
+ * file except in compliance with the License. You can obtain a copy of the CDDL at
+ * http://www.opensource.org/licenses/cddl1.php and a copy of the LGPLv2.1 at
+ * http://www.opensource.org/licenses/lgpl-license.php. See the License for the 
+ * specific language governing permissions and limitations under the License. When
+ * distributing the software, include this License Header Notice in each file and
+ * include the full text of the License in the License file as well as the
+ * following notice:
+ * 
+ * NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND DISTRIBUTION LICENSE
+ * (CDDL)
+ * For Covered Software in this distribution, this License shall be governed by the
+ * laws of the State of California (excluding conflict-of-law provisions).
+ * Any litigation relating to this License shall be subject to the jurisdiction of
+ * the Federal Courts of the Northern District of California and the state courts
+ * of the State of California, with venue lying in Santa Clara County, California.
+ * 
+ * Contributor(s):
+ * 
+ * If you wish your version of this file to be governed by only the CDDL or only
+ * the LGPL Version 2.1, indicate your decision by adding "[Contributor]" elects to
+ * include this software in this distribution under the [CDDL or LGPL Version 2.1]
+ * license." If you don't indicate a single choice of license, a recipient has the
+ * option to distribute your version of this file under either the CDDL or the LGPL
+ * Version 2.1, or to extend the choice of license to its licensees as provided
+ * above. However, if you add LGPL Version 2.1 code and therefore, elected the LGPL
+ * Version 2 license, then the option applies only if the new code is made subject
+ * to such option by the copyright holder. 
+ */
+
+#ifndef SUNPINYIN_LOOKUP_TABLE_H
+#define SUNPINYIN_LOOKUP_TABLE_H
+
+#define Uses_SCIM_LOOKUP_TABLE
+#include <scim.h>
+
+using namespace scim;
+
+class ICandidateList;
+
+class SunLookupTable : public LookupTable
+{
+    class SunLookupTableImpl;
+    SunLookupTableImpl* m_impl;
+
+    SunLookupTable (const SunLookupTable &);
+    const SunLookupTable & operator= (const SunLookupTable &);
+
+    uint32 m_total;
+    
+public:
+    SunLookupTable(int page_size = 10);
+    ~SunLookupTable();
+    virtual WideString get_candidate (int index) const;
+    virtual AttributeList get_attributes (int index) const;
+    virtual uint32 number_of_candidates () const;
+    virtual void clear();
+
+public:
+    /**
+     * @brief Update all candidates in current page
+     * called by winHandler::updateCandidates()
+     */
+    void update(const ICandidateList& cl);
+
+private:
+    /**
+     * translate the index in the list to the index in current page
+     */
+    int translate_index(int index) const;
+    int append_candidate(const ICandidateList& cl, int i, int begin);
+};
+
+#endif//SUNPINYIN_LOOKUP_TABLE_H
diff --git a/wrapper/scim/src/sunpinyin_private.h b/wrapper/scim/src/sunpinyin_private.h
new file mode 100644 (file)
index 0000000..e9c8d4d
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2007 Kov Chai <tchaikov@gmail.com>
+ *
+ * The contents of this file are subject to the terms of either the GNU Lesser
+ * General Public License Version 2.1 only ("LGPL") or the Common Development and
+ * Distribution License ("CDDL")(collectively, the "License"). You may not use this
+ * file except in compliance with the License. You can obtain a copy of the CDDL at
+ * http://www.opensource.org/licenses/cddl1.php and a copy of the LGPLv2.1 at
+ * http://www.opensource.org/licenses/lgpl-license.php. See the License for the 
+ * specific language governing permissions and limitations under the License. When
+ * distributing the software, include this License Header Notice in each file and
+ * include the full text of the License in the License file as well as the
+ * following notice:
+ * 
+ * NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND DISTRIBUTION LICENSE
+ * (CDDL)
+ * For Covered Software in this distribution, this License shall be governed by the
+ * laws of the State of California (excluding conflict-of-law provisions).
+ * Any litigation relating to this License shall be subject to the jurisdiction of
+ * the Federal Courts of the Northern District of California and the state courts
+ * of the State of California, with venue lying in Santa Clara County, California.
+ * 
+ * Contributor(s):
+ * 
+ * If you wish your version of this file to be governed by only the CDDL or only
+ * the LGPL Version 2.1, indicate your decision by adding "[Contributor]" elects to
+ * include this software in this distribution under the [CDDL or LGPL Version 2.1]
+ * license." If you don't indicate a single choice of license, a recipient has the
+ * option to distribute your version of this file under either the CDDL or the LGPL
+ * Version 2.1, or to extend the choice of license to its licensees as provided
+ * above. However, if you add LGPL Version 2.1 code and therefore, elected the LGPL
+ * Version 2 license, then the option applies only if the new code is made subject
+ * to such option by the copyright holder. 
+ */
+
+#ifndef SUNPINYIN_PRIVATE_H
+#define SUNPINYIN_PRIVATE_H
+
+// Include scim-sunpin configuration header
+#ifdef HAVE_CONFIG_H
+  #include <config.h>
+#endif
+
+#if defined(HAVE_LIBINTL_H) && defined(ENABLE_NLS)
+  #include <libintl.h>
+  #define _(String) dgettext(GETTEXT_PACKAGE,String)
+  #define N_(String) (String)
+#else
+  #define _(String) (String)
+  #define N_(String) (String)
+  #define bindtextdomain(Package,Directory)
+  #define textdomain(domain)
+  #define bind_textdomain_codeset(domain,codeset)
+#endif
+
+#endif //SUNPINYIN_PRIVATE_H
diff --git a/wrapper/scim/src/sunpinyin_utils.cpp b/wrapper/scim/src/sunpinyin_utils.cpp
new file mode 100644 (file)
index 0000000..b75c658
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2007 Kov Chai <tchaikov@gmail.com>
+ *
+ * The contents of this file are subject to the terms of either the GNU Lesser
+ * General Public License Version 2.1 only ("LGPL") or the Common Development and
+ * Distribution License ("CDDL")(collectively, the "License"). You may not use this
+ * file except in compliance with the License. You can obtain a copy of the CDDL at
+ * http://www.opensource.org/licenses/cddl1.php and a copy of the LGPLv2.1 at
+ * http://www.opensource.org/licenses/lgpl-license.php. See the License for the 
+ * specific language governing permissions and limitations under the License. When
+ * distributing the software, include this License Header Notice in each file and
+ * include the full text of the License in the License file as well as the
+ * following notice:
+ * 
+ * NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND DISTRIBUTION LICENSE
+ * (CDDL)
+ * For Covered Software in this distribution, this License shall be governed by the
+ * laws of the State of California (excluding conflict-of-law provisions).
+ * Any litigation relating to this License shall be subject to the jurisdiction of
+ * the Federal Courts of the Northern District of California and the state courts
+ * of the State of California, with venue lying in Santa Clara County, California.
+ * 
+ * Contributor(s):
+ * 
+ * If you wish your version of this file to be governed by only the CDDL or only
+ * the LGPL Version 2.1, indicate your decision by adding "[Contributor]" elects to
+ * include this software in this distribution under the [CDDL or LGPL Version 2.1]
+ * license." If you don't indicate a single choice of license, a recipient has the
+ * option to distribute your version of this file under either the CDDL or the LGPL
+ * Version 2.1, or to extend the choice of license to its licensees as provided
+ * above. However, if you add LGPL Version 2.1 code and therefore, elected the LGPL
+ * Version 2 license, then the option applies only if the new code is made subject
+ * to such option by the copyright holder. 
+ */
+
+#include "sunpinyin_utils.h"
+#include "sunpinyin_keycode.h"
+
+using namespace scim;
+
+WideString
+wstr_to_widestr(const TWCHAR* wstr)
+{
+    WideString wide_str;
+    copy(wstr, wstr+WCSLEN(wstr)+1, back_inserter(wide_str));
+    return wide_str;
+}
+
+WideString
+wstr_to_widestr(const TWCHAR* wstr, size_t len)
+{
+    WideString wide_str;
+    copy(wstr, wstr+len+1, back_inserter(wide_str));
+    return wide_str;
+}
+
diff --git a/wrapper/scim/src/sunpinyin_utils.h b/wrapper/scim/src/sunpinyin_utils.h
new file mode 100644 (file)
index 0000000..1f861c6
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2007 Kov Chai <tchaikov@gmail.com>
+ * 
+ * The contents of this file are subject to the terms of either the GNU Lesser
+ * General Public License Version 2.1 only ("LGPL") or the Common Development and
+ * Distribution License ("CDDL")(collectively, the "License"). You may not use this
+ * file except in compliance with the License. You can obtain a copy of the CDDL at
+ * http://www.opensource.org/licenses/cddl1.php and a copy of the LGPLv2.1 at
+ * http://www.opensource.org/licenses/lgpl-license.php. See the License for the 
+ * specific language governing permissions and limitations under the License. When
+ * distributing the software, include this License Header Notice in each file and
+ * include the full text of the License in the License file as well as the
+ * following notice:
+ * 
+ * NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND DISTRIBUTION LICENSE
+ * (CDDL)
+ * For Covered Software in this distribution, this License shall be governed by the
+ * laws of the State of California (excluding conflict-of-law provisions).
+ * Any litigation relating to this License shall be subject to the jurisdiction of
+ * the Federal Courts of the Northern District of California and the state courts
+ * of the State of California, with venue lying in Santa Clara County, California.
+ * 
+ * Contributor(s):
+ * 
+ * If you wish your version of this file to be governed by only the CDDL or only
+ * the LGPL Version 2.1, indicate your decision by adding "[Contributor]" elects to
+ * include this software in this distribution under the [CDDL or LGPL Version 2.1]
+ * license." If you don't indicate a single choice of license, a recipient has the
+ * option to distribute your version of this file under either the CDDL or the LGPL
+ * Version 2.1, or to extend the choice of license to its licensees as provided
+ * above. However, if you add LGPL Version 2.1 code and therefore, elected the LGPL
+ * Version 2 license, then the option applies only if the new code is made subject
+ * to such option by the copyright holder. 
+ */
+
+#ifndef SUNPINYIN_UTIL_H
+#define SUNPINYIN_UTIL_H
+
+#define Uses_SCIM_UTILITY
+
+#include "portability.h"
+
+#include <scim.h>
+
+using namespace scim;
+
+WideString wstr_to_widestr(const TWCHAR* wstr);
+WideString wstr_to_widestr(const TWCHAR* wstr, size_t);
+
+#endif// SUNPINYIN_UTIL_H
diff --git a/wrapper/xim/COPYING b/wrapper/xim/COPYING
new file mode 100644 (file)
index 0000000..a82e03e
--- /dev/null
@@ -0,0 +1 @@
+Refer to LGPL.LICENSE and OPENSOLARIS.LICENSE.
diff --git a/wrapper/xim/IMdkit/FrameMgr.c b/wrapper/xim/IMdkit/FrameMgr.c
new file mode 100644 (file)
index 0000000..9b49794
--- /dev/null
@@ -0,0 +1,2466 @@
+/******************************************************************
+Copyright 1993, 1994 by Digital Equipment Corporation, Maynard, Massachusetts,
+                        All Rights Reserved
+Permission to use, copy, modify, and distribute this software and its 
+documentation for any purpose and without fee is hereby granted, 
+provided that the above copyright notice appear in all copies and that
+both that copyright notice and this permission notice appear in 
+supporting documentation, and that the names of Digital or MIT not be
+used in advertising or publicity pertaining to distribution of the
+software without specific, written prior permission.  
+DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
+ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
+DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
+ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+SOFTWARE.
+  Author: Hiroyuki Miyamoto  Digital Equipment Corporation
+                             miyamoto@jrd.dec.com
+
+    This version tidied and debugged by Steve Underwood May 1999
+
+******************************************************************/
+
+#include <X11/Xlibint.h>
+#include <stdlib.h>
+#include "FrameMgr.h"
+
+/* Convenient macro */
+
+#define _UNIT(n)   ((int)(n) & 0xFF)
+#define _NUMBER(n) (((int)(n) >> 8) & 0xFF)
+
+/* For byte swapping */
+
+#define Swap16(p, n) ((p)->byte_swap ?       \
+(((n) << 8 & 0xFF00) | \
+ ((n) >> 8 & 0xFF)     \
+) : n)
+#define Swap32(p, n) ((p)->byte_swap ?            \
+        (((n) << 24 & 0xFF000000) | \
+         ((n) <<  8 & 0xFF0000) |   \
+         ((n) >>  8 & 0xFF00) |     \
+         ((n) >> 24 & 0xFF)         \
+        ) : n)
+#define Swap64(p, n) ((p)->byte_swap ?            \
+        (((n) << 56 & 0xFF00000000000000) | \
+         ((n) << 40 & 0xFF000000000000) |   \
+         ((n) << 24 & 0xFF0000000000) |     \
+         ((n) <<  8 & 0xFF00000000) |       \
+         ((n) >>  8 & 0xFF000000) |         \
+         ((n) >> 24 & 0xFF0000) |           \
+         ((n) >> 40 & 0xFF00) |             \
+         ((n) >> 56 & 0xFF)                 \
+        ) : n)
+
+/* Type definition */
+
+typedef struct _Iter *Iter;
+
+typedef struct _FrameInst *FrameInst;
+
+typedef union
+{
+    int num;           /* For BARRAY */
+    FrameInst fi;      /* For POINTER */
+    Iter iter;                 /* For ITER */
+} ExtraDataRec, *ExtraData;
+
+typedef struct _Chain
+{
+    ExtraDataRec d;
+    int frame_no;
+    struct _Chain *next;
+} ChainRec, *Chain;
+
+typedef struct _ChainMgr
+{
+    Chain top;
+    Chain tail;
+} ChainMgrRec, *ChainMgr;
+
+typedef struct _ChainIter
+{
+    Chain cur;
+} ChainIterRec, *ChainIter;
+
+typedef struct _FrameIter
+{
+    Iter iter;
+    Bool counting;
+    unsigned int counter;
+    int end;
+    struct _FrameIter* next;
+} FrameIterRec, *FrameIter;
+
+typedef struct _FrameInst
+{
+    XimFrame template;
+    ChainMgrRec cm;
+    int cur_no;
+} FrameInstRec;
+
+typedef void (*IterStartWatchProc) (Iter it, void *client_data);
+
+typedef struct _Iter
+{
+    XimFrame template;
+    int max_count;
+    Bool allow_expansion;
+    ChainMgrRec cm;
+    int cur_no;
+    IterStartWatchProc start_watch_proc;
+    void *client_data;
+    Bool start_counter;
+} IterRec;
+
+typedef struct _FrameMgr
+{
+    XimFrame frame;
+    FrameInst fi;
+    char *area;
+    int idx;
+    Bool byte_swap;
+    int total_size;
+    FrameIter iters;
+} FrameMgrRec;
+
+typedef union
+{
+    int num;           /* For BARRAY and PAD */
+    struct
+    {          /* For COUNTER_* */
+        Iter iter;
+        Bool is_byte_len;
+    } counter;
+} XimFrameTypeInfoRec, *XimFrameTypeInfo;
+
+/* Special values */
+#define NO_VALUE -1
+#define NO_VALID_FIELD -2
+
+static FrameInst FrameInstInit(XimFrame frame);
+static void FrameInstFree(FrameInst fi);
+static XimFrameType FrameInstGetNextType(FrameInst fi, XimFrameTypeInfo info);
+static XimFrameType FrameInstPeekNextType(FrameInst fi, XimFrameTypeInfo info);
+static FmStatus FrameInstSetSize(FrameInst fi, int num);
+static FmStatus FrameInstSetIterCount(FrameInst fi, int num);
+static int FrameInstGetTotalSize(FrameInst fi);
+static void FrameInstReset(FrameInst fi);
+
+static Iter IterInit(XimFrame frame, int count);
+static void IterFree(Iter it);
+static int FrameInstGetSize(FrameInst fi);
+static int IterGetSize(Iter it);
+static XimFrameType IterGetNextType(Iter it, XimFrameTypeInfo info);
+static XimFrameType IterPeekNextType(Iter it, XimFrameTypeInfo info);
+static FmStatus IterSetSize(Iter it, int num);
+static FmStatus IterSetIterCount(Iter it, int num);
+static int IterGetTotalSize(Iter it);
+static void IterReset(Iter it);
+static Bool IterIsLoopEnd(Iter it, Bool* myself);
+static void IterSetStartWatch(Iter it, IterStartWatchProc proc, void* client_data);
+static void _IterStartWatch(Iter it, void* client_data);
+
+static ExtraData ChainMgrGetExtraData(ChainMgr cm, int frame_no);
+static ExtraData ChainMgrSetData(ChainMgr cm, int frame_no,
+                                 ExtraDataRec data);
+static Bool ChainIterGetNext(ChainIter ci, int* frame_no, ExtraData d);
+static int _FrameInstIncrement(XimFrame frame, int count);
+static int _FrameInstDecrement(XimFrame frame, int count);
+static int _FrameInstGetItemSize(FrameInst fi, int cur_no);
+static Bool FrameInstIsIterLoopEnd(FrameInst fi);
+
+static FrameIter _FrameMgrAppendIter(FrameMgr fm, Iter it, int end);
+static FrameIter _FrameIterCounterIncr(FrameIter fitr, int i);
+static void _FrameMgrRemoveIter(FrameMgr fm, FrameIter it);
+static Bool _FrameMgrIsIterLoopEnd(FrameMgr fm);
+static Bool _FrameMgrProcessPadding(FrameMgr fm, FmStatus* status);
+
+#define IterGetIterCount(it) ((it)->allow_expansion ? \
+NO_VALUE : (it)->max_count)
+
+#define IterFixIteration(it) ((it)->allow_expansion = False)
+
+#define IterSetStarter(it) ((it)->start_counter = True)
+
+#define ChainMgrInit(cm) (cm)->top = (cm)->tail = NULL
+#define ChainMgrFree(cm)                \
+{                                       \
+    Chain tmp;                          \
+    Chain cur = (cm)->top;              \
+                                       \
+    while (cur)                         \
+    {                                   \
+        tmp = cur->next;                \
+        Xfree (cur);                    \
+       cur = tmp;                      \
+    }                                   \
+}
+
+#define ChainIterInit(ci, cm)           \
+{                                       \
+    (ci)->cur = (cm)->top;              \
+}
+
+/* ChainIterFree has nothing to do. */
+#define ChainIterFree(ci)
+
+#define FrameInstIsEnd(fi) ((fi)->template[(fi)->cur_no].type == EOL)
+
+FrameMgr FrameMgrInit (XimFrame frame, char* area, Bool byte_swap)
+{
+    FrameMgr fm;
+
+    fm = (FrameMgr) Xmalloc (sizeof (FrameMgrRec));
+
+    fm->frame = frame;
+    fm->fi = FrameInstInit (frame);
+    fm->area = (char *) area;
+    fm->idx = 0;
+    fm->byte_swap = byte_swap;
+    fm->total_size = NO_VALUE;
+    fm->iters = NULL;
+
+    return fm;
+}
+
+void FrameMgrInitWithData (FrameMgr fm,
+                           XimFrame frame,
+                           void * area,
+                           Bool byte_swap)
+{
+    fm->frame = frame;
+    fm->fi = FrameInstInit (frame);
+    fm->area = (char *) area;
+    fm->idx = 0;
+    fm->byte_swap = byte_swap;
+    fm->total_size = NO_VALUE;
+}
+
+void FrameMgrFree (FrameMgr fm)
+{
+    FrameIter p, cur;
+
+    p = fm->iters;
+    cur = p;
+
+    while (p)
+    {
+        p = p->next;
+        Xfree (cur);
+        cur = p;
+    }
+    /*endwhile*/
+
+    FrameInstFree (fm->fi);
+    Xfree (fm);
+}
+
+FmStatus FrameMgrSetBuffer (FrameMgr fm, void* area)
+{
+    if (fm->area)
+        return FmBufExist;
+    fm->area = (char *) area;
+    return FmSuccess;
+}
+
+FmStatus _FrameMgrPutToken (FrameMgr fm, void *data, int data_size)
+{
+    XimFrameType type;
+    XimFrameTypeInfoRec info;
+
+    if (fm->total_size != NO_VALUE  &&  fm->idx >= fm->total_size)
+        return FmNoMoreData;
+    /*endif*/
+    
+    type = FrameInstGetNextType(fm->fi, &info);
+
+    if (type & COUNTER_MASK)
+    {
+        unsigned long input_length;
+
+        if (info.counter.is_byte_len)
+        {
+            if ((input_length = IterGetTotalSize (info.counter.iter))
+                    == NO_VALUE)
+            {
+                return FmCannotCalc;
+            }
+            /*endif*/
+        }
+        else
+        {
+            if ((input_length = IterGetIterCount (info.counter.iter))
+                == NO_VALUE)
+            {
+                return FmCannotCalc;
+            }
+            /*endif*/
+        }
+        /*endif*/
+        switch (type)
+        {
+        case COUNTER_BIT8:
+            *(CARD8 *) (fm->area + fm->idx) = input_length;
+            fm->idx++;
+            break;
+        
+        case COUNTER_BIT16:
+            *(CARD16 *) (fm->area + fm->idx) = Swap16 (fm, input_length);
+            fm->idx += 2;
+            break;
+            
+        case COUNTER_BIT32:
+            *(CARD32 *) (fm->area + fm->idx) = Swap32 (fm, input_length);
+            fm->idx += 4;
+            break;
+
+#if defined(_NEED64BIT)
+        case COUNTER_BIT64:
+            *(CARD64 *) (fm->area + fm->idx) = Swap64 (fm, input_length);
+            fm->idx += 8;
+            break;
+#endif
+       default:
+           break;
+        }
+        /*endswitch*/
+        _FrameMgrPutToken(fm, data, data_size);
+        return FmSuccess;
+    }
+    /*endif*/
+
+    switch (type)
+    {
+    case BIT8:
+        if (data_size == sizeof (unsigned char))
+        {
+            unsigned long num = *(unsigned char *) data;
+            *(CARD8 *) (fm->area + fm->idx) = num;
+        }
+        else if (data_size == sizeof (unsigned short))
+        {
+            unsigned long num = *(unsigned short *) data;
+            *(CARD8 *) (fm->area + fm->idx) = num;
+        }
+        else if (data_size == sizeof (unsigned int))
+        {
+            unsigned long num = *(unsigned int *) data;
+            *(CARD8 *) (fm->area + fm->idx) = num;
+        }
+        else if (data_size == sizeof (unsigned long))
+        {
+            unsigned long num = *(unsigned long *) data;
+            *(CARD8 *) (fm->area + fm->idx) = num;
+        }
+        else
+        {
+            ; /* Should never be reached */
+        }
+        /*endif*/
+        fm->idx++;
+        return FmSuccess;
+
+    case BIT16:
+        if (data_size == sizeof (unsigned char))
+        {
+            unsigned long num = *(unsigned char *) data;
+            *(CARD16*)(fm->area + fm->idx) = Swap16 (fm, num);
+        }
+        else if (data_size == sizeof (unsigned short))
+        {
+            unsigned long num = *(unsigned short *) data;
+            *(CARD16 *) (fm->area + fm->idx) = Swap16 (fm, num);
+        }
+        else if (data_size == sizeof (unsigned int))
+        {
+            unsigned long num = *(unsigned int *) data;
+            *(CARD16 *) (fm->area + fm->idx) = Swap16 (fm, num);
+        }
+        else if (data_size == sizeof (unsigned long))
+        {
+            unsigned long num = *(unsigned long *) data;
+            *(CARD16 *) (fm->area + fm->idx) = Swap16 (fm, num);
+        }
+        else
+        {
+            ; /* Should never reached */
+        }
+        /*endif*/
+        fm->idx += 2;
+        return FmSuccess;
+
+    case BIT32:
+        if (data_size == sizeof (unsigned char))
+        {
+            unsigned long num = *(unsigned char *) data;
+            *(CARD32 *) (fm->area + fm->idx) = Swap32 (fm, num);
+        }
+        else if (data_size == sizeof (unsigned short))
+        {
+            unsigned long num = *(unsigned short *) data;
+            *(CARD32 *) (fm->area + fm->idx) = Swap32 (fm, num);
+        }
+        else if (data_size == sizeof (unsigned int))
+        {
+            unsigned long num = *(unsigned int *) data;
+            *(CARD32 *) (fm->area + fm->idx) = Swap32 (fm, num);
+        }
+        else if (data_size == sizeof (unsigned long))
+        {
+            unsigned long num = *(unsigned long *) data;
+            *(CARD32 *) (fm->area + fm->idx) = Swap32 (fm, num);
+        }
+        else
+        {
+            ; /* Should never reached */
+        }
+        /*endif*/
+        fm->idx += 4;
+        return FmSuccess;
+
+#if defined(_NEED64BIT)
+    case BIT64:
+        if (data_size == sizeof (unsigned char))
+        {
+            unsigned long num = *(unsigned char *) data;
+            *(CARD64 *) (fm->area + fm->idx) = Swap64 (fm, num);
+        }
+        else if (data_size == sizeof (unsigned short))
+        {
+            unsigned long num = *(unsigned short *) data;
+            *(CARD64 *) (fm->area + fm->idx) = Swap64 (fm, num);
+        }
+        else if (data_size == sizeof (unsigned int))
+        {
+            unsigned long num = *(unsigned int *) data;
+            *(CARD64 *) (fm->area + fm->idx) = Swap64 (fm, num);
+        }
+        else if (data_size == sizeof (unsigned long))
+        {
+            unsigned long num = *(unsigned long *) data;
+            *(CARD64 *) (fm->area + fm->idx) = Swap64 (fm, num);
+        }
+        else
+        {
+            ; /* Should never reached */
+        }
+        /*endif*/
+        fm->idx += 4;
+        return FmSuccess;
+#endif
+
+    case BARRAY:
+        if (info.num == NO_VALUE)
+            return FmInvalidCall;
+        /*endif*/
+        if (info.num > 0)
+        {
+            bcopy (*(char **) data, fm->area + fm->idx, info.num);
+            fm->idx += info.num;
+        }
+        /*endif*/
+        return FmSuccess;
+
+    case PADDING:
+        if (info.num == NO_VALUE)
+            return FmInvalidCall;
+        /*endif*/
+        fm->idx += info.num;
+        return _FrameMgrPutToken(fm, data, data_size);
+
+    case ITER:
+        return FmInvalidCall;
+        
+    case EOL:
+        return FmEOD;
+    default:
+       break;
+    }
+    /*endswitch*/
+    return (FmStatus) NULL;  /* Should never be reached */
+}
+
+FmStatus _FrameMgrGetToken (FrameMgr fm , void* data, int data_size)
+{
+    XimFrameType type;
+    static XimFrameTypeInfoRec info;  /* memory */
+    FrameIter fitr;
+
+    if (fm->total_size != NO_VALUE  &&  fm->idx >= fm->total_size)
+        return FmNoMoreData;
+    /*endif*/
+    
+    type = FrameInstGetNextType(fm->fi, &info);
+
+    if (type & COUNTER_MASK)
+    {
+        int end=0;
+        FrameIter client_data;
+
+        type &= ~COUNTER_MASK;
+        switch (type)
+        {
+        case BIT8:
+            end = *(CARD8 *) (fm->area + fm->idx);
+            break;
+        
+        case BIT16:
+            end = Swap16 (fm, *(CARD16 *) (fm->area + fm->idx));
+            break;
+        
+        case BIT32:
+            end = Swap32 (fm, *(CARD32 *) (fm->area + fm->idx));
+            break;
+
+#if defined(_NEED64BIT)        
+        case BIT64:
+            end = Swap64 (fm, *(CARD64 *) (fm->area + fm->idx));
+            break;
+#endif
+       default:
+           break;
+        }
+        /*endswitch*/
+        
+        if ((client_data = _FrameMgrAppendIter (fm, info.counter.iter, end)))
+        {
+            IterSetStarter (info.counter.iter);
+            IterSetStartWatch (info.counter.iter,
+                               _IterStartWatch,
+                               (void *) client_data);
+        }
+        /*endif*/
+    }
+    /*endif*/
+
+    type &= ~COUNTER_MASK;
+    switch (type)
+    {
+    case BIT8:
+        if (data_size == sizeof (unsigned char))
+        {
+            *(unsigned char*) data = *(CARD8 *) (fm->area + fm->idx);
+        }
+        else if (data_size == sizeof (unsigned short))
+        {
+            *(unsigned short *) data = *(CARD8 *) (fm->area + fm->idx);
+        }
+        else if (data_size == sizeof (unsigned int))
+        {
+            *(unsigned int *) data = *(CARD8 *) (fm->area + fm->idx);
+        }
+        else if (data_size == sizeof (unsigned long))
+        {
+            *(unsigned long *) data = *(CARD8 *) (fm->area + fm->idx);
+        }
+        else
+        {
+            ; /* Should never reached */
+        }
+        /*endif*/
+        fm->idx++;
+        if ((fitr = _FrameIterCounterIncr (fm->iters, 1/*BIT8*/)))
+            _FrameMgrRemoveIter (fm, fitr);
+        /*endif*/
+        return FmSuccess;
+
+    case BIT16:
+        if (data_size == sizeof (unsigned char))
+        {
+            *(unsigned char *) data =
+                Swap16 (fm, *(CARD16 *) (fm->area + fm->idx));
+        }
+        else if (data_size == sizeof (unsigned short))
+        {
+            *(unsigned short *) data =
+                Swap16 (fm, *(CARD16 *) (fm->area + fm->idx));
+        }
+        else if (data_size == sizeof (unsigned int))
+        {
+            *(unsigned int *) data =
+                Swap16 (fm, *(CARD16 *) (fm->area + fm->idx));
+        }
+        else if (data_size == sizeof (unsigned long))
+        {
+            *(unsigned long *) data =
+                Swap16 (fm, *(CARD16 *) (fm->area + fm->idx));
+        }
+        else
+        {
+            ; /* Should never reached */
+        }
+        /*endif*/
+        fm->idx += 2;
+        if ((fitr = _FrameIterCounterIncr (fm->iters, 2/*BIT16*/)))
+            _FrameMgrRemoveIter(fm, fitr);
+        /*endif*/
+        return FmSuccess;
+
+    case BIT32:
+        if (data_size == sizeof (unsigned char))
+        {
+            *(unsigned char *) data =
+                Swap32 (fm, *(CARD32 *) (fm->area + fm->idx));
+        }
+        else if (data_size == sizeof (unsigned short))
+        {
+            *(unsigned short *) data =
+                Swap32 (fm, *(CARD32 *) (fm->area + fm->idx));
+        }
+        else if (data_size == sizeof (unsigned int))
+        {
+            *(unsigned int *) data =
+                Swap32 (fm, *(CARD32 *) (fm->area + fm->idx));
+        }
+        else if (data_size == sizeof (unsigned long))
+        {
+            *(unsigned long *) data =
+                Swap32 (fm, *(CARD32 *) (fm->area + fm->idx));
+        }
+        else
+        {
+            ; /* Should never reached */
+        }
+        /*endif*/
+        fm->idx += 4;
+        if ((fitr = _FrameIterCounterIncr (fm->iters, 4/*BIT32*/)))
+            _FrameMgrRemoveIter (fm, fitr);
+        /*endif*/
+        return FmSuccess;
+
+#if defined(_NEED64BIT)    
+    case BIT64:
+        if (data_size == sizeof (unsigned char))
+        {
+            *(unsigned char *) data =
+                Swap64 (fm, *(CARD64 *) (fm->area + fm->idx));
+        }
+        else if (data_size == sizeof (unsigned short))
+        {
+            *(unsigned short *) data =
+                Swap64 (fm, *(CARD64 *) (fm->area + fm->idx));
+        }
+        else if (data_size == sizeof (unsigned int))
+        {
+            *(unsigned int *) data =
+                Swap64 (fm, *(CARD64 *) (fm->area + fm->idx));
+        }
+        else if (data_size == sizeof (unsigned long))
+        {
+            *(unsigned long *) data =
+                Swap64 (fm, *(CARD64 *) (fm->area + fm->idx));
+        }
+        else
+        {
+            ; /* Should never reached */
+        }
+        /*endif*/
+        fm->idx += 8;
+        if ((fitr = _FrameIterCounterIncr (fm->iters, 8/*BIT64*/)))
+            _FrameMgrRemoveIter (fm, fitr);
+        /*endif*/
+        return FmSuccess;
+#endif
+
+    case BARRAY:
+        if (info.num == NO_VALUE)
+            return FmInvalidCall;
+        /*endif*/
+        if (info.num > 0)
+        {
+            *(char **) data = fm->area + fm->idx;
+            
+            fm->idx += info.num;
+            if ((fitr = _FrameIterCounterIncr (fm->iters, info.num)))
+                _FrameMgrRemoveIter (fm, fitr);
+            /*endif*/
+        }
+        else
+        {
+            *(char **) data = NULL;
+        }
+        /*endif*/
+        return FmSuccess;
+
+    case PADDING:
+        if (info.num == NO_VALUE)
+            return FmInvalidCall;
+        /*endif*/
+        fm->idx += info.num;
+        if ((fitr = _FrameIterCounterIncr (fm->iters, info.num)))
+            _FrameMgrRemoveIter (fm, fitr);
+        /*endif*/
+        return _FrameMgrGetToken (fm, data, data_size);
+
+    case ITER:
+        return FmInvalidCall;  /* if comes here, it's a bug! */
+
+    case EOL:
+        return FmEOD;
+    default:
+       break;
+    }
+    /*endswitch*/
+    return (FmStatus) NULL;  /* Should never be reached */
+}
+
+FmStatus FrameMgrSetSize (FrameMgr fm, int barray_size)
+{
+    if (FrameInstSetSize (fm->fi, barray_size) == FmSuccess)
+        return FmSuccess;
+    /*endif*/
+    return FmNoMoreData;
+}
+
+FmStatus FrameMgrSetIterCount (FrameMgr fm, int count)
+{
+    if (FrameInstSetIterCount (fm->fi, count) == FmSuccess)
+        return FmSuccess;
+    /*endif*/
+    return FmNoMoreData;
+}
+
+FmStatus FrameMgrSetTotalSize (FrameMgr fm, int total_size)
+{
+    fm->total_size = total_size;
+    return FmSuccess;
+}
+
+int FrameMgrGetTotalSize (FrameMgr fm)
+{
+    return FrameInstGetTotalSize (fm->fi);
+}
+
+int FrameMgrGetSize (FrameMgr fm)
+{
+    register int ret_size;
+
+    ret_size = FrameInstGetSize (fm->fi);
+    if (ret_size == NO_VALID_FIELD)
+        return NO_VALUE;
+    /*endif*/
+    return ret_size;
+}
+
+FmStatus FrameMgrSkipToken (FrameMgr fm, int skip_count)
+{
+    XimFrameType type;
+    XimFrameTypeInfoRec info;
+    register int i;
+
+    if (fm->total_size != NO_VALUE  &&  fm->idx >= fm->total_size)
+        return FmNoMoreData;
+    /*endif*/
+    for (i = 0;  i < skip_count;  i++)
+    {
+        type = FrameInstGetNextType (fm->fi, &info);
+        type &= ~COUNTER_MASK;
+
+        switch (type)
+        {
+        case BIT8:
+            fm->idx++;
+            break;
+            
+        case BIT16:
+            fm->idx += 2;
+            break;
+            
+        case BIT32:
+            fm->idx += 4;
+            break;
+            
+        case BIT64:
+            fm->idx += 8;
+            break;
+            
+        case BARRAY:
+            if (info.num == NO_VALUE)
+                return FmInvalidCall;
+            /*endif*/
+            fm->idx += info.num;
+            break;
+            
+        case PADDING:
+            if (info.num == NO_VALUE)
+                return FmInvalidCall;
+            /*endif*/
+            fm->idx += info.num;
+            return FrameMgrSkipToken (fm, skip_count);
+            
+        case ITER:
+            return FmInvalidCall;
+            
+        case EOL:
+            return FmEOD;
+       default:
+           break;
+        }
+        /*endswitch*/
+    }
+    /*endfor*/
+    return FmSuccess;
+}
+
+void FrameMgrReset (FrameMgr fm)
+{
+    fm->idx = 0;
+    FrameInstReset (fm->fi);
+}
+
+Bool FrameMgrIsIterLoopEnd (FrameMgr fm, FmStatus* status)
+{
+    do
+    {
+        if (_FrameMgrIsIterLoopEnd (fm))
+            return  True;
+        /*endif*/
+    }
+    while (_FrameMgrProcessPadding (fm, status));
+
+    return False;
+}
+
+
+/* Internal routines */
+
+static Bool _FrameMgrIsIterLoopEnd (FrameMgr fm)
+{
+    return FrameInstIsIterLoopEnd (fm->fi);
+}
+
+static Bool _FrameMgrProcessPadding (FrameMgr fm, FmStatus* status)
+{
+    XimFrameTypeInfoRec info;
+    XimFrameType next_type = FrameInstPeekNextType (fm->fi, &info);
+    FrameIter fitr;
+
+    if (next_type == PADDING)
+    {
+        if (info.num == NO_VALUE)
+        {
+            *status = FmInvalidCall;
+            return True;
+        }
+        /*endif*/
+        next_type = FrameInstGetNextType (fm->fi, &info);
+        fm->idx += info.num;
+        if ((fitr = _FrameIterCounterIncr (fm->iters, info.num)))
+            _FrameMgrRemoveIter (fm, fitr);
+        /*endif*/
+        *status = FmSuccess;
+        return True;
+    }
+    /*endif*/
+    *status = FmSuccess;
+    return False;
+}
+
+static FrameInst FrameInstInit (XimFrame frame)
+{
+    FrameInst fi;
+
+    fi = (FrameInst) Xmalloc (sizeof (FrameInstRec));
+
+    fi->template = frame;
+    fi->cur_no = 0;
+    ChainMgrInit (&fi->cm);
+    return fi;
+}
+
+static void FrameInstFree (FrameInst fi)
+{
+    ChainIterRec ci;
+    int frame_no;
+    ExtraDataRec d;
+
+    ChainIterInit (&ci, &fi->cm);
+
+    while (ChainIterGetNext (&ci, &frame_no, &d))
+    {
+        register XimFrameType type;
+        type = fi->template[frame_no].type;
+        if (type == ITER)
+        {
+            if (d.iter)
+                IterFree (d.iter);
+            /*endif*/
+        }
+        else if (type == POINTER)
+        {
+            if (d.fi)
+                FrameInstFree (d.fi);
+            /*endif*/
+        }
+        /*endif*/
+    }
+    /*endwhile*/
+    ChainIterFree (&ci);
+    ChainMgrFree (&fi->cm);
+    Xfree (fi);
+}
+
+static XimFrameType FrameInstGetNextType(FrameInst fi, XimFrameTypeInfo info)
+{
+    XimFrameType ret_type;
+
+    ret_type = fi->template[fi->cur_no].type;
+
+    switch (ret_type)
+    {
+    case BIT8:
+    case BIT16:
+    case BIT32:
+    case BIT64:
+    case EOL:
+        fi->cur_no = _FrameInstIncrement(fi->template, fi->cur_no);
+        break;
+
+    case COUNTER_BIT8:
+    case COUNTER_BIT16:
+    case COUNTER_BIT32:
+    case COUNTER_BIT64:
+        if (info)
+        {
+            register int offset, iter_idx;
+
+            info->counter.is_byte_len =
+                (((long) fi->template[fi->cur_no].data & 0xFF)) == FmCounterByte;
+            offset = ((long) fi->template[fi->cur_no].data) >> 8;
+            iter_idx = fi->cur_no + offset;
+            if (fi->template[iter_idx].type == ITER)
+            {
+                ExtraData d;
+                ExtraDataRec dr;
+
+                if ((d = ChainMgrGetExtraData (&fi->cm, iter_idx)) == NULL)
+                {
+                    dr.iter = IterInit (&fi->template[iter_idx + 1], NO_VALUE);
+                    d = ChainMgrSetData (&fi->cm, iter_idx, dr);
+                }
+                /*endif*/
+                info->counter.iter = d->iter;
+            }
+            else
+            {
+                /* Should never reach here */
+            }
+            /*endif*/
+        }
+        /*endif*/
+        fi->cur_no = _FrameInstIncrement (fi->template, fi->cur_no);
+        break;
+
+    case BARRAY:
+        if (info)
+        {
+            ExtraData d;
+
+            if ((d = ChainMgrGetExtraData (&fi->cm, fi->cur_no)) == NULL)
+                info->num = NO_VALUE;
+            else
+                info->num = d->num;
+            /*endif*/
+        }
+        /*endif*/
+        fi->cur_no = _FrameInstIncrement (fi->template, fi->cur_no);
+        break;
+
+    case PADDING:
+        if (info)
+        {
+            register int unit;
+            register int number;
+            register int size;
+            register int i;
+
+            unit = _UNIT ((long) fi->template[fi->cur_no].data);
+            number = _NUMBER ((long) fi->template[fi->cur_no].data);
+
+            i = fi->cur_no;
+            size = 0;
+            while (number > 0)
+            {
+                i = _FrameInstDecrement (fi->template, i);
+                size += _FrameInstGetItemSize (fi, i);
+                number--;
+            }
+            /*endwhile*/
+            info->num = (unit - (size%unit))%unit;
+        }
+        /*endif*/
+        fi->cur_no = _FrameInstIncrement (fi->template, fi->cur_no);
+        break;
+
+    case ITER:
+        {
+            ExtraData d;
+            ExtraDataRec dr;
+            XimFrameType sub_type;
+
+
+            if ((d = ChainMgrGetExtraData (&fi->cm, fi->cur_no)) == NULL)
+            {
+                dr.iter = IterInit (&fi->template[fi->cur_no + 1], NO_VALUE);
+                d = ChainMgrSetData (&fi->cm, fi->cur_no, dr);
+            }
+            /*endif*/
+            sub_type = IterGetNextType (d->iter, info);
+            if (sub_type == EOL)
+            {
+                fi->cur_no = _FrameInstIncrement (fi->template, fi->cur_no);
+                ret_type = FrameInstGetNextType (fi, info);
+            }
+            else
+            {
+                ret_type = sub_type;
+            }
+            /*endif*/
+        }
+        break;
+
+    case POINTER:
+        {
+            ExtraData d;
+            ExtraDataRec dr;
+            XimFrameType sub_type;
+
+            if ((d = ChainMgrGetExtraData (&fi->cm, fi->cur_no)) == NULL)
+            {
+                dr.fi = FrameInstInit (fi->template[fi->cur_no + 1].data);
+                d = ChainMgrSetData (&fi->cm, fi->cur_no, dr);
+            }
+            /*endif*/
+            sub_type = FrameInstGetNextType (d->fi, info);
+            if (sub_type == EOL)
+            {
+                fi->cur_no = _FrameInstIncrement (fi->template, fi->cur_no);
+                ret_type = FrameInstGetNextType (fi, info);
+            }
+            else
+            {
+                ret_type = sub_type;
+            }
+            /*endif*/
+        }
+        break;
+    default:
+       break;
+    }
+    /*endswitch*/
+    return ret_type;
+}
+
+static XimFrameType FrameInstPeekNextType (FrameInst fi, XimFrameTypeInfo info)
+{
+    XimFrameType ret_type;
+
+    ret_type = fi->template[fi->cur_no].type;
+
+    switch (ret_type)
+    {
+    case BIT8:
+    case BIT16:
+    case BIT32:
+    case BIT64:
+    case EOL:
+        break;
+
+    case COUNTER_BIT8:
+    case COUNTER_BIT16:
+    case COUNTER_BIT32:
+    case COUNTER_BIT64:
+        if (info)
+        {
+            register int offset;
+           register int iter_idx;
+
+            info->counter.is_byte_len =
+                (((long) fi->template[fi->cur_no].data) & 0xFF) == FmCounterByte;
+            offset = ((long)fi->template[fi->cur_no].data) >> 8;
+            iter_idx = fi->cur_no + offset;
+            if (fi->template[iter_idx].type == ITER)
+            {
+                ExtraData d;
+                ExtraDataRec dr;
+
+                if ((d = ChainMgrGetExtraData (&fi->cm, iter_idx)) == NULL)
+                {
+                    dr.iter = IterInit (&fi->template[iter_idx + 1], NO_VALUE);
+                    d = ChainMgrSetData (&fi->cm, iter_idx, dr);
+                }
+                /*endif*/
+                info->counter.iter = d->iter;
+            }
+            else
+            {
+                /* Should not be reached here */
+            }
+            /*endif*/
+        }
+        /*endif*/
+        break;
+
+    case BARRAY:
+        if (info)
+        {
+            ExtraData d;
+
+            if ((d = ChainMgrGetExtraData (&fi->cm, fi->cur_no)) == NULL)
+                info->num = NO_VALUE;
+            else
+                info->num = d->num;
+            /*endif*/
+        }
+        /*endif*/
+        break;
+
+    case PADDING:
+        if (info)
+        {
+            register int unit;
+            register int number;
+            register int size;
+            register int i;
+
+            unit = _UNIT ((long) fi->template[fi->cur_no].data);
+            number = _NUMBER ((long) fi->template[fi->cur_no].data);
+
+            i = fi->cur_no;
+            size = 0;
+            while (number > 0)
+            {
+                i = _FrameInstDecrement (fi->template, i);
+                size += _FrameInstGetItemSize (fi, i);
+                number--;
+            }
+            /*endwhile*/
+            info->num = (unit - (size%unit))%unit;
+        }
+        /*endif*/
+        break;
+
+    case ITER:
+        {
+            ExtraData d;
+            ExtraDataRec dr;
+            XimFrameType sub_type;
+
+            if ((d = ChainMgrGetExtraData (&fi->cm, fi->cur_no)) == NULL)
+            {
+                dr.iter = IterInit (&fi->template[fi->cur_no + 1], NO_VALUE);
+                d = ChainMgrSetData (&fi->cm, fi->cur_no, dr);
+            }
+            /*endif*/
+            sub_type = IterPeekNextType (d->iter, info);
+            if (sub_type == EOL)
+                ret_type = FrameInstPeekNextType (fi, info);
+            else
+                ret_type = sub_type;
+            /*endif*/
+        }
+        break;
+
+    case POINTER:
+        {
+            ExtraData d;
+            ExtraDataRec dr;
+            XimFrameType sub_type;
+
+            if ((d = ChainMgrGetExtraData (&fi->cm, fi->cur_no)) == NULL)
+            {
+                dr.fi = FrameInstInit (fi->template[fi->cur_no + 1].data);
+                d = ChainMgrSetData (&fi->cm, fi->cur_no, dr);
+            }
+            /*endif*/
+            sub_type = FrameInstPeekNextType (d->fi, info);
+            if (sub_type == EOL)
+                ret_type = FrameInstPeekNextType (fi, info);
+            else
+                ret_type = sub_type;
+            /*endif*/
+       default:
+           break;
+        }
+        break;
+    }
+    /*endswitch*/
+    return ret_type;
+}
+
+static Bool FrameInstIsIterLoopEnd (FrameInst fi)
+{
+    Bool ret = False;
+
+    if (fi->template[fi->cur_no].type == ITER)
+    {
+        ExtraData d = ChainMgrGetExtraData (&fi->cm, fi->cur_no);
+        Bool yourself;
+
+        if (d)
+        {
+            ret = IterIsLoopEnd (d->iter, &yourself);
+            if (ret  &&  yourself)
+                fi->cur_no = _FrameInstIncrement (fi->template, fi->cur_no);
+            /*endif*/
+        }
+        /*endif*/
+    }
+    /*endif*/
+    return (ret);
+}
+
+static FrameIter _FrameMgrAppendIter (FrameMgr fm, Iter it, int end)
+{
+    FrameIter p = fm->iters;
+
+    while (p  &&  p->next)
+        p = p->next;
+    /*endwhile*/
+    
+    if (!p)
+    {
+        fm->iters =
+        p = (FrameIter) Xmalloc (sizeof (FrameIterRec));
+    }
+    else
+    {
+        p->next = (FrameIter) Xmalloc (sizeof (FrameIterRec));
+        p = p->next;
+    }
+    /*endif*/
+    if (p)
+    {
+        p->iter = it;
+        p->counting = False;
+        p->counter = 0;
+        p->end = end;
+        p->next = NULL;
+    }
+    /*endif*/
+    return (p);
+}
+
+static void _FrameMgrRemoveIter (FrameMgr fm, FrameIter it)
+{
+    FrameIter prev;
+    FrameIter p;
+
+    prev = NULL;
+    p = fm->iters;
+    while (p)
+    {
+        if (p == it)
+        {
+            if (prev)
+                prev->next = p->next;
+            else
+                fm->iters = p->next;
+            /*endif*/
+            Xfree (p);
+            break;
+        }
+        /*endif*/
+        prev = p;
+        p = p->next;
+    }
+    /*endwhile*/
+}
+
+static FrameIter _FrameIterCounterIncr (FrameIter fitr, int i)
+{
+    FrameIter p = fitr;
+
+    while (p)
+    {
+        if (p->counting)
+        {
+            p->counter += i;
+            if (p->counter >= p->end)
+            {
+                IterFixIteration (p->iter);
+                return (p);
+            }
+            /*endif*/
+        }
+        /*endif*/
+        p = p->next;
+    }
+    /*endwhile*/
+    return (NULL);
+}
+
+static void _IterStartWatch (Iter it, void *client_data)
+{
+    FrameIter p = (FrameIter) client_data;
+    p->counting = True;
+}
+
+static FmStatus FrameInstSetSize (FrameInst fi, int num)
+{
+    ExtraData d;
+    ExtraDataRec dr;
+    XimFrameType type;
+    register int i;
+
+    i = 0;
+    while ((type = fi->template[i].type) != EOL)
+    {
+        switch (type)
+        {
+        case BARRAY:
+            if ((d = ChainMgrGetExtraData (&fi->cm, i)) == NULL)
+            {
+                dr.num = -1;
+                d = ChainMgrSetData (&fi->cm, i, dr);
+            }
+            /*endif*/
+            if (d->num == NO_VALUE)
+            {
+                d->num = num;
+                return FmSuccess;
+            }
+            /*endif*/
+            break;
+        case ITER:
+            if ((d = ChainMgrGetExtraData (&fi->cm, i)) == NULL)
+            {
+                dr.iter = IterInit (&fi->template[i + 1], NO_VALUE);
+                d = ChainMgrSetData (&fi->cm, i, dr);
+            }
+            /*endif*/
+            if (IterSetSize (d->iter, num) == FmSuccess)
+                return FmSuccess;
+            /*endif*/
+            break;
+            
+        case POINTER:
+            if ((d = ChainMgrGetExtraData(&fi->cm, i)) == NULL)
+            {
+                dr.fi = FrameInstInit(fi->template[i + 1].data);
+                d = ChainMgrSetData(&fi->cm, i, dr);
+            }
+            /*endif*/
+            if (FrameInstSetSize(d->fi, num) == FmSuccess)
+                return FmSuccess;
+            /*endif*/
+            break;
+       default:
+           break;
+        }
+        /*endswitch*/
+        i = _FrameInstIncrement(fi->template, i);
+    }
+    /*endwhile*/
+    return FmNoMoreData;
+}
+
+static int FrameInstGetSize (FrameInst fi)
+{
+    XimFrameType type;
+    register int i;
+    ExtraData d;
+    ExtraDataRec dr;
+    int ret_size;
+
+    i = fi->cur_no;
+    while ((type = fi->template[i].type) != EOL)
+    {
+        switch (type)
+        {
+        case BARRAY:
+            if ((d = ChainMgrGetExtraData (&fi->cm, i)) == NULL)
+                return NO_VALUE;
+            /*endif*/
+            return d->num;
+
+        case ITER:
+            if ((d = ChainMgrGetExtraData (&fi->cm, i)) == NULL)
+            {
+                dr.iter = IterInit (&fi->template[i + 1], NO_VALUE);
+                d = ChainMgrSetData (&fi->cm, i, dr);
+            }
+            /*endif*/
+            ret_size = IterGetSize(d->iter);
+            if (ret_size != NO_VALID_FIELD)
+                return ret_size;
+            /*endif*/
+            break;
+            
+        case POINTER:
+            if ((d = ChainMgrGetExtraData (&fi->cm, i)) == NULL)
+            {
+                dr.fi = FrameInstInit (fi->template[i + 1].data);
+                d = ChainMgrSetData (&fi->cm, i, dr);
+            }
+            /*endif*/
+            ret_size = FrameInstGetSize (d->fi);
+            if (ret_size != NO_VALID_FIELD)
+                return ret_size;
+            /*endif*/
+            break;
+       default:
+           break;
+        }
+        /*endswitch*/
+        i = _FrameInstIncrement (fi->template, i);
+    }
+    /*endwhile*/
+    return NO_VALID_FIELD;
+}
+
+static FmStatus FrameInstSetIterCount (FrameInst fi, int num)
+{
+    ExtraData d;
+    ExtraDataRec dr;
+    register int i;
+    XimFrameType type;
+
+    i = 0;
+    while ((type = fi->template[i].type) != EOL)
+    {
+        switch (type)
+        {
+        case ITER:
+            if ((d = ChainMgrGetExtraData (&fi->cm, i)) == NULL)
+            {
+                dr.iter = IterInit (&fi->template[i + 1], num);
+                (void)ChainMgrSetData (&fi->cm, i, dr);
+                return FmSuccess;
+            }
+            /*endif*/
+            if (IterSetIterCount (d->iter, num) == FmSuccess)
+                return FmSuccess;
+            /*endif*/
+            break;
+            
+        case POINTER:
+            if ((d = ChainMgrGetExtraData (&fi->cm, i)) == NULL)
+            {
+                dr.fi = FrameInstInit (fi->template[i + 1].data);
+                d = ChainMgrSetData (&fi->cm, i, dr);
+            }
+            /*endif*/
+            if (FrameInstSetIterCount (d->fi, num) == FmSuccess)
+                return FmSuccess;
+            /*endif*/
+            break;
+
+       default:
+           break;
+        }
+        /*endswitch*/
+        i = _FrameInstIncrement (fi->template, i);
+    }
+    /*endwhile*/
+    return FmNoMoreData;
+}
+
+static int FrameInstGetTotalSize (FrameInst fi)
+{
+    register int size;
+    register int i;
+
+    size = 0;
+    i = 0;
+
+    while (fi->template[i].type != EOL)
+    {
+        size += _FrameInstGetItemSize (fi, i);
+        i = _FrameInstIncrement (fi->template, i);
+    }
+    /*endwhile*/
+    return size;
+}
+
+static void FrameInstReset (FrameInst fi)
+{
+    ChainIterRec ci;
+    int frame_no;
+    ExtraDataRec d;
+
+    ChainIterInit (&ci, &fi->cm);
+
+    while (ChainIterGetNext (&ci, &frame_no, &d))
+    {
+        register XimFrameType type;
+        type = fi->template[frame_no].type;
+        if (type == ITER)
+        {
+            if (d.iter)
+                IterReset (d.iter);
+            /*endif*/
+        }
+        else if (type == POINTER)
+        {
+            if (d.fi)
+                FrameInstReset (d.fi);
+            /*endif*/
+        }
+        /*endif*/
+    }
+    /*endwhile*/
+    ChainIterFree (&ci);
+
+    fi->cur_no = 0;
+}
+
+static Iter IterInit (XimFrame frame, int count)
+{
+    Iter it;
+    register XimFrameType type;
+
+    it = (Iter) Xmalloc (sizeof (IterRec));
+    it->template = frame;
+    it->max_count = (count == NO_VALUE)  ?  0  :  count;
+    it->allow_expansion = (count == NO_VALUE);
+    it->cur_no = 0;
+    it->start_watch_proc = NULL;
+    it->client_data = NULL;
+    it->start_counter = False;
+
+    type = frame->type;
+    if (type & COUNTER_MASK)
+    {
+        /* COUNTER_XXX cannot be an item of a ITER */
+        Xfree (it);
+        return NULL;
+    }
+    /*endif*/
+
+    switch (type)
+    {
+    case BIT8:
+    case BIT16:
+    case BIT32:
+    case BIT64:
+        /* Do nothing */
+        break;
+        
+    case BARRAY:
+    case ITER:
+    case POINTER:
+        ChainMgrInit (&it->cm);
+        break;
+        
+    default:
+        Xfree (it);
+        return NULL; /* This should never occur */
+    }
+    /*endswitch*/
+    return it;
+}
+
+static void IterFree (Iter it)
+{
+    switch (it->template->type)
+    {
+    case BARRAY:
+        ChainMgrFree (&it->cm);
+        break;
+    
+    case ITER:
+        {
+            ChainIterRec ci;
+            int count;
+            ExtraDataRec d;
+
+            ChainIterInit (&ci, &it->cm);
+            while (ChainIterGetNext (&ci, &count, &d))
+                IterFree (d.iter);
+            /*endwhile*/
+            ChainIterFree (&ci);
+            ChainMgrFree (&it->cm);
+        }
+        break;
+    
+    case POINTER:
+        {
+            ChainIterRec ci;
+            int count;
+            ExtraDataRec dr;
+    
+            ChainIterInit (&ci, &it->cm);
+            while (ChainIterGetNext (&ci, &count, &dr))
+                FrameInstFree (dr.fi);
+            /*endwhile*/
+            ChainIterFree (&ci);
+            ChainMgrFree (&it->cm);
+        }
+        break;
+
+    default:
+       break;
+    }
+    /*endswitch*/
+    Xfree (it);
+}
+
+static Bool IterIsLoopEnd (Iter it, Bool *myself)
+{
+    Bool ret = False;
+    *myself = False;
+
+    if (!it->allow_expansion  &&  (it->cur_no == it->max_count))
+    {
+        *myself = True;
+        return True;
+    }
+    /*endif*/
+    
+    if (it->template->type == POINTER)
+    {
+        ExtraData d = ChainMgrGetExtraData (&it->cm, it->cur_no);
+        if (d)
+        {
+            if (FrameInstIsIterLoopEnd (d->fi))
+            {
+                ret = True;
+            }
+            else
+            {
+                if (FrameInstIsEnd (d->fi))
+                {
+                    it->cur_no++;
+                    if (!it->allow_expansion  &&  it->cur_no == it->max_count)
+                    {
+                        *myself = True;
+                        ret = True;
+                    }
+                    /*endif*/
+                }
+                /*endif*/
+            }
+            /*endif*/
+        }
+        /*endif*/
+    }
+    else if (it->template->type == ITER)
+    {
+        ExtraData d = ChainMgrGetExtraData (&it->cm, it->cur_no);
+        if (d)
+        {
+            Bool yourself;
+            
+            if (IterIsLoopEnd (d->iter, &yourself))
+                ret = True;
+            /*endif*/
+        }
+        /*endif*/
+    }
+    /*endif*/
+
+    return ret;
+}
+
+static XimFrameType IterGetNextType (Iter it, XimFrameTypeInfo info)
+{
+    XimFrameType type = it->template->type;
+
+    if (it->start_counter)
+    {
+        (*it->start_watch_proc) (it, it->client_data);
+        it->start_counter = False;
+    }
+    /*endif*/
+    if (it->cur_no >= it->max_count)
+    {
+        if (it->allow_expansion)
+            it->max_count = it->cur_no + 1;
+        else
+            return EOL;
+        /*endif*/
+    }
+    /*endif*/
+
+    switch (type)
+    {
+    case BIT8:
+    case BIT16:
+    case BIT32:
+    case BIT64:
+        it->cur_no++;
+        return type;
+
+    case BARRAY:
+        if (info)
+        {
+            ExtraData d;
+    
+            if ((d = ChainMgrGetExtraData (&it->cm, it->cur_no)) == NULL)
+                info->num = NO_VALUE;
+            else
+                info->num = d->num;
+            /*endif*/
+        }
+        /*endif*/
+        it->cur_no++;
+        return BARRAY;
+
+    case ITER:
+        {
+            XimFrameType ret_type;
+            ExtraData d;
+            ExtraDataRec dr;
+
+            if ((d = ChainMgrGetExtraData (&it->cm, it->cur_no)) == NULL)
+            {
+                dr.iter = IterInit (it->template + 1, NO_VALUE);
+                d = ChainMgrSetData (&it->cm, it->cur_no, dr);
+            }
+            /*endif*/
+
+            ret_type = IterGetNextType (d->iter, info);
+            if (ret_type == EOL)
+            {
+                it->cur_no++;
+                ret_type = IterGetNextType (it, info);
+            }
+            /*endif*/
+           return ret_type;
+        }
+
+    case POINTER:
+        {
+            XimFrameType ret_type;
+            ExtraData d;
+            ExtraDataRec dr;
+
+            if ((d = ChainMgrGetExtraData (&it->cm, it->cur_no)) == NULL)
+            {
+                dr.fi = FrameInstInit (it->template[1].data);
+                d = ChainMgrSetData (&it->cm, it->cur_no, dr);
+            }
+            /*endif*/
+
+            ret_type = FrameInstGetNextType (d->fi, info);
+            if (ret_type == EOL)
+            {
+                it->cur_no++;
+                ret_type = IterGetNextType (it, info);
+            }
+            /*endif*/
+           return ret_type;
+        }
+
+    default:
+       return (XimFrameType) NULL;
+    }
+    /*endswitch*/
+    return (XimFrameType) NULL;  /* This should never occur */
+}
+
+static XimFrameType IterPeekNextType (Iter it, XimFrameTypeInfo info)
+{
+    XimFrameType type = it->template->type;
+
+    if (!it->allow_expansion  &&  it->cur_no >= it->max_count)
+        return (EOL);
+    /*endif*/
+    
+    switch (type)
+    {
+    case BIT8:
+    case BIT16:
+    case BIT32:
+    case BIT64:
+        return type;
+
+    case BARRAY:
+        if (info)
+        {
+            ExtraData d;
+
+            if ((d = ChainMgrGetExtraData (&it->cm, it->cur_no)) == NULL)
+                info->num = NO_VALUE;
+            else
+                info->num = d->num;
+            /*endif*/
+        }
+        /*endif*/
+        return BARRAY;
+    
+    case ITER:
+        {
+            XimFrameType ret_type;
+            ExtraData d;
+            ExtraDataRec dr;
+
+            if ((d = ChainMgrGetExtraData (&it->cm, it->cur_no)) == NULL)
+            {
+                dr.iter = IterInit (it->template + 1, NO_VALUE);
+                d = ChainMgrSetData (&it->cm, it->cur_no, dr);
+            }
+            /*endif*/
+
+            ret_type = IterPeekNextType (d->iter, info);
+            if (ret_type == EOL)
+                ret_type = IterPeekNextType (it, info);
+            /*endif*/
+            return ret_type;
+        }
+        
+    case POINTER:
+        {
+            XimFrameType ret_type;
+            ExtraData d;
+            ExtraDataRec dr;
+
+            if ((d = ChainMgrGetExtraData (&it->cm, it->cur_no)) == NULL)
+            {
+                dr.fi = FrameInstInit (it->template[1].data);
+                d = ChainMgrSetData (&it->cm, it->cur_no, dr);
+            }
+            /*endif*/
+
+            ret_type = FrameInstPeekNextType (d->fi, info);
+            if (ret_type == EOL)
+                ret_type = IterPeekNextType (it, info);
+            /*endif*/
+            return (ret_type);
+        }
+
+    default:
+       break;
+    }
+    /*endswitch*/
+    /* Reaching here is a bug! */
+    return (XimFrameType) NULL;
+}
+
+static FmStatus IterSetSize (Iter it, int num)
+{
+    XimFrameType type;
+    register int i;
+
+    if (!it->allow_expansion  &&  it->max_count == 0)
+        return FmNoMoreData;
+    /*endif*/
+    
+    type = it->template->type;
+    switch (type)
+    {
+    case BARRAY:
+        {
+            ExtraData d;
+            ExtraDataRec dr;
+
+            for (i = 0;  i < it->max_count;  i++)
+            {
+                if ((d = ChainMgrGetExtraData (&it->cm, i)) == NULL)
+                {
+                    dr.num = NO_VALUE;
+                    d = ChainMgrSetData (&it->cm, i, dr);
+                }
+                /*endif*/
+                if (d->num == NO_VALUE)
+                {
+                    d->num = num;
+                    return FmSuccess;
+                }
+                /*endif*/
+            }
+            /*endfor*/
+            if (it->allow_expansion)
+            {
+                ExtraDataRec dr;
+                
+                dr.num = num;
+                ChainMgrSetData (&it->cm, it->max_count, dr);
+                it->max_count++;
+    
+                return FmSuccess;
+            }
+            /*endif*/
+        }   
+        return FmNoMoreData;
+
+    case ITER:
+        {
+            ExtraData d;
+            ExtraDataRec dr;
+
+            for (i = 0;  i < it->max_count;  i++)
+            {
+                if ((d = ChainMgrGetExtraData (&it->cm, i)) == NULL)
+                {
+                    dr.iter = IterInit (it->template + 1, NO_VALUE);
+                    d = ChainMgrSetData (&it->cm, i, dr);
+                }
+                /*endif*/
+                if (IterSetSize (d->iter, num) == FmSuccess)
+                    return FmSuccess;
+                /*endif*/
+            }
+            /*endfor*/
+            if (it->allow_expansion)
+            {
+                ExtraDataRec dr;
+
+                dr.iter = IterInit (it->template + 1, NO_VALUE);
+                ChainMgrSetData (&it->cm, it->max_count, dr);
+                it->max_count++;
+
+                if (IterSetSize(dr.iter, num) == FmSuccess)
+                    return FmSuccess;
+                /*endif*/
+            }
+            /*endif*/
+        }
+        return FmNoMoreData;
+
+    case POINTER:
+        {
+            ExtraData d;
+            ExtraDataRec dr;
+
+            for (i = 0;  i < it->max_count;  i++)
+            {
+                if ((d = ChainMgrGetExtraData (&it->cm, i)) == NULL)
+                {
+                    dr.fi = FrameInstInit (it->template[1].data);
+                    d = ChainMgrSetData (&it->cm, i, dr);
+                }
+                /*endif*/
+                if (FrameInstSetSize (d->fi, num) == FmSuccess)
+                    return FmSuccess;
+                /*endif*/
+            }
+            /*endfor*/
+            if (it->allow_expansion)
+            {
+                ExtraDataRec dr;
+
+                dr.fi = FrameInstInit (it->template[1].data);
+                ChainMgrSetData (&it->cm, it->max_count, dr);
+                it->max_count++;
+
+                if (FrameInstSetSize (dr.fi, num) == FmSuccess)
+                    return FmSuccess;
+                /*endif*/
+            }
+            /*endif*/
+        }
+        return FmNoMoreData;
+
+    default:
+       break;
+    }
+    /*endswitch*/
+    return FmNoMoreData;
+}
+
+static int IterGetSize (Iter it)
+{
+    register int i;
+    ExtraData d;
+    ExtraDataRec dr;
+
+    if (it->cur_no >= it->max_count)
+        return NO_VALID_FIELD;
+    /*endif*/
+    
+    switch (it->template->type)
+    {
+    case BARRAY:
+        if ((d = ChainMgrGetExtraData (&it->cm, it->cur_no)) == NULL)
+            return NO_VALUE;
+        /*endif*/
+        return d->num;
+
+    case ITER:
+        for (i = it->cur_no; i < it->max_count; i++)
+        {
+            int ret_size;
+
+            if ((d = ChainMgrGetExtraData (&it->cm, i)) == NULL)
+            {
+                dr.iter = IterInit (it->template + 1, NO_VALUE);
+                d = ChainMgrSetData (&it->cm, i, dr);
+            }
+            /*endif*/
+            ret_size = IterGetSize (d->iter);
+            if (ret_size != NO_VALID_FIELD)
+                return ret_size;
+            /*endif*/
+        }
+        /*endfor*/
+        return NO_VALID_FIELD;
+    
+    case POINTER:
+        for (i = it->cur_no;  i < it->max_count;  i++)
+        {
+            int ret_size;
+            
+            if ((d = ChainMgrGetExtraData (&it->cm, i)) == NULL)
+            {
+                dr.fi = FrameInstInit (it->template[1].data);
+                d = ChainMgrSetData (&it->cm, i, dr);
+            }
+            /*endif*/
+            ret_size = FrameInstGetSize (d->fi);
+            if (ret_size != NO_VALID_FIELD)
+                return ret_size;
+            /*endif*/
+        }
+        /*endfor*/
+        return NO_VALID_FIELD;
+
+    default:
+       break;
+    }
+    /*endswitch*/
+    return NO_VALID_FIELD;
+}
+
+static FmStatus IterSetIterCount (Iter it, int num)
+{
+    register int i;
+
+    if (it->allow_expansion)
+    {
+        it->max_count = num;
+        it->allow_expansion = False;
+        return FmSuccess;
+    }
+    /*endif*/
+
+    if (it->max_count == 0)
+        return FmNoMoreData;
+    /*endif*/
+
+    switch (it->template->type)
+    {
+    case ITER:
+        for (i = 0;  i < it->max_count;  i++)
+        {
+            ExtraData d;
+            ExtraDataRec dr;
+
+            if ((d = ChainMgrGetExtraData(&it->cm, i)) == NULL)
+            {
+                dr.iter = IterInit(it->template + 1, num);
+                (void)ChainMgrSetData(&it->cm, i, dr);
+                return FmSuccess;
+            }
+            /*endif*/
+            if (IterSetIterCount(d->iter, num) == FmSuccess)
+                return FmSuccess;
+            /*endif*/
+        }
+        /*endfor*/
+        if (it->allow_expansion)
+        {
+            ExtraDataRec dr;
+
+            dr.iter = IterInit (it->template + 1, num);
+            ChainMgrSetData (&it->cm, it->max_count, dr);
+            it->max_count++;
+
+            return FmSuccess;
+        }
+        /*endif*/
+        break;
+    
+    case POINTER:
+        for (i = 0;  i < it->max_count;  i++)
+        {
+            ExtraData d;
+            ExtraDataRec dr;
+            
+            if ((d = ChainMgrGetExtraData (&it->cm, i)) == NULL)
+            {
+                dr.fi = FrameInstInit (it->template[1].data);
+                d = ChainMgrSetData (&it->cm, i, dr);
+            }
+            /*endif*/
+            if (FrameInstSetIterCount (d->fi, num) == FmSuccess)
+                return FmSuccess;
+            /*endif*/
+        }
+        /*endfor*/
+        if (it->allow_expansion)
+        {
+            ExtraDataRec dr;
+            
+            dr.fi = FrameInstInit (it->template[1].data);
+            ChainMgrSetData (&it->cm, it->max_count, dr);
+            it->max_count++;
+
+            if (FrameInstSetIterCount (dr.fi, num) == FmSuccess)
+                return FmSuccess;
+            /*endif*/
+        }
+        /*endif*/
+        break;
+
+    default:
+       break;
+    }
+    /*endswitch*/
+    return FmNoMoreData;
+}
+
+static int IterGetTotalSize (Iter it)
+{
+    register int size, i;
+    XimFrameType type;
+
+    if (it->allow_expansion)
+        return NO_VALUE;
+    /*endif*/
+    if (it->max_count == 0)
+        return 0;
+    /*endif*/
+
+    size = 0;
+    type = it->template->type;
+
+    switch (type)
+    {
+    case BIT8:
+        size = it->max_count;
+        break;
+
+    case BIT16:
+        size = it->max_count*2;
+        break;
+
+    case BIT32:
+        size = it->max_count*4;
+        break;
+
+    case BIT64:
+        size = it->max_count*8;
+        break;
+
+    case BARRAY:
+        for (i = 0;  i < it->max_count;  i++)
+        {
+            register int num;
+            ExtraData d;
+            
+            if ((d = ChainMgrGetExtraData (&it->cm, i)) == NULL)
+                return  NO_VALUE;
+            /*endif*/
+            if ((num = d->num) == NO_VALUE)
+                return  NO_VALUE;
+            /*endif*/
+            size += num;
+        }
+        /*endfor*/
+        break;
+        
+    case ITER:
+        for (i = 0;  i < it->max_count;  i++)
+        {
+            register int num;
+            ExtraData d;
+            
+            if ((d = ChainMgrGetExtraData (&it->cm, i)) == NULL)
+                return  NO_VALUE;
+            /*endif*/
+            if ((num = IterGetTotalSize (d->iter)) == NO_VALUE)
+                return  NO_VALUE;
+            /*endif*/
+            size += num;
+        }
+        /*endfor*/
+        break;
+        
+    case POINTER:
+        for (i = 0;  i < it->max_count;  i++)
+        {
+            register int num;
+            ExtraData d;
+            ExtraDataRec dr;
+            
+            if ((d = ChainMgrGetExtraData (&it->cm, i)) == NULL)
+            {
+                dr.fi = FrameInstInit (it->template[1].data);
+                d = ChainMgrSetData (&it->cm, i, dr);
+            }
+            /*endif*/
+            if ((num = FrameInstGetTotalSize (d->fi)) == NO_VALUE)
+                return NO_VALUE;
+            /*endif*/
+            size += num;
+        }
+        /*endfor*/
+        break;
+
+    default:
+       break;
+    }
+    /*endswitch*/
+    return  size;
+}
+
+static void IterReset (Iter it)
+{
+    ChainIterRec ci;
+    int count;
+    ExtraDataRec d;
+
+    switch (it->template->type)
+    {
+    case ITER:
+        ChainIterInit (&ci, &it->cm);
+        while (ChainIterGetNext (&ci, &count, &d))
+            IterReset (d.iter);
+        /*endwhile*/
+        ChainIterFree (&ci);
+        break;
+  
+    case POINTER:
+        ChainIterInit (&ci, &it->cm);
+        while (ChainIterGetNext (&ci, &count, &d))
+            FrameInstReset (d.fi);
+        /*endwhile*/
+        ChainIterFree (&ci);
+        break;
+
+    default:
+       break;
+    }
+    /*endswitch*/
+    it->cur_no = 0;
+}
+
+static void IterSetStartWatch (Iter it,
+                               IterStartWatchProc proc,
+                               void *client_data)
+{
+    it->start_watch_proc = proc;
+    it->client_data = client_data;
+}
+
+static ExtraData ChainMgrSetData (ChainMgr cm,
+                                  int frame_no,
+                                  ExtraDataRec data)
+{
+    Chain cur = (Chain) Xmalloc (sizeof (ChainRec));
+
+    cur->frame_no = frame_no;
+    cur->d = data;
+    cur->next = NULL;
+
+    if (cm->top == NULL)
+    {
+        cm->top = cm->tail = cur;
+    }
+    else
+    {
+        cm->tail->next = cur;
+        cm->tail = cur;
+    }
+    /*endif*/
+    return &cur->d;
+}
+
+static ExtraData ChainMgrGetExtraData (ChainMgr cm, int frame_no)
+{
+    Chain cur;
+
+    cur = cm->top;
+
+    while (cur)
+    {
+        if (cur->frame_no == frame_no)
+            return &cur->d;
+        /*endif*/
+        cur = cur->next;
+    }
+    /*endwhile*/
+    return NULL;
+}
+
+static Bool ChainIterGetNext (ChainIter ci, int *frame_no, ExtraData d)
+{
+    if (ci->cur == NULL)
+        return False;
+    /*endif*/
+    
+    *frame_no = ci->cur->frame_no;
+    *d = ci->cur->d;
+
+    ci->cur = ci->cur->next;
+
+    return True;
+}
+
+static int _FrameInstIncrement (XimFrame frame, int count)
+{
+    XimFrameType type;
+
+    type = frame[count].type;
+    type &= ~COUNTER_MASK;
+
+    switch (type)
+    {
+    case BIT8:
+    case BIT16:
+    case BIT32:
+    case BIT64:
+    case BARRAY:
+    case PADDING:
+        return count + 1;
+        
+    case POINTER:
+        return count + 2;
+        
+    case ITER:
+        return _FrameInstIncrement (frame, count + 1);
+    default:
+       break;
+    }
+    /*endswitch*/
+    return - 1;    /* Error */
+}
+
+static int _FrameInstDecrement (XimFrame frame, int count)
+{
+    register int i;
+    XimFrameType type;
+
+    if (count == 0)
+        return - 1;    /* cannot decrement */
+    /*endif*/
+    
+    if (count == 1)
+        return 0;     /* BOGUS - It should check the contents of data */
+    /*endif*/
+    
+    type = frame[count - 2].type;
+    type &= ~COUNTER_MASK;
+
+    switch (type)
+    {
+    case BIT8:
+    case BIT16:
+    case BIT32:
+    case BIT64:
+    case BARRAY:
+    case PADDING:
+    case PTR_ITEM:
+        return count - 1;
+
+    case POINTER:
+    case ITER:
+        i = count - 3;
+        while (i >= 0)
+        {
+            if (frame[i].type != ITER)
+                return i + 1;
+            /*endif*/
+            i--;
+        }
+        /*endwhile*/
+        return 0;
+    default:
+       break;
+    }
+    /*enswitch*/
+    return - 1;    /* Error */
+}
+
+static int _FrameInstGetItemSize (FrameInst fi, int cur_no)
+{
+    XimFrameType type;
+
+    type = fi->template[cur_no].type;
+    type &= ~COUNTER_MASK;
+
+    switch (type)
+    {
+    case BIT8:
+        return 1;
+
+    case BIT16:
+        return 2;
+
+    case BIT32:
+        return 4;
+
+    case BIT64:
+        return 8;
+
+    case BARRAY:
+        {
+            ExtraData d;
+
+            if ((d = ChainMgrGetExtraData (&fi->cm, cur_no)) == NULL)
+                return NO_VALUE;
+            /*endif*/
+            if (d->num == NO_VALUE)
+                return NO_VALUE;
+            /*endif*/
+            return d->num;
+        }
+
+    case PADDING:
+        {
+            register int unit;
+            register int number;
+            register int size;
+            register int i;
+
+            unit = _UNIT ((long) fi->template[cur_no].data);
+            number = _NUMBER ((long) fi->template[cur_no].data);
+
+            i = cur_no;
+            size = 0;
+            while (number > 0)
+            {
+                i = _FrameInstDecrement (fi->template, i);
+                size += _FrameInstGetItemSize (fi, i);
+                number--;
+            }
+            /*endwhile*/
+            size = (unit - (size%unit))%unit;
+            return size;
+        }
+
+    case ITER:
+        {
+            ExtraData d;
+            int sub_size;
+
+            if ((d = ChainMgrGetExtraData (&fi->cm, cur_no)) == NULL)
+                return NO_VALUE;
+            /*endif*/
+            sub_size = IterGetTotalSize (d->iter);
+            if (sub_size == NO_VALUE)
+                return NO_VALUE;
+            /*endif*/
+            return sub_size;
+        }
+
+    case POINTER:
+        {
+            ExtraData d;
+            int sub_size;
+
+            if ((d = ChainMgrGetExtraData (&fi->cm, cur_no)) == NULL)
+                return NO_VALUE;
+            /*endif*/
+            sub_size = FrameInstGetTotalSize (d->fi);
+            if (sub_size == NO_VALUE)
+                return NO_VALUE;
+            /*endif*/
+            return sub_size;
+        }
+
+    default:
+       break;
+    }
+    /*endswitch*/
+    return NO_VALUE;
+}
diff --git a/wrapper/xim/IMdkit/FrameMgr.h b/wrapper/xim/IMdkit/FrameMgr.h
new file mode 100644 (file)
index 0000000..ce7ed50
--- /dev/null
@@ -0,0 +1,131 @@
+/******************************************************************
+Copyright 1993, 1994 by Digital Equipment Corporation, Maynard, Massachusetts,
+
+                        All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and its 
+documentation for any purpose and without fee is hereby granted, 
+provided that the above copyright notice appear in all copies and that
+both that copyright notice and this permission notice appear in 
+supporting documentation, and that the names of Digital or MIT not be
+used in advertising or publicity pertaining to distribution of the
+software without specific, written prior permission.  
+
+DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
+ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
+DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
+ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+SOFTWARE.
+
+  Author: Hiroyuki Miyamoto  Digital Equipment Corporation
+                             miyamoto@jrd.dec.com
+
+    This version tidied and debugged by Steve Underwood May 1999
+
+******************************************************************/
+
+#ifndef FRAMEMGR_H
+#define FRAMEMGR_H
+
+#include <X11/Xmd.h>
+#include <X11/Xlib.h>
+#include <stdio.h>
+
+#if defined(VAXC) && !defined(__DECC)
+#define xim_externalref globalref
+#define xim_externaldef globaldef
+#else
+#define xim_externalref extern
+#define xim_externaldef
+#endif
+
+/* Definitions for FrameMgr */
+
+#define COUNTER_MASK 0x10
+
+typedef enum
+{
+    BIT8     = 0x1,       /* {CARD8* | INT8*}   */
+    BIT16    = 0x2,       /* {CARD16* | INT16*} */
+    BIT32    = 0x3,       /* {CARD32* | INT32*} */
+    BIT64    = 0x4,      /* {CARD64* | INT64*} */
+    BARRAY   = 0x5,       /* int*, void*        */
+    ITER     = 0x6,       /* int*               */
+    POINTER  = 0x7,       /* specifies next item is a PTR_ITEM */
+    PTR_ITEM = 0x8,       /* specifies the item has a pointer */
+    /* BOGUS - POINTER and PTR_ITEM
+     *   In the current implementation, PTR_ITEM should be lead by
+     *   POINTER.  But actually, it's just redundant logically.  Someone 
+     *   may remove this redundancy and POINTER from the enum member but he
+     *   should also modify the logic in FrameMgr program.
+     */
+    PADDING  = 0x9,       /* specifies that a padding is needed.
+                          * This requires extra data in data field.
+                          */
+    EOL      = 0xA,       /* specifies the end of list */
+
+    COUNTER_BIT8  = COUNTER_MASK | 0x1,
+    COUNTER_BIT16 = COUNTER_MASK | 0x2,
+    COUNTER_BIT32 = COUNTER_MASK | 0x3,
+    COUNTER_BIT64 = COUNTER_MASK | 0x4
+} XimFrameType;
+
+/* Convenient macro */
+#define _FRAME(a) {a, NULL}
+#define _PTR(p)   {PTR_ITEM, (void *)p}
+/* PADDING's usage of data field
+ * B15-B8  : Shows the number of effective items.
+ * B7-B0   : Shows padding unit.  ex) 04 shows 4 unit padding.
+ */
+#define _PAD2(n)   {PADDING, (void*)((n)<<8|2)}
+#define _PAD4(n)   {PADDING, (void*)((n)<<8|4)}
+
+#define FmCounterByte 0
+#define FmCounterNumber 1
+    
+#define _BYTE_COUNTER(type, offset) \
+               {(COUNTER_MASK|type), (void*)((offset)<<8|FmCounterByte)}
+
+#define _NUMBER_COUNTER(type, offset) \
+               {(COUNTER_MASK|type), (void*)((offset)<<8|FmCounterNumber)}
+
+typedef struct _XimFrame
+{
+    XimFrameType type;
+    void* data;       /* For PTR_ITEM and PADDING */
+} XimFrameRec, *XimFrame;
+
+typedef enum
+{
+    FmSuccess, 
+    FmEOD,
+    FmInvalidCall,
+    FmBufExist,
+    FmCannotCalc,
+    FmNoMoreData
+} FmStatus;
+
+typedef struct _FrameMgr *FrameMgr;
+
+FrameMgr FrameMgrInit(XimFrame frame, char* area, Bool byte_swap);
+void FrameMgrInitWithData(FrameMgr fm, XimFrame frame, void* area,
+                         Bool byte_swap);
+void FrameMgrFree(FrameMgr fm);
+FmStatus FrameMgrSetBuffer(FrameMgr, void*);
+FmStatus _FrameMgrPutToken(FrameMgr, void*, int);
+FmStatus _FrameMgrGetToken(FrameMgr, void*, int);
+FmStatus FrameMgrSetSize(FrameMgr, int);
+FmStatus FrameMgrSetIterCount(FrameMgr, int);
+FmStatus FrameMgrSetTotalSize(FrameMgr, int);
+int FrameMgrGetTotalSize(FrameMgr);
+int FrameMgrGetSize(FrameMgr);
+FmStatus FrameMgrSkipToken(FrameMgr, int);
+void FrameMgrReset(FrameMgr);
+Bool FrameMgrIsIterLoopEnd(FrameMgr, FmStatus*);
+
+#define FrameMgrPutToken(fm, obj) _FrameMgrPutToken((fm), &(obj), sizeof(obj))
+#define FrameMgrGetToken(fm, obj) _FrameMgrGetToken((fm), &(obj), sizeof(obj))
+
+#endif /* FRAMEMGR_H */
diff --git a/wrapper/xim/IMdkit/IMConn.c b/wrapper/xim/IMdkit/IMConn.c
new file mode 100644 (file)
index 0000000..6d36589
--- /dev/null
@@ -0,0 +1,176 @@
+/******************************************************************
+         Copyright 1994, 1995 by Sun Microsystems, Inc.
+         Copyright 1993, 1994 by Hewlett-Packard Company
+Permission to use, copy, modify, distribute, and sell this software
+and its documentation for any purpose is hereby granted without fee,
+provided that the above copyright notice appear in all copies and
+that both that copyright notice and this permission notice appear
+in supporting documentation, and that the name of Sun Microsystems, Inc.
+and Hewlett-Packard not be used in advertising or publicity pertaining to
+distribution of the software without specific, written prior permission.
+Sun Microsystems, Inc. and Hewlett-Packard make no representations about
+the suitability of this software for any purpose.  It is provided "as is"
+without express or implied warranty.
+SUN MICROSYSTEMS INC. AND HEWLETT-PACKARD COMPANY DISCLAIMS ALL
+WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
+SUN MICROSYSTEMS, INC. AND HEWLETT-PACKARD COMPANY BE LIABLE FOR ANY
+SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
+RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
+CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
+IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+  Author: Hidetoshi Tajima(tajima@Eng.Sun.COM) Sun Microsystems, Inc.
+
+    This version tidied and debugged by Steve Underwood May 1999
+******************************************************************/
+
+#include <X11/Xlib.h>
+#include <stdlib.h>
+#include <string.h>
+#include "IMdkit.h"
+#include <stdarg.h>
+
+#define Va_start(a,b) va_start(a,b)
+
+static void _IMCountVaList(va_list var, int *total_count)
+{
+    char *attr;
+
+    *total_count = 0;
+
+    for (attr = va_arg (var, char*);  attr;  attr = va_arg (var, char*))
+    {
+       (void)va_arg (var, XIMArg *);
+       ++(*total_count);
+    }
+    /*endfor*/
+}
+
+static void _IMVaToNestedList(va_list var, int max_count, XIMArg **args_return)
+{
+    XIMArg *args;
+    char   *attr;
+
+    if (max_count <= 0)
+    {
+       *args_return = (XIMArg *) NULL;
+       return;
+    }
+    /*endif*/
+
+    args = (XIMArg *) malloc ((unsigned) (max_count + 1)*sizeof (XIMArg));
+    *args_return = args;
+    if (!args)
+        return;
+    /*endif*/
+
+    for (attr = va_arg (var, char*);  attr;  attr = va_arg (var, char *))
+    {
+       args->name = attr;
+       args->value = va_arg (var, XPointer);
+       args++;
+    }
+    /*endfor*/
+    args->name = (char*)NULL;
+}
+
+static char *_FindModifiers (XIMArg *args)
+{
+    char *modifiers;
+
+    while (args->name)
+    {
+       if (strcmp (args->name, IMModifiers) == 0)
+       {
+           modifiers = args->value;
+           return modifiers;
+       }
+       else
+       {
+           args++;
+       }
+       /*endif*/
+    }
+    /*endwhile*/
+    return NULL;
+}
+
+XIMS _GetIMS (char *modifiers)
+{
+    XIMS ims;
+    extern IMMethodsRec Xi18n_im_methods;
+
+    if ((ims = (XIMS) malloc (sizeof (XIMProtocolRec))) == (XIMS) NULL)
+       return ((XIMS) NULL);
+    /*endif*/
+    memset ((void *) ims, 0, sizeof (XIMProtocolRec));
+
+    if (modifiers == NULL
+       ||
+       modifiers[0] == '\0'
+       ||
+       strcmp (modifiers, "Xi18n") == 0)
+    {
+       ims->methods = &Xi18n_im_methods;
+       return ims;
+    }
+    /*endif*/
+    XFree (ims);
+    return (XIMS) NULL;
+}
+
+XIMS IMOpenIM (Display *display, ...)
+{
+    va_list var;
+    int total_count;
+    XIMArg *args;
+    XIMS ims;
+    char *modifiers;
+    Status ret;
+
+    Va_start (var, display);
+    _IMCountVaList (var, &total_count);
+    va_end (var);
+
+    Va_start (var, display);
+    _IMVaToNestedList (var, total_count, &args);
+    va_end (var);
+
+    modifiers = _FindModifiers (args);
+
+    ims = _GetIMS (modifiers);
+    if (ims == (XIMS) NULL)
+        return (XIMS) NULL;
+    /*endif*/
+    
+    ims->core.display = display;
+
+    ims->protocol = (*ims->methods->setup) (display, args);
+    XFree (args);
+    if (ims->protocol == (void *) NULL)
+    {
+       XFree (ims);
+       return (XIMS) NULL;
+    }
+    /*endif*/
+    ret = (ims->methods->openIM) (ims);
+    if (ret == False)
+    {
+       XFree (ims);
+       return (XIMS) NULL;
+    }
+    /*endif*/
+    return (XIMS) ims;
+}
+
+Status IMCloseIM (XIMS ims)
+{
+    (ims->methods->closeIM) (ims);
+    XFree (ims);
+    return True;
+}
diff --git a/wrapper/xim/IMdkit/IMMethod.c b/wrapper/xim/IMdkit/IMMethod.c
new file mode 100644 (file)
index 0000000..5a33878
--- /dev/null
@@ -0,0 +1,65 @@
+/******************************************************************
+         Copyright 1994, 1995 by Sun Microsystems, Inc.
+         Copyright 1993, 1994 by Hewlett-Packard Company
+Permission to use, copy, modify, distribute, and sell this software
+and its documentation for any purpose is hereby granted without fee,
+provided that the above copyright notice appear in all copies and
+that both that copyright notice and this permission notice appear
+in supporting documentation, and that the name of Sun Microsystems, Inc.
+and Hewlett-Packard not be used in advertising or publicity pertaining to
+distribution of the software without specific, written prior permission.
+Sun Microsystems, Inc. and Hewlett-Packard make no representations about
+the suitability of this software for any purpose.  It is provided "as is"
+without express or implied warranty.
+SUN MICROSYSTEMS INC. AND HEWLETT-PACKARD COMPANY DISCLAIMS ALL
+WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
+SUN MICROSYSTEMS, INC. AND HEWLETT-PACKARD COMPANY BE LIABLE FOR ANY
+SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
+RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
+CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
+IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+  Author: Hidetoshi Tajima(tajima@Eng.Sun.COM) Sun Microsystems, Inc.
+
+    This version tidied and debugged by Steve Underwood May 1999
+******************************************************************/
+
+#include <X11/Xlib.h>
+#include "IMdkit.h"
+
+/* Public Function */
+void IMForwardEvent (XIMS ims, XPointer call_data)
+{
+    (ims->methods->forwardEvent) (ims, call_data);
+}
+
+void IMCommitString (XIMS ims, XPointer call_data)
+{
+    (ims->methods->commitString) (ims, call_data);
+}
+
+int IMCallCallback (XIMS ims, XPointer call_data)
+{
+    return (ims->methods->callCallback) (ims, call_data);
+}
+
+int IMPreeditStart (XIMS ims, XPointer call_data)
+{
+    return (ims->methods->preeditStart) (ims, call_data);
+}
+
+int IMPreeditEnd (XIMS ims, XPointer call_data)
+{
+    return (ims->methods->preeditEnd) (ims, call_data);
+}
+
+int IMSyncXlib(XIMS ims, XPointer call_data)
+{
+    ims->sync = True;
+    return (ims->methods->syncXlib) (ims, call_data);
+}
diff --git a/wrapper/xim/IMdkit/IMValues.c b/wrapper/xim/IMdkit/IMValues.c
new file mode 100644 (file)
index 0000000..687014a
--- /dev/null
@@ -0,0 +1,124 @@
+/******************************************************************
+         Copyright 1994, 1995 by Sun Microsystems, Inc.
+         Copyright 1993, 1994 by Hewlett-Packard Company
+Permission to use, copy, modify, distribute, and sell this software
+and its documentation for any purpose is hereby granted without fee,
+provided that the above copyright notice appear in all copies and
+that both that copyright notice and this permission notice appear
+in supporting documentation, and that the name of Sun Microsystems, Inc.
+and Hewlett-Packard not be used in advertising or publicity pertaining to
+distribution of the software without specific, written prior permission.
+Sun Microsystems, Inc. and Hewlett-Packard make no representations about
+the suitability of this software for any purpose.  It is provided "as is"
+without express or implied warranty.
+SUN MICROSYSTEMS INC. AND HEWLETT-PACKARD COMPANY DISCLAIMS ALL
+WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
+SUN MICROSYSTEMS, INC. AND HEWLETT-PACKARD COMPANY BE LIABLE FOR ANY
+SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
+RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
+CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
+IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+  Author: Hidetoshi Tajima(tajima@Eng.Sun.COM) Sun Microsystems, Inc.
+
+    This version tidied and debugged by Steve Underwood May 1999
+******************************************************************/
+
+#include <stdlib.h>
+#include <X11/Xlib.h>
+#include "IMdkit.h"
+#include <stdarg.h>
+
+#define Va_start(a,b) va_start(a,b)
+
+static void _IMCountVaList (va_list var, int *total_count)
+{
+    char *attr;
+
+    *total_count = 0;
+
+    for (attr = va_arg (var, char *);  attr;  attr = va_arg (var, char *))
+    {
+       (void)va_arg (var, XIMArg *);
+       ++(*total_count);
+    }
+    /*endfor*/
+}
+
+static void _IMVaToNestedList (va_list var, int max_count, XIMArg **args_return)
+{
+    XIMArg *args;
+    char   *attr;
+
+    if (max_count <= 0)
+    {
+       *args_return = (XIMArg *) NULL;
+       return;
+    }
+    /*endif*/
+
+    args = (XIMArg *) malloc ((unsigned) (max_count + 1)*sizeof (XIMArg));
+    *args_return = args;
+    if (!args)
+        return;
+    /*endif*/
+    for (attr = va_arg (var, char *);  attr;  attr = va_arg (var, char *))
+    {
+       args->name = attr;
+       args->value = va_arg (var, XPointer);
+       args++;
+    }
+    /*endfor*/
+    args->name = (char *) NULL;
+}
+
+char *IMGetIMValues (XIMS ims, ...)
+{
+    va_list var;
+    int total_count;
+    XIMArg *args;
+    char *ret;
+
+    Va_start (var, ims);
+    _IMCountVaList (var, &total_count);
+    va_end (var);
+
+    Va_start (var, ims);
+    _IMVaToNestedList (var, total_count, &args);
+    va_end (var);
+
+    ret = (*ims->methods->getIMValues) (ims, args);
+
+    if (args)
+        XFree ((char *) args);
+    /*endif*/
+    return ret;
+}
+
+char *IMSetIMValues (XIMS ims, ...)
+{
+    va_list var;
+    int total_count;
+    XIMArg *args;
+    char *ret;  
+
+    Va_start (var, ims);
+    _IMCountVaList (var, &total_count);
+    va_end (var);
+
+    Va_start (var, ims);
+    _IMVaToNestedList (var, total_count, &args);
+    va_end (var);
+
+    ret = (*ims->methods->setIMValues) (ims, args);
+
+    if (args)
+        XFree ((char *) args);
+    /*endif*/
+    return ret;
+}
diff --git a/wrapper/xim/IMdkit/IMdkit.h b/wrapper/xim/IMdkit/IMdkit.h
new file mode 100644 (file)
index 0000000..6f8d673
--- /dev/null
@@ -0,0 +1,144 @@
+/******************************************************************
+         Copyright 1994, 1995 by Sun Microsystems, Inc.
+         Copyright 1993, 1994 by Hewlett-Packard Company
+Permission to use, copy, modify, distribute, and sell this software
+and its documentation for any purpose is hereby granted without fee,
+provided that the above copyright notice appear in all copies and
+that both that copyright notice and this permission notice appear
+in supporting documentation, and that the name of Sun Microsystems, Inc.
+and Hewlett-Packard not be used in advertising or publicity pertaining to
+distribution of the software without specific, written prior permission.
+Sun Microsystems, Inc. and Hewlett-Packard make no representations about
+the suitability of this software for any purpose.  It is provided "as is"
+without express or implied warranty.
+SUN MICROSYSTEMS INC. AND HEWLETT-PACKARD COMPANY DISCLAIMS ALL
+WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
+SUN MICROSYSTEMS, INC. AND HEWLETT-PACKARD COMPANY BE LIABLE FOR ANY
+SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
+RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
+CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
+IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+  Author: Hidetoshi Tajima(tajima@Eng.Sun.COM) Sun Microsystems, Inc.
+
+    This version tidied and debugged by Steve Underwood May 1999
+******************************************************************/
+
+#ifndef _IMdkit_h
+#define _IMdkit_h
+
+#include <X11/Xmd.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* IM Attributes Name */
+#define IMModifiers            "modifiers"
+#define IMServerWindow         "serverWindow"
+#define IMServerName           "serverName"
+#define IMServerTransport      "serverTransport"
+#define IMLocale               "locale"
+#define IMInputStyles          "inputStyles"
+#define IMProtocolHandler      "protocolHandler"
+#define IMOnKeysList           "onKeysList"
+#define IMOffKeysList          "offKeysList"
+#define IMEncodingList         "encodingList"
+#define IMFilterEventMask      "filterEventMask"
+#define IMProtocolDepend       "protocolDepend"
+
+/* Masks for IM Attributes Name */
+#define I18N_IMSERVER_WIN      0x0001 /* IMServerWindow */
+#define I18N_IM_NAME           0x0002 /* IMServerName */
+#define I18N_IM_LOCALE         0x0004 /* IMLocale */
+#define I18N_IM_ADDRESS                0x0008 /* IMServerTransport */
+#define I18N_INPUT_STYLES      0x0010 /* IMInputStyles */
+#define I18N_ON_KEYS           0x0020 /* IMOnKeysList */
+#define I18N_OFF_KEYS          0x0040 /* IMOffKeysList */
+#define I18N_IM_HANDLER                0x0080 /* IMProtocolHander */
+#define I18N_ENCODINGS         0x0100 /* IMEncodingList */
+#define I18N_FILTERMASK                0x0200 /* IMFilterEventMask */
+#define I18N_PROTO_DEPEND      0x0400 /* IMProtoDepend */
+
+typedef struct
+{
+    char       *name;
+    XPointer   value;
+} XIMArg;
+
+typedef struct
+{
+    CARD32     keysym;
+    CARD32     modifier;
+    CARD32     modifier_mask;
+} XIMTriggerKey;
+
+typedef struct
+{
+    unsigned short count_keys;
+    XIMTriggerKey *keylist;
+} XIMTriggerKeys;
+
+typedef char *XIMEncoding;
+
+typedef struct
+{
+    unsigned short count_encodings;
+    XIMEncoding *supported_encodings;
+} XIMEncodings;
+
+typedef struct _XIMS *XIMS;
+
+typedef struct
+{
+    void*      (*setup) (Display *, XIMArg *);
+    Status     (*openIM) (XIMS);
+    Status     (*closeIM) (XIMS);
+    char*      (*setIMValues) (XIMS, XIMArg *);
+    char*      (*getIMValues) (XIMS, XIMArg *);
+    Status     (*forwardEvent) (XIMS, XPointer);
+    Status     (*commitString) (XIMS, XPointer);
+    int                (*callCallback) (XIMS, XPointer);
+    int                (*preeditStart) (XIMS, XPointer);
+    int                (*preeditEnd) (XIMS, XPointer);
+    int                (*syncXlib) (XIMS, XPointer);
+} IMMethodsRec, *IMMethods;
+
+typedef struct
+{
+    Display    *display;
+    int                screen;
+} IMCoreRec, *IMCore;
+
+typedef struct _XIMS
+{
+    IMMethods  methods;
+    IMCoreRec  core;
+    Bool       sync;
+    void       *protocol;
+} XIMProtocolRec;
+
+/* 
+ * X function declarations.
+ */
+extern XIMS IMOpenIM (Display *, ...);
+extern Status IMCloseIM (XIMS);
+extern char *IMSetIMValues (XIMS, ...);
+extern char *IMGetIMValues (XIMS, ...);
+void IMForwardEvent (XIMS, XPointer);
+void IMCommitString (XIMS, XPointer);
+int IMCallCallback (XIMS, XPointer);
+int IMPreeditStart (XIMS, XPointer);
+int IMPreeditEnd (XIMS, XPointer);
+int IMSyncXlib (XIMS, XPointer);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* IMdkit_h */
diff --git a/wrapper/xim/IMdkit/Xi18n.h b/wrapper/xim/IMdkit/Xi18n.h
new file mode 100644 (file)
index 0000000..484cc62
--- /dev/null
@@ -0,0 +1,507 @@
+/******************************************************************
+         Copyright 1994, 1995 by Sun Microsystems, Inc.
+         Copyright 1993, 1994 by Hewlett-Packard Company
+Permission to use, copy, modify, distribute, and sell this software
+and its documentation for any purpose is hereby granted without fee,
+provided that the above copyright notice appear in all copies and
+that both that copyright notice and this permission notice appear
+in supporting documentation, and that the name of Sun Microsystems, Inc.
+and Hewlett-Packard not be used in advertising or publicity pertaining to
+distribution of the software without specific, written prior permission.
+Sun Microsystems, Inc. and Hewlett-Packard make no representations about
+the suitability of this software for any purpose.  It is provided "as is"
+without express or implied warranty.
+SUN MICROSYSTEMS INC. AND HEWLETT-PACKARD COMPANY DISCLAIMS ALL
+WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
+SUN MICROSYSTEMS, INC. AND HEWLETT-PACKARD COMPANY BE LIABLE FOR ANY
+SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
+RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
+CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
+IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+  Author: Hidetoshi Tajima(tajima@Eng.Sun.COM) Sun Microsystems, Inc.
+
+    This version tidied and debugged by Steve Underwood May 1999
+******************************************************************/
+
+#ifndef _Xi18n_h
+#define _Xi18n_h
+#include <X11/Xlib.h>
+#include <X11/Xfuncs.h>
+#include <X11/Xos.h>
+#include "XimProto.h"
+
+/*
+ * Minor Protocol Number for Extension Protocol 
+ */
+#define XIM_EXTENSION                          128
+#define XIM_EXT_SET_EVENT_MASK                 (0x30)
+#define XIM_EXT_FORWARD_KEYEVENT               (0x32)
+#define XIM_EXT_MOVE                           (0x33)
+#define COMMON_EXTENSIONS_NUM                  3
+
+#include <stdlib.h>
+#include "IMdkit.h"
+
+/* XI18N Valid Attribute Name Definition */
+#define ExtForwardKeyEvent     "extForwardKeyEvent"
+#define ExtMove                        "extMove"
+#define ExtSetEventMask                "extSetEventMask"
+
+/*
+ * Padding macro
+ */
+#define IMPAD(length) ((4 - ((length)%4))%4)
+
+/*
+ * Target Atom for Transport Connection
+ */
+#define LOCALES                "LOCALES"
+#define TRANSPORT      "TRANSPORT"
+
+#define I18N_OPEN      0
+#define I18N_SET       1
+#define I18N_GET       2
+
+typedef struct
+{
+    char        *transportname;
+    int         namelen;
+    Bool        (*checkAddr) ();
+} TransportSW;
+
+typedef struct _XIMPending
+{
+    unsigned    char *p;
+    struct _XIMPending *next;
+} XIMPending;
+
+typedef struct _XimProtoHdr
+{
+    CARD8      major_opcode;
+    CARD8      minor_opcode;
+    CARD16     length;
+} XimProtoHdr;
+
+typedef struct
+{
+    CARD16     attribute_id;
+    CARD16     type;
+    CARD16     length;
+    char       *name;
+} XIMAttr;
+
+typedef struct
+{
+    CARD16     attribute_id;
+    CARD16     type;
+    CARD16     length;
+    char       *name;
+} XICAttr;
+
+typedef struct
+{
+    int                attribute_id;
+    CARD16     name_length; 
+    char       *name;
+    int                value_length;
+    void       *value;
+    int                type;
+} XIMAttribute;
+
+typedef struct
+{
+    int                attribute_id;
+    CARD16     name_length;
+    char       *name;
+    int                value_length;
+    void       *value;
+    int                type;
+} XICAttribute;
+
+typedef struct
+{
+    int                length;
+    char       *name;
+} XIMStr;
+
+typedef struct
+{
+    CARD16     major_opcode;
+    CARD16     minor_opcode;
+    CARD16     length;
+    char       *name;
+} XIMExt;
+
+typedef struct _Xi18nClient
+{
+    int                connect_id;
+    CARD8      byte_order;
+    /*
+       '?': initial value
+       'B': for Big-Endian
+       'l': for little-endian
+     */
+    int                sync;
+    XIMPending  *pending;
+    /* property offset to read next data */
+    long        property_offset;
+    void *trans_rec;           /* contains transport specific data  */
+    struct _Xi18nClient *next;
+} Xi18nClient;
+
+typedef struct _Xi18nCore *Xi18n;
+
+/*
+ * Callback Struct for XIM Protocol
+ */
+typedef struct
+{
+    int                major_code;
+    int                minor_code;
+    CARD16     connect_id;
+} IMAnyStruct;
+
+typedef struct
+{
+    int                major_code;
+    int                minor_code;
+    CARD16     connect_id;
+    CARD8      byte_order;
+    CARD16     major_version;
+    CARD16     minor_version;
+} IMConnectStruct;
+
+typedef struct
+{
+    int                major_code;
+    int                minor_code;
+    CARD16     connect_id;
+} IMDisConnectStruct;
+
+typedef struct
+{
+    int                major_code;
+    int                minor_code;
+    CARD16     connect_id;
+    XIMStr     lang;
+} IMOpenStruct;
+
+typedef struct
+{
+    int                major_code;
+    int                minor_code;
+    CARD16     connect_id;
+} IMCloseStruct;
+
+typedef struct
+{
+    int                major_code;
+    int                minor_code;
+    CARD16     connect_id;
+    CARD16     number;
+    XIMStr     *extension;
+} IMQueryExtensionStruct;
+
+typedef struct
+{
+    int                major_code;
+    int                minor_code;
+    CARD16     connect_id;
+    CARD16     number;
+    char       **im_attr_list;
+} IMGetIMValuesStruct;
+
+typedef struct
+{
+    int                major_code;
+    int                minor_code;
+    CARD16     connect_id;
+    CARD16     icid;
+    CARD16     preedit_attr_num;
+    CARD16     status_attr_num;
+    CARD16     ic_attr_num;
+    XICAttribute *preedit_attr;
+    XICAttribute *status_attr;
+    XICAttribute *ic_attr;
+} IMChangeICStruct;
+
+typedef struct
+{
+    int                major_code;
+    int                minor_code;
+    CARD16     connect_id;
+    CARD16     icid;
+} IMDestroyICStruct;
+
+typedef struct
+{
+    int                major_code;
+    int                minor_code;
+    CARD16     connect_id;
+    CARD16     icid;
+    CARD16     length;
+    char       *commit_string;
+} IMResetICStruct;
+
+typedef struct
+{
+    int                major_code;
+    int                minor_code;
+    CARD16     connect_id;
+    CARD16     icid;
+} IMChangeFocusStruct;
+
+typedef struct
+{
+    int                major_code;
+    int                minor_code;
+    CARD16     connect_id;
+    CARD16     icid;
+    BITMASK16  sync_bit;
+    CARD16     serial_number;
+    XEvent     event;
+} IMForwardEventStruct;
+
+typedef struct
+{
+    int                major_code;
+    int                minor_code;
+    CARD16     connect_id;
+    CARD16     icid;
+    CARD16     flag;
+    KeySym     keysym;
+    char       *commit_string;
+} IMCommitStruct;
+
+typedef struct
+{
+    int                major_code;
+    int                minor_code;
+    CARD16     connect_id;
+    CARD16     icid;
+    CARD32     flag;
+    CARD32     key_index;
+    CARD32     event_mask;
+} IMTriggerNotifyStruct;
+
+typedef struct
+{
+    int                major_code;
+    int                minor_code;
+    CARD16     connect_id;
+    CARD16     encoding_number;
+    XIMStr     *encoding;      /* name information */
+    CARD16     encoding_info_number;
+    XIMStr     *encodinginfo;  /* detailed information */
+    CARD16     category;       /* #0 for name, #1 for detail */
+    INT16      enc_index;      /* index of the encoding determined */
+} IMEncodingNegotiationStruct;
+
+typedef struct
+{
+    int                major_code;
+    int                minor_code;
+    CARD16     connect_id;
+    CARD16     icid;
+    CARD32     flag;
+    CARD32     forward_event_mask;
+    CARD32     sync_event_mask;
+} IMSetEventMaskStruct;
+
+typedef struct
+{
+    int                major_code;
+    int                minor_code;
+    CARD16     connect_id;
+    CARD16     icid;
+    CARD32     filter_event_mask;
+    CARD32     intercept_event_mask;
+    CARD32     select_event_mask;
+    CARD32     forward_event_mask;
+    CARD32     sync_event_mask;
+} IMExtSetEventMaskStruct;
+
+typedef struct
+{
+    int                major_code;
+    int                minor_code;
+    CARD16     connect_id;
+    CARD16     icid;
+    CARD16     x;
+    CARD16     y;
+} IMMoveStruct;
+
+typedef struct
+{
+    int                major_code;
+    int                minor_code;
+    CARD16     connect_id;
+    CARD16     icid;
+    BITMASK16  flag;
+    CARD16     error_code;
+    CARD16     str_length;
+    CARD16     error_type;
+    char       *error_detail;
+} IMErrorStruct;
+
+typedef struct
+{
+    int                major_code;
+    int                minor_code;
+    CARD16     connect_id;
+    CARD16     icid;
+} IMPreeditStateStruct;
+
+/* Callbacks */
+typedef struct
+{
+    int                major_code;
+    int                minor_code;
+    CARD16     connect_id;
+    CARD16     icid;
+} IMGeometryCBStruct;
+
+typedef struct
+{
+    int                major_code;
+    int                minor_code;
+    CARD16     connect_id;
+    CARD16     icid;
+    union
+    {
+       int return_value;                       /* PreeditStart */
+       XIMPreeditDrawCallbackStruct draw;      /* PreeditDraw */
+       XIMPreeditCaretCallbackStruct caret;    /* PreeditCaret */
+    } todo;
+} IMPreeditCBStruct;
+
+typedef struct
+{
+    int                major_code;
+    int                minor_code;
+    CARD16     connect_id;
+    CARD16     icid;
+    union
+    {
+       XIMStatusDrawCallbackStruct draw;       /* StatusDraw */
+    } todo;
+} IMStatusCBStruct;
+
+typedef struct
+{
+    int                major_code;
+    int                minor_code;
+    CARD16     connect_id;
+    CARD16     icid;
+    XIMStringConversionCallbackStruct strconv;
+} IMStrConvCBStruct;
+
+typedef struct
+{
+    int                major_code;
+    int                minor_code;
+    CARD16     connect_id;
+    CARD16     icid;
+} IMSyncXlibStruct;
+
+typedef union _IMProtocol
+{
+    int        major_code;
+    IMAnyStruct any;
+    IMConnectStruct imconnect;
+    IMDisConnectStruct imdisconnect;
+    IMOpenStruct imopen;
+    IMCloseStruct imclose;
+    IMQueryExtensionStruct queryext;
+    IMGetIMValuesStruct getim;
+    IMEncodingNegotiationStruct encodingnego;
+    IMExtSetEventMaskStruct extsetevent;
+    IMMoveStruct extmove;
+    IMSetEventMaskStruct setevent;
+    IMChangeICStruct changeic;
+    IMDestroyICStruct destroyic;
+    IMResetICStruct resetic;
+    IMChangeFocusStruct changefocus;
+    IMCommitStruct commitstring;
+    IMForwardEventStruct forwardevent;
+    IMTriggerNotifyStruct triggernotify;
+    IMPreeditStateStruct preedit_state;
+    IMErrorStruct imerror;
+    IMGeometryCBStruct geometry_callback;
+    IMPreeditCBStruct preedit_callback;
+    IMStatusCBStruct status_callback;
+    IMStrConvCBStruct strconv_callback;
+    IMSyncXlibStruct sync_xlib;
+    long pad[32];
+} IMProtocol;
+
+typedef int (*IMProtoHandler) (XIMS, IMProtocol*);
+
+#define DEFAULT_FILTER_MASK    (KeyPressMask)
+
+/* Xi18nAddressRec structure */
+typedef struct _Xi18nAddressRec
+{
+    Display    *dpy;
+    CARD8      im_byteOrder;   /* byte order 'B' or 'l' */
+    /* IM Values */
+    long       imvalue_mask;
+    Window     im_window;      /* IMServerWindow */
+    char       *im_name;       /* IMServerName */
+    char       *im_locale;     /* IMLocale */
+    char       *im_addr;       /* IMServerTransport */
+    XIMStyles  input_styles;   /* IMInputStyles */
+    XIMTriggerKeys on_keys;    /* IMOnKeysList */
+    XIMTriggerKeys off_keys;   /* IMOffKeysList */
+    XIMEncodings encoding_list; /* IMEncodingList */
+    IMProtoHandler improto;    /* IMProtocolHander */
+    long       filterevent_mask; /* IMFilterEventMask */
+    /* XIM_SERVERS target Atoms */
+    Atom       selection;
+    Atom       Localename;
+    Atom       Transportname;
+    /* XIM/XIC Attr */
+    int                im_attr_num;
+    XIMAttr    *xim_attr;
+    int                ic_attr_num;
+    XICAttr    *xic_attr;
+    CARD16     preeditAttr_id;
+    CARD16     statusAttr_id;
+    CARD16     separatorAttr_id;
+    /* XIMExtension List */
+    int                ext_num;
+    XIMExt     extension[COMMON_EXTENSIONS_NUM];
+    /* transport specific connection address */
+    void       *connect_addr;
+    /* actual data is defined:
+       XSpecRec in Xi18nX.h for X-based connection.
+       TransSpecRec in Xi18nTr.h for Socket-based connection.
+     */
+    /* clients table */
+    Xi18nClient *clients;
+    Xi18nClient *free_clients;
+} Xi18nAddressRec;
+
+typedef struct _Xi18nMethodsRec
+{
+    Bool (*begin) (XIMS);
+    Bool (*end) (XIMS);
+    Bool (*send) (XIMS, CARD16, unsigned char*, long);
+    Bool (*wait) (XIMS, CARD16, CARD8, CARD8);
+    Bool (*disconnect) (XIMS, CARD16);
+} Xi18nMethodsRec;
+
+typedef struct _Xi18nCore
+{
+    Xi18nAddressRec address;
+    Xi18nMethodsRec methods;
+} Xi18nCore;
+
+#endif
+
diff --git a/wrapper/xim/IMdkit/Xi18nX.h b/wrapper/xim/IMdkit/Xi18nX.h
new file mode 100644 (file)
index 0000000..ff91b1a
--- /dev/null
@@ -0,0 +1,52 @@
+/******************************************************************
+         Copyright 1994, 1995 by Sun Microsystems, Inc.
+         Copyright 1993, 1994 by Hewlett-Packard Company
+Permission to use, copy, modify, distribute, and sell this software
+and its documentation for any purpose is hereby granted without fee,
+provided that the above copyright notice appear in all copies and
+that both that copyright notice and this permission notice appear
+in supporting documentation, and that the name of Sun Microsystems, Inc.
+and Hewlett-Packard not be used in advertising or publicity pertaining to
+distribution of the software without specific, written prior permission.
+Sun Microsystems, Inc. and Hewlett-Packard make no representations about
+the suitability of this software for any purpose.  It is provided "as is"
+without express or implied warranty.
+SUN MICROSYSTEMS INC. AND HEWLETT-PACKARD COMPANY DISCLAIMS ALL
+WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
+SUN MICROSYSTEMS, INC. AND HEWLETT-PACKARD COMPANY BE LIABLE FOR ANY
+SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
+RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
+CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
+IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+  Author: Hidetoshi Tajima(tajima@Eng.Sun.COM) Sun Microsystems, Inc.
+
+    This version tidied and debugged by Steve Underwood May 1999
+******************************************************************/
+
+#ifndef _Xi18nTrX_h
+#define _Xi18nTrX_h
+
+#define _XIM_PROTOCOL           "_XIM_PROTOCOL"
+#define _XIM_XCONNECT           "_XIM_XCONNECT"
+
+#define XCM_DATA_LIMIT         20
+
+typedef struct _XClient
+{
+    Window     client_win;     /* client window */
+    Window     accept_win;     /* accept window */
+} XClient;
+
+typedef struct
+{
+    Atom       xim_request;
+    Atom       connect_request;
+} XSpecRec;
+
+#endif
diff --git a/wrapper/xim/IMdkit/XimFunc.h b/wrapper/xim/IMdkit/XimFunc.h
new file mode 100644 (file)
index 0000000..a9f4a04
--- /dev/null
@@ -0,0 +1,72 @@
+/******************************************************************
+         Copyright 1994, 1995 by Sun Microsystems, Inc.
+         Copyright 1993, 1994 by Hewlett-Packard Company
+Permission to use, copy, modify, distribute, and sell this software
+and its documentation for any purpose is hereby granted without fee,
+provided that the above copyright notice appear in all copies and
+that both that copyright notice and this permission notice appear
+in supporting documentation, and that the name of Sun Microsystems, Inc.
+and Hewlett-Packard not be used in advertising or publicity pertaining to
+distribution of the software without specific, written prior permission.
+Sun Microsystems, Inc. and Hewlett-Packard make no representations about
+the suitability of this software for any purpose.  It is provided "as is"
+without express or implied warranty.
+SUN MICROSYSTEMS INC. AND HEWLETT-PACKARD COMPANY DISCLAIMS ALL
+WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
+SUN MICROSYSTEMS, INC. AND HEWLETT-PACKARD COMPANY BE LIABLE FOR ANY
+SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
+RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
+CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
+IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+  Author: Hidetoshi Tajima(tajima@Eng.Sun.COM) Sun Microsystems, Inc.
+
+    This version tidied and debugged by Steve Underwood May 1999
+******************************************************************/
+
+#ifndef _XimFunc_h
+#define _XimFunc_h
+
+/* i18nAttr.c */
+void _Xi18nInitAttrList (Xi18n i18n_core);
+void _Xi18nInitExtension(Xi18n i18n_core);
+
+/* i18nClbk.c */
+int _Xi18nGeometryCallback (XIMS ims, IMProtocol *call_data);
+int _Xi18nPreeditStartCallback (XIMS ims, IMProtocol *call_data);
+int _Xi18nPreeditDrawCallback (XIMS ims, IMProtocol *call_data);
+int _Xi18nPreeditCaretCallback (XIMS ims, IMProtocol *call_data);
+int _Xi18nPreeditDoneCallback (XIMS ims, IMProtocol *call_data);
+int _Xi18nStatusStartCallback (XIMS ims, IMProtocol *call_data);
+int _Xi18nStatusDrawCallback (XIMS ims, IMProtocol *call_data);
+int _Xi18nStatusDoneCallback (XIMS ims, IMProtocol *call_data);
+int _Xi18nStringConversionCallback (XIMS ims, IMProtocol *call_data);
+
+/* i18nIc.c */
+void _Xi18nChangeIC (XIMS ims, IMProtocol *call_data, unsigned char *p,
+                     int create_flag);
+void _Xi18nGetIC (XIMS ims, IMProtocol *call_data, unsigned char *p);
+
+/* i18nUtil.c */
+int _Xi18nNeedSwap (Xi18n i18n_core, CARD16 connect_id);
+Xi18nClient *_Xi18nNewClient(Xi18n i18n_core);
+Xi18nClient *_Xi18nFindClient (Xi18n i18n_core, CARD16 connect_id);
+void _Xi18nDeleteClient (Xi18n i18n_core, CARD16 connect_id);
+void _Xi18nSendMessage (XIMS ims, CARD16 connect_id, CARD8 major_opcode,
+                        CARD8 minor_opcode, unsigned char *data, long length);
+void _Xi18nSendTriggerKey (XIMS ims, CARD16 connect_id);
+void _Xi18nSetEventMask (XIMS ims, CARD16 connect_id, CARD16 im_id,
+                         CARD16 ic_id, CARD32 forward_mask, CARD32 sync_mask);
+
+/* Xlib internal */
+void _XRegisterFilterByType(Display*, Window, int, int,
+               Bool (*filter)(Display*, Window, XEvent*, XPointer), XPointer);
+void _XUnregisterFilter(Display*, Window, 
+               Bool (*filter)(Display*, Window, XEvent*, XPointer), XPointer);
+
+#endif
diff --git a/wrapper/xim/IMdkit/XimProto.h b/wrapper/xim/IMdkit/XimProto.h
new file mode 100644 (file)
index 0000000..e3ed168
--- /dev/null
@@ -0,0 +1,230 @@
+/* $XConsortium: XimProto.h,v 1.2 94/01/20 18:02:24 rws Exp $ */
+/******************************************************************
+
+           Copyright 1992, 1993, 1994 by FUJITSU LIMITED
+
+Permission to use, copy, modify, distribute, and sell this software
+and its documentation for any purpose is hereby granted without fee,
+provided that the above copyright notice appear in all copies and
+that both that copyright notice and this permission notice appear
+in supporting documentation, and that the name of FUJITSU LIMITED
+not be used in advertising or publicity pertaining to distribution
+of the software without specific, written prior permission.
+FUJITSU LIMITED makes no representations about the suitability of
+this software for any purpose. 
+It is provided "as is" without express or implied warranty.
+
+FUJITSU LIMITED DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+EVENT SHALL FUJITSU LIMITED BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+PERFORMANCE OF THIS SOFTWARE.
+
+  Author: Takashi Fujiwara     FUJITSU LIMITED 
+                               fujiwara@a80.tech.yk.fujitsu.co.jp
+
+    This version tidied and debugged by Steve Underwood May 1999
+
+******************************************************************/
+
+#ifndef _XIMPROTO_H
+#define _XIMPROTO_H
+
+/*
+ * Default Preconnection selection target
+ */
+#define XIM_SERVERS            "XIM_SERVERS"
+#define XIM_LOCALES            "LOCALES"
+#define XIM_TRANSPORT          "TRANSPORT"
+
+/*
+ * categories in XIM_SERVERS
+ */
+#define XIM_SERVER_CATEGORY    "@server="
+#define XIM_LOCAL_CATEGORY     "@locale="
+#define XIM_TRANSPORT_CATEGORY "@transport="
+
+/*
+ * Xim implementation revision
+ */
+#define PROTOCOLMAJORVERSION           0
+#define PROTOCOLMINORVERSION           0
+
+/*
+ * Major Protocol number
+ */
+#define        XIM_CONNECT                       1
+#define        XIM_CONNECT_REPLY                 2
+#define        XIM_DISCONNECT                    3
+#define        XIM_DISCONNECT_REPLY              4
+
+#define XIM_AUTH_REQUIRED               10
+#define XIM_AUTH_REPLY                  11
+#define XIM_AUTH_NEXT                   12
+#define XIM_AUTH_SETUP                  13
+#define XIM_AUTH_NG                     14
+
+#define        XIM_ERROR                        20
+
+#define        XIM_OPEN                         30
+#define        XIM_OPEN_REPLY                   31
+#define        XIM_CLOSE                        32
+#define        XIM_CLOSE_REPLY                  33
+#define        XIM_REGISTER_TRIGGERKEYS         34
+#define        XIM_TRIGGER_NOTIFY               35
+#define        XIM_TRIGGER_NOTIFY_REPLY         36
+#define        XIM_SET_EVENT_MASK               37
+#define        XIM_ENCODING_NEGOTIATION         38
+#define        XIM_ENCODING_NEGOTIATION_REPLY   39
+#define        XIM_QUERY_EXTENSION              40
+#define        XIM_QUERY_EXTENSION_REPLY        41
+#define        XIM_SET_IM_VALUES                42
+#define        XIM_SET_IM_VALUES_REPLY          43
+#define        XIM_GET_IM_VALUES                44
+#define        XIM_GET_IM_VALUES_REPLY          45
+
+#define XIM_CREATE_IC                   50
+#define        XIM_CREATE_IC_REPLY              51
+#define        XIM_DESTROY_IC                   52
+#define        XIM_DESTROY_IC_REPLY             53
+#define XIM_SET_IC_VALUES               54
+#define        XIM_SET_IC_VALUES_REPLY          55
+#define XIM_GET_IC_VALUES               56
+#define XIM_GET_IC_VALUES_REPLY                 57
+#define        XIM_SET_IC_FOCUS                 58
+#define        XIM_UNSET_IC_FOCUS               59
+#define        XIM_FORWARD_EVENT                60
+#define        XIM_SYNC                         61
+#define        XIM_SYNC_REPLY                   62
+#define        XIM_COMMIT                       63
+#define        XIM_RESET_IC                     64
+#define        XIM_RESET_IC_REPLY               65
+
+#define        XIM_GEOMETRY                     70
+#define        XIM_STR_CONVERSION               71
+#define        XIM_STR_CONVERSION_REPLY         72
+#define        XIM_PREEDIT_START                73
+#define        XIM_PREEDIT_START_REPLY          74
+#define        XIM_PREEDIT_DRAW                 75
+#define        XIM_PREEDIT_CARET                76
+#define XIM_PREEDIT_CARET_REPLY                 77
+#define        XIM_PREEDIT_DONE                 78
+#define        XIM_STATUS_START                 79
+#define        XIM_STATUS_DRAW                  80
+#define        XIM_STATUS_DONE                  81
+
+/*
+ * values for the flag of XIM_ERROR
+ */
+#define        XIM_IMID_VALID                  0x0001
+#define        XIM_ICID_VALID                  0x0002
+
+/*
+ * XIM Error Code
+ */
+#define XIM_BadAlloc                   1
+#define XIM_BadStyle                   2
+#define XIM_BadClientWindow            3
+#define XIM_BadFocusWindow             4
+#define XIM_BadArea                    5
+#define XIM_BadSpotLocation            6
+#define XIM_BadColormap                        7
+#define XIM_BadAtom                    8
+#define XIM_BadPixel                   9
+#define XIM_BadPixmap                  10
+#define XIM_BadName                    11
+#define XIM_BadCursor                  12
+#define XIM_BadProtocol                        13
+#define XIM_BadForeground              14
+#define XIM_BadBackground              15
+#define XIM_LocaleNotSupported         16
+#define XIM_BadSomething               999
+
+/*
+ * byte order
+ */
+#define BIGENDIAN      (CARD8) 0x42    /* MSB first */
+#define LITTLEENDIAN   (CARD8) 0x6c    /* LSB first */
+
+/*
+ * values for the type of XIMATTR & XICATTR
+ */
+#define        XimType_SeparatorOfNestedList   0
+#define        XimType_CARD8                   1
+#define        XimType_CARD16                  2
+#define        XimType_CARD32                  3
+#define        XimType_STRING8                 4
+#define        XimType_Window                  5
+#define        XimType_XIMStyles               10
+#define        XimType_XRectangle              11
+#define        XimType_XPoint                  12
+#define XimType_XFontSet               13
+#define XimType_XIMOptions             14
+#define XimType_XIMHotKeyTriggers      15
+#define XimType_XIMHotKeyState         16
+#define XimType_XIMStringConversion    17
+#define XimType_XIMValuesList          18
+#define        XimType_NEST                    0x7FFF
+
+/*
+ * values for the category of XIM_ENCODING_NEGOTIATON_REPLY
+ */
+#define        XIM_Encoding_NameCategory       0
+#define        XIM_Encoding_DetailCategory     1
+
+/*
+ * value for the index of XIM_ENCODING_NEGOTIATON_REPLY
+ */
+#define        XIM_Default_Encoding_IDX        -1
+
+/*
+ * value for the flag of XIM_FORWARD_EVENT, XIM_COMMIT
+ */
+#define XimSYNCHRONUS            0x0001
+#define XimLookupChars           0x0002
+#define XimLookupKeySym                  0x0004
+#define XimLookupBoth            0x0006
+
+/*
+ * request packet header size
+ */
+#define XIM_HEADER_SIZE                                                \
+         sizeof(CARD8)         /* sizeof mejor-opcode */       \
+       + sizeof(CARD8)         /* sizeof minor-opcode */       \
+       + sizeof(INT16)         /* sizeof length */
+
+/*
+ * Client Message data size
+ */
+#define        XIM_CM_DATA_SIZE        20
+
+/*
+ * XIM data structure
+ */
+typedef CARD16 BITMASK16;
+typedef CARD32 BITMASK32;
+typedef CARD32 EVENTMASK;
+
+typedef CARD16 XIMID;          /* Input Method ID */
+typedef CARD16 XICID;          /* Input Context ID */
+
+/*
+ * Padding macro
+ */
+#define        XIM_PAD(length) ((4 - ((length) % 4)) % 4)
+
+#define XIM_SET_PAD(ptr, length)                                       \
+    {                                                                  \
+       register int     Counter = XIM_PAD((int)length);                \
+       if (Counter) {                                                  \
+           register char       *Ptr = (char *)(ptr) + (length);        \
+           length += Counter;                                          \
+           for (; Counter; --Counter, ++Ptr)                           \
+               *Ptr = '\0';                                            \
+       }                                                               \
+    }
+
+#endif
+
diff --git a/wrapper/xim/IMdkit/i18nAttr.c b/wrapper/xim/IMdkit/i18nAttr.c
new file mode 100644 (file)
index 0000000..a52370b
--- /dev/null
@@ -0,0 +1,175 @@
+/******************************************************************
+         Copyright 1994, 1995 by Sun Microsystems, Inc.
+         Copyright 1993, 1994 by Hewlett-Packard Company
+Permission to use, copy, modify, distribute, and sell this software
+and its documentation for any purpose is hereby granted without fee,
+provided that the above copyright notice appear in all copies and
+that both that copyright notice and this permission notice appear
+in supporting documentation, and that the name of Sun Microsystems, Inc.
+and Hewlett-Packard not be used in advertising or publicity pertaining to
+distribution of the software without specific, written prior permission.
+Sun Microsystems, Inc. and Hewlett-Packard make no representations about
+the suitability of this software for any purpose.  It is provided "as is"
+without express or implied warranty.
+SUN MICROSYSTEMS INC. AND HEWLETT-PACKARD COMPANY DISCLAIMS ALL
+WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
+SUN MICROSYSTEMS, INC. AND HEWLETT-PACKARD COMPANY BE LIABLE FOR ANY
+SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
+RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
+CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
+IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+  Author: Hidetoshi Tajima(tajima@Eng.Sun.COM) Sun Microsystems, Inc.
+
+    This version tidied and debugged by Steve Underwood May 1999
+******************************************************************/
+
+#include <X11/Xlib.h>
+#include <X11/Xresource.h>
+#include "IMdkit.h"
+#include "Xi18n.h"
+#include "XimFunc.h"
+
+typedef struct 
+{
+    char *name;
+    CARD16 type;
+} IMListOfAttr;
+
+typedef struct
+{
+    char *name;
+    CARD8 major_opcode;
+    CARD8 minor_opcode;
+} IMExtList;
+
+IMListOfAttr Default_IMattr[] =
+{
+    {XNQueryInputStyle,   XimType_XIMStyles},
+/*    {XNQueryIMValuesList, XimType_XIMValuesList},    */
+    {(char *) NULL, (CARD16) 0}
+};
+
+IMListOfAttr Default_ICattr[] =
+{
+    {XNInputStyle,              XimType_CARD32},
+    {XNClientWindow,            XimType_Window},
+    {XNFocusWindow,             XimType_Window},
+    {XNFilterEvents,            XimType_CARD32},
+    {XNPreeditAttributes,       XimType_NEST},
+    {XNStatusAttributes,        XimType_NEST},
+    {XNFontSet,                 XimType_XFontSet},
+    {XNArea,                    XimType_XRectangle},
+    {XNAreaNeeded,              XimType_XRectangle},
+    {XNColormap,                XimType_CARD32},
+    {XNStdColormap,             XimType_CARD32},
+    {XNForeground,              XimType_CARD32},
+    {XNBackground,              XimType_CARD32},
+    {XNBackgroundPixmap,        XimType_CARD32},
+    {XNSpotLocation,            XimType_XPoint},
+    {XNLineSpace,               XimType_CARD32},
+    {XNPreeditState,            XimType_CARD32},
+    {XNSeparatorofNestedList,   XimType_SeparatorOfNestedList},
+    {(char *) NULL, 0}
+};
+
+IMExtList Default_Extension[] =
+{
+    {"XIM_EXT_MOVE", XIM_EXTENSION, XIM_EXT_MOVE},
+    {"XIM_EXT_SET_EVENT_MASK", XIM_EXTENSION, XIM_EXT_SET_EVENT_MASK},
+    {"XIM_EXT_FORWARD_KEYEVENT", XIM_EXTENSION, XIM_EXT_FORWARD_KEYEVENT},
+    {(char *) NULL, 0, 0}
+};
+
+static void CountAttrList(IMListOfAttr *attr, int *total_count)
+{
+    *total_count = 0;
+
+    while (attr->name != NULL)
+    {
+        attr++;
+        ++(*total_count);
+    }
+}
+
+static XIMAttr *CreateAttrList (Xi18n i18n_core,
+                                IMListOfAttr *attr,
+                                int *total_count)
+{
+    XIMAttr *args, *p;
+    unsigned int buf_size;
+
+    CountAttrList(attr, total_count);
+
+    buf_size = (unsigned) (*total_count + 1)*sizeof (XIMAttr);
+    args = (XIMAttr *) malloc (buf_size);
+    if (!args)
+        return (XIMAttr *) NULL;
+    /*endif*/
+    memset (args, 0, buf_size);
+
+    for (p = args;  attr->name != NULL;  attr++, p++)
+    {
+        p->name = attr->name;
+        p->length = strlen (attr->name);
+        p->type = (CARD16) attr->type;
+        p->attribute_id = XrmStringToQuark (p->name);
+        if (strcmp (p->name, XNPreeditAttributes) == 0)
+            i18n_core->address.preeditAttr_id = p->attribute_id;
+        else if (strcmp (p->name, XNStatusAttributes) == 0)
+            i18n_core->address.statusAttr_id = p->attribute_id;
+        else if (strcmp (p->name, XNSeparatorofNestedList) == 0)
+            i18n_core->address.separatorAttr_id = p->attribute_id;
+        /*endif*/
+    }
+    /*endfor*/
+    p->name = (char *) NULL;
+
+    return args;
+}
+
+void _Xi18nInitAttrList (Xi18n i18n_core)
+{
+    XIMAttr *args;
+    int        total_count;
+
+    /* init IMAttr list */
+    if (i18n_core->address.xim_attr)
+        XFree ((char *)i18n_core->address.xim_attr);
+    /*endif*/
+    args = CreateAttrList (i18n_core, Default_IMattr, &total_count);
+
+    i18n_core->address.im_attr_num = total_count;
+    i18n_core->address.xim_attr = (XIMAttr *)args;
+
+    /* init ICAttr list */
+    if (i18n_core->address.xic_attr)
+        XFree ((char *) i18n_core->address.xic_attr);
+    /*endif*/
+    args = CreateAttrList (i18n_core, Default_ICattr, &total_count);
+
+    i18n_core->address.ic_attr_num = total_count;
+    i18n_core->address.xic_attr = (XICAttr *) args;
+}
+
+void _Xi18nInitExtension(Xi18n i18n_core)
+{
+    register int i;
+    IMExtList *extensions = (IMExtList *) Default_Extension;
+    XIMExt *ext_list = (XIMExt *) i18n_core->address.extension;
+
+    for (i = 0;  extensions->name;  i++, ext_list++, extensions++)
+    {
+        ext_list->major_opcode = extensions->major_opcode;
+        ext_list->minor_opcode = extensions->minor_opcode;
+        ext_list->name = extensions->name;
+        ext_list->length = strlen(ext_list->name);
+    }
+    /*endfor*/
+    i18n_core->address.ext_num = i;
+}
diff --git a/wrapper/xim/IMdkit/i18nClbk.c b/wrapper/xim/IMdkit/i18nClbk.c
new file mode 100644 (file)
index 0000000..b3edf3a
--- /dev/null
@@ -0,0 +1,513 @@
+/******************************************************************
+         Copyright 1994, 1995 by Sun Microsystems, Inc.
+         Copyright 1993, 1994 by Hewlett-Packard Company
+Permission to use, copy, modify, distribute, and sell this software
+and its documentation for any purpose is hereby granted without fee,
+provided that the above copyright notice appear in all copies and
+that both that copyright notice and this permission notice appear
+in supporting documentation, and that the name of Sun Microsystems, Inc.
+and Hewlett-Packard not be used in advertising or publicity pertaining to
+distribution of the software without specific, written prior permission.
+Sun Microsystems, Inc. and Hewlett-Packard make no representations about
+the suitability of this software for any purpose.  It is provided "as is"
+without express or implied warranty.
+SUN MICROSYSTEMS INC. AND HEWLETT-PACKARD COMPANY DISCLAIMS ALL
+WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
+SUN MICROSYSTEMS, INC. AND HEWLETT-PACKARD COMPANY BE LIABLE FOR ANY
+SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
+RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
+CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
+IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+  Author: Hidetoshi Tajima(tajima@Eng.Sun.COM) Sun Microsystems, Inc.
+
+    This version tidied and debugged by Steve Underwood May 1999
+******************************************************************/
+
+#include <X11/Xlib.h>
+#include "IMdkit.h"
+#include "Xi18n.h"
+#include "FrameMgr.h"
+#include "XimFunc.h"
+
+int _Xi18nGeometryCallback (XIMS ims, IMProtocol *call_data)
+{
+    Xi18n i18n_core = ims->protocol;
+    FrameMgr fm;
+    extern XimFrameRec geometry_fr[];
+    register int total_size;
+    unsigned char *reply = NULL;
+    IMGeometryCBStruct *geometry_CB =
+        (IMGeometryCBStruct *) &call_data->geometry_callback;
+    CARD16 connect_id = call_data->any.connect_id;
+
+    fm = FrameMgrInit (geometry_fr,
+                       NULL,
+                       _Xi18nNeedSwap (i18n_core, connect_id));
+
+    total_size = FrameMgrGetTotalSize (fm);
+    reply = (unsigned char *) malloc (total_size);
+    if (!reply)
+    {
+        _Xi18nSendMessage (ims, connect_id, XIM_ERROR, 0, 0, 0);
+        return False;
+    }
+    /*endif*/
+    memset (reply, 0, total_size);
+    FrameMgrSetBuffer (fm, reply);
+
+    FrameMgrPutToken (fm, connect_id);
+    FrameMgrPutToken (fm, geometry_CB->icid);
+
+    _Xi18nSendMessage (ims,
+                       connect_id,
+                       XIM_GEOMETRY,
+                       0,
+                       reply,
+                       total_size);
+    FrameMgrFree (fm);
+    XFree (reply);
+
+    /* XIM_GEOMETRY is an asyncronous protocol,
+       so return immediately. */
+    return True;
+}
+
+int _Xi18nPreeditStartCallback (XIMS ims, IMProtocol *call_data)
+{
+    Xi18n i18n_core = ims->protocol;
+    FrameMgr fm;
+    extern XimFrameRec preedit_start_fr[];
+    register int total_size;
+    unsigned char *reply = NULL;
+    IMPreeditCBStruct *preedit_CB =
+        (IMPreeditCBStruct*) &call_data->preedit_callback;
+    CARD16 connect_id = call_data->any.connect_id;
+
+    fm = FrameMgrInit (preedit_start_fr,
+                       NULL,
+                       _Xi18nNeedSwap (i18n_core, connect_id));
+    total_size = FrameMgrGetTotalSize (fm);
+    reply = (unsigned char *) malloc (total_size);
+    if (!reply)
+    {
+        _Xi18nSendMessage(ims, connect_id, XIM_ERROR, 0, 0, 0);
+        return False;
+    }
+    /*endif*/
+    memset (reply, 0, total_size);
+    FrameMgrSetBuffer (fm, reply);
+
+    FrameMgrPutToken (fm, connect_id);
+    FrameMgrPutToken (fm, preedit_CB->icid);
+
+    _Xi18nSendMessage (ims,
+                       connect_id,
+                       XIM_PREEDIT_START,
+                       0,
+                       reply,
+                       total_size);
+    FrameMgrFree (fm);
+    XFree (reply);
+
+    return True;
+}
+
+int _Xi18nPreeditDrawCallback (XIMS ims, IMProtocol *call_data)
+{
+    Xi18n i18n_core = ims->protocol;
+    FrameMgr fm;
+    extern XimFrameRec preedit_draw_fr[];
+    register int total_size;
+    unsigned char *reply = NULL;
+    IMPreeditCBStruct *preedit_CB =
+        (IMPreeditCBStruct *) &call_data->preedit_callback;
+    XIMPreeditDrawCallbackStruct *draw =
+        (XIMPreeditDrawCallbackStruct *) &preedit_CB->todo.draw;
+    CARD16 connect_id = call_data->any.connect_id;
+    register int feedback_count;
+    register int i;
+    BITMASK32 status = 0x0;
+
+    if (draw->text->length == 0)
+        status = 0x00000001;
+    else if (draw->text->feedback[0] == 0)
+        status = 0x00000002;
+    /*endif*/
+
+    fm = FrameMgrInit (preedit_draw_fr,
+                       NULL,
+                       _Xi18nNeedSwap (i18n_core, connect_id));
+
+    /* set length of preedit string */
+    FrameMgrSetSize (fm, draw->text->length);
+
+    /* set iteration count for list of feedback */
+    for (i = 0;  draw->text->feedback[i] != 0;  i++)
+        ;
+    /*endfor*/
+    feedback_count = i;
+    FrameMgrSetIterCount (fm, feedback_count);
+
+    total_size = FrameMgrGetTotalSize (fm);
+    reply = (unsigned char *) malloc (total_size);
+    if (!reply)
+    {
+        _Xi18nSendMessage (ims, connect_id, XIM_ERROR, 0, 0, 0);
+        return False;
+    }
+    /*endif*/
+    memset (reply, 0, total_size);
+    FrameMgrSetBuffer (fm, reply);
+
+    FrameMgrPutToken (fm, connect_id);
+    FrameMgrPutToken (fm, preedit_CB->icid);
+    FrameMgrPutToken (fm, draw->caret);
+    FrameMgrPutToken (fm, draw->chg_first);
+    FrameMgrPutToken (fm, draw->chg_length);
+    FrameMgrPutToken (fm, status);
+    FrameMgrPutToken (fm, draw->text->length);
+    FrameMgrPutToken (fm, draw->text->string);
+    for (i = 0;  i < feedback_count;  i++)
+        FrameMgrPutToken (fm, draw->text->feedback[i]);
+    /*endfor*/
+    
+    _Xi18nSendMessage (ims,
+                       connect_id,
+                       XIM_PREEDIT_DRAW,
+                       0,
+                       reply,
+                       total_size);
+    FrameMgrFree (fm);
+    XFree (reply);
+
+    /* XIM_PREEDIT_DRAW is an asyncronous protocol, so return immediately. */
+    return True;
+}
+
+int _Xi18nPreeditCaretCallback (XIMS ims, IMProtocol *call_data)
+{
+    Xi18n i18n_core = ims->protocol;
+    FrameMgr fm;
+    extern XimFrameRec preedit_caret_fr[];
+    register int total_size;
+    unsigned char *reply = NULL;
+    IMPreeditCBStruct *preedit_CB =
+        (IMPreeditCBStruct*) &call_data->preedit_callback;
+    XIMPreeditCaretCallbackStruct *caret =
+        (XIMPreeditCaretCallbackStruct *) &preedit_CB->todo.caret;
+    CARD16 connect_id = call_data->any.connect_id;
+
+    fm = FrameMgrInit (preedit_caret_fr,
+                       NULL,
+                       _Xi18nNeedSwap (i18n_core, connect_id));
+
+    total_size = FrameMgrGetTotalSize (fm);
+    reply = (unsigned char *) malloc (total_size);
+    if (!reply)
+    {
+        _Xi18nSendMessage (ims, connect_id, XIM_ERROR, 0, 0, 0);
+        return False;
+    }
+    /*endif*/
+    memset (reply, 0, total_size);
+    FrameMgrSetBuffer (fm, reply);
+
+    FrameMgrPutToken (fm, connect_id);
+    FrameMgrPutToken (fm, preedit_CB->icid);
+    FrameMgrPutToken (fm, caret->position);
+    FrameMgrPutToken (fm, caret->direction);
+    FrameMgrPutToken (fm, caret->style);
+
+    _Xi18nSendMessage (ims,
+                       connect_id,
+                       XIM_PREEDIT_CARET,
+                       0,
+                       reply,
+                       total_size);
+    FrameMgrFree (fm);
+    XFree (reply);
+
+    return True;
+}
+
+int _Xi18nPreeditDoneCallback (XIMS ims, IMProtocol *call_data)
+{
+    Xi18n i18n_core = ims->protocol;
+    FrameMgr fm;
+    extern XimFrameRec preedit_done_fr[];
+    register int total_size;
+    unsigned char *reply = NULL;
+    IMPreeditCBStruct *preedit_CB =
+        (IMPreeditCBStruct *) &call_data->preedit_callback;
+    CARD16 connect_id = call_data->any.connect_id;
+
+    fm = FrameMgrInit (preedit_done_fr,
+                       NULL,
+                       _Xi18nNeedSwap (i18n_core, connect_id));
+
+    total_size = FrameMgrGetTotalSize (fm);
+    reply = (unsigned char *) malloc (total_size);
+    if (!reply)
+    {
+        _Xi18nSendMessage (ims, connect_id, XIM_ERROR, 0, 0, 0);
+        return False;
+    }
+    /*endif*/
+    memset (reply, 0, total_size);
+    FrameMgrSetBuffer (fm, reply);
+
+    FrameMgrPutToken (fm, connect_id);
+    FrameMgrPutToken (fm, preedit_CB->icid);
+
+    _Xi18nSendMessage (ims,
+                       connect_id,
+                       XIM_PREEDIT_DONE,
+                       0,
+                       reply,
+                       total_size);
+    FrameMgrFree (fm);
+    XFree (reply);
+
+    /* XIM_PREEDIT_DONE is an asyncronous protocol, so return immediately. */
+    return True;
+}
+
+int _Xi18nStatusStartCallback (XIMS ims, IMProtocol *call_data)
+{
+    Xi18n i18n_core = ims->protocol;
+    FrameMgr fm;
+    extern XimFrameRec status_start_fr[];
+    register int total_size;
+    unsigned char *reply = NULL;
+    IMStatusCBStruct *status_CB =
+        (IMStatusCBStruct*) &call_data->status_callback;
+    CARD16 connect_id = call_data->any.connect_id;
+
+    fm = FrameMgrInit (status_start_fr,
+                       NULL,
+                       _Xi18nNeedSwap (i18n_core, connect_id));
+    total_size = FrameMgrGetTotalSize (fm);
+    reply = (unsigned char *) malloc (total_size);
+    if (!reply)
+    {
+        _Xi18nSendMessage (ims, connect_id, XIM_ERROR, 0, 0, 0);
+        return False;
+    }
+    /*endif*/
+    memset (reply, 0, total_size);
+    FrameMgrSetBuffer (fm, reply);
+
+    FrameMgrPutToken (fm, connect_id);
+    FrameMgrPutToken (fm, status_CB->icid);
+
+    _Xi18nSendMessage (ims,
+                       connect_id,
+                       XIM_STATUS_START,
+                       0,
+                       reply,
+                       total_size);
+    FrameMgrFree (fm);
+    XFree (reply);
+
+    /* XIM_STATUS_START is an asyncronous protocol, so return immediately. */
+    return True;
+}
+
+int _Xi18nStatusDrawCallback (XIMS ims, IMProtocol *call_data)
+{
+    Xi18n i18n_core = ims->protocol;
+    FrameMgr fm = (FrameMgr)0;
+    extern XimFrameRec status_draw_text_fr[];
+    extern XimFrameRec status_draw_bitmap_fr[];
+    register int total_size = 0;
+    unsigned char *reply = NULL;
+    IMStatusCBStruct *status_CB =
+        (IMStatusCBStruct *) &call_data->status_callback;
+    XIMStatusDrawCallbackStruct *draw =
+        (XIMStatusDrawCallbackStruct *) &status_CB->todo.draw;
+    CARD16 connect_id = call_data->any.connect_id;
+    register int feedback_count;
+    register int i;
+    BITMASK32 status = 0x0;
+
+    switch (draw->type)
+    {
+    case XIMTextType:
+        fm = FrameMgrInit (status_draw_text_fr,
+                           NULL,
+                           _Xi18nNeedSwap (i18n_core, connect_id));
+
+        if (draw->data.text->length == 0)
+            status = 0x00000001;
+        else if (draw->data.text->feedback[0] == 0)
+            status = 0x00000002;
+        /*endif*/
+        
+        /* set length of status string */
+        FrameMgrSetSize(fm, draw->data.text->length);
+        /* set iteration count for list of feedback */
+        for (i = 0;  draw->data.text->feedback[i] != 0;  i++)
+            ;
+        /*endfor*/
+        feedback_count = i;
+        FrameMgrSetIterCount (fm, feedback_count);
+
+        total_size = FrameMgrGetTotalSize (fm);
+        reply = (unsigned char *) malloc (total_size);
+        if (!reply)
+        {
+            _Xi18nSendMessage (ims, connect_id, XIM_ERROR, 0, 0, 0);
+            return False;
+        }
+        /*endif*/
+        memset (reply, 0, total_size);
+        FrameMgrSetBuffer (fm, reply);
+
+        FrameMgrPutToken (fm, connect_id);
+        FrameMgrPutToken (fm, status_CB->icid);
+        FrameMgrPutToken (fm, draw->type);
+        FrameMgrPutToken (fm, status);
+        FrameMgrPutToken (fm, draw->data.text->length);
+        FrameMgrPutToken (fm, draw->data.text->string);
+        for (i = 0;  i < feedback_count;  i++)
+            FrameMgrPutToken (fm, draw->data.text->feedback[i]);
+        /*endfor*/
+        break;
+
+    case XIMBitmapType:
+        fm = FrameMgrInit (status_draw_bitmap_fr,
+                           NULL,
+                           _Xi18nNeedSwap (i18n_core, connect_id));
+
+        total_size = FrameMgrGetTotalSize (fm);
+        reply = (unsigned char *) malloc (total_size);
+        if (!reply)
+        {
+            _Xi18nSendMessage (ims, connect_id, XIM_ERROR, 0, 0, 0);
+            return False;
+        }
+        /*endif*/
+        memset (reply, 0, total_size);
+        FrameMgrSetBuffer (fm, reply);
+
+        FrameMgrPutToken (fm, connect_id);
+        FrameMgrPutToken (fm, status_CB->icid);
+        FrameMgrPutToken (fm, draw->data.bitmap);
+        break;
+    }
+    /*endswitch*/
+    _Xi18nSendMessage (ims,
+                       connect_id,
+                       XIM_STATUS_DRAW,
+                       0,
+                       reply,
+                       total_size);
+    FrameMgrFree (fm);
+    XFree (reply);
+
+    /* XIM_STATUS_DRAW is an asyncronous protocol, so return immediately. */
+    return True;
+}
+
+int _Xi18nStatusDoneCallback (XIMS ims, IMProtocol *call_data)
+{
+    Xi18n i18n_core = ims->protocol;
+    FrameMgr fm;
+    extern XimFrameRec status_done_fr[];
+    register int total_size;
+    unsigned char *reply = NULL;
+    IMStatusCBStruct *status_CB =
+        (IMStatusCBStruct *) &call_data->status_callback;
+    CARD16 connect_id = call_data->any.connect_id;
+
+    fm = FrameMgrInit (status_done_fr,
+                       NULL,
+                       _Xi18nNeedSwap (i18n_core, connect_id));
+
+    total_size = FrameMgrGetTotalSize (fm);
+    reply = (unsigned char *) malloc (total_size);
+    if (!reply)
+    {
+        _Xi18nSendMessage (ims, connect_id, XIM_ERROR, 0, 0, 0);
+        return False;
+    }
+    /*endif*/
+    memset (reply, 0, total_size);
+    FrameMgrSetBuffer (fm, reply);
+
+    FrameMgrPutToken (fm, connect_id);
+    FrameMgrPutToken (fm, status_CB->icid);
+
+    _Xi18nSendMessage (ims,
+                       connect_id,
+                       XIM_STATUS_DONE,
+                       0,
+                       reply,
+                       total_size);
+    FrameMgrFree (fm);
+    XFree (reply);
+
+    /* XIM_STATUS_DONE is an asyncronous protocol, so return immediately. */
+    return True;
+}
+
+int _Xi18nStringConversionCallback (XIMS ims, IMProtocol *call_data)
+{
+    Xi18n i18n_core = ims->protocol;
+    FrameMgr fm;
+    extern XimFrameRec str_conversion_fr[];
+    register int total_size;
+    unsigned char *reply = NULL;
+    IMStrConvCBStruct *call_back =
+        (IMStrConvCBStruct *) &call_data->strconv_callback;
+    XIMStringConversionCallbackStruct *strconv =
+        (XIMStringConversionCallbackStruct *) &call_back->strconv;
+    CARD16 connect_id = call_data->any.connect_id;
+
+    fm = FrameMgrInit (str_conversion_fr,
+                       NULL,
+                      _Xi18nNeedSwap (i18n_core, connect_id));
+
+    total_size = FrameMgrGetTotalSize (fm);
+    reply = (unsigned char *) malloc (total_size);
+    if (!reply)
+    {
+        _Xi18nSendMessage (ims, connect_id, XIM_ERROR, 0, 0, 0);
+        return False;
+    }
+    /*endif*/
+    memset (reply, 0, total_size);
+    FrameMgrSetBuffer (fm, reply);
+
+    FrameMgrPutToken (fm, connect_id);
+    FrameMgrPutToken (fm, call_back->icid);
+    FrameMgrPutToken (fm, strconv->position);
+    FrameMgrPutToken (fm, strconv->direction);
+    FrameMgrPutToken (fm, strconv->operation);
+
+    _Xi18nSendMessage (ims, connect_id,
+                       XIM_STR_CONVERSION,
+                       0,
+                       reply,
+                       total_size);
+    FrameMgrFree (fm);
+    XFree (reply);
+
+    /* XIM_STR_CONVERSION is a syncronous protocol,
+       so should wait here for XIM_STR_CONVERSION_REPLY. */
+    if (i18n_core->methods.wait (ims,
+                                 connect_id,
+                                 XIM_STR_CONVERSION_REPLY,
+                                 0) == False)
+    {
+        return False;
+    }
+    /*endif*/
+    return True;
+}
diff --git a/wrapper/xim/IMdkit/i18nIMProto.c b/wrapper/xim/IMdkit/i18nIMProto.c
new file mode 100644 (file)
index 0000000..618da9d
--- /dev/null
@@ -0,0 +1,773 @@
+/******************************************************************
+Copyright 1993, 1994 by Digital Equipment Corporation, Maynard, Massachusetts,
+Copyright 1993, 1994 by Hewlett-Packard Company
+Copyright 1994, 1995 by Sun Microsystems, Inc.
+                        All Rights Reserved
+Permission to use, copy, modify, and distribute this software and its 
+documentation for any purpose and without fee is hereby granted, 
+provided that the above copyright notice appear in all copies and that
+both that copyright notice and this permission notice appear in 
+supporting documentation, and that the names of Digital or MIT not be
+used in advertising or publicity pertaining to distribution of the
+software without specific, written prior permission.  
+DIGITAL AND HEWLETT-PACKARD COMPANY DISCLAIMS ALL WARRANTIES WITH REGARD
+TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+FITNESS, IN NO EVENT SHALL DIGITAL AND HEWLETT-PACKARD COMPANY BE LIABLE
+FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
+RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
+CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+  Author: Hiroyuki Miyamoto  Digital Equipment Corporation
+                             miyamoto@jrd.dec.com
+         Hidetoshi Tajima(tajima@Eng.Sun.COM) Sun Microsystems, Inc.
+
+    This version tidied and debugged by Steve Underwood May 1999
+******************************************************************/
+
+/* Protocol Packet frames */
+
+#include "FrameMgr.h"
+
+/* Data type definitions */
+
+static XimFrameRec ximattr_fr[] =
+{
+    _FRAME(BIT16),             /* attribute ID */
+    _FRAME(BIT16),             /* type of the value */
+    _FRAME(BIT16),             /* length of im-attribute */
+    _FRAME(BARRAY),            /* im-attribute */
+    _PAD4(2),
+    _FRAME(EOL),
+};
+
+static XimFrameRec xicattr_fr[] =
+{
+    _FRAME(BIT16),             /* attribute ID */
+    _FRAME(BIT16),             /* type of the value */
+    _FRAME(BIT16),             /* length of ic-attribute */
+    _FRAME(BARRAY),            /* ic-attribute */
+    _PAD4(2),
+    _FRAME(EOL),
+};
+
+static XimFrameRec ximattribute_fr[] =
+{
+    _FRAME(BIT16),             /* attribute ID */
+    _FRAME(BIT16),             /* value length */
+    _FRAME(BARRAY),             /* value */
+    _PAD4(1),
+    _FRAME(EOL),
+};
+
+static XimFrameRec xicattribute_fr[] =
+{
+    _FRAME(BIT16),             /* attribute ID */
+    _FRAME(BIT16),             /* value length */
+    _FRAME(BARRAY),             /* value */
+    _PAD4(1),
+    _FRAME(EOL),
+};
+
+static XimFrameRec ximtriggerkey_fr[] =
+{
+    _FRAME(BIT32),             /* keysym */
+    _FRAME(BIT32),             /* modifier */
+    _FRAME(BIT32),             /* modifier mask */
+    _FRAME(EOL),
+};
+
+static XimFrameRec encodinginfo_fr[] =
+{
+    _FRAME(BIT16),             /* length of encoding info */
+    _FRAME(BARRAY),            /* encoding info */
+    _PAD4(2),
+    _FRAME(EOL),
+};
+
+static XimFrameRec str_fr[] =
+{
+    _FRAME(BIT8),              /* number of byte */
+    _FRAME(BARRAY),            /* string */
+    _FRAME(EOL),
+};
+
+static XimFrameRec xpcs_fr[] =
+{
+    _FRAME(BIT16),             /* length of string in bytes */
+    _FRAME(BARRAY),            /* string */
+    _PAD4(2),
+};
+
+static XimFrameRec ext_fr[] =
+{
+    _FRAME(BIT8),              /* extension major-opcode */
+    _FRAME(BIT8),              /* extension minor-opcode */
+    _FRAME(BIT16),             /* length of extension name */
+    _FRAME(BARRAY),            /* extension name */
+    _PAD4(1),
+    _FRAME(EOL),
+};
+
+static XimFrameRec inputstyle_fr[] =
+{
+    _FRAME(BIT32),             /* inputstyle */
+    _FRAME(EOL),
+};
+/* Protocol definitions */
+
+xim_externaldef XimFrameRec attr_head_fr[] =
+{
+    _FRAME(BIT16),     /* attribute id */
+    _FRAME(BIT16),     /* attribute length */
+    _FRAME(EOL),
+};
+
+xim_externaldef XimFrameRec short_fr[] =
+{
+    _FRAME(BIT16),     /* value */
+    _FRAME(EOL),
+};
+
+xim_externaldef XimFrameRec long_fr[] =
+{
+    _FRAME(BIT32),     /* value */
+    _FRAME(EOL),
+};
+
+xim_externaldef XimFrameRec xrectangle_fr[] =
+{
+    _FRAME(BIT16),     /* x */
+    _FRAME(BIT16),     /* y */
+    _FRAME(BIT16),     /* width */
+    _FRAME(BIT16),     /* height */
+    _FRAME(EOL),
+};
+
+xim_externaldef XimFrameRec xpoint_fr[] =
+{
+    _FRAME(BIT16),     /* x */
+    _FRAME(BIT16),     /* y */
+    _FRAME(EOL),
+};
+
+xim_externaldef XimFrameRec fontset_fr[] =
+{
+    _FRAME(BIT16),     /* length of base font name */
+    _FRAME(BARRAY),    /* base font name list */
+    _PAD4(2),          /* unused */
+    _FRAME(EOL),
+};
+
+xim_externaldef XimFrameRec input_styles_fr[] =
+{
+    _FRAME(BIT16),             /* number of list */
+    _PAD4(1),                  /* unused */
+    _FRAME(ITER),              /* XIMStyle list */
+    _FRAME(POINTER),
+    _PTR(inputstyle_fr),
+    _FRAME(EOL),
+};
+
+xim_externaldef XimFrameRec packet_header_fr[] =
+{
+    _FRAME(BIT8),              /* major-opcode */
+    _FRAME(BIT8),              /* minor-opcode */
+    _FRAME(BIT16),             /* length */
+    _FRAME(EOL),
+};
+
+xim_externaldef XimFrameRec error_fr[] =
+{
+    _FRAME(BIT16),             /* input-method-ID */
+    _FRAME(BIT16),             /* input-context-ID */
+    _FRAME(BIT16),             /* flag */
+    _FRAME(BIT16),             /* Error Code */
+    _FRAME(BIT16),             /* length of error detail */
+    _FRAME(BIT16),             /* type of error detail */
+    _FRAME(BARRAY),            /* error detail */
+    _PAD4(1),
+    _FRAME(EOL),
+};
+
+xim_externaldef XimFrameRec connect_fr[] =
+{
+    _FRAME(BIT8),              /* byte order */
+    _PAD2(1),                  /* unused */
+    _FRAME(BIT16),             /* client-major-protocol-version */
+    _FRAME(BIT16),             /* client-minor-protocol-version */
+    _BYTE_COUNTER(BIT16, 1),   /* length of client-auth-protocol-names */
+    _FRAME(ITER),              /* client-auth-protocol-names */
+    _FRAME(POINTER),
+    _PTR(xpcs_fr),
+    _FRAME(EOL),
+};
+
+xim_externaldef XimFrameRec connect_reply_fr[] =
+{
+    _FRAME(BIT16),             /* server-major-protocol-version */
+    _FRAME(BIT16),             /* server-minor-protocol-version */
+    _FRAME(EOL),
+};
+
+xim_externaldef XimFrameRec auth_required_fr[] =
+{
+    _FRAME(BIT8),              /* auth-protocol-index */
+    _FRAME(BIT8),              /* auth-data1 */
+    _FRAME(BARRAY),            /* auth-data2 */
+    _PAD4(3),
+    _FRAME(EOL),
+};
+
+
+xim_externaldef XimFrameRec auth_reply_fr[] =
+{
+    _FRAME(BIT8),
+    _FRAME(BARRAY),
+    _PAD4(2),
+    _FRAME(EOL),
+};
+
+xim_externaldef XimFrameRec auth_next_fr[] =
+{
+    _FRAME(BIT8),              /* auth-data1 */
+    _FRAME(BARRAY),            /* auth-data2 */
+    _PAD4(2),
+    _FRAME(EOL),
+};
+
+xim_externaldef XimFrameRec auth_setup_fr[] =
+{
+    _BYTE_COUNTER(BIT16, 2),   /* number of client-auth-protocol-names */
+    _PAD4(1),                  /* unused */
+    _FRAME(ITER),              /* server-auth-protocol-names */
+    _FRAME(POINTER),
+    _PTR(xpcs_fr),
+    _FRAME(EOL),
+};
+
+xim_externaldef XimFrameRec auth_ng_fr[] =
+{
+    _FRAME(EOL),
+};
+
+xim_externaldef XimFrameRec disconnect_fr[] =
+{
+    _FRAME(EOL),
+};
+
+xim_externaldef XimFrameRec disconnect_reply_fr[] =
+{
+    _FRAME(EOL),
+};
+
+xim_externaldef XimFrameRec open_fr[] =
+{
+    _FRAME(POINTER),           /* locale name */
+    _PTR(str_fr),
+    _PAD4(1),
+    _FRAME(EOL),
+};
+
+xim_externaldef XimFrameRec open_reply_fr[] =
+{
+    _FRAME(BIT16),             /* input-method-ID */
+    _BYTE_COUNTER(BIT16, 1),   /* byte length of IM attributes supported */
+    _FRAME(ITER),              /* IM attribute supported */
+    _FRAME(POINTER),
+    _PTR(ximattr_fr),
+    _BYTE_COUNTER(BIT16, 2),   /* number of IC attribute supported */
+    _PAD4(1),                  /* unused */
+    _FRAME(ITER),              /* IC attribute supported */
+    _FRAME(POINTER),
+    _PTR(xicattr_fr),
+    _FRAME(EOL),
+};
+
+xim_externaldef XimFrameRec close_fr[] =
+{
+    _FRAME(BIT16),             /* input-method-ID */
+    _PAD4(1),                  /* unused */
+    _FRAME(EOL),
+};
+
+xim_externaldef XimFrameRec close_reply_fr[] =
+{
+    _FRAME(BIT16),             /* input-method-ID */
+    _PAD4(1),                  /* unused */
+    _FRAME(EOL),
+};
+
+xim_externaldef XimFrameRec register_triggerkeys_fr[] =
+{
+    _FRAME(BIT16),             /* input-method-ID */
+    _PAD4(1),                  /* unused */
+    _BYTE_COUNTER(BIT32, 1),    /* byte length of on-keys */
+    _FRAME(ITER),              /* on-keys list */
+    _FRAME(POINTER),
+    _PTR(ximtriggerkey_fr),
+    _BYTE_COUNTER(BIT32, 1),   /* byte length of off-keys */
+    _FRAME(ITER),              /* off-keys list */
+    _FRAME(POINTER),
+    _PTR(ximtriggerkey_fr),
+    _FRAME(EOL),
+};
+
+xim_externaldef XimFrameRec trigger_notify_fr[] =
+{
+    _FRAME(BIT16),             /* input-mehotd-ID */
+    _FRAME(BIT16),             /* input-context-ID */
+    _FRAME(BIT32),             /* flag */
+    _FRAME(BIT32),             /* index of keys list */
+    _FRAME(BIT32),             /* client-select-event-mask */
+    _FRAME(EOL),
+};
+
+xim_externaldef XimFrameRec trigger_notify_reply_fr[] =
+{
+    _FRAME(BIT16),             /* input-method-ID */
+    _FRAME(BIT16),             /* input-context-ID */
+    _FRAME(EOL),
+};
+
+xim_externaldef XimFrameRec set_event_mask_fr[] =
+{
+    _FRAME(BIT16),             /* input-method-ID */
+    _FRAME(BIT16),             /* input-context-ID */
+    _FRAME(BIT32),             /* forward-event-mask */
+    _FRAME(BIT32),             /* synchronous-event-mask */
+    _FRAME(EOL),
+};
+
+xim_externaldef XimFrameRec encoding_negotiation_fr[] =
+{
+    _FRAME(BIT16),             /* input-method-ID */
+    _BYTE_COUNTER(BIT16, 1),   /* byte length of encodings listed by name */
+    _FRAME(ITER),              /* supported list of encoding in IM library */
+    _FRAME(POINTER),
+    _PTR(str_fr),
+    _PAD4(1),
+    _BYTE_COUNTER(BIT16, 2),   /* byte length of encodings listed by
+                                       detailed data */
+    _PAD4(1),
+    _FRAME(ITER),              /* list of encodings supported in the
+                                  IM library */
+    _FRAME(POINTER),
+    _PTR(encodinginfo_fr),
+    _FRAME(EOL),
+};
+
+xim_externaldef XimFrameRec encoding_negotiation_reply_fr[] =
+{
+    _FRAME(BIT16),             /* input-method-ID */
+    _FRAME(BIT16),             /* category of the encoding determined */
+    _FRAME(BIT16),             /* index of the encoding dterminated */
+    _PAD4(1),
+    _FRAME(EOL),
+};
+
+xim_externaldef XimFrameRec query_extension_fr[] =
+{
+    _FRAME(BIT16),             /* input-method-ID */
+    _BYTE_COUNTER(BIT16, 1),   /* byte length of extensions supported
+                                  by the IM library */
+    _FRAME(ITER),              /* extensions supported by the IM library */
+    _FRAME(POINTER),
+    _PTR(str_fr),
+    _PAD4(1),
+    _FRAME(EOL),
+};
+
+xim_externaldef XimFrameRec query_extension_reply_fr[] =
+{
+    _FRAME(BIT16),             /* input-method-ID */
+    _BYTE_COUNTER(BIT16, 1),   /* byte length of extensions supported
+                                  by the IM server */
+    _FRAME(ITER),              /* list of extensions supported by the
+                                  IM server */
+    _FRAME(POINTER),
+    _PTR(ext_fr),
+    _FRAME(EOL),
+};
+
+xim_externaldef XimFrameRec get_im_values_fr[] =
+{
+    _FRAME(BIT16),             /* input-method-ID */
+    _BYTE_COUNTER(BIT16, 1),   /* byte length of im-attribute-id */
+    _FRAME(ITER),              /* im-attribute-id */
+    _FRAME(BIT16),
+    _PAD4(1),
+    _FRAME(EOL),
+};
+
+xim_externaldef XimFrameRec get_im_values_reply_fr[] =
+{
+    _FRAME(BIT16),             /* input-method-ID */
+    _BYTE_COUNTER(BIT16, 1),   /* byte length of im-attribute returned */
+    _FRAME(ITER),              /* im-attribute returned */
+    _FRAME(POINTER),
+    _PTR(ximattribute_fr),
+    _FRAME(EOL),
+};
+
+xim_externaldef XimFrameRec create_ic_fr[] =
+{
+    _FRAME(BIT16),             /* input-method-ID */
+    _BYTE_COUNTER(BIT16, 1),   /* byte length of ic-attributes */
+    _FRAME(ITER),              /* ic-attributes */
+    _FRAME(POINTER),
+    _PTR(xicattribute_fr),
+    _FRAME(EOL),
+};
+
+xim_externaldef XimFrameRec create_ic_reply_fr[] =
+{
+    _FRAME(BIT16),             /* input-method-ID */
+    _FRAME(BIT16),             /* input-context-ID */
+    _FRAME(EOL),
+};
+
+xim_externaldef XimFrameRec destroy_ic_fr[] =
+{
+    _FRAME(BIT16),             /* input-method-ID */
+    _FRAME(BIT16),             /* input-context-ID */
+    _FRAME(EOL),
+};
+
+xim_externaldef XimFrameRec destroy_ic_reply_fr[] =
+{
+    _FRAME(BIT16),             /* input-method-ID */
+    _FRAME(BIT16),             /* input-context-ID */
+    _FRAME(EOL),
+};
+
+xim_externaldef XimFrameRec set_ic_values_fr[] =
+{
+    _FRAME(BIT16),             /* input-method-ID */
+    _FRAME(BIT16),             /* input-context-ID */
+    _BYTE_COUNTER(BIT16, 2),   /* byte length of ic-attributes */
+    _PAD4(1),
+    _FRAME(ITER),              /* ic-attribute */
+    _FRAME(POINTER),
+    _PTR(xicattribute_fr),
+    _FRAME(EOL),
+};
+
+xim_externaldef XimFrameRec set_ic_values_reply_fr[] =
+{
+    _FRAME(BIT16),             /* input-method-ID */
+    _FRAME(BIT16),             /* input-context-ID */
+    _FRAME(EOL),
+};
+
+xim_externaldef XimFrameRec get_ic_values_fr[] =
+{
+    _FRAME(BIT16),             /* input-method-ID */
+    _FRAME(BIT16),             /* input-context-ID */
+    _BYTE_COUNTER(BIT16, 1),   /* byte length of ic-attribute-id */
+    _FRAME(ITER),              /* ic-attribute */
+    _FRAME(BIT16),
+    _PAD4(2),
+    _FRAME(EOL),
+};
+
+xim_externaldef XimFrameRec get_ic_values_reply_fr[] =
+{
+    _FRAME(BIT16),             /* input-method-ID */
+    _FRAME(BIT16),             /* input-context-ID */
+    _BYTE_COUNTER(BIT16, 2),   /* byte length of ic-attribute */
+    _PAD4(1),
+    _FRAME(ITER),              /* ic-attribute */
+    _FRAME(POINTER),
+    _PTR(xicattribute_fr),
+    _FRAME(EOL),
+};
+
+xim_externaldef XimFrameRec set_ic_focus_fr[] =
+{
+    _FRAME(BIT16),             /* input-method-ID */
+    _FRAME(BIT16),             /* input-context-ID */
+    _FRAME(EOL),
+};
+
+xim_externaldef XimFrameRec unset_ic_focus_fr[] =
+{
+    _FRAME(BIT16),             /* input-method-ID */
+    _FRAME(BIT16),             /* input-context-ID */
+    _FRAME(EOL),
+};
+
+xim_externaldef XimFrameRec forward_event_fr[] =
+{
+    _FRAME(BIT16),             /* input-method-ID */
+    _FRAME(BIT16),             /* input-context-ID */
+    _FRAME(BIT16),             /* flag */
+    _FRAME(BIT16),             /* sequence number */
+    _FRAME(EOL),
+};
+
+xim_externaldef XimFrameRec wire_keyevent_fr[] = {
+    _FRAME(BIT8),              /* type */
+    _FRAME(BIT8),              /* detail */
+    _FRAME(BIT16),             /* serial number */
+    _FRAME(BIT32),             /* time */
+    _FRAME(BIT32),             /* root */
+    _FRAME(BIT32),             /* window */
+    _FRAME(BIT32),             /* subwindow */
+    _FRAME(BIT16),             /* rootX */
+    _FRAME(BIT16),             /* rootY */
+    _FRAME(BIT16),             /* X */
+    _FRAME(BIT16),             /* Y */
+    _FRAME(BIT16),             /* state */
+    _FRAME(BIT8),              /* sameScreen */
+    _FRAME(EOL),
+};
+
+xim_externaldef XimFrameRec sync_fr[] =
+{
+    _FRAME(BIT16),             /* input-method-ID */
+    _FRAME(BIT16),             /* input-context-ID */
+    _FRAME(EOL),
+};
+
+xim_externaldef XimFrameRec sync_reply_fr[] =
+{
+    _FRAME(BIT16),             /* input-method-ID */
+    _FRAME(BIT16),             /* input-context-ID */
+    _FRAME(EOL),
+};
+
+#if 0
+xim_externaldef XimFrameRec commit_fr[] =
+{
+    _FRAME(BIT16),             /* input-method-ID */
+    _FRAME(BIT16),             /* input-context-ID */
+    _FRAME(BIT16),             /* flag */
+    _FRAME(BIT16),             /* byte length of committed string */
+    _FRAME(BARRAY),            /* committed string */
+    _PAD4(1),
+    _BYTE_COUNTER(BIT16, 1),   /* byte length of keysym */
+    _FRAME(ITER),              /* keysym */
+    _FRAME(BIT32),
+    _PAD4(1),
+    _FRAME(EOL),
+};
+#endif
+
+xim_externaldef XimFrameRec commit_chars_fr[] =
+{
+    _FRAME(BIT16),             /* input-method-ID */
+    _FRAME(BIT16),             /* input-context-ID */
+    _FRAME(BIT16),             /* flag */
+    _FRAME(BIT16),             /* byte length of committed string */
+    _FRAME(BARRAY),            /* committed string */
+    _PAD4(1),
+    _FRAME(EOL),
+};
+
+xim_externaldef XimFrameRec commit_both_fr[] =
+{
+    _FRAME(BIT16),             /* input-method-ID */
+    _FRAME(BIT16),             /* input-context-ID */
+    _FRAME(BIT16),             /* flag */
+    _PAD4(1),                  /* unused */
+    _FRAME(BIT32),             /* keysym */
+    _FRAME(BIT16),             /* byte length of committed string */
+    _FRAME(BARRAY),            /* committed string */
+    _PAD4(2),
+    _FRAME(EOL),
+};
+
+xim_externaldef XimFrameRec reset_ic_fr[] =
+{
+    _FRAME(BIT16),             /* input-method-ID */
+    _FRAME(BIT16),             /* input-context-ID */
+    _FRAME(EOL),
+};
+
+xim_externaldef XimFrameRec reset_ic_reply_fr[] =
+{
+    _FRAME(BIT16),             /* input-method-ID */
+    _FRAME(BIT16),             /* input-context-ID */
+    _FRAME(BIT16),             /* byte length of committed string */
+    _FRAME(BARRAY),            /* committed string */
+    _PAD4(2),
+    _FRAME(EOL),
+};
+
+xim_externaldef XimFrameRec geometry_fr[] =
+{
+    _FRAME(BIT16),             /* input-method-ID */
+    _FRAME(BIT16),             /* input-context-ID */
+    _FRAME(EOL),
+};
+
+xim_externaldef XimFrameRec str_conversion_fr[] =
+{
+    _FRAME(BIT16),             /* input-method-ID */
+    _FRAME(BIT16),             /* input-context-ID */
+    _FRAME(BIT32),             /* XIMStringConversionPosition */
+    _FRAME(BIT32),             /* XIMStringConversionType */
+    _FRAME(BIT32),             /* XIMStringConversionOperation */
+    _FRAME(BIT16),             /* length to multiply the
+                                  XIMStringConversionType */
+    _FRAME(BIT16),             /* length of the string to be
+                                  substituted */
+#if 0
+    _FRAME(BARRAY),            /* string */
+    _PAD4(1),
+#endif
+    _FRAME(EOL),
+};
+
+xim_externaldef XimFrameRec str_conversion_reply_fr[] =
+{
+    _FRAME(BIT16),             /* input-method-ID */
+    _FRAME(BIT16),             /* input-context-ID */
+    _FRAME(BIT32),             /* XIMStringConversionFeedback */
+    _FRAME(BIT16),             /* length of the retrieved string */
+    _FRAME(BARRAY),            /* retrieved string */
+    _PAD4(2),
+    _BYTE_COUNTER(BIT16, 2),   /* number of feedback array */
+    _PAD4(1),
+    _FRAME(ITER),              /* feedback array */
+    _FRAME(BIT32),
+    _FRAME(EOL),
+};
+
+xim_externaldef XimFrameRec preedit_start_fr[] =
+{
+    _FRAME(BIT16),             /* input-method-ID */
+    _FRAME(BIT16),             /* input-context-ID */
+    _FRAME(EOL),
+};
+
+xim_externaldef XimFrameRec preedit_start_reply_fr[] =
+{
+    _FRAME(BIT16),             /* input-method-ID */
+    _FRAME(BIT16),             /* input-context-ID */
+    _FRAME(BIT32),             /* return value */
+    _FRAME(EOL),
+};
+
+xim_externaldef XimFrameRec preedit_draw_fr[] =
+{
+    _FRAME(BIT16),             /* input-method-ID */
+    _FRAME(BIT16),             /* input-context-ID */
+    _FRAME(BIT32),             /* caret */
+    _FRAME(BIT32),             /* chg_first */
+    _FRAME(BIT32),             /* chg_length */
+    _FRAME(BIT32),             /* status */
+    _FRAME(BIT16),             /* length of preedit string */
+    _FRAME(BARRAY),            /* preedit string */
+    _PAD4(2),
+    _BYTE_COUNTER(BIT16, 2),   /* number of feedback array */
+    _PAD4(1),
+    _FRAME(ITER),              /* feedback array */
+    _FRAME(BIT32),
+    _FRAME(EOL),
+};
+
+xim_externaldef XimFrameRec preedit_caret_fr[] =
+{
+    _FRAME(BIT16),             /* input-method-ID */
+    _FRAME(BIT16),             /* input-context-ID */
+    _FRAME(BIT32),             /* position */
+    _FRAME(BIT32),             /* direction */
+    _FRAME(BIT32),             /* style */
+    _FRAME(EOL),
+};
+
+xim_externaldef XimFrameRec preedit_caret_reply_fr[] =
+{
+    _FRAME(BIT16),             /* input-method-ID */
+    _FRAME(BIT16),             /* input-context-ID */
+    _FRAME(BIT32),             /* position */
+    _FRAME(EOL),
+};
+
+xim_externaldef XimFrameRec preedit_done_fr[] =
+{
+    _FRAME(BIT16),             /* input-method-ID */
+    _FRAME(BIT16),             /* input-context-ID */
+    _FRAME(EOL),
+};
+
+xim_externaldef XimFrameRec status_start_fr[] =
+{
+    _FRAME(BIT16),             /* input-method-ID */
+    _FRAME(BIT16),             /* input-context-ID */
+    _FRAME(EOL),
+};
+
+xim_externaldef XimFrameRec status_draw_text_fr[] =
+{
+    _FRAME(BIT16),             /* input-method-ID */
+    _FRAME(BIT16),             /* input-context-ID */
+    _FRAME(BIT32),             /* type */
+    _FRAME(BIT32),             /* status */
+    _FRAME(BIT16),             /* length of status string */
+    _FRAME(BARRAY),            /* status string */
+    _PAD4(2),
+    _BYTE_COUNTER(BIT16, 2),   /* number of feedback array */
+    _PAD4(1),
+    _FRAME(ITER),              /* feedback array */
+    _FRAME(BIT32),
+    _FRAME(EOL),
+};
+
+xim_externaldef XimFrameRec status_draw_bitmap_fr[] =
+{
+    _FRAME(BIT16),             /* input-method-ID */
+    _FRAME(BIT16),             /* input-context-ID */
+    _FRAME(BIT32),             /* type */
+    _FRAME(BIT32),             /* pixmap data */
+    _FRAME(EOL),
+};
+
+xim_externaldef XimFrameRec status_done_fr[] =
+{
+    _FRAME(BIT16),             /* input-method-ID */
+    _FRAME(BIT16),             /* input-context-ID */
+    _FRAME(EOL),
+};
+
+xim_externaldef XimFrameRec ext_set_event_mask_fr[] =
+{
+    _FRAME(BIT16),             /* input-method-ID */
+    _FRAME(BIT16),             /* input-context-ID */
+    _FRAME(BIT32),             /* filter-event-mask */
+    _FRAME(BIT32),             /* intercept-event-mask */
+    _FRAME(BIT32),             /* select-event-mask */
+    _FRAME(BIT32),             /* forward-event-mask */
+    _FRAME(BIT32),             /* synchronous-event-mask */
+    _FRAME(EOL),
+};
+
+xim_externaldef XimFrameRec ext_forward_keyevent_fr[] =
+{
+    _FRAME(BIT16),             /* input-method-ID */
+    _FRAME(BIT16),             /* input-context-ID */
+    _FRAME(BIT16),             /* flag */
+    _FRAME(BIT16),             /* sequence number */
+    _FRAME(BIT8),              /* xEvent.u.u.type */
+    _FRAME(BIT8),              /* keycode */
+    _FRAME(BIT16),             /* state */
+    _FRAME(BIT32),             /* time */
+    _FRAME(BIT32),             /* window */
+    _FRAME(EOL),
+};
+
+xim_externaldef XimFrameRec ext_move_fr[] =
+{
+    _FRAME(BIT16),             /* input-method-ID */
+    _FRAME(BIT16),             /* input-context-ID */
+    _FRAME(BIT16),             /* X */
+    _FRAME(BIT16),             /* Y */
+    _FRAME(EOL),
+};
diff --git a/wrapper/xim/IMdkit/i18nIc.c b/wrapper/xim/IMdkit/i18nIc.c
new file mode 100644 (file)
index 0000000..8af0a57
--- /dev/null
@@ -0,0 +1,1108 @@
+/******************************************************************
+         Copyright 1994, 1995 by Sun Microsystems, Inc.
+         Copyright 1993, 1994 by Hewlett-Packard Company
+Permission to use, copy, modify, distribute, and sell this software
+and its documentation for any purpose is hereby granted without fee,
+provided that the above copyright notice appear in all copies and
+that both that copyright notice and this permission notice appear
+in supporting documentation, and that the name of Sun Microsystems, Inc.
+and Hewlett-Packard not be used in advertising or publicity pertaining to
+distribution of the software without specific, written prior permission.
+Sun Microsystems, Inc. and Hewlett-Packard make no representations about
+the suitability of this software for any purpose.  It is provided "as is"
+without express or implied warranty.
+SUN MICROSYSTEMS INC. AND HEWLETT-PACKARD COMPANY DISCLAIMS ALL
+WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
+SUN MICROSYSTEMS, INC. AND HEWLETT-PACKARD COMPANY BE LIABLE FOR ANY
+SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
+RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
+CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
+IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+  Author: Hidetoshi Tajima(tajima@Eng.Sun.COM) Sun Microsystems, Inc.
+
+    This version tidied and debugged by Steve Underwood May 1999
+******************************************************************/
+
+#include <X11/Xlib.h>
+#include "IMdkit.h"
+#include "Xi18n.h"
+#include "FrameMgr.h"
+#include "XimFunc.h"
+
+#define IC_SIZE 64
+
+/* Set IC values */
+static void SetCardAttribute (XICAttribute *value_ret,
+                              char *p,
+                              XICAttr *ic_attr,
+                              int value_length,
+                              int need_swap,
+                              void **value_buf)
+{
+    FrameMgr fm;
+
+    /*endif*/
+    if (value_length == sizeof (CARD8))
+    {
+        memmove (*value_buf, p, value_length);
+    }
+    else if (value_length == sizeof (CARD16))
+    {
+        INT16 value;
+        extern XimFrameRec short_fr[];
+
+        fm = FrameMgrInit (short_fr, (char *) p, need_swap);
+        /* get data */
+        FrameMgrGetToken (fm, value);
+        FrameMgrFree (fm);
+        memmove (*value_buf, &value, value_length);
+    }
+    else if (value_length == sizeof(CARD32))
+    {
+        INT32 value;
+        extern XimFrameRec long_fr[];
+        
+        fm = FrameMgrInit (long_fr, (char *) p, need_swap);
+        /* get data */
+        FrameMgrGetToken (fm, value);
+        FrameMgrFree (fm);
+        memmove (*value_buf, &value, value_length);
+    }
+    /*endif*/
+    value_ret->attribute_id = ic_attr->attribute_id;
+    value_ret->name = ic_attr->name;
+    value_ret->name_length = ic_attr->length;
+    value_ret->type = ic_attr->type;
+    value_ret->value_length = value_length;
+    value_ret->value = *value_buf;
+    *value_buf += value_length;
+}
+
+static void SetFontAttribute (XICAttribute *value_ret,
+                              char *p,
+                              XICAttr *ic_attr,
+                              int value_length,
+                              int need_swap,
+                              void **value_buf)
+{
+    char *base_name;
+    CARD16 base_length;
+    FrameMgr fm;
+    extern XimFrameRec fontset_fr[];
+
+    fm = FrameMgrInit (fontset_fr, (char *) p, need_swap);
+    /* get data */
+    FrameMgrGetToken (fm, base_length);
+    FrameMgrSetSize (fm, base_length);
+
+    /*endif*/
+    FrameMgrGetToken (fm, base_name);
+    FrameMgrFree(fm);
+    strncpy ((char *) (*value_buf), base_name, base_length);
+    ((char *) *value_buf)[base_length] = (char) 0;
+
+    value_ret->attribute_id = ic_attr->attribute_id;
+    value_ret->name = ic_attr->name;
+    value_ret->name_length = ic_attr->length;
+    value_ret->type = ic_attr->type;
+    value_ret->value_length = value_length;
+    value_ret->value = *value_buf;
+
+    *value_buf += (base_length + 1);
+}
+
+static void SetPointAttribute (XICAttribute *value_ret,
+                               char *p,
+                               XICAttr *ic_attr,
+                               int value_length,
+                               int need_swap,
+                               void **value_buf)
+{
+    XPoint *buf;
+    FrameMgr fm;
+    extern XimFrameRec xpoint_fr[];
+
+    buf = (XPoint *) (*value_buf);
+
+    fm = FrameMgrInit (xpoint_fr, (char *) p, need_swap);
+    /* get data */
+    FrameMgrGetToken (fm, buf->x);
+    FrameMgrGetToken (fm, buf->y);
+    FrameMgrFree (fm);
+
+    value_ret->attribute_id = ic_attr->attribute_id;
+    value_ret->name = ic_attr->name;
+    value_ret->name_length = ic_attr->length;
+    value_ret->type = ic_attr->type;
+    value_ret->value_length = value_length;
+    value_ret->value = (char *) buf;
+
+    *value_buf += value_length;
+}
+
+static void SetRectAttribute (XICAttribute *value_ret,
+                              char *p,
+                              XICAttr *ic_attr,
+                              int value_length,
+                              int need_swap,
+                              void **value_buf)
+{
+    XRectangle *buf;
+    FrameMgr fm;
+    extern XimFrameRec xrectangle_fr[];
+
+    buf = (XRectangle *) (*value_buf);
+    fm = FrameMgrInit (xrectangle_fr, (char *) p, need_swap);
+    /* get data */
+    FrameMgrGetToken (fm, buf->x);
+    FrameMgrGetToken (fm, buf->y);
+    FrameMgrGetToken (fm, buf->width);
+    FrameMgrGetToken (fm, buf->height);
+    FrameMgrFree (fm);
+
+    value_ret->attribute_id = ic_attr->attribute_id;
+    value_ret->name = ic_attr->name;
+    value_ret->name_length = ic_attr->length;
+    value_ret->type = ic_attr->type;
+    value_ret->value_length = value_length;
+    value_ret->value = (char *) buf;
+
+    *value_buf += value_length;
+}
+
+#if 0
+static void SetHotKeyAttribute (XICAttribute *value_ret,
+                                char *p,
+                                XICAttr *ic_attr,
+                                int value_length,
+                                int need_swap,
+                                void **value_buf)
+{
+    INT32 list_number;
+    XIMTriggerKey *hotkeys;
+
+    memmove (&list_number, p, sizeof(INT32)); p += sizeof(INT32);
+
+    hotkeys = (XIMTriggerKey *) (*value_buf);
+
+    memmove (hotkeys, p, list_number*sizeof (XIMTriggerKey));
+
+    value_ret->attribute_id = ic_attr->attribute_id;
+    value_ret->name = ic_attr->name;
+    value_ret->name_length = ic_attr->length;
+    value_ret->type = ic_attr->type;
+    value_ret->value_length = value_length;
+    value_ret->value = (char *) hotkeys;
+
+    *value_buf += value_length;
+}
+#endif
+
+/* get IC values */
+static void GetAttrHeader (unsigned char *rec,
+                           XICAttribute *list,
+                           int need_swap)
+{
+    FrameMgr fm;
+    extern XimFrameRec attr_head_fr[];
+
+    fm = FrameMgrInit (attr_head_fr, (char *) rec, need_swap);
+    /* put data */
+    FrameMgrPutToken (fm, list->attribute_id);
+    FrameMgrPutToken (fm, list->value_length);
+    FrameMgrFree (fm);
+}
+
+static void GetCardAttribute (char *rec, XICAttribute *list, int need_swap)
+{
+    FrameMgr fm;
+    unsigned char *recp = (unsigned char *) rec;
+
+    GetAttrHeader (recp, list, need_swap);
+    recp += sizeof (CARD16)*2;
+
+    if (list->value_length == sizeof (CARD8))
+    {
+        memmove (recp, list->value, list->value_length);
+    }
+    else if (list->value_length == sizeof (CARD16))
+    {
+        INT16 *value = (INT16 *) list->value;
+        extern XimFrameRec short_fr[];
+
+        fm = FrameMgrInit (short_fr, (char *) recp, need_swap);
+        /* put data */
+        FrameMgrPutToken (fm, *value);
+        FrameMgrFree (fm);
+    }
+    else if (list->value_length == sizeof (CARD32))
+    {
+        INT32 *value = (INT32 *) list->value;
+        extern XimFrameRec long_fr[];
+
+        fm = FrameMgrInit (long_fr, (char *) recp, need_swap);
+        /* put data */
+        FrameMgrPutToken (fm, *value);
+        FrameMgrFree (fm);
+    }
+    /*endif*/
+}
+
+static void GetFontAttribute(char *rec, XICAttribute *list, int need_swap)
+{
+    FrameMgr fm;
+    extern XimFrameRec fontset_fr[];
+    char *base_name = (char *) list->value;
+    unsigned char *recp = (unsigned char *) rec;
+
+    GetAttrHeader (recp, list, need_swap);
+    recp += sizeof (CARD16)*2;
+
+    fm = FrameMgrInit (fontset_fr, (char *)recp, need_swap);
+    /* put data */
+    FrameMgrSetSize (fm, list->value_length);
+    FrameMgrPutToken (fm, list->value_length);
+    FrameMgrPutToken (fm, base_name);
+    FrameMgrFree (fm);
+}
+
+static void GetRectAttribute (char *rec, XICAttribute *list, int need_swap)
+{
+    FrameMgr fm;
+    extern XimFrameRec xrectangle_fr[];
+    XRectangle *rect = (XRectangle *) list->value;
+    unsigned char *recp = (unsigned char *) rec;
+
+    GetAttrHeader (recp, list, need_swap);
+    recp += sizeof(CARD16)*2;
+
+    if (rect) {
+        fm = FrameMgrInit (xrectangle_fr, (char *) recp, need_swap);
+        /* put data */
+        FrameMgrPutToken (fm, rect->x);
+        FrameMgrPutToken (fm, rect->y);
+        FrameMgrPutToken (fm, rect->width);
+        FrameMgrPutToken (fm, rect->height);
+        FrameMgrFree (fm);
+    }
+}
+
+static void GetPointAttribute (char *rec, XICAttribute *list, int need_swap)
+{
+    FrameMgr fm;
+    extern XimFrameRec xpoint_fr[];
+    XPoint *rect = (XPoint *) list->value;
+    unsigned char *recp = (unsigned char *) rec;
+
+    GetAttrHeader (recp, list, need_swap);
+    recp += sizeof(CARD16)*2;
+
+    fm = FrameMgrInit (xpoint_fr, (char *) recp, need_swap);
+    /* put data */
+    FrameMgrPutToken (fm, rect->x);
+    FrameMgrPutToken (fm, rect->y);
+    FrameMgrFree (fm);
+}
+
+static int ReadICValue (Xi18n i18n_core,
+                        CARD16 icvalue_id,
+                        int value_length,
+                        void *p,
+                        XICAttribute *value_ret,
+                        CARD16 *number_ret,
+                        int need_swap,
+                        void **value_buf)
+{
+    XICAttr *ic_attr = i18n_core->address.xic_attr;
+    int i;
+
+    *number_ret = (CARD16) 0;
+
+    for (i = 0;  i < i18n_core->address.ic_attr_num;  i++, ic_attr++)
+    {
+        if (ic_attr->attribute_id == icvalue_id)
+            break;
+        /*endif*/
+    }
+    /*endfor*/
+    switch (ic_attr->type)
+    {
+    case XimType_NEST:
+        {
+            int total_length = 0;
+            CARD16 attribute_ID;
+            INT16 attribute_length;
+            unsigned char *p1 = (unsigned char *) p;
+            CARD16 ic_len = 0;
+            CARD16 number;
+            FrameMgr fm;
+            extern XimFrameRec attr_head_fr[];
+
+            while (total_length < value_length)
+            {
+                fm = FrameMgrInit (attr_head_fr, (char *) p1, need_swap);
+                /* get data */
+                FrameMgrGetToken (fm, attribute_ID);
+                FrameMgrGetToken (fm, attribute_length);
+                FrameMgrFree (fm);
+                p1 += sizeof (CARD16)*2;
+                ReadICValue (i18n_core,
+                             attribute_ID,
+                             attribute_length,
+                             p1,
+                             (value_ret + ic_len),
+                             &number,
+                             need_swap,
+                             value_buf);
+                ic_len++;
+                *number_ret += number;
+                p1 += attribute_length;
+                p1 += IMPAD (attribute_length);
+                total_length += (CARD16) sizeof(CARD16)*2
+                                + (INT16) attribute_length
+                                + IMPAD (attribute_length);
+            }
+           /*endwhile*/
+            return ic_len;
+        }
+
+    case XimType_CARD8:
+    case XimType_CARD16:
+    case XimType_CARD32:
+    case XimType_Window:
+        SetCardAttribute (value_ret, p, ic_attr, value_length, need_swap, value_buf);
+        *number_ret = (CARD16) 1;
+        return *number_ret;
+
+    case XimType_XFontSet:
+        SetFontAttribute (value_ret, p, ic_attr, value_length, need_swap, value_buf);
+        *number_ret = (CARD16) 1;
+        return *number_ret;
+
+    case XimType_XRectangle:
+        SetRectAttribute (value_ret, p, ic_attr, value_length, need_swap, value_buf);
+        *number_ret = (CARD16) 1;
+        return *number_ret;
+
+    case XimType_XPoint:
+        SetPointAttribute(value_ret, p, ic_attr, value_length, need_swap, value_buf);
+        *number_ret = (CARD16) 1;
+        return *number_ret;
+
+#if 0
+    case XimType_XIMHotKeyTriggers:
+        SetHotKeyAttribute (value_ret, p, ic_attr, value_length, need_swap, value_buf);
+       *number_ret = (CARD16) 1;
+       return *number_ret;
+#endif
+    }
+    /*endswitch*/
+    return 0;
+}
+
+static XICAttribute *CreateNestedList (CARD16 attr_id,
+                                       XICAttribute *list,
+                                       int number,
+                                       int need_swap)
+{
+    XICAttribute *nest_list = NULL;
+    register int i;
+    char *values = NULL;
+    char *valuesp;
+    int value_length = 0;
+
+    if (number == 0)
+        return NULL;
+    /*endif*/
+    for (i = 0;  i < number;  i++)
+    {
+        value_length += sizeof (CARD16)*2;
+        value_length += list[i].value_length;
+        value_length += IMPAD (list[i].value_length);
+    }
+    /*endfor*/
+    if ((values = (char *) malloc (value_length)) == NULL)
+        return NULL;
+    /*endif*/
+    memset (values, 0, value_length);
+
+    valuesp = values;
+    for (i = 0;  i < number;  i++)
+    {
+        switch (list[i].type)
+        {
+        case XimType_CARD8:
+        case XimType_CARD16:
+        case XimType_CARD32:
+        case XimType_Window:
+            GetCardAttribute (valuesp, &list[i], need_swap);
+            break;
+
+        case XimType_XFontSet:
+            GetFontAttribute (valuesp, &list[i], need_swap);
+            break;
+
+        case XimType_XRectangle:
+            GetRectAttribute (valuesp, &list[i], need_swap);
+            break;
+
+        case XimType_XPoint:
+            GetPointAttribute (valuesp, &list[i], need_swap);
+            break;
+
+#if 0
+        case XimType_XIMHotKeyTriggers:
+            GetHotKeyAttribute (valuesp, &list[i], need_swap);
+            break;
+#endif
+        }
+        /*endswitch*/
+        valuesp += sizeof (CARD16)*2;
+        valuesp += list[i].value_length;
+        valuesp += IMPAD(list[i].value_length);
+    }
+    /*endfor*/
+    
+    nest_list = (XICAttribute *) malloc (sizeof (XICAttribute));
+    if (nest_list == NULL)
+        return NULL;
+    /*endif*/
+    memset (nest_list, 0, sizeof (XICAttribute));
+    nest_list->value = (void *) malloc (value_length);
+    if (nest_list->value == NULL)
+        return NULL;
+    /*endif*/
+    memset (nest_list->value, 0, sizeof (value_length));
+
+    nest_list->attribute_id = attr_id;
+    nest_list->value_length = value_length;
+    memmove (nest_list->value, values, value_length);
+
+    XFree (values);
+    return nest_list;
+}
+
+static Bool IsNestedList (Xi18n i18n_core, CARD16 icvalue_id)
+{
+    XICAttr *ic_attr = i18n_core->address.xic_attr;
+    int i;
+
+    for (i = 0;  i < i18n_core->address.ic_attr_num;  i++, ic_attr++)
+    {
+        if (ic_attr->attribute_id == icvalue_id)
+        {
+            if (ic_attr->type == XimType_NEST)
+                return True;
+            /*endif*/
+            return False;
+        }
+        /*endif*/
+    }
+    /*endfor*/
+    return False;
+}
+
+static Bool IsSeparator (Xi18n i18n_core, CARD16 icvalue_id)
+{
+    return (i18n_core->address.separatorAttr_id == icvalue_id);
+}
+
+static int GetICValue (Xi18n i18n_core,
+                       XICAttribute *attr_ret,
+                       CARD16 *id_list,
+                       int list_num)
+{
+    XICAttr *xic_attr = i18n_core->address.xic_attr;
+    register int i;
+    register int j;
+    register int n;
+
+    i =
+    n = 0;
+    if (IsNestedList (i18n_core, id_list[i]))
+    {
+        i++;
+        while (i < list_num  &&  !IsSeparator (i18n_core, id_list[i]))
+        {
+            for (j = 0;  j < i18n_core->address.ic_attr_num;  j++)
+            {
+                if (xic_attr[j].attribute_id == id_list[i])
+                {
+                    attr_ret[n].attribute_id = xic_attr[j].attribute_id;
+                    attr_ret[n].name_length = xic_attr[j].length;
+                    attr_ret[n].name = malloc (xic_attr[j].length + 1);
+                   strcpy(attr_ret[n].name, xic_attr[j].name);
+                    attr_ret[n].type = xic_attr[j].type;
+                    n++;
+                    i++;
+                    break;
+                }
+                /*endif*/
+            }
+            /*endfor*/
+        }
+        /*endwhile*/
+    }
+    else
+    {
+        for (j = 0;  j < i18n_core->address.ic_attr_num;  j++)
+        {
+            if (xic_attr[j].attribute_id == id_list[i])
+            {
+                attr_ret[n].attribute_id = xic_attr[j].attribute_id;
+                attr_ret[n].name_length = xic_attr[j].length;
+                attr_ret[n].name = malloc (xic_attr[j].length + 1);
+               strcpy(attr_ret[n].name, xic_attr[j].name);
+                attr_ret[n].type = xic_attr[j].type;
+                n++;
+                break;
+            }
+            /*endif*/
+        }
+        /*endfor*/
+    }
+    /*endif*/
+    return n;
+}
+
+static void SwapAttributes (XICAttribute *list,
+                          int number){
+    FrameMgr fm;
+    CARD16 c16;
+    extern XimFrameRec short_fr[];
+    CARD32 c32;
+    extern XimFrameRec long_fr[];
+    XPoint xpoint;
+    extern XimFrameRec xpoint_fr[];
+    XRectangle xrect;
+    extern XimFrameRec xrectangle_fr[];
+    int i;
+
+    for (i = 0; i < number; ++i, ++list) {
+       if (list->value == NULL)
+           continue;
+       switch (list->type) {
+       case XimType_CARD16:
+           fm = FrameMgrInit (short_fr, (char *)list->value, 1);
+           FrameMgrGetToken (fm, c16);
+           memmove(list->value, &c16, sizeof(CARD16));
+           FrameMgrFree (fm);
+           break;
+       case XimType_CARD32:
+       case XimType_Window:
+           fm = FrameMgrInit (long_fr, (char *)list->value, 1);
+           FrameMgrGetToken (fm, c32);
+           memmove(list->value, &c32, sizeof(CARD32));
+           FrameMgrFree (fm);
+           break;
+       case XimType_XRectangle:
+           fm = FrameMgrInit (xrectangle_fr, (char *)list->value, 1);
+           FrameMgrGetToken (fm, xrect);
+           memmove(list->value, &xrect, sizeof(XRectangle));
+           FrameMgrFree (fm);
+           break;
+       case XimType_XPoint:
+           fm = FrameMgrInit (xpoint_fr, (char *)list->value, 1);
+           FrameMgrGetToken (fm, xpoint);
+           memmove(list->value, &xpoint, sizeof(XPoint));
+           FrameMgrFree (fm);
+           break;
+       default:
+           break;
+       }
+    }
+}
+
+/* called from CreateICMessageProc and SetICValueMessageProc */
+void _Xi18nChangeIC (XIMS ims,
+                     IMProtocol *call_data,
+                     unsigned char *p,
+                     int create_flag)
+{
+    Xi18n i18n_core = ims->protocol;
+    FrameMgr fm;
+    FmStatus status;
+    CARD16 byte_length;
+    register int total_size;
+    unsigned char *reply = NULL;
+    register int i;
+    register int attrib_num;
+    XICAttribute *attrib_list;
+    XICAttribute pre_attr[IC_SIZE];
+    XICAttribute sts_attr[IC_SIZE];
+    XICAttribute ic_attr[IC_SIZE];
+    CARD16 preedit_ic_num = 0;
+    CARD16 status_ic_num = 0;
+    CARD16 ic_num = 0;
+    CARD16 connect_id = call_data->any.connect_id;
+    IMChangeICStruct *changeic = (IMChangeICStruct *) &call_data->changeic;
+    extern XimFrameRec create_ic_fr[];
+    extern XimFrameRec create_ic_reply_fr[];
+    extern XimFrameRec set_ic_values_fr[];
+    extern XimFrameRec set_ic_values_reply_fr[];
+    CARD16 input_method_ID;
+    void *value_buf = NULL;
+    void *value_buf_ptr;
+
+    register int total_value_length = 0;
+
+    memset (pre_attr, 0, sizeof (XICAttribute)*IC_SIZE);
+    memset (sts_attr, 0, sizeof (XICAttribute)*IC_SIZE);
+    memset (ic_attr, 0, sizeof (XICAttribute)*IC_SIZE);
+
+    if (create_flag == True)
+    {
+        fm = FrameMgrInit (create_ic_fr,
+                           (char *) p,
+                           _Xi18nNeedSwap (i18n_core, connect_id));
+        /* get data */
+        FrameMgrGetToken (fm, input_method_ID);
+        FrameMgrGetToken (fm, byte_length);
+    }
+    else
+    {
+        fm = FrameMgrInit (set_ic_values_fr,
+                           (char *) p,
+                           _Xi18nNeedSwap (i18n_core, connect_id));
+        /* get data */
+        FrameMgrGetToken (fm, input_method_ID);
+        FrameMgrGetToken (fm, changeic->icid);
+        FrameMgrGetToken (fm, byte_length);
+    }
+    /*endif*/
+    attrib_list = (XICAttribute *) malloc (sizeof (XICAttribute)*IC_SIZE);
+    if (!attrib_list)
+    {
+        _Xi18nSendMessage (ims, connect_id, XIM_ERROR, 0, 0, 0);
+        return;
+    }
+    /*endif*/
+    memset (attrib_list, 0, sizeof(XICAttribute)*IC_SIZE);
+
+    attrib_num = 0;
+    while (FrameMgrIsIterLoopEnd (fm, &status) == False)
+    {
+        void *value;
+        int value_length;
+        
+        FrameMgrGetToken (fm, attrib_list[attrib_num].attribute_id);
+        FrameMgrGetToken (fm, value_length);
+        FrameMgrSetSize (fm, value_length);
+        attrib_list[attrib_num].value_length = value_length;
+        FrameMgrGetToken (fm, value);
+        attrib_list[attrib_num].value = (void *) malloc (value_length + 1);
+        memmove (attrib_list[attrib_num].value, value, value_length);
+       ((char *)attrib_list[attrib_num].value)[value_length] = '\0';
+        attrib_num++;
+        total_value_length += (value_length + 1);
+    }
+    /*endwhile*/
+
+    value_buf = (void *) malloc (total_value_length);
+    value_buf_ptr = value_buf;
+
+    if (!value_buf)
+    {
+        _Xi18nSendMessage (ims, connect_id, XIM_ERROR, 0, 0, 0);
+        for (i = 0;  i < attrib_num;  i++)
+            XFree (attrib_list[i].value);
+        /*endfor*/
+        XFree (attrib_list);
+        return;
+    }
+    /*endif*/
+
+    for (i = 0;  i < attrib_num;  i++)
+    {
+        CARD16 number;
+        
+        if (IsNestedList (i18n_core, attrib_list[i].attribute_id))
+        {
+            if (attrib_list[i].attribute_id
+                == i18n_core->address.preeditAttr_id)
+            {
+                ReadICValue (i18n_core,
+                             attrib_list[i].attribute_id,
+                             attrib_list[i].value_length,
+                             attrib_list[i].value,
+                             &pre_attr[preedit_ic_num],
+                             &number,
+                             _Xi18nNeedSwap(i18n_core, connect_id),
+                             &value_buf_ptr);
+                preedit_ic_num += number;
+            }
+            else if (attrib_list[i].attribute_id == i18n_core->address.statusAttr_id)
+            {
+                ReadICValue (i18n_core,
+                             attrib_list[i].attribute_id,
+                             attrib_list[i].value_length,
+                             attrib_list[i].value,
+                             &sts_attr[status_ic_num],
+                             &number,
+                             _Xi18nNeedSwap (i18n_core, connect_id),
+                             &value_buf_ptr);
+                status_ic_num += number;
+            }
+            else
+            {
+                /* another nested list.. possible? */
+            }
+            /*endif*/
+        }
+        else
+        {
+            ReadICValue (i18n_core,
+                         attrib_list[i].attribute_id,
+                         attrib_list[i].value_length,
+                         attrib_list[i].value,
+                         &ic_attr[ic_num],
+                         &number,
+                         _Xi18nNeedSwap (i18n_core, connect_id),
+                         &value_buf_ptr);
+            ic_num += number;
+        }
+        /*endif*/
+    }
+    /*endfor*/
+    for (i = 0;  i < attrib_num;  i++)
+        XFree (attrib_list[i].value);
+    /*endfor*/
+    XFree (attrib_list);
+
+    FrameMgrFree (fm);
+
+    changeic->preedit_attr_num = preedit_ic_num;
+    changeic->status_attr_num = status_ic_num;
+    changeic->ic_attr_num = ic_num;
+    changeic->preedit_attr = pre_attr;
+    changeic->status_attr = sts_attr;
+    changeic->ic_attr = ic_attr;
+
+    if (i18n_core->address.improto)
+    {
+        if (!(i18n_core->address.improto(ims, call_data))) {
+            XFree (value_buf);
+            return;
+        }
+        /*endif*/
+    }
+
+    XFree (value_buf);
+
+    /*endif*/
+    if (create_flag == True)
+    {
+        fm = FrameMgrInit (create_ic_reply_fr,
+                           NULL,
+                           _Xi18nNeedSwap (i18n_core, connect_id));
+    }
+    else
+    {
+        fm = FrameMgrInit (set_ic_values_reply_fr,
+                           NULL,
+                           _Xi18nNeedSwap (i18n_core, connect_id));
+    }
+    /*endif*/
+    total_size = FrameMgrGetTotalSize (fm);
+    reply = (unsigned char *) malloc (total_size);
+    
+    if (!reply)
+    {
+        _Xi18nSendMessage (ims, connect_id, XIM_ERROR, 0, 0, 0);
+        return;
+    }
+    /*endif*/
+    memset (reply, 0, total_size);
+    FrameMgrSetBuffer (fm, reply);
+
+    FrameMgrPutToken (fm, input_method_ID);
+    FrameMgrPutToken (fm, changeic->icid);
+
+    if (create_flag == True)
+    {
+        _Xi18nSendMessage (ims,
+                           connect_id,
+                           XIM_CREATE_IC_REPLY,
+                           0,
+                           reply,
+                           total_size);
+    }
+    else
+    {
+        _Xi18nSendMessage (ims,
+                           connect_id,
+                           XIM_SET_IC_VALUES_REPLY,
+                           0,
+                           reply,
+                           total_size);
+    }
+    /*endif*/
+    if (create_flag == True)
+    {
+        int on_key_num = i18n_core->address.on_keys.count_keys;
+        int off_key_num = i18n_core->address.off_keys.count_keys;
+
+        if (on_key_num == 0  &&  off_key_num == 0)
+        {
+            long mask;
+
+            if (i18n_core->address.imvalue_mask & I18N_FILTERMASK)
+                mask = i18n_core->address.filterevent_mask;
+            else
+                mask = DEFAULT_FILTER_MASK;
+            /*endif*/
+            /* static event flow is default */
+            _Xi18nSetEventMask (ims,
+                                connect_id,
+                                input_method_ID,
+                                changeic->icid,
+                                mask,
+                                ~mask);
+        }
+        /*endif*/
+    }
+    /*endif*/
+    FrameMgrFree (fm);
+    XFree(reply);
+}
+
+/* called from GetICValueMessageProc */
+void _Xi18nGetIC (XIMS ims, IMProtocol *call_data, unsigned char *p)
+{
+    Xi18n i18n_core = ims->protocol;
+    FrameMgr fm;
+    FmStatus status;
+    extern XimFrameRec get_ic_values_fr[];
+    extern XimFrameRec get_ic_values_reply_fr[];
+    CARD16 byte_length;
+    register int total_size;
+    unsigned char *reply = NULL;
+    XICAttribute *preedit_ret = NULL;
+    XICAttribute *status_ret = NULL;
+    register int i;
+    register int number;
+    int iter_count;
+    CARD16 *attrID_list;
+    XICAttribute pre_attr[IC_SIZE];
+    XICAttribute sts_attr[IC_SIZE];
+    XICAttribute ic_attr[IC_SIZE];
+    CARD16 pre_count = 0;
+    CARD16 sts_count = 0;
+    CARD16 ic_count = 0;
+    IMChangeICStruct *getic = (IMChangeICStruct *) &call_data->changeic;
+    CARD16 connect_id = call_data->any.connect_id;
+    CARD16 input_method_ID;
+
+    memset (pre_attr, 0, sizeof (XICAttribute)*IC_SIZE);
+    memset (sts_attr, 0, sizeof (XICAttribute)*IC_SIZE);
+    memset (ic_attr, 0, sizeof (XICAttribute)*IC_SIZE);
+
+    fm = FrameMgrInit (get_ic_values_fr,
+                       (char *) p,
+                       _Xi18nNeedSwap (i18n_core, connect_id));
+
+    /* get data */
+    FrameMgrGetToken (fm, input_method_ID);
+    FrameMgrGetToken (fm, getic->icid);
+    FrameMgrGetToken (fm, byte_length);
+
+    attrID_list = (CARD16 *) malloc (sizeof (CARD16)*IC_SIZE);  /* bogus */
+    memset (attrID_list, 0, sizeof (CARD16)*IC_SIZE);
+
+    number = 0;
+    while (FrameMgrIsIterLoopEnd (fm, &status) == False)
+        FrameMgrGetToken (fm, attrID_list[number++]);
+    /*endwhile*/
+    FrameMgrFree (fm);
+
+    i = 0;
+    while (i < number)
+    {
+        int read_number;
+        
+        if (IsNestedList (i18n_core, attrID_list[i]))
+        {
+            if (attrID_list[i] == i18n_core->address.preeditAttr_id)
+            {
+                read_number = GetICValue (i18n_core,
+                                          &pre_attr[pre_count],
+                                          &attrID_list[i],
+                                          number);
+                i += read_number + 1;
+                pre_count += read_number;
+            }
+            else if (attrID_list[i] == i18n_core->address.statusAttr_id)
+            {
+                read_number = GetICValue (i18n_core,
+                                          &sts_attr[sts_count],
+                                          &attrID_list[i],
+                                          number);
+                i += read_number + 1;
+                sts_count += read_number;
+            }
+            else
+            {
+                /* another nested list.. possible? */
+            }
+            /*endif*/
+        }
+        else
+        {
+            read_number = GetICValue (i18n_core,
+                                      &ic_attr[ic_count],
+                                      &attrID_list[i],
+                                      number);
+            i += read_number;
+            ic_count += read_number;
+        }
+        /*endif*/
+    }
+    /*endwhile*/
+    getic->preedit_attr_num = pre_count;
+    getic->status_attr_num = sts_count;
+    getic->ic_attr_num = ic_count;
+    getic->preedit_attr = pre_attr;
+    getic->status_attr = sts_attr;
+    getic->ic_attr = ic_attr;
+    if (i18n_core->address.improto)
+    {
+        if (!(i18n_core->address.improto (ims, call_data)))
+            return;
+        /*endif*/
+       if (_Xi18nNeedSwap (i18n_core, connect_id))
+         SwapAttributes(getic->ic_attr, getic->ic_attr_num);
+    }
+    /*endif*/
+    iter_count = getic->ic_attr_num;
+
+    preedit_ret = CreateNestedList (i18n_core->address.preeditAttr_id,
+                                    getic->preedit_attr,
+                                    getic->preedit_attr_num,
+                                    _Xi18nNeedSwap (i18n_core, connect_id));
+    if (preedit_ret)
+        iter_count++;
+    /*endif*/
+    status_ret = CreateNestedList (i18n_core->address.statusAttr_id,
+                                   getic->status_attr,
+                                   getic->status_attr_num,
+                                   _Xi18nNeedSwap (i18n_core, connect_id));
+    if (status_ret)
+        iter_count++;
+    /*endif*/
+
+    fm = FrameMgrInit (get_ic_values_reply_fr,
+                       NULL,
+                       _Xi18nNeedSwap (i18n_core, connect_id));
+
+    /* set iteration count for list of ic_attribute */
+    FrameMgrSetIterCount (fm, iter_count);
+
+    /* set length of BARRAY item in xicattribute_fr */
+    for (i = 0;  i < (int) getic->ic_attr_num;  i++)
+        FrameMgrSetSize (fm, ic_attr[i].value_length);
+    /*endfor*/
+    
+    if (preedit_ret)
+        FrameMgrSetSize (fm, preedit_ret->value_length);
+    /*endif*/
+    if (status_ret)
+        FrameMgrSetSize (fm, status_ret->value_length);
+    /*endif*/
+    total_size = FrameMgrGetTotalSize (fm);
+    reply = (unsigned char *) malloc (total_size);
+    if (reply == NULL)
+    {
+        _Xi18nSendMessage (ims, connect_id, XIM_ERROR, 0, 0, 0);
+        return;
+    }
+    /*endif*/
+    memset (reply, 0, total_size);
+    FrameMgrSetBuffer (fm, reply);
+
+    FrameMgrPutToken (fm, input_method_ID);
+    FrameMgrPutToken (fm, getic->icid);
+
+    for (i = 0;  i < (int) getic->ic_attr_num;  i++)
+    {
+        FrameMgrPutToken (fm, ic_attr[i].attribute_id);
+        FrameMgrPutToken (fm, ic_attr[i].value_length);
+        FrameMgrPutToken (fm, ic_attr[i].value);
+    }
+    /*endfor*/
+    if (preedit_ret)
+    {
+        FrameMgrPutToken (fm, preedit_ret->attribute_id);
+        FrameMgrPutToken (fm, preedit_ret->value_length);
+        FrameMgrPutToken (fm, preedit_ret->value);
+    }
+    /*endif*/
+    if (status_ret)
+    {
+        FrameMgrPutToken (fm, status_ret->attribute_id);
+        FrameMgrPutToken (fm, status_ret->value_length);
+        FrameMgrPutToken (fm, status_ret->value);
+    }
+    /*endif*/
+    _Xi18nSendMessage (ims,
+                       connect_id,
+                       XIM_GET_IC_VALUES_REPLY,
+                       0,
+                       reply,
+                       total_size);
+    XFree (reply);
+    XFree (attrID_list);
+
+    for (i = 0;  i < (int) getic->ic_attr_num;  i++)
+    {
+       if (getic->ic_attr[i].name)
+           XFree (getic->ic_attr[i].name);
+       /*endif*/
+        if (getic->ic_attr[i].value)
+            XFree (getic->ic_attr[i].value);
+        /*endif*/
+    }
+    /*endfor*/
+    for (i = 0;  i < (int) getic->preedit_attr_num;  i++)
+    {
+       if (getic->preedit_attr[i].name)
+           XFree (getic->preedit_attr[i].name);
+       /*endif*/
+       if (getic->preedit_attr[i].value)
+           XFree (getic->preedit_attr[i].value);
+       /*endif*/
+    }
+    /*endfor*/
+    for (i = 0;  i < (int) getic->status_attr_num;  i++)
+    {
+       if (getic->status_attr[i].name)
+           XFree (getic->status_attr[i].name);
+       /*endif*/
+       if (getic->status_attr[i].value)
+           XFree (getic->status_attr[i].value);
+       /*endif*/
+    }
+    /*endfor*/
+    
+    if (preedit_ret)
+    {
+        XFree (preedit_ret->value);
+        XFree (preedit_ret);
+    }
+    /*endif*/
+    if (status_ret)
+    {
+        XFree (status_ret->value);
+        XFree (status_ret);
+    }
+    /*endif*/
+    FrameMgrFree (fm);
+}
diff --git a/wrapper/xim/IMdkit/i18nMethod.c b/wrapper/xim/IMdkit/i18nMethod.c
new file mode 100644 (file)
index 0000000..84a9d18
--- /dev/null
@@ -0,0 +1,1151 @@
+/******************************************************************
+
+         Copyright 1994, 1995 by Sun Microsystems, Inc.
+         Copyright 1993, 1994 by Hewlett-Packard Company
+
+Permission to use, copy, modify, distribute, and sell this software
+and its documentation for any purpose is hereby granted without fee,
+provided that the above copyright notice appear in all copies and
+that both that copyright notice and this permission notice appear
+in supporting documentation, and that the name of Sun Microsystems, Inc.
+and Hewlett-Packard not be used in advertising or publicity pertaining to
+distribution of the software without specific, written prior permission.
+Sun Microsystems, Inc. and Hewlett-Packard make no representations about
+the suitability of this software for any purpose.  It is provided "as is"
+without express or implied warranty.
+
+SUN MICROSYSTEMS INC. AND HEWLETT-PACKARD COMPANY DISCLAIMS ALL
+WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
+SUN MICROSYSTEMS, INC. AND HEWLETT-PACKARD COMPANY BE LIABLE FOR ANY
+SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
+RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
+CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
+IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+  Author: Hidetoshi Tajima(tajima@Eng.Sun.COM) Sun Microsystems, Inc.
+
+    This version tidied and debugged by Steve Underwood May 1999
+
+******************************************************************/
+
+#include <X11/Xlib.h>
+#include <X11/Xatom.h>
+#ifndef NEED_EVENTS
+#define NEED_EVENTS
+#endif
+#include <X11/Xproto.h>
+#undef NEED_EVENTS
+#include "FrameMgr.h"
+#include "IMdkit.h"
+#include "Xi18n.h"
+#include "XimFunc.h"
+
+extern Xi18nClient *_Xi18nFindClient (Xi18n, CARD16);
+
+static void *xi18n_setup (Display *, XIMArg *);
+static Status xi18n_openIM (XIMS);
+static Status xi18n_closeIM (XIMS);
+static char *xi18n_setIMValues (XIMS, XIMArg *);
+static char *xi18n_getIMValues (XIMS, XIMArg *);
+static Status xi18n_forwardEvent (XIMS, XPointer);
+static Status xi18n_commit (XIMS, XPointer);
+static int xi18n_callCallback (XIMS, XPointer);
+static int xi18n_preeditStart (XIMS, XPointer);
+static int xi18n_preeditEnd (XIMS, XPointer);
+static int xi18n_syncXlib (XIMS, XPointer);
+
+#ifndef XIM_SERVERS
+#define XIM_SERVERS "XIM_SERVERS"
+#endif
+static Atom XIM_Servers = None;
+
+
+IMMethodsRec Xi18n_im_methods =
+{
+    xi18n_setup,
+    xi18n_openIM,
+    xi18n_closeIM,
+    xi18n_setIMValues,
+    xi18n_getIMValues,
+    xi18n_forwardEvent,
+    xi18n_commit,
+    xi18n_callCallback,
+    xi18n_preeditStart,
+    xi18n_preeditEnd,
+    xi18n_syncXlib,
+};
+
+extern Bool _Xi18nCheckXAddress (Xi18n, TransportSW *, char *);
+extern Bool _Xi18nCheckTransAddress (Xi18n, TransportSW *, char *);
+
+TransportSW _TransR[] =
+{
+    {"X",               1, _Xi18nCheckXAddress},
+#ifdef TCPCONN
+    {"tcp",             3, _Xi18nCheckTransAddress},
+    {"local",           5, _Xi18nCheckTransAddress},
+#endif
+#ifdef DNETCONN
+    {"decnet",          6, _Xi18nCheckTransAddress},
+#endif
+    {(char *) NULL,     0, (Bool (*) ()) NULL}
+};
+
+static Bool GetInputStyles (Xi18n i18n_core, XIMStyles **p_style)
+{
+    Xi18nAddressRec *address = (Xi18nAddressRec *) &i18n_core->address;
+    XIMStyles *p;
+    int        i;
+
+    p = &address->input_styles;
+    if ((*p_style = (XIMStyles *) malloc (sizeof (XIMStyles)
+                                          + p->count_styles*sizeof (XIMStyle)))
+        == NULL)
+    {
+        return False;
+    }
+    /*endif*/
+    (*p_style)->count_styles = p->count_styles;
+    (*p_style)->supported_styles = (XIMStyle *) ((XPointer) *p_style + sizeof (XIMStyles));
+    for (i = 0;  i < (int) p->count_styles;  i++)
+        (*p_style)->supported_styles[i] = p->supported_styles[i];
+    /*endfor*/
+    return True;
+}
+
+static Bool GetOnOffKeys (Xi18n i18n_core, long mask, XIMTriggerKeys **p_key)
+{
+    Xi18nAddressRec *address = (Xi18nAddressRec *) &i18n_core->address;
+    XIMTriggerKeys *p;
+    int        i;
+
+    if (mask & I18N_ON_KEYS)
+        p = &address->on_keys;
+    else
+        p = &address->off_keys;
+    /*endif*/
+    if ((*p_key = (XIMTriggerKeys *) malloc (sizeof(XIMTriggerKeys)
+                                             + p->count_keys*sizeof(XIMTriggerKey)))
+        == NULL)
+    {
+        return False;
+    }
+    /*endif*/
+    (*p_key)->count_keys = p->count_keys;
+    (*p_key)->keylist =
+        (XIMTriggerKey *) ((XPointer) *p_key + sizeof(XIMTriggerKeys));
+    for (i = 0;  i < (int) p->count_keys;  i++)
+    {
+        (*p_key)->keylist[i].keysym = p->keylist[i].keysym;
+        (*p_key)->keylist[i].modifier = p->keylist[i].modifier;
+        (*p_key)->keylist[i].modifier_mask = p->keylist[i].modifier_mask;
+    }
+    /*endfor*/
+    return True;
+}
+
+static Bool GetEncodings(Xi18n i18n_core, XIMEncodings **p_encoding)
+{
+    Xi18nAddressRec *address = (Xi18nAddressRec *) &i18n_core->address;
+    XIMEncodings *p;
+    int        i;
+
+    p = &address->encoding_list;
+
+    if ((*p_encoding = (XIMEncodings *) malloc (sizeof (XIMEncodings)
+                                              + p->count_encodings*sizeof(XIMEncoding))) == NULL)
+    {
+        return False;
+    }
+    /*endif*/
+    (*p_encoding)->count_encodings = p->count_encodings;
+    (*p_encoding)->supported_encodings =
+        (XIMEncoding *) ((XPointer)*p_encoding + sizeof (XIMEncodings));
+    for (i = 0;  i < (int) p->count_encodings;  i++)
+    {
+        (*p_encoding)->supported_encodings[i]
+            = (char *) malloc (strlen (p->supported_encodings[i]) + 1);
+        strcpy ((*p_encoding)->supported_encodings[i],
+                p->supported_encodings[i]);
+    }
+    /*endif*/
+    return True;
+}
+
+static char *ParseArgs (Xi18n i18n_core, int mode, XIMArg *args)
+{
+    Xi18nAddressRec *address = (Xi18nAddressRec *) &i18n_core->address;
+    XIMArg *p;
+
+    if (mode == I18N_OPEN  ||  mode == I18N_SET)
+    {
+        for (p = args;  p->name != NULL;  p++)
+        {
+            if (strcmp (p->name, IMLocale) == 0)
+            {
+                if (address->imvalue_mask & I18N_IM_LOCALE)
+                    return IMLocale;
+                /*endif*/
+                address->im_locale = (char *) malloc (strlen (p->value) + 1);
+                if (!address->im_locale)
+                    return IMLocale;
+                /*endif*/
+                strcpy (address->im_locale, p->value);
+                address->imvalue_mask |= I18N_IM_LOCALE;
+            }
+            else if (strcmp (p->name, IMServerTransport) == 0)
+            {
+                if (address->imvalue_mask & I18N_IM_ADDRESS)
+                    return IMServerTransport;
+                /*endif*/
+                address->im_addr = (char *) malloc (strlen (p->value) + 1);
+                if (!address->im_addr)
+                    return IMServerTransport;
+                /*endif*/
+                strcpy(address->im_addr, p->value);
+                address->imvalue_mask |= I18N_IM_ADDRESS;
+            }
+            else if (strcmp (p->name, IMServerName) == 0)
+            {
+                if (address->imvalue_mask & I18N_IM_NAME)
+                    return IMServerName;
+                /*endif*/
+                address->im_name = (char *) malloc (strlen (p->value) + 1);
+                if (!address->im_name)
+                    return IMServerName;
+                /*endif*/
+                strcpy (address->im_name, p->value);
+                address->imvalue_mask |= I18N_IM_NAME;
+            }
+            else if (strcmp (p->name, IMServerWindow) == 0)
+            {
+                if (address->imvalue_mask & I18N_IMSERVER_WIN)
+                    return IMServerWindow;
+                /*endif*/
+                address->im_window = (Window) p->value;
+                address->imvalue_mask |= I18N_IMSERVER_WIN;
+            }
+            else if (strcmp (p->name, IMInputStyles) == 0)
+            {
+                if (address->imvalue_mask & I18N_INPUT_STYLES)
+                    return IMInputStyles;
+                /*endif*/
+                address->input_styles.count_styles =
+                    ((XIMStyles*)p->value)->count_styles;
+                address->input_styles.supported_styles =
+                    (XIMStyle *) malloc (sizeof (XIMStyle)*address->input_styles.count_styles);
+                if (address->input_styles.supported_styles == (XIMStyle *) NULL)
+                    return IMInputStyles;
+                /*endif*/
+                memmove (address->input_styles.supported_styles,
+                         ((XIMStyles *) p->value)->supported_styles,
+                         sizeof (XIMStyle)*address->input_styles.count_styles);
+                address->imvalue_mask |= I18N_INPUT_STYLES;
+            }
+            else if (strcmp (p->name, IMProtocolHandler) == 0)
+            {
+                address->improto = (IMProtoHandler) p->value;
+                address->imvalue_mask |= I18N_IM_HANDLER;
+            }
+            else if (strcmp (p->name, IMOnKeysList) == 0)
+            {
+                if (address->imvalue_mask & I18N_ON_KEYS)
+                    return IMOnKeysList;
+                /*endif*/
+                address->on_keys.count_keys =
+                    ((XIMTriggerKeys *) p->value)->count_keys;
+                address->on_keys.keylist =
+                    (XIMTriggerKey *) malloc (sizeof (XIMTriggerKey)*address->on_keys.count_keys);
+                if (address->on_keys.keylist == (XIMTriggerKey *) NULL)
+                    return IMOnKeysList;
+                /*endif*/
+                memmove (address->on_keys.keylist,
+                         ((XIMTriggerKeys *) p->value)->keylist,
+                         sizeof (XIMTriggerKey)*address->on_keys.count_keys);
+                address->imvalue_mask |= I18N_ON_KEYS;
+            }
+            else if (strcmp (p->name, IMOffKeysList) == 0)
+            {
+                if (address->imvalue_mask & I18N_OFF_KEYS)
+                    return IMOffKeysList;
+                /*endif*/
+                address->off_keys.count_keys =
+                    ((XIMTriggerKeys *) p->value)->count_keys;
+                address->off_keys.keylist =
+                    (XIMTriggerKey *) malloc (sizeof (XIMTriggerKey)*address->off_keys.count_keys);
+                if (address->off_keys.keylist == (XIMTriggerKey *) NULL)
+                    return IMOffKeysList;
+                /*endif*/
+                memmove (address->off_keys.keylist,
+                         ((XIMTriggerKeys *) p->value)->keylist,
+                         sizeof (XIMTriggerKey)*address->off_keys.count_keys);
+                address->imvalue_mask |= I18N_OFF_KEYS;
+            }
+            else if (strcmp (p->name, IMEncodingList) == 0)
+            {
+                if (address->imvalue_mask & I18N_ENCODINGS)
+                    return IMEncodingList;
+                /*endif*/
+                address->encoding_list.count_encodings =
+                    ((XIMEncodings *) p->value)->count_encodings;
+                address->encoding_list.supported_encodings =
+                    (XIMEncoding *) malloc (sizeof (XIMEncoding)*address->encoding_list.count_encodings);
+                if (address->encoding_list.supported_encodings
+                    == (XIMEncoding *) NULL)
+                {
+                    return IMEncodingList;
+                }
+                /*endif*/
+                memmove (address->encoding_list.supported_encodings,
+                         ((XIMEncodings *) p->value)->supported_encodings,
+                         sizeof (XIMEncoding)*address->encoding_list.count_encodings);
+                address->imvalue_mask |= I18N_ENCODINGS;
+            }
+            else if (strcmp (p->name, IMFilterEventMask) == 0)
+            {
+                if (address->imvalue_mask & I18N_FILTERMASK)
+                    return IMFilterEventMask;
+                /*endif*/
+                address->filterevent_mask = (long) p->value;
+                address->imvalue_mask |= I18N_FILTERMASK;
+            }
+            /*endif*/
+        }
+        /*endfor*/
+        if (mode == I18N_OPEN)
+        {
+            /* check mandatory IM values */
+            if (!(address->imvalue_mask & I18N_IM_LOCALE))
+            {
+                /* locales must be set in IMOpenIM */
+                return IMLocale;
+            }
+            /*endif*/
+            if (!(address->imvalue_mask & I18N_IM_ADDRESS))
+            {
+                /* address must be set in IMOpenIM */
+                return IMServerTransport;
+            }
+            /*endif*/
+        }
+        /*endif*/
+    }
+    else if (mode == I18N_GET)
+    {
+        for (p = args;  p->name != NULL;  p++)
+        {
+            if (strcmp (p->name, IMLocale) == 0)
+            {
+                p->value = (char *) malloc (strlen (address->im_locale) + 1);
+                if (!p->value)
+                    return IMLocale;
+                /*endif*/
+                strcpy (p->value, address->im_locale);
+            }
+            else if (strcmp (p->name, IMServerTransport) == 0)
+            {
+                p->value = (char *) malloc (strlen (address->im_addr) + 1);
+                if (!p->value)
+                    return IMServerTransport;
+                /*endif*/
+                strcpy (p->value, address->im_addr);
+            }
+            else if (strcmp (p->name, IMServerName) == 0)
+            {
+                if (address->imvalue_mask & I18N_IM_NAME)
+                {
+                    p->value = (char *) malloc (strlen (address->im_name) + 1);
+                    if (!p->value)
+                        return IMServerName;
+                    /*endif*/
+                    strcpy (p->value, address->im_name);
+                }
+                else
+                {
+                    return IMServerName;
+                }
+                /*endif*/
+            }
+            else if (strcmp (p->name, IMServerWindow) == 0)
+            {
+                if (address->imvalue_mask & I18N_IMSERVER_WIN)
+                    *((Window *) (p->value)) = address->im_window;
+                else
+                    return IMServerWindow;
+                /*endif*/
+            }
+            else if (strcmp (p->name, IMInputStyles) == 0)
+            {
+                if (GetInputStyles (i18n_core,
+                                    (XIMStyles **) p->value) == False)
+                {
+                    return IMInputStyles;
+                }
+                /*endif*/
+            }
+            else if (strcmp (p->name, IMProtocolHandler) == 0)
+            {
+                if (address->imvalue_mask & I18N_IM_HANDLER)
+                    *((IMProtoHandler *) (p->value)) = address->improto;
+                else
+                    return IMProtocolHandler;
+                /*endif*/
+            }
+            else if (strcmp (p->name, IMOnKeysList) == 0)
+            {
+                if (address->imvalue_mask & I18N_ON_KEYS)
+                {
+                    if (GetOnOffKeys (i18n_core,
+                                      I18N_ON_KEYS,
+                                      (XIMTriggerKeys **) p->value) == False)
+                    {
+                        return IMOnKeysList;
+                    }
+                    /*endif*/
+                }
+                else
+                {
+                    return IMOnKeysList;
+                }
+                /*endif*/
+            }
+            else if (strcmp (p->name, IMOffKeysList) == 0)
+            {
+                if (address->imvalue_mask & I18N_OFF_KEYS)
+                {
+                    if (GetOnOffKeys (i18n_core,
+                                      I18N_OFF_KEYS,
+                                      (XIMTriggerKeys **) p->value) == False)
+                    {
+                        return IMOffKeysList;
+                    }
+                    /*endif*/
+                }
+                else
+                {
+                    return IMOffKeysList;
+                }
+                /*endif*/
+            }
+            else if (strcmp (p->name, IMEncodingList) == 0)
+            {
+                if (address->imvalue_mask & I18N_ENCODINGS)
+                {
+                    if (GetEncodings (i18n_core,
+                                      (XIMEncodings **) p->value) == False)
+                    {
+                        return IMEncodingList;
+                    }
+                    /*endif*/
+                }
+                else
+                {
+                    return IMEncodingList;
+                }
+                /*endif*/
+            }
+            else if (strcmp (p->name, IMFilterEventMask) == 0)
+            {
+                if (address->imvalue_mask & I18N_FILTERMASK)
+                    *((long *) (p->value)) = address->filterevent_mask;
+                else
+                    return IMFilterEventMask;
+                /*endif*/
+            }
+            /*endif*/
+        }
+        /*endfor*/
+    }
+    /*endif*/
+    return NULL;
+}
+
+static int CheckIMName (Xi18n i18n_core)
+{
+    char *address = i18n_core->address.im_addr;
+    int i;
+
+    for (i = 0;  _TransR[i].transportname;  i++)
+    {
+        while (*address == ' '  ||  *address == '\t')
+            address++;
+        /*endwhile*/
+        if (strncmp (address,
+                     _TransR[i].transportname,
+                     _TransR[i].namelen) == 0
+            &&
+            address[_TransR[i].namelen] == '/')
+        {
+            if (_TransR[i].checkAddr (i18n_core,
+                                      &_TransR[i],
+                                      address + _TransR[i].namelen + 1) == True)
+            {
+                return True;
+            }
+            /*endif*/
+            return False;
+        }
+        /*endif*/
+    }
+    /*endfor*/
+    return False;
+}
+
+static int SetXi18nSelectionOwner(Xi18n i18n_core)
+{
+    Display *dpy = i18n_core->address.dpy;
+    Window ims_win = i18n_core->address.im_window;
+    Window root = RootWindow (dpy, DefaultScreen (dpy));
+    Atom realtype;
+    int realformat;
+    unsigned long bytesafter;
+    long *data=NULL;
+    unsigned long length;
+    Atom atom;
+    int i;
+    int found;
+    int forse = False;
+    char buf[256];
+
+    (void)snprintf(buf, 256, "@server=%s", i18n_core->address.im_name);
+    if ((atom = XInternAtom(dpy, buf, False)) == 0)
+        return False;
+    i18n_core->address.selection = atom;
+
+    if (XIM_Servers == None)
+        XIM_Servers = XInternAtom (dpy, XIM_SERVERS, False);
+    /*endif*/
+    XGetWindowProperty (dpy,
+                        root,
+                        XIM_Servers,
+                        0L,
+                        1000000L,
+                        False,
+                        XA_ATOM,
+                        &realtype,
+                        &realformat,
+                        &length,
+                        &bytesafter,
+                        (unsigned char **) (&data));
+    if (realtype != None && (realtype != XA_ATOM || realformat != 32)) {
+        if (data != NULL)
+            XFree ((char *) data);
+        return False;
+    }
+
+    found = False;
+    for (i = 0; i < length; i++) {
+        if (data[i] == atom) {
+            Window owner;
+            found = True;
+            if ((owner = XGetSelectionOwner (dpy, atom)) != ims_win) {
+                if (owner == None  ||  forse == True)
+                    XSetSelectionOwner (dpy, atom, ims_win, CurrentTime);
+                else
+                    return False;
+            }
+            break;
+        }
+    }
+
+    if (found == False) {
+        XSetSelectionOwner (dpy, atom, ims_win, CurrentTime);
+        XChangeProperty (dpy,
+                         root,
+                         XIM_Servers,
+                         XA_ATOM,
+                         32,
+                         PropModePrepend,
+                         (unsigned char *) &atom,
+                         1);
+    }
+    else {
+       /*
+        * We always need to generate the PropertyNotify to the Root Window
+        */
+        XChangeProperty (dpy,
+                         root,
+                         XIM_Servers,
+                         XA_ATOM,
+                         32,
+                         PropModePrepend,
+                         (unsigned char *) data,
+                         0);
+    }
+    if (data != NULL)
+        XFree ((char *) data);
+
+    /* Intern "LOCALES" and "TRANSOPORT" Target Atoms */
+    i18n_core->address.Localename = XInternAtom (dpy, LOCALES, False);
+    i18n_core->address.Transportname = XInternAtom (dpy, TRANSPORT, False);
+    return (XGetSelectionOwner (dpy, atom) == ims_win);
+}
+
+static int DeleteXi18nAtom(Xi18n i18n_core)
+{
+    Display *dpy = i18n_core->address.dpy;
+    Window root = RootWindow (dpy, DefaultScreen (dpy));
+    Atom realtype;
+    int realformat;
+    unsigned long bytesafter;
+    long *data=NULL;
+    unsigned long length;
+    Atom atom;
+    int i, ret;
+    int found;
+    char buf[256];
+
+    (void)snprintf(buf, 256, "@server=%s", i18n_core->address.im_name);
+    if ((atom = XInternAtom(dpy, buf, False)) == 0)
+        return False;
+    i18n_core->address.selection = atom;
+
+    if (XIM_Servers == None)
+        XIM_Servers = XInternAtom (dpy, XIM_SERVERS, False);
+    XGetWindowProperty (dpy,
+                        root,
+                        XIM_Servers,
+                        0L,
+                        1000000L,
+                        False,
+                        XA_ATOM,
+                        &realtype,
+                        &realformat,
+                        &length,
+                        &bytesafter,
+                        (unsigned char **) (&data));
+    if (realtype != XA_ATOM || realformat != 32) {
+        if (data != NULL)
+            XFree ((char *) data);
+        return False;
+    }
+
+    found = False;
+    for (i = 0; i < length; i++) {
+        if (data[i] == atom) {
+            found = True;
+            break;
+        }
+    }
+
+    if (found == True) {
+        for (i=i+1; i<length; i++)
+            data[i-1] = data[i];
+        XChangeProperty (dpy,
+                         root,
+                         XIM_Servers,
+                         XA_ATOM,
+                         32,
+                         PropModeReplace,
+                         (unsigned char *)data,
+                         length-1);
+        ret = True;
+    }
+    else {
+        XChangeProperty (dpy,
+                         root,
+                         XIM_Servers,
+                         XA_ATOM,
+                         32,
+                         PropModePrepend,
+                         (unsigned char *)data,
+                         0);
+        ret = False;
+    }
+    if (data != NULL)
+        XFree ((char *) data);
+    return ret;
+}
+
+
+/* XIM protocol methods */
+static void *xi18n_setup (Display *dpy, XIMArg *args)
+{
+    Xi18n i18n_core;
+    CARD16 endian = 1;
+
+    if ((i18n_core = (Xi18n) malloc (sizeof (Xi18nCore))) == (Xi18n) NULL)
+        return NULL;
+    /*endif*/
+
+    memset (i18n_core, 0, sizeof (Xi18nCore));
+
+    i18n_core->address.dpy = dpy;
+
+    if (ParseArgs (i18n_core, I18N_OPEN, args) != NULL)
+    {
+        XFree (i18n_core);
+        return NULL;
+    }
+    /*endif*/
+    if (*(char *) &endian)
+        i18n_core->address.im_byteOrder = 'l';
+    else
+        i18n_core->address.im_byteOrder = 'B';
+    /*endif*/
+
+    /* install IMAttr and ICAttr list in i18n_core */
+    _Xi18nInitAttrList (i18n_core);
+
+    /* install IMExtension list in i18n_core */
+    _Xi18nInitExtension (i18n_core);
+
+    return i18n_core;
+}
+
+static void ReturnSelectionNotify (Xi18n i18n_core, XSelectionRequestEvent *ev)
+{
+    XEvent event;
+    Display *dpy = i18n_core->address.dpy;
+    char buf[4096];
+
+    event.type = SelectionNotify;
+    event.xselection.requestor = ev->requestor;
+    event.xselection.selection = ev->selection;
+    event.xselection.target = ev->target;
+    event.xselection.time = ev->time;
+    event.xselection.property = ev->property;
+    if (ev->target == i18n_core->address.Localename)
+    {
+        snprintf (buf, 4096, "@locale=%s", i18n_core->address.im_locale);
+    }
+    else if (ev->target == i18n_core->address.Transportname)
+    {
+        snprintf (buf, 4096, "@transport=%s", i18n_core->address.im_addr);
+    }
+    /*endif*/
+    XChangeProperty (dpy,
+                     event.xselection.requestor,
+                     ev->target,
+                     ev->target,
+                     8,
+                     PropModeReplace,
+                     (unsigned char *) buf,
+                     strlen (buf));
+    XSendEvent (dpy, event.xselection.requestor, False, NoEventMask, &event);
+    XFlush (i18n_core->address.dpy);
+}
+
+static Bool WaitXSelectionRequest (Display *dpy,
+                                   Window win,
+                                   XEvent *ev,
+                                   XPointer client_data)
+{
+    XIMS ims = (XIMS) client_data;
+    Xi18n i18n_core = ims->protocol;
+
+    if (((XSelectionRequestEvent *) ev)->selection
+        == i18n_core->address.selection)
+    {
+        ReturnSelectionNotify (i18n_core, (XSelectionRequestEvent *) ev);
+        return True;
+    }
+    /*endif*/
+    return False;
+}
+
+static Status xi18n_openIM(XIMS ims)
+{
+    Xi18n i18n_core = ims->protocol;
+    Display *dpy = i18n_core->address.dpy;
+
+    if (!CheckIMName (i18n_core)
+        ||
+        !SetXi18nSelectionOwner (i18n_core)
+        ||
+        !i18n_core->methods.begin (ims))
+    {
+        XFree (i18n_core->address.im_name);
+        XFree (i18n_core->address.im_locale);
+        XFree (i18n_core->address.im_addr);
+        XFree (i18n_core);
+        return False;
+    }
+    /*endif*/
+
+    _XRegisterFilterByType (dpy,
+                            i18n_core->address.im_window,
+                            SelectionRequest,
+                            SelectionRequest,
+                            WaitXSelectionRequest,
+                            (XPointer)ims);
+    XFlush(dpy);
+    return True;
+}
+
+static Status xi18n_closeIM(XIMS ims)
+{
+    Xi18n i18n_core = ims->protocol;
+    Display *dpy = i18n_core->address.dpy;
+
+    DeleteXi18nAtom(i18n_core);
+    if (!i18n_core->methods.end (ims))
+        return False;
+
+    _XUnregisterFilter (dpy,
+                        i18n_core->address.im_window,
+                        WaitXSelectionRequest,
+                        (XPointer)ims);
+    XFree (i18n_core->address.im_name);
+    XFree (i18n_core->address.im_locale);
+    XFree (i18n_core->address.im_addr);
+    XFree (i18n_core);
+    return True;
+}
+
+static char *xi18n_setIMValues (XIMS ims, XIMArg *args)
+{
+    Xi18n i18n_core = ims->protocol;
+    char *ret;
+
+    if ((ret = ParseArgs (i18n_core, I18N_SET, args)) != NULL)
+        return ret;
+    /*endif*/
+    return NULL;
+}
+
+static char *xi18n_getIMValues (XIMS ims, XIMArg *args)
+{
+    Xi18n i18n_core = ims->protocol;
+    char *ret;
+
+    if ((ret = ParseArgs (i18n_core, I18N_GET, args)) != NULL)
+        return ret;
+    /*endif*/
+    return NULL;
+}
+
+static void EventToWireEvent (XEvent *ev, xEvent *event,
+                             CARD16 *serial, Bool byte_swap)
+{
+    FrameMgr fm;
+    extern XimFrameRec wire_keyevent_fr[];
+    extern XimFrameRec short_fr[];
+    BYTE b;
+    CARD16 c16;
+    CARD32 c32;
+
+    *serial = (CARD16)(ev->xany.serial >> 16);
+    switch (ev->type) {
+      case KeyPress:
+      case KeyRelease:
+       {
+           XKeyEvent *kev = (XKeyEvent*)ev;
+           /* create FrameMgr */
+           fm = FrameMgrInit(wire_keyevent_fr, (char *)(&(event->u)), byte_swap);
+
+           /* set values */
+           b = (BYTE)kev->type;          FrameMgrPutToken(fm, b);
+           b = (BYTE)kev->keycode;       FrameMgrPutToken(fm, b);
+           c16 = (CARD16)(kev->serial & (unsigned long)0xffff);
+                                         FrameMgrPutToken(fm, c16);
+           c32 = (CARD32)kev->time;      FrameMgrPutToken(fm, c32);
+           c32 = (CARD32)kev->root;      FrameMgrPutToken(fm, c32);
+           c32 = (CARD32)kev->window;    FrameMgrPutToken(fm, c32);
+           c32 = (CARD32)kev->subwindow; FrameMgrPutToken(fm, c32);
+           c16 = (CARD16)kev->x_root;    FrameMgrPutToken(fm, c16);
+           c16 = (CARD16)kev->y_root;    FrameMgrPutToken(fm, c16);
+           c16 = (CARD16)kev->x;         FrameMgrPutToken(fm, c16);
+           c16 = (CARD16)kev->y;         FrameMgrPutToken(fm, c16);
+           c16 = (CARD16)kev->state;     FrameMgrPutToken(fm, c16);
+           b = (BYTE)kev->same_screen;   FrameMgrPutToken(fm, b);
+       }
+       break;
+      default:
+         /* create FrameMgr */
+         fm = FrameMgrInit(short_fr, (char *)(&(event->u.u.sequenceNumber)),
+                           byte_swap);
+         c16 = (CARD16)(ev->xany.serial & (unsigned long)0xffff);
+         FrameMgrPutToken(fm, c16);
+         break;
+    }
+    /* free FrameMgr */
+    FrameMgrFree(fm);
+}
+
+static Status xi18n_forwardEvent (XIMS ims, XPointer xp)
+{
+    Xi18n i18n_core = ims->protocol;
+    IMForwardEventStruct *call_data = (IMForwardEventStruct *)xp;
+    FrameMgr fm;
+    extern XimFrameRec forward_event_fr[];
+    register int total_size;
+    unsigned char *reply = NULL;
+    unsigned char *replyp;
+    CARD16 serial;
+    int event_size;
+    Xi18nClient *client;
+
+    client = (Xi18nClient *) _Xi18nFindClient (i18n_core, call_data->connect_id);
+
+    /* create FrameMgr */
+    fm = FrameMgrInit (forward_event_fr,
+                       NULL,
+                       _Xi18nNeedSwap (i18n_core, call_data->connect_id));
+
+    total_size = FrameMgrGetTotalSize (fm);
+    event_size = sizeof (xEvent);
+    reply = (unsigned char *) malloc (total_size + event_size);
+    if (!reply)
+    {
+        _Xi18nSendMessage (ims,
+                           call_data->connect_id,
+                           XIM_ERROR,
+                           0,
+                           0,
+                           0);
+        return False;
+    }
+    /*endif*/
+    memset (reply, 0, total_size + event_size);
+    FrameMgrSetBuffer (fm, reply);
+    replyp = reply;
+
+    call_data->sync_bit = 1;   /* always sync */
+    client->sync = True;
+
+    FrameMgrPutToken (fm, call_data->connect_id);
+    FrameMgrPutToken (fm, call_data->icid);
+    FrameMgrPutToken (fm, call_data->sync_bit);
+
+    replyp += total_size;
+    EventToWireEvent (&(call_data->event),
+                      (xEvent *) replyp,
+                      &serial,
+                      _Xi18nNeedSwap (i18n_core, call_data->connect_id));
+
+    FrameMgrPutToken (fm, serial);
+
+    _Xi18nSendMessage (ims,
+                       call_data->connect_id,
+                       XIM_FORWARD_EVENT,
+                       0,
+                       reply,
+                       total_size + event_size);
+
+    XFree (reply);
+    FrameMgrFree (fm);
+
+    return True;
+}
+
+static Status xi18n_commit (XIMS ims, XPointer xp)
+{
+    Xi18n i18n_core = ims->protocol;
+    IMCommitStruct *call_data = (IMCommitStruct *)xp;
+    FrameMgr fm;
+    extern XimFrameRec commit_chars_fr[];
+    extern XimFrameRec commit_both_fr[];
+    register int total_size;
+    unsigned char *reply = NULL;
+    CARD16 str_length;
+
+    call_data->flag |= XimSYNCHRONUS;  /* always sync */
+
+    if (!(call_data->flag & XimLookupKeySym)
+        &&
+        (call_data->flag & XimLookupChars))
+    {
+        fm = FrameMgrInit (commit_chars_fr,
+                           NULL,
+                           _Xi18nNeedSwap (i18n_core, call_data->connect_id));
+
+        /* set length of STRING8 */
+        str_length = strlen (call_data->commit_string);
+        FrameMgrSetSize (fm, str_length);
+        total_size = FrameMgrGetTotalSize (fm);
+        reply = (unsigned char *) malloc (total_size);
+        if (!reply)
+        {
+            _Xi18nSendMessage (ims,
+                               call_data->connect_id,
+                               XIM_ERROR,
+                               0,
+                               0,
+                               0);
+            return False;
+        }
+        /*endif*/
+        memset (reply, 0, total_size);
+        FrameMgrSetBuffer (fm, reply);
+
+        str_length = FrameMgrGetSize (fm);
+        FrameMgrPutToken (fm, call_data->connect_id);
+        FrameMgrPutToken (fm, call_data->icid);
+        FrameMgrPutToken (fm, call_data->flag);
+        FrameMgrPutToken (fm, str_length);
+        FrameMgrPutToken (fm, call_data->commit_string);
+    }
+    else
+    {
+        fm = FrameMgrInit (commit_both_fr,
+                           NULL,
+                           _Xi18nNeedSwap (i18n_core, call_data->connect_id));
+        /* set length of STRING8 */
+        str_length = strlen (call_data->commit_string);
+        if (str_length > 0)
+            FrameMgrSetSize (fm, str_length);
+        /*endif*/
+        total_size = FrameMgrGetTotalSize (fm);
+        reply = (unsigned char *) malloc (total_size);
+        if (!reply)
+        {
+            _Xi18nSendMessage (ims,
+                               call_data->connect_id,
+                               XIM_ERROR,
+                               0,
+                               0,
+                               0);
+            return False;
+        }
+        /*endif*/
+        FrameMgrSetBuffer (fm, reply);
+        FrameMgrPutToken (fm, call_data->connect_id);
+        FrameMgrPutToken (fm, call_data->icid);
+        FrameMgrPutToken (fm, call_data->flag);
+        FrameMgrPutToken (fm, call_data->keysym);
+        if (str_length > 0)
+        {
+            str_length = FrameMgrGetSize (fm);
+            FrameMgrPutToken (fm, str_length);
+            FrameMgrPutToken (fm, call_data->commit_string);
+        }
+        /*endif*/
+    }
+    /*endif*/
+
+    _Xi18nSendMessage (ims,
+                       call_data->connect_id,
+                       XIM_COMMIT,
+                       0,
+                       reply,
+                       total_size);
+    FrameMgrFree (fm);
+    XFree (reply);
+
+    return True;
+}
+
+static int xi18n_callCallback (XIMS ims, XPointer xp)
+{
+    IMProtocol *call_data = (IMProtocol *)xp;
+    switch (call_data->major_code)
+    {
+    case XIM_GEOMETRY:
+        return _Xi18nGeometryCallback (ims, call_data);
+
+    case XIM_PREEDIT_START:
+        return _Xi18nPreeditStartCallback (ims, call_data);
+
+    case XIM_PREEDIT_DRAW:
+        return _Xi18nPreeditDrawCallback (ims, call_data);
+
+    case XIM_PREEDIT_CARET:
+        return _Xi18nPreeditCaretCallback (ims, call_data);
+
+    case XIM_PREEDIT_DONE:
+        return _Xi18nPreeditDoneCallback (ims, call_data);
+
+    case XIM_STATUS_START:
+        return _Xi18nStatusStartCallback (ims, call_data);
+
+    case XIM_STATUS_DRAW:
+        return _Xi18nStatusDrawCallback (ims, call_data);
+
+    case XIM_STATUS_DONE:
+        return _Xi18nStatusDoneCallback (ims, call_data);
+
+    case XIM_STR_CONVERSION:
+        return _Xi18nStringConversionCallback (ims, call_data);
+    }
+    /*endswitch*/
+    return False;
+}
+
+/* preeditStart and preeditEnd are used only for Dynamic Event Flow. */
+static int xi18n_preeditStart (XIMS ims, XPointer xp)
+{
+    IMProtocol *call_data = (IMProtocol *)xp;
+    Xi18n i18n_core = ims->protocol;
+    IMPreeditStateStruct *preedit_state =
+        (IMPreeditStateStruct *) &call_data->preedit_state;
+    long mask;
+    int on_key_num = i18n_core->address.on_keys.count_keys;
+    int off_key_num = i18n_core->address.off_keys.count_keys;
+
+    if (on_key_num == 0  &&  off_key_num == 0)
+        return False;
+    /*endif*/
+    if (i18n_core->address.imvalue_mask & I18N_FILTERMASK)
+        mask = i18n_core->address.filterevent_mask;
+    else
+        mask = DEFAULT_FILTER_MASK;
+    /*endif*/
+    _Xi18nSetEventMask (ims,
+                        preedit_state->connect_id,
+                        preedit_state->connect_id,
+                        preedit_state->icid,
+                        mask,
+                        ~mask);
+    return True;
+}
+
+static int xi18n_preeditEnd (XIMS ims, XPointer xp)
+{
+    IMProtocol *call_data = (IMProtocol *)xp;
+    Xi18n i18n_core = ims->protocol;
+    int on_key_num = i18n_core->address.on_keys.count_keys;
+    int off_key_num = i18n_core->address.off_keys.count_keys;
+    IMPreeditStateStruct *preedit_state;
+
+    preedit_state = (IMPreeditStateStruct *) &call_data->preedit_state;
+
+    if (on_key_num == 0  &&  off_key_num == 0)
+        return False;
+    /*endif*/
+
+    _Xi18nSetEventMask (ims,
+                        preedit_state->connect_id,
+                        preedit_state->connect_id,
+                        preedit_state->icid,
+                        0,
+                        0);
+    return True;
+}
+
+static int xi18n_syncXlib (XIMS ims, XPointer xp)
+{
+    IMProtocol *call_data = (IMProtocol *)xp;
+    Xi18n i18n_core = ims->protocol;
+    IMSyncXlibStruct *sync_xlib;
+
+    extern XimFrameRec sync_fr[];
+    FrameMgr fm;
+    CARD16 connect_id = call_data->any.connect_id;
+    int total_size;
+    unsigned char *reply;
+
+    sync_xlib = (IMSyncXlibStruct *) &call_data->sync_xlib;
+    fm = FrameMgrInit (sync_fr, NULL,
+                       _Xi18nNeedSwap (i18n_core, connect_id));
+    total_size = FrameMgrGetTotalSize(fm);
+    reply = (unsigned char *) malloc (total_size);
+    if (!reply) {
+        _Xi18nSendMessage (ims, connect_id, XIM_ERROR, 0, 0, 0);
+        return False;
+    }
+    memset (reply, 0, total_size);
+    FrameMgrSetBuffer (fm, reply);
+
+    /* input input-method ID */
+    FrameMgrPutToken (fm, connect_id);
+    /* input input-context ID */
+    FrameMgrPutToken (fm, sync_xlib->icid);
+    _Xi18nSendMessage (ims, connect_id, XIM_SYNC, 0, reply, total_size);
+
+    FrameMgrFree (fm);
+    XFree(reply);
+    return True;
+}
+
diff --git a/wrapper/xim/IMdkit/i18nPtHdr.c b/wrapper/xim/IMdkit/i18nPtHdr.c
new file mode 100644 (file)
index 0000000..d350354
--- /dev/null
@@ -0,0 +1,1848 @@
+/******************************************************************
+         Copyright 1994, 1995 by Sun Microsystems, Inc.
+         Copyright 1993, 1994 by Hewlett-Packard Company
+Permission to use, copy, modify, distribute, and sell this software
+and its documentation for any purpose is hereby granted without fee,
+provided that the above copyright notice appear in all copies and
+that both that copyright notice and this permission notice appear
+in supporting documentation, and that the name of Sun Microsystems, Inc.
+and Hewlett-Packard not be used in advertising or publicity pertaining to
+distribution of the software without specific, written prior permission.
+Sun Microsystems, Inc. and Hewlett-Packard make no representations about
+the suitability of this software for any purpose.  It is provided "as is"
+without express or implied warranty.
+SUN MICROSYSTEMS INC. AND HEWLETT-PACKARD COMPANY DISCLAIMS ALL
+WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
+SUN MICROSYSTEMS, INC. AND HEWLETT-PACKARD COMPANY BE LIABLE FOR ANY
+SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
+RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
+CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
+IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+  Author: Hidetoshi Tajima(tajima@Eng.Sun.COM) Sun Microsystems, Inc.
+
+    This version tidied and debugged by Steve Underwood May 1999
+******************************************************************/
+
+#include <stdlib.h>
+#include <sys/param.h>
+#include <X11/Xlib.h>
+#ifndef NEED_EVENTS
+#define NEED_EVENTS
+#endif
+#include <X11/Xproto.h>
+#undef NEED_EVENTS
+#include "FrameMgr.h"
+#include "IMdkit.h"
+#include "Xi18n.h"
+#include "XimFunc.h"
+
+#ifdef XIM_DEBUG
+#include <stdio.h>
+
+static void    DebugLog(char * msg)
+{
+       fprintf(stderr, msg);
+}
+#endif
+
+extern Xi18nClient *_Xi18nFindClient (Xi18n, CARD16);
+
+static void GetProtocolVersion (CARD16 client_major,
+                                CARD16 client_minor,
+                                CARD16 *server_major,
+                                CARD16 *server_minor)
+{
+    *server_major = client_major;
+    *server_minor = client_minor;
+}
+
+static void ConnectMessageProc (XIMS ims,
+                                IMProtocol *call_data,
+                                unsigned char *p)
+{
+    Xi18n i18n_core = ims->protocol;
+    FrameMgr fm;
+    extern XimFrameRec connect_fr[], connect_reply_fr[];
+    register int total_size;
+    CARD16 server_major_version, server_minor_version;
+    unsigned char *reply = NULL;
+    IMConnectStruct *imconnect =
+        (IMConnectStruct*) &call_data->imconnect;
+    CARD16 connect_id = call_data->any.connect_id;
+
+    fm = FrameMgrInit (connect_fr,
+                       (char *) p,
+                       _Xi18nNeedSwap (i18n_core, connect_id));
+
+    /* get data */
+    FrameMgrGetToken (fm, imconnect->byte_order);
+    FrameMgrGetToken (fm, imconnect->major_version);
+    FrameMgrGetToken (fm, imconnect->minor_version);
+
+    FrameMgrFree (fm);
+
+    GetProtocolVersion (imconnect->major_version,
+                        imconnect->minor_version,
+                        &server_major_version,
+                        &server_minor_version);
+#ifdef PROTOCOL_RICH
+    if (i18n_core->address.improto)
+    {
+        if (!(i18n_core->address.improto(ims, call_data)))
+            return;
+        /*endif*/
+    }
+    /*endif*/
+#endif  /* PROTOCOL_RICH */
+
+    fm = FrameMgrInit (connect_reply_fr,
+                       NULL,
+                       _Xi18nNeedSwap (i18n_core, connect_id));
+
+    total_size = FrameMgrGetTotalSize (fm);
+    reply = (unsigned char *) malloc (total_size);
+    if (!reply)
+    {
+        _Xi18nSendMessage (ims, connect_id, XIM_ERROR, 0, 0, 0);
+        return;
+    }
+    /*endif*/
+    memset (reply, 0, total_size);
+    FrameMgrSetBuffer (fm, reply);
+
+    FrameMgrPutToken (fm, server_major_version);
+    FrameMgrPutToken (fm, server_minor_version);
+
+    _Xi18nSendMessage (ims,
+                       connect_id,
+                       XIM_CONNECT_REPLY,
+                       0,
+                       reply,
+                       total_size);
+
+    FrameMgrFree (fm);
+    XFree (reply);
+}
+
+static void DisConnectMessageProc (XIMS ims, IMProtocol *call_data)
+{
+    Xi18n i18n_core = ims->protocol;
+    unsigned char *reply = NULL;
+    CARD16 connect_id = call_data->any.connect_id;
+
+#ifdef PROTOCOL_RICH
+    if (i18n_core->address.improto)
+    {
+        if (!(i18n_core->address.improto (ims, call_data)))
+            return;
+        /*endif*/
+    }
+    /*endif*/
+#endif  /* PROTOCOL_RICH */
+
+    _Xi18nSendMessage (ims,
+                       connect_id,
+                       XIM_DISCONNECT_REPLY,
+                       0,
+                       reply,
+                       0);
+
+    i18n_core->methods.disconnect (ims, connect_id);
+}
+
+static void OpenMessageProc(XIMS ims, IMProtocol *call_data, unsigned char *p)
+{
+    Xi18n i18n_core = ims->protocol;
+    FrameMgr fm;
+    extern XimFrameRec open_fr[];
+    extern XimFrameRec open_reply_fr[];
+    unsigned char *reply = NULL;
+    int str_size;
+    register int i, total_size;
+    CARD16 connect_id = call_data->any.connect_id;
+    int str_length;
+    char *name;
+    IMOpenStruct *imopen = (IMOpenStruct *) &call_data->imopen;
+
+    fm = FrameMgrInit (open_fr,
+                       (char *) p,
+                       _Xi18nNeedSwap (i18n_core, connect_id));
+
+    /* get data */
+    FrameMgrGetToken (fm, str_length);
+    FrameMgrSetSize (fm, str_length);
+    FrameMgrGetToken (fm, name);
+    imopen->lang.length = str_length;
+    imopen->lang.name = malloc (str_length + 1);
+    strncpy (imopen->lang.name, name, str_length);
+    imopen->lang.name[str_length] = (char) 0;
+
+    FrameMgrFree (fm);
+
+    if (i18n_core->address.improto)
+    {
+        if (!(i18n_core->address.improto(ims, call_data)))
+            return;
+        /*endif*/
+    }
+    /*endif*/
+    if ((i18n_core->address.imvalue_mask & I18N_ON_KEYS)
+        ||
+        (i18n_core->address.imvalue_mask & I18N_OFF_KEYS))
+    {
+        _Xi18nSendTriggerKey (ims, connect_id);
+    }
+    /*endif*/
+    XFree (imopen->lang.name);
+
+    fm = FrameMgrInit (open_reply_fr,
+                       NULL,
+                       _Xi18nNeedSwap (i18n_core, connect_id));
+
+    /* set iteration count for list of imattr */
+    FrameMgrSetIterCount (fm, i18n_core->address.im_attr_num);
+
+    /* set length of BARRAY item in ximattr_fr */
+    for (i = 0;  i < i18n_core->address.im_attr_num;  i++)
+    {
+        str_size = strlen (i18n_core->address.xim_attr[i].name);
+        FrameMgrSetSize (fm, str_size);
+    }
+    /*endfor*/
+    /* set iteration count for list of icattr */
+    FrameMgrSetIterCount (fm, i18n_core->address.ic_attr_num);
+    /* set length of BARRAY item in xicattr_fr */
+    for (i = 0;  i < i18n_core->address.ic_attr_num;  i++)
+    {
+        str_size = strlen (i18n_core->address.xic_attr[i].name);
+        FrameMgrSetSize (fm, str_size);
+    }
+    /*endfor*/
+
+    total_size = FrameMgrGetTotalSize (fm);
+    reply = (unsigned char *) malloc (total_size);
+    if (!reply)
+    {
+        _Xi18nSendMessage (ims, connect_id, XIM_ERROR, 0, 0, 0);
+        return;
+    }
+    /*endif*/
+    memset (reply, 0, total_size);
+    FrameMgrSetBuffer (fm, reply);
+
+    /* input input-method ID */
+    FrameMgrPutToken (fm, connect_id);
+
+    for (i = 0;  i < i18n_core->address.im_attr_num;  i++)
+    {
+        str_size = FrameMgrGetSize (fm);
+        FrameMgrPutToken (fm, i18n_core->address.xim_attr[i].attribute_id);
+        FrameMgrPutToken (fm, i18n_core->address.xim_attr[i].type);
+        FrameMgrPutToken (fm, str_size);
+        FrameMgrPutToken (fm, i18n_core->address.xim_attr[i].name);
+    }
+    /*endfor*/
+    for (i = 0;  i < i18n_core->address.ic_attr_num;  i++)
+    {
+        str_size = FrameMgrGetSize (fm);
+        FrameMgrPutToken (fm, i18n_core->address.xic_attr[i].attribute_id);
+        FrameMgrPutToken (fm, i18n_core->address.xic_attr[i].type);
+        FrameMgrPutToken (fm, str_size);
+        FrameMgrPutToken (fm, i18n_core->address.xic_attr[i].name);
+    }
+    /*endfor*/
+
+    _Xi18nSendMessage (ims,
+                       connect_id,
+                       XIM_OPEN_REPLY,
+                       0,
+                       reply,
+                       total_size);
+
+    FrameMgrFree (fm);
+    XFree (reply);
+}
+
+static void CloseMessageProc (XIMS ims,
+                              IMProtocol *call_data,
+                              unsigned char *p)
+{
+    Xi18n i18n_core = ims->protocol;
+    FrameMgr fm;
+    extern XimFrameRec close_fr[];
+    extern XimFrameRec close_reply_fr[];
+    unsigned char *reply = NULL;
+    register int total_size;
+    CARD16 connect_id = call_data->any.connect_id;
+    CARD16 input_method_ID;
+
+    fm = FrameMgrInit (close_fr,
+                       (char *) p,
+                       _Xi18nNeedSwap (i18n_core, connect_id));
+
+    FrameMgrGetToken (fm, input_method_ID);
+
+    FrameMgrFree (fm);
+
+    if (i18n_core->address.improto)
+    {
+        if (!(i18n_core->address.improto (ims, call_data)))
+            return;
+        /*endif*/
+    }
+    /*endif*/
+
+    fm = FrameMgrInit (close_reply_fr,
+                       NULL,
+                       _Xi18nNeedSwap (i18n_core, connect_id));
+
+    total_size = FrameMgrGetTotalSize (fm);
+    reply = (unsigned char *) malloc (total_size);
+    if (!reply)
+    {
+        _Xi18nSendMessage (ims,
+                           connect_id,
+                           XIM_ERROR,
+                           0,
+                           0,
+                           0);
+        return;
+    }
+    /*endif*/
+    memset (reply, 0, total_size);
+    FrameMgrSetBuffer (fm, reply);
+
+    FrameMgrPutToken (fm, input_method_ID);
+
+    _Xi18nSendMessage (ims,
+                       connect_id,
+                       XIM_CLOSE_REPLY,
+                       0,
+                       reply,
+                       total_size);
+
+    FrameMgrFree (fm);
+    XFree (reply);
+}
+
+static XIMExt *MakeExtensionList (Xi18n i18n_core,
+                                  XIMStr *lib_extension,
+                                  int number,
+                                  int *reply_number)
+{
+    XIMExt *ext_list;
+    XIMExt *im_ext = (XIMExt *) i18n_core->address.extension;
+    int im_ext_len = i18n_core->address.ext_num;
+    int i;
+    int j;
+
+    *reply_number = 0;
+
+    if (number == 0)
+    {
+        /* query all extensions */
+        *reply_number = im_ext_len;
+    }
+    else
+    {
+        for (i = 0;  i < im_ext_len;  i++)
+        {
+            for (j = 0;  j < (int) number;  j++)
+            {
+                if (strcmp (lib_extension[j].name, im_ext[i].name) == 0)
+                {
+                    (*reply_number)++;
+                    break;
+                }
+                /*endif*/
+            }
+            /*endfor*/
+        }
+        /*endfor*/
+    }
+    /*endif*/
+
+    if (!(*reply_number))
+        return NULL;
+    /*endif*/
+    ext_list = (XIMExt *) malloc (sizeof (XIMExt)*(*reply_number));
+    if (!ext_list)
+        return NULL;
+    /*endif*/
+    memset (ext_list, 0, sizeof (XIMExt)*(*reply_number));
+
+    if (number == 0)
+    {
+        /* query all extensions */
+        for (i = 0;  i < im_ext_len;  i++)
+        {
+            ext_list[i].major_opcode = im_ext[i].major_opcode;
+            ext_list[i].minor_opcode = im_ext[i].minor_opcode;
+            ext_list[i].length = im_ext[i].length;
+            ext_list[i].name = malloc (im_ext[i].length + 1);
+            strcpy (ext_list[i].name, im_ext[i].name);
+        }
+        /*endfor*/
+    }
+    else
+    {
+        int n = 0;
+
+        for (i = 0;  i < im_ext_len;  i++)
+        {
+            for (j = 0;  j < (int)number;  j++)
+            {
+                if (strcmp (lib_extension[j].name, im_ext[i].name) == 0)
+                {
+                    ext_list[n].major_opcode = im_ext[i].major_opcode;
+                    ext_list[n].minor_opcode = im_ext[i].minor_opcode;
+                    ext_list[n].length = im_ext[i].length;
+                    ext_list[n].name = malloc (im_ext[i].length + 1);
+                    strcpy (ext_list[n].name, im_ext[i].name);
+                    n++;
+                    break;
+                }
+                /*endif*/
+            }
+            /*endfor*/
+        }
+        /*endfor*/
+    }
+    /*endif*/
+    return ext_list;
+}
+
+static void QueryExtensionMessageProc (XIMS ims,
+                                       IMProtocol *call_data,
+                                       unsigned char *p)
+{
+    Xi18n i18n_core = ims->protocol;
+    FrameMgr fm;
+    FmStatus status;
+    extern XimFrameRec query_extension_fr[];
+    extern XimFrameRec query_extension_reply_fr[];
+    unsigned char *reply = NULL;
+    int str_size;
+    register int i;
+    register int number;
+    register int total_size;
+    int byte_length;
+    int reply_number = 0;
+    XIMExt *ext_list;
+    IMQueryExtensionStruct *query_ext =
+        (IMQueryExtensionStruct *) &call_data->queryext;
+    CARD16 connect_id = call_data->any.connect_id;
+    CARD16 input_method_ID;
+
+    fm = FrameMgrInit (query_extension_fr,
+                       (char *) p,
+                       _Xi18nNeedSwap (i18n_core, connect_id));
+
+    FrameMgrGetToken (fm, input_method_ID);
+    FrameMgrGetToken (fm, byte_length);
+    query_ext->extension = (XIMStr *) malloc (sizeof (XIMStr)*10);
+    memset (query_ext->extension, 0, sizeof (XIMStr)*10);
+    number = 0;
+    while (FrameMgrIsIterLoopEnd (fm, &status) == False)
+    {
+        char *name;
+        int str_length;
+        
+        FrameMgrGetToken (fm, str_length);
+        FrameMgrSetSize (fm, str_length);
+        query_ext->extension[number].length = str_length;
+        FrameMgrGetToken (fm, name);
+        query_ext->extension[number].name = malloc (str_length + 1);
+        strncpy (query_ext->extension[number].name, name, str_length);
+        query_ext->extension[number].name[str_length] = (char) 0;
+        number++;
+    }
+    /*endwhile*/
+    query_ext->number = number;
+
+#ifdef PROTOCOL_RICH
+    if (i18n_core->address.improto)
+    {
+        if (!(i18n_core->address.improto(ims, call_data)))
+            return;
+        /*endif*/
+    }
+    /*endif*/
+#endif  /* PROTOCOL_RICH */
+
+    FrameMgrFree (fm);
+
+    ext_list = MakeExtensionList (i18n_core,
+                                  query_ext->extension,
+                                  number,
+                                  &reply_number);
+
+    for (i = 0;  i < number;  i++)
+        XFree (query_ext->extension[i].name);
+    /*endfor*/
+    XFree (query_ext->extension);
+
+    fm = FrameMgrInit (query_extension_reply_fr,
+                       NULL,
+                       _Xi18nNeedSwap (i18n_core, connect_id));
+
+    /* set iteration count for list of extensions */
+    FrameMgrSetIterCount (fm, reply_number);
+
+    /* set length of BARRAY item in ext_fr */
+    for (i = 0;  i < reply_number;  i++)
+    {
+        str_size = strlen (ext_list[i].name);
+        FrameMgrSetSize (fm, str_size);
+    }
+    /*endfor*/
+
+    total_size = FrameMgrGetTotalSize (fm);
+    reply = (unsigned char *) malloc (total_size);
+    if (!reply)
+    {
+        _Xi18nSendMessage (ims,
+                           connect_id,
+                           XIM_ERROR,
+                           0,
+                           0,
+                           0);
+        return;
+    }
+    /*endif*/
+    memset (reply, 0, total_size);
+    FrameMgrSetBuffer (fm, reply);
+
+    FrameMgrPutToken (fm, input_method_ID);
+
+    for (i = 0;  i < reply_number;  i++)
+    {
+        str_size = FrameMgrGetSize (fm);
+        FrameMgrPutToken (fm, ext_list[i].major_opcode);
+        FrameMgrPutToken (fm, ext_list[i].minor_opcode);
+        FrameMgrPutToken (fm, str_size);
+        FrameMgrPutToken (fm, ext_list[i].name);
+    }
+    /*endfor*/
+    _Xi18nSendMessage (ims,
+                       connect_id,
+                       XIM_QUERY_EXTENSION_REPLY,
+                       0,
+                       reply,
+                       total_size);
+    FrameMgrFree (fm);
+    XFree (reply);
+
+    for (i = 0;  i < reply_number;  i++)
+        XFree (ext_list[i].name);
+    /*endfor*/
+    XFree ((char *) ext_list);
+}
+
+static void SyncReplyMessageProc (XIMS ims,
+                                  IMProtocol *call_data,
+                                  unsigned char *p)
+{
+    Xi18n i18n_core = ims->protocol;
+    FrameMgr fm;
+    extern XimFrameRec sync_reply_fr[];
+    CARD16 connect_id = call_data->any.connect_id;
+    Xi18nClient *client;
+    CARD16 input_method_ID;
+    CARD16 input_context_ID;
+
+    client = (Xi18nClient *)_Xi18nFindClient (i18n_core, connect_id);
+    fm = FrameMgrInit (sync_reply_fr,
+                       (char *) p,
+                       _Xi18nNeedSwap (i18n_core, connect_id));
+    FrameMgrGetToken (fm, input_method_ID);
+    FrameMgrGetToken (fm, input_context_ID);
+    FrameMgrFree (fm);
+
+    client->sync = False;
+
+    if (ims->sync == True) {
+       ims->sync = False;
+       if (i18n_core->address.improto) {
+           call_data->sync_xlib.major_code = XIM_SYNC_REPLY;
+           call_data->sync_xlib.minor_code = 0;
+           call_data->sync_xlib.connect_id = input_method_ID;
+           call_data->sync_xlib.icid = input_context_ID;
+           i18n_core->address.improto(ims, call_data);
+       }
+    }
+}
+
+static void GetIMValueFromName (Xi18n i18n_core,
+                                CARD16 connect_id,
+                                char *buf,
+                                char *name,
+                                int *length)
+{
+    register int i;
+
+    if (strcmp (name, XNQueryInputStyle) == 0)
+    {
+        XIMStyles *styles = (XIMStyles *) &i18n_core->address.input_styles;
+
+        *length = sizeof (CARD16)*2;   /* count_styles, unused */
+        *length += styles->count_styles*sizeof (CARD32);
+
+        if (buf != NULL)
+        {
+            FrameMgr fm;
+            extern XimFrameRec input_styles_fr[];
+            unsigned char *data = NULL;
+            int total_size;
+            
+            fm = FrameMgrInit (input_styles_fr,
+                               NULL,
+                               _Xi18nNeedSwap (i18n_core, connect_id));
+
+            /* set iteration count for list of input_style */
+            FrameMgrSetIterCount (fm, styles->count_styles);
+
+            total_size = FrameMgrGetTotalSize (fm);
+            data = (unsigned char *) malloc (total_size);
+            if (!data)
+                return;
+            /*endif*/
+            memset (data, 0, total_size);
+            FrameMgrSetBuffer (fm, data);
+
+            FrameMgrPutToken (fm, styles->count_styles);
+            for (i = 0;  i < (int) styles->count_styles;  i++)
+                FrameMgrPutToken (fm, styles->supported_styles[i]);
+            /*endfor*/
+            memmove (buf, data, total_size);
+            FrameMgrFree (fm);
+
+            /* ADDED BY SUZHE */
+            free (data);
+            /* ADDED BY SUZHE */
+        }
+        /*endif*/
+    }
+    /*endif*/
+
+    else if (strcmp (name, XNQueryIMValuesList) == 0) {
+    }
+}
+
+static XIMAttribute *MakeIMAttributeList (Xi18n i18n_core,
+                                          CARD16 connect_id,
+                                          CARD16 *list,
+                                          int *number,
+                                          int *length)
+{
+    XIMAttribute *attrib_list;
+    int list_num;
+    XIMAttr *attr = i18n_core->address.xim_attr;
+    int list_len = i18n_core->address.im_attr_num;
+    register int i;
+    register int j;
+    int value_length;
+    int number_ret = 0;
+
+    *length = 0;
+    list_num = 0;
+    for (i = 0;  i < *number;  i++)
+    {
+        for (j = 0;  j < list_len;  j++)
+        {
+            if (attr[j].attribute_id == list[i])
+            {
+                list_num++;
+                break;
+            }
+            /*endif*/
+        }
+        /*endfor*/
+    }
+    /*endfor*/
+    attrib_list = (XIMAttribute *) malloc (sizeof (XIMAttribute)*list_num);
+    if (!attrib_list)
+        return NULL;
+    /*endif*/
+    memset (attrib_list, 0, sizeof (XIMAttribute)*list_num);
+    number_ret = list_num;
+    list_num = 0;
+    for (i = 0;  i < *number;  i++)
+    {
+        for (j = 0;  j < list_len;  j++)
+        {
+            if (attr[j].attribute_id == list[i])
+            {
+                attrib_list[list_num].attribute_id = attr[j].attribute_id;
+                attrib_list[list_num].name_length = attr[j].length;
+                attrib_list[list_num].name = attr[j].name;
+                attrib_list[list_num].type = attr[j].type;
+                GetIMValueFromName (i18n_core,
+                                    connect_id,
+                                    NULL,
+                                    attr[j].name,
+                                    &value_length);
+                attrib_list[list_num].value_length = value_length;
+                attrib_list[list_num].value = (void *) malloc (value_length);
+                memset(attrib_list[list_num].value, 0, value_length);
+                GetIMValueFromName (i18n_core,
+                                    connect_id,
+                                    attrib_list[list_num].value,
+                                    attr[j].name,
+                                    &value_length);
+                *length += sizeof (CARD16)*2;
+                *length += value_length;
+                *length += IMPAD (value_length);
+                list_num++;
+                break;
+            }
+            /*endif*/
+        }
+        /*endfor*/
+    }
+    /*endfor*/
+    *number = number_ret;
+    return attrib_list;
+}
+
+static void GetIMValuesMessageProc (XIMS ims,
+                                    IMProtocol *call_data,
+                                    unsigned char *p)
+{
+    Xi18n i18n_core = ims->protocol;
+    FrameMgr fm;
+    FmStatus status;
+    extern XimFrameRec get_im_values_fr[];
+    extern XimFrameRec get_im_values_reply_fr[];
+    CARD16 byte_length;
+    int list_len, total_size;
+    unsigned char *reply = NULL;
+    int iter_count;
+    register int i;
+    register int j;
+    int number;
+    CARD16 *im_attrID_list;
+    char **name_list;
+    CARD16 name_number;
+    XIMAttribute *im_attribute_list;
+    IMGetIMValuesStruct *getim = (IMGetIMValuesStruct *)&call_data->getim;
+    CARD16 connect_id = call_data->any.connect_id;
+    CARD16 input_method_ID;
+
+    /* create FrameMgr */
+    fm = FrameMgrInit (get_im_values_fr,
+                       (char *) p,
+                       _Xi18nNeedSwap (i18n_core, connect_id));
+
+    FrameMgrGetToken (fm, input_method_ID);
+    FrameMgrGetToken (fm, byte_length);
+    im_attrID_list = (CARD16 *) malloc (sizeof (CARD16)*20);
+    memset (im_attrID_list, 0, sizeof (CARD16)*20);
+    name_list = (char **)malloc(sizeof(char *) * 20);
+    memset(name_list, 0, sizeof(char *) * 20);
+    number = 0;
+    while (FrameMgrIsIterLoopEnd (fm, &status) == False)
+    {
+        FrameMgrGetToken (fm, im_attrID_list[number]);
+        number++;
+    }
+    FrameMgrFree (fm);
+
+    name_number = 0;
+    for (i = 0;  i < number;  i++) {
+        for (j = 0;  j < i18n_core->address.im_attr_num;  j++) {
+            if (i18n_core->address.xim_attr[j].attribute_id ==
+                    im_attrID_list[i]) {
+                name_list[name_number++] = 
+                       i18n_core->address.xim_attr[j].name;
+                break;
+            }
+        }
+    }
+    getim->number = name_number;
+    getim->im_attr_list = name_list;
+    XFree (name_list);
+
+
+#ifdef PROTOCOL_RICH
+    if (i18n_core->address.improto) {
+        if (!(i18n_core->address.improto (ims, call_data)))
+            return;
+    }
+#endif  /* PROTOCOL_RICH */
+
+    im_attribute_list = MakeIMAttributeList (i18n_core,
+                                             connect_id,
+                                             im_attrID_list,
+                                             &number,
+                                             &list_len);
+    if (im_attrID_list)
+        XFree (im_attrID_list);
+    /*endif*/
+
+    fm = FrameMgrInit (get_im_values_reply_fr,
+                       NULL,
+                       _Xi18nNeedSwap (i18n_core, connect_id));
+
+    iter_count = number;
+
+    /* set iteration count for list of im_attribute */
+    FrameMgrSetIterCount (fm, iter_count);
+
+    /* set length of BARRAY item in ximattribute_fr */
+    for (i = 0;  i < iter_count;  i++)
+        FrameMgrSetSize (fm, im_attribute_list[i].value_length);
+    /*endfor*/
+    
+    total_size = FrameMgrGetTotalSize (fm);
+    reply = (unsigned char *) malloc (total_size);
+    if (!reply)
+    {
+        _Xi18nSendMessage (ims, connect_id, XIM_ERROR, 0, 0, 0);
+        return;
+    }
+    /*endif*/
+    memset (reply, 0, total_size);
+    FrameMgrSetBuffer (fm, reply);
+
+    FrameMgrPutToken (fm, input_method_ID);
+
+    for (i = 0;  i < iter_count;  i++)
+    {
+        FrameMgrPutToken (fm, im_attribute_list[i].attribute_id);
+        FrameMgrPutToken (fm, im_attribute_list[i].value_length);
+        FrameMgrPutToken (fm, im_attribute_list[i].value);
+    }
+    /*endfor*/
+    _Xi18nSendMessage (ims,
+                       connect_id,
+                       XIM_GET_IM_VALUES_REPLY,
+                       0,
+                       reply,
+                       total_size);
+    FrameMgrFree (fm);
+    XFree (reply);
+
+    for (i = 0; i < iter_count; i++)
+        XFree(im_attribute_list[i].value);
+    XFree (im_attribute_list);
+}
+
+static void CreateICMessageProc (XIMS ims,
+                                 IMProtocol *call_data,
+                                 unsigned char *p)
+{
+    _Xi18nChangeIC (ims, call_data, p, True);
+}
+
+static void SetICValuesMessageProc (XIMS ims,
+                                    IMProtocol *call_data,
+                                    unsigned char *p)
+{
+    _Xi18nChangeIC (ims, call_data, p, False);
+}
+
+static void GetICValuesMessageProc (XIMS ims,
+                                    IMProtocol *call_data,
+                                    unsigned char *p)
+{
+    _Xi18nGetIC (ims, call_data, p);
+}
+
+static void SetICFocusMessageProc (XIMS ims,
+                                   IMProtocol *call_data,
+                                   unsigned char *p)
+{
+    Xi18n i18n_core = ims->protocol;
+    FrameMgr fm;
+    extern XimFrameRec set_ic_focus_fr[];
+    IMChangeFocusStruct *setfocus;
+    CARD16 connect_id = call_data->any.connect_id;
+    CARD16 input_method_ID;
+
+    setfocus = (IMChangeFocusStruct *) &call_data->changefocus;
+
+    fm = FrameMgrInit (set_ic_focus_fr,
+                       (char *) p,
+                       _Xi18nNeedSwap (i18n_core, connect_id));
+
+    /* get data */
+    FrameMgrGetToken (fm, input_method_ID);
+    FrameMgrGetToken (fm, setfocus->icid);
+
+    FrameMgrFree (fm);
+
+    if (i18n_core->address.improto)
+    {
+        if (!(i18n_core->address.improto (ims, call_data)))
+            return;
+        /*endif*/
+    }
+    /*endif*/
+}
+
+static void UnsetICFocusMessageProc (XIMS ims,
+                                     IMProtocol *call_data,
+                                     unsigned char *p)
+{
+    Xi18n i18n_core = ims->protocol;
+    FrameMgr fm;
+    extern XimFrameRec unset_ic_focus_fr[];
+    IMChangeFocusStruct *unsetfocus;
+    CARD16 connect_id = call_data->any.connect_id;
+    CARD16 input_method_ID;
+
+    unsetfocus = (IMChangeFocusStruct *) &call_data->changefocus;
+
+    fm = FrameMgrInit (unset_ic_focus_fr,
+                       (char *) p,
+                       _Xi18nNeedSwap (i18n_core, connect_id));
+
+    /* get data */
+    FrameMgrGetToken (fm, input_method_ID);
+    FrameMgrGetToken (fm, unsetfocus->icid);
+
+    FrameMgrFree (fm);
+
+    if (i18n_core->address.improto)
+    {
+        if (!(i18n_core->address.improto (ims, call_data)))
+            return;
+        /*endif*/
+    }
+    /*endif*/
+}
+
+static void DestroyICMessageProc (XIMS ims,
+                                  IMProtocol *call_data,
+                                  unsigned char *p)
+{
+    Xi18n i18n_core = ims->protocol;
+    FrameMgr fm;
+    extern XimFrameRec destroy_ic_fr[];
+    extern XimFrameRec destroy_ic_reply_fr[];
+    register int total_size;
+    unsigned char *reply = NULL;
+    IMDestroyICStruct *destroy =
+        (IMDestroyICStruct *) &call_data->destroyic;
+    CARD16 connect_id = call_data->any.connect_id;
+    CARD16 input_method_ID;
+
+    fm = FrameMgrInit (destroy_ic_fr,
+                       (char *) p,
+                       _Xi18nNeedSwap (i18n_core, connect_id));
+
+    /* get data */
+    FrameMgrGetToken (fm, input_method_ID);
+    FrameMgrGetToken (fm, destroy->icid);
+
+    FrameMgrFree (fm);
+
+    if (i18n_core->address.improto)
+    {
+        if (!(i18n_core->address.improto (ims, call_data)))
+            return;
+        /*endif*/
+    }
+    /*endif*/
+    
+    fm = FrameMgrInit (destroy_ic_reply_fr,
+                       NULL,
+                       _Xi18nNeedSwap (i18n_core, connect_id));
+
+    total_size = FrameMgrGetTotalSize (fm);
+    reply = (unsigned char *) malloc (total_size);
+    if (!reply)
+    {
+        _Xi18nSendMessage (ims, connect_id, XIM_ERROR, 0, 0, 0);
+        return;
+    }
+    /*endif*/
+    memset (reply, 0, total_size);
+    FrameMgrSetBuffer (fm, reply);
+
+    FrameMgrPutToken (fm, input_method_ID);
+    FrameMgrPutToken (fm, destroy->icid);
+
+    _Xi18nSendMessage (ims,
+                       connect_id,
+                       XIM_DESTROY_IC_REPLY,
+                       0,
+                       reply,
+                       total_size);
+    XFree(reply);
+    FrameMgrFree (fm);
+}
+
+static void ResetICMessageProc (XIMS ims,
+                                IMProtocol *call_data,
+                                unsigned char *p)
+{
+    Xi18n i18n_core = ims->protocol;
+    FrameMgr fm;
+    extern XimFrameRec reset_ic_fr[];
+    extern XimFrameRec reset_ic_reply_fr[];
+    register int total_size;
+    unsigned char *reply = NULL;
+    IMResetICStruct *resetic =
+        (IMResetICStruct *) &call_data->resetic;
+    CARD16 connect_id = call_data->any.connect_id;
+    CARD16 input_method_ID;
+
+    fm = FrameMgrInit (reset_ic_fr,
+                       (char *) p,
+                       _Xi18nNeedSwap (i18n_core, connect_id));
+
+    /* get data */
+    FrameMgrGetToken (fm, input_method_ID);
+    FrameMgrGetToken (fm, resetic->icid);
+
+    FrameMgrFree (fm);
+
+    if (i18n_core->address.improto)
+    {
+        if (!(i18n_core->address.improto(ims, call_data)))
+            return;
+        /*endif*/
+    }
+    /*endif*/
+    
+    /* create FrameMgr */
+    fm = FrameMgrInit (reset_ic_reply_fr,
+                       NULL,
+                       _Xi18nNeedSwap (i18n_core, connect_id));
+
+    /* set length of STRING8 */
+    FrameMgrSetSize (fm, resetic->length);
+
+    total_size = FrameMgrGetTotalSize (fm);
+    reply = (unsigned char *) malloc (total_size);
+    if (!reply)
+    {
+        _Xi18nSendMessage (ims, connect_id, XIM_ERROR, 0, 0, 0);
+        return;
+    }
+    /*endif*/
+    memset (reply, 0, total_size);
+    FrameMgrSetBuffer (fm, reply);
+
+    FrameMgrPutToken (fm, input_method_ID);
+    FrameMgrPutToken (fm, resetic->icid);
+    FrameMgrPutToken(fm, resetic->length);
+    FrameMgrPutToken (fm, resetic->commit_string);
+
+    _Xi18nSendMessage (ims,
+                       connect_id,
+                       XIM_RESET_IC_REPLY,
+                       0,
+                       reply,
+                       total_size);
+    FrameMgrFree (fm);
+    XFree(reply);
+}
+
+static int WireEventToEvent (Xi18n i18n_core,
+                             xEvent *event,
+                             CARD16 serial,
+                             XEvent *ev,
+                             Bool byte_swap)
+{
+    FrameMgr fm;
+    extern XimFrameRec wire_keyevent_fr[];
+    BYTE b;
+    CARD16 c16;
+    CARD32 c32;
+    int ret = False;
+
+    /* create FrameMgr */
+    fm = FrameMgrInit(wire_keyevent_fr, (char *)(&(event->u)), byte_swap);
+
+
+    /* get & set type */
+    FrameMgrGetToken(fm, b);
+    ev->type = (unsigned int)b;
+    /* get detail */
+    FrameMgrGetToken(fm, b);
+    /* get & set serial */
+    FrameMgrGetToken(fm, c16);
+    ev->xany.serial = (unsigned long)c16;
+    ev->xany.serial |= serial << 16;
+    ev->xany.send_event = False;
+    ev->xany.display = i18n_core->address.dpy;
+
+    /* Remove SendEvent flag from event type to emulate KeyPress/Release */
+    ev->type &= 0x7F;
+
+    switch (ev->type) {
+      case KeyPress:
+      case KeyRelease:
+      {
+          XKeyEvent *kev = (XKeyEvent*)ev;
+
+          /* set keycode (detail) */
+          kev->keycode = (unsigned int)b;
+
+          /* get & set values */
+          FrameMgrGetToken(fm, c32); kev->time = (Time)c32;
+          FrameMgrGetToken(fm, c32); kev->root = (Window)c32;
+          FrameMgrGetToken(fm, c32); kev->window = (Window)c32;
+          FrameMgrGetToken(fm, c32); kev->subwindow = (Window)c32;
+          FrameMgrGetToken(fm, c16); kev->x_root = (int)c16;
+          FrameMgrGetToken(fm, c16); kev->y_root = (int)c16;
+          FrameMgrGetToken(fm, c16); kev->x = (int)c16;
+          FrameMgrGetToken(fm, c16); kev->y = (int)c16;
+          FrameMgrGetToken(fm, c16); kev->state = (unsigned int)c16;
+          FrameMgrGetToken(fm, b);   kev->same_screen = (Bool)b;
+      }
+      ret = True;
+      break;
+      default:
+      break;
+    }
+    /* free FrameMgr */
+    FrameMgrFree(fm);
+    return ret;
+}
+
+static void ForwardEventMessageProc (XIMS ims,
+                                     IMProtocol *call_data,
+                                     unsigned char *p)
+{
+    Xi18n i18n_core = ims->protocol;
+    FrameMgr fm;
+    extern XimFrameRec forward_event_fr[];
+    xEvent wire_event;
+    IMForwardEventStruct *forward =
+        (IMForwardEventStruct*) &call_data->forwardevent;
+    CARD16 connect_id = call_data->any.connect_id;
+    CARD16 input_method_ID;
+
+    fm = FrameMgrInit (forward_event_fr,
+                       (char *) p,
+                       _Xi18nNeedSwap (i18n_core, connect_id));
+    /* get data */
+    FrameMgrGetToken (fm, input_method_ID);
+    FrameMgrGetToken (fm, forward->icid);
+    FrameMgrGetToken (fm, forward->sync_bit);
+    FrameMgrGetToken (fm, forward->serial_number);
+    p += sizeof (CARD16)*4;
+    memmove (&wire_event, p, sizeof (xEvent));
+
+    FrameMgrFree (fm);
+
+    if (WireEventToEvent (i18n_core,
+                          &wire_event,
+                          forward->serial_number,
+                          &forward->event,
+                         _Xi18nNeedSwap (i18n_core, connect_id)) == True)
+    {
+        if (i18n_core->address.improto)
+        {
+            if (!(i18n_core->address.improto(ims, call_data)))
+                return;
+            /*endif*/
+        }
+        /*endif*/
+    }
+    /*endif*/
+}
+
+static void ExtForwardKeyEventMessageProc (XIMS ims,
+                                           IMProtocol *call_data,
+                                           unsigned char *p)
+{
+    Xi18n i18n_core = ims->protocol;
+    FrameMgr fm;
+    extern XimFrameRec ext_forward_keyevent_fr[];
+    CARD8 type, keycode;
+    CARD16 state;
+    CARD32 ev_time, window;
+    IMForwardEventStruct *forward =
+        (IMForwardEventStruct *) &call_data->forwardevent;
+    XEvent *ev = (XEvent *) &forward->event;
+    CARD16 connect_id = call_data->any.connect_id;
+    CARD16 input_method_ID;
+
+    fm = FrameMgrInit (ext_forward_keyevent_fr,
+                       (char *) p,
+                       _Xi18nNeedSwap (i18n_core, connect_id));
+    /* get data */
+    FrameMgrGetToken (fm, input_method_ID);
+    FrameMgrGetToken (fm, forward->icid);
+    FrameMgrGetToken (fm, forward->sync_bit);
+    FrameMgrGetToken (fm, forward->serial_number);
+    FrameMgrGetToken (fm, type);
+    FrameMgrGetToken (fm, keycode);
+    FrameMgrGetToken (fm, state);
+    FrameMgrGetToken (fm, ev_time);
+    FrameMgrGetToken (fm, window);
+
+    FrameMgrFree (fm);
+
+    if (type != KeyPress)
+    {
+        _Xi18nSendMessage (ims, connect_id, XIM_ERROR, 0, 0, 0);
+        return;
+    }
+    /*endif*/
+    
+    /* make a faked keypress event */
+    ev->type = (int)type;
+    ev->xany.send_event = True;
+    ev->xany.display = i18n_core->address.dpy;
+    ev->xany.serial = (unsigned long) forward->serial_number;
+    ((XKeyEvent *) ev)->keycode = (unsigned int) keycode;
+    ((XKeyEvent *) ev)->state = (unsigned int) state;
+    ((XKeyEvent *) ev)->time = (Time) ev_time;
+    ((XKeyEvent *) ev)->window = (Window) window;
+    ((XKeyEvent *) ev)->root = DefaultRootWindow (ev->xany.display);
+    ((XKeyEvent *) ev)->x = 0;
+    ((XKeyEvent *) ev)->y = 0;
+    ((XKeyEvent *) ev)->x_root = 0;
+    ((XKeyEvent *) ev)->y_root = 0;
+
+    if (i18n_core->address.improto)
+    {
+        if (!(i18n_core->address.improto (ims, call_data)))
+            return;
+        /*endif*/
+    }
+    /*endif*/
+}
+
+static void ExtMoveMessageProc (XIMS ims,
+                                IMProtocol *call_data,
+                                unsigned char *p)
+{
+    Xi18n i18n_core = ims->protocol;
+    FrameMgr fm;
+    extern XimFrameRec ext_move_fr[];
+    IMMoveStruct *extmove =
+        (IMMoveStruct*) & call_data->extmove;
+    CARD16 connect_id = call_data->any.connect_id;
+    CARD16 input_method_ID;
+
+    fm = FrameMgrInit (ext_move_fr,
+                       (char *) p,
+                       _Xi18nNeedSwap (i18n_core, connect_id));
+    /* get data */
+    FrameMgrGetToken (fm, input_method_ID);
+    FrameMgrGetToken (fm, extmove->icid);
+    FrameMgrGetToken (fm, extmove->x);
+    FrameMgrGetToken (fm, extmove->y);
+
+    FrameMgrFree (fm);
+
+    if (i18n_core->address.improto)
+    {
+        if (!(i18n_core->address.improto (ims, call_data)))
+            return;
+        /*endif*/
+    }
+    /*endif*/
+}
+
+static void ExtensionMessageProc (XIMS ims,
+                                  IMProtocol *call_data,
+                                  unsigned char *p)
+{
+    switch (call_data->any.minor_code)
+    {
+    case XIM_EXT_FORWARD_KEYEVENT:
+        ExtForwardKeyEventMessageProc (ims, call_data, p);
+        break;
+
+    case XIM_EXT_MOVE:
+        ExtMoveMessageProc (ims, call_data, p);
+        break;
+    }
+    /*endswitch*/
+}
+
+static void TriggerNotifyMessageProc (XIMS ims,
+                                      IMProtocol *call_data,
+                                      unsigned char *p)
+{
+    Xi18n i18n_core = ims->protocol;
+    FrameMgr fm;
+    extern XimFrameRec trigger_notify_fr[], trigger_notify_reply_fr[];
+    register int total_size;
+    unsigned char *reply = NULL;
+    IMTriggerNotifyStruct *trigger =
+        (IMTriggerNotifyStruct *) &call_data->triggernotify;
+    CARD16 connect_id = call_data->any.connect_id;
+    CARD16 input_method_ID;
+    CARD32 flag;
+
+    fm = FrameMgrInit (trigger_notify_fr,
+                       (char *) p,
+                       _Xi18nNeedSwap (i18n_core, connect_id));
+    /* get data */
+    FrameMgrGetToken (fm, input_method_ID);
+    FrameMgrGetToken (fm, trigger->icid);
+    FrameMgrGetToken (fm, trigger->flag);
+    FrameMgrGetToken (fm, trigger->key_index);
+    FrameMgrGetToken (fm, trigger->event_mask);
+    /*
+      In order to support Front End Method, this event_mask must be saved
+      per clients so that it should be restored by an XIM_EXT_SET_EVENT_MASK
+      call when preediting mode is reset to off.
+     */
+
+    flag = trigger->flag;
+
+    FrameMgrFree (fm);
+
+    fm = FrameMgrInit (trigger_notify_reply_fr,
+                       NULL,
+                       _Xi18nNeedSwap (i18n_core, connect_id));
+    total_size = FrameMgrGetTotalSize (fm);
+    reply = (unsigned char *) malloc (total_size);
+    if (!reply)
+    {
+        _Xi18nSendMessage (ims, connect_id, XIM_ERROR, 0, 0, 0);
+        return;
+    }
+    /*endif*/
+    memset (reply, 0, total_size);
+    FrameMgrSetBuffer (fm, reply);
+
+    FrameMgrPutToken (fm, input_method_ID);
+    FrameMgrPutToken (fm, trigger->icid);
+
+    /* NOTE:
+       XIM_TRIGGER_NOTIFY_REPLY should be sent before XIM_SET_EVENT_MASK
+       in case of XIM_TRIGGER_NOTIFY(flag == ON), while it should be
+       sent after XIM_SET_EVENT_MASK in case of
+       XIM_TRIGGER_NOTIFY(flag == OFF).
+       */
+    if (flag == 0)
+    {
+        /* on key */
+        _Xi18nSendMessage (ims,
+                           connect_id,
+                           XIM_TRIGGER_NOTIFY_REPLY,
+                           0,
+                           reply,
+                           total_size);
+        IMPreeditStart (ims, (XPointer)call_data);
+    }
+    /*endif*/
+    if (i18n_core->address.improto)
+    {
+        if (!(i18n_core->address.improto(ims, call_data)))
+            return;
+        /*endif*/
+    }
+    /*endif*/
+
+    if (flag == 1)
+    {
+        /* off key */
+        IMPreeditEnd (ims, (XPointer) call_data);
+        _Xi18nSendMessage (ims,
+                           connect_id,
+                           XIM_TRIGGER_NOTIFY_REPLY,
+                           0,
+                           reply,
+                           total_size);
+    }
+    /*endif*/
+    FrameMgrFree (fm);
+    XFree (reply);
+}
+
+static INT16 ChooseEncoding (Xi18n i18n_core,
+                             IMEncodingNegotiationStruct *enc_nego)
+{
+    Xi18nAddressRec *address = (Xi18nAddressRec *) & i18n_core->address;
+    XIMEncodings *p;
+    int i, j;
+    int enc_index=0;
+
+    p = (XIMEncodings *) &address->encoding_list;
+    for (i = 0;  i < (int) p->count_encodings;  i++)
+    {
+        for (j = 0;  j < (int) enc_nego->encoding_number;  j++)
+        {
+            if (strcmp (p->supported_encodings[i],
+                        enc_nego->encoding[j].name) == 0)
+            {
+                enc_index = j;
+                break;
+            }
+            /*endif*/
+        }
+        /*endfor*/
+    }
+    /*endfor*/
+
+    return (INT16) enc_index;
+#if 0
+    return (INT16) XIM_Default_Encoding_IDX;
+#endif
+}
+
+static void EncodingNegotiatonMessageProc (XIMS ims,
+                                           IMProtocol *call_data,
+                                           unsigned char *p)
+{
+    Xi18n i18n_core = ims->protocol;
+    FrameMgr fm;
+    FmStatus status;
+    CARD16 byte_length;
+    extern XimFrameRec encoding_negotiation_fr[];
+    extern XimFrameRec encoding_negotiation_reply_fr[];
+    register int i, total_size;
+    unsigned char *reply = NULL;
+    IMEncodingNegotiationStruct *enc_nego =
+        (IMEncodingNegotiationStruct *) &call_data->encodingnego;
+    CARD16 connect_id = call_data->any.connect_id;
+    CARD16 input_method_ID;
+
+    fm = FrameMgrInit (encoding_negotiation_fr,
+                       (char *) p,
+                       _Xi18nNeedSwap (i18n_core, connect_id));
+
+    FrameMgrGetToken (fm, input_method_ID);
+
+    /* get ENCODING STR field */
+    FrameMgrGetToken (fm, byte_length);
+    if (byte_length > 0)
+    {
+        enc_nego->encoding = (XIMStr *) malloc (sizeof (XIMStr)*10);
+        memset (enc_nego->encoding, 0, sizeof (XIMStr)*10);
+        i = 0;
+        while (FrameMgrIsIterLoopEnd (fm, &status) == False)
+        {
+            char *name;
+            int str_length;
+            
+            FrameMgrGetToken (fm, str_length);
+            FrameMgrSetSize (fm, str_length);
+            enc_nego->encoding[i].length = str_length;
+            FrameMgrGetToken (fm, name);
+            enc_nego->encoding[i].name = malloc (str_length + 1);
+            strncpy (enc_nego->encoding[i].name, name, str_length);
+            enc_nego->encoding[i].name[str_length] = '\0';
+            i++;
+        }
+        /*endwhile*/
+        enc_nego->encoding_number = i;
+    }
+    /*endif*/
+    /* get ENCODING INFO field */
+    FrameMgrGetToken (fm, byte_length);
+    if (byte_length > 0)
+    {
+        enc_nego->encodinginfo = (XIMStr *) malloc (sizeof (XIMStr)*10);
+        memset (enc_nego->encoding, 0, sizeof (XIMStr)*10);
+        i = 0;
+        while (FrameMgrIsIterLoopEnd (fm, &status) == False)
+        {
+            char *name;
+            int str_length;
+            
+            FrameMgrGetToken (fm, str_length);
+            FrameMgrSetSize (fm, str_length);
+            enc_nego->encodinginfo[i].length = str_length;
+            FrameMgrGetToken (fm, name);
+            enc_nego->encodinginfo[i].name = malloc (str_length + 1);
+            strncpy (enc_nego->encodinginfo[i].name, name, str_length);
+            enc_nego->encodinginfo[i].name[str_length] = '\0';
+            i++;
+        }
+        /*endwhile*/
+        enc_nego->encoding_info_number = i;
+    }
+    /*endif*/
+
+    enc_nego->enc_index = ChooseEncoding (i18n_core, enc_nego);
+    enc_nego->category = 0;
+
+#ifdef PROTOCOL_RICH
+    if (i18n_core->address.improto)
+    {
+        if (!(i18n_core->address.improto(ims, call_data)))
+            return;
+        /*endif*/
+    }
+    /*endif*/
+#endif  /* PROTOCOL_RICH */
+
+    FrameMgrFree (fm);
+
+    fm = FrameMgrInit (encoding_negotiation_reply_fr,
+                       NULL,
+                       _Xi18nNeedSwap (i18n_core, connect_id));
+
+    total_size = FrameMgrGetTotalSize (fm);
+    reply = (unsigned char *) malloc (total_size);
+    if (!reply)
+    {
+        _Xi18nSendMessage (ims, connect_id, XIM_ERROR, 0, 0, 0);
+        return;
+    }
+    /*endif*/
+    memset (reply, 0, total_size);
+    FrameMgrSetBuffer (fm, reply);
+
+    FrameMgrPutToken (fm, input_method_ID);
+    FrameMgrPutToken (fm, enc_nego->category);
+    FrameMgrPutToken (fm, enc_nego->enc_index);
+
+    _Xi18nSendMessage (ims,
+                       connect_id,
+                       XIM_ENCODING_NEGOTIATION_REPLY,
+                       0,
+                       reply,
+                       total_size);
+    XFree (reply);
+
+    /* free data for encoding list */
+    if (enc_nego->encoding)
+    {
+        for (i = 0;  i < (int) enc_nego->encoding_number;  i++)
+            XFree (enc_nego->encoding[i].name);
+        /*endfor*/
+        XFree (enc_nego->encoding);
+    }
+    /*endif*/
+    if (enc_nego->encodinginfo)
+    {
+        for (i = 0;  i < (int) enc_nego->encoding_info_number;  i++)
+            XFree (enc_nego->encodinginfo[i].name);
+        /*endfor*/
+        XFree (enc_nego->encodinginfo);
+    }
+    /*endif*/
+    FrameMgrFree (fm);
+}
+
+void PreeditStartReplyMessageProc (XIMS ims,
+                                   IMProtocol *call_data,
+                                   unsigned char *p)
+{
+    Xi18n i18n_core = ims->protocol;
+    FrameMgr fm;
+    extern XimFrameRec preedit_start_reply_fr[];
+    IMPreeditCBStruct *preedit_CB =
+        (IMPreeditCBStruct *) &call_data->preedit_callback;
+    CARD16 connect_id = call_data->any.connect_id;
+    CARD16 input_method_ID;
+
+    fm = FrameMgrInit (preedit_start_reply_fr,
+                       (char *) p,
+                       _Xi18nNeedSwap (i18n_core, connect_id));
+    /* get data */
+    FrameMgrGetToken (fm, input_method_ID);
+    FrameMgrGetToken (fm, preedit_CB->icid);
+    FrameMgrGetToken (fm, preedit_CB->todo.return_value);
+
+    FrameMgrFree (fm);
+
+    if (i18n_core->address.improto)
+    {
+        if (!(i18n_core->address.improto (ims, call_data)))
+            return;
+        /*endif*/
+    }
+    /*endif*/
+}
+
+void PreeditCaretReplyMessageProc (XIMS ims,
+                                   IMProtocol *call_data,
+                                   unsigned char *p)
+{
+    Xi18n i18n_core = ims->protocol;
+    FrameMgr fm;
+    extern XimFrameRec preedit_caret_reply_fr[];
+    IMPreeditCBStruct *preedit_CB =
+        (IMPreeditCBStruct *) &call_data->preedit_callback;
+    XIMPreeditCaretCallbackStruct *caret =
+        (XIMPreeditCaretCallbackStruct *) & preedit_CB->todo.caret;
+    CARD16 connect_id = call_data->any.connect_id;
+    CARD16 input_method_ID;
+
+    fm = FrameMgrInit (preedit_caret_reply_fr,
+                       (char *) p,
+                       _Xi18nNeedSwap (i18n_core, connect_id));
+    /* get data */
+    FrameMgrGetToken (fm, input_method_ID);
+    FrameMgrGetToken (fm, preedit_CB->icid);
+    FrameMgrGetToken (fm, caret->position);
+
+    FrameMgrFree (fm);
+
+    if (i18n_core->address.improto)
+    {
+        if (!(i18n_core->address.improto(ims, call_data)))
+            return;
+        /*endif*/
+    }
+    /*endif*/
+}
+
+void StrConvReplyMessageProc (XIMS ims,
+                              IMProtocol *call_data,
+                              unsigned char *p)
+{
+    return;
+}
+
+static void AddQueue (Xi18nClient *client, unsigned char *p)
+{
+    XIMPending *new;
+    XIMPending *last;
+
+    if ((new = (XIMPending *) malloc (sizeof (XIMPending))) == NULL)
+        return;
+    /*endif*/
+    new->p = p;
+    new->next = (XIMPending *) NULL;
+    if (!client->pending)
+    {
+        client->pending = new;
+    }
+    else
+    {
+        for (last = client->pending;  last->next;  last = last->next)
+            ;
+        /*endfor*/
+        last->next = new;
+    }
+    /*endif*/
+    return;
+}
+
+static void ProcessQueue (XIMS ims, CARD16 connect_id)
+{
+    Xi18n i18n_core = ims->protocol;
+    Xi18nClient *client = (Xi18nClient *) _Xi18nFindClient (i18n_core,
+                                                            connect_id);
+
+    while (client->sync == False  &&  client->pending)
+    {
+        XimProtoHdr *hdr = (XimProtoHdr *) client->pending->p;
+        unsigned char *p1 = (unsigned char *) (hdr + 1);
+        IMProtocol call_data;
+
+        call_data.major_code = hdr->major_opcode;
+        call_data.any.minor_code = hdr->minor_opcode;
+        call_data.any.connect_id = connect_id;
+
+        switch (hdr->major_opcode)
+        {
+        case XIM_FORWARD_EVENT:
+            ForwardEventMessageProc(ims, &call_data, p1);
+            break;
+        }
+        /*endswitch*/
+        XFree (hdr);
+        {
+            XIMPending *old = client->pending;
+
+            client->pending = old->next;
+            XFree (old);
+        }
+    }
+    /*endwhile*/
+    return;
+}
+
+
+void _Xi18nMessageHandler (XIMS ims,
+                           CARD16 connect_id,
+                           unsigned char *p,
+                           Bool *delete)
+{
+    XimProtoHdr        *hdr = (XimProtoHdr *)p;
+    unsigned char *p1 = (unsigned char *)(hdr + 1);
+    IMProtocol call_data;
+    Xi18n i18n_core = ims->protocol;
+    Xi18nClient *client;
+
+    client = (Xi18nClient *) _Xi18nFindClient (i18n_core, connect_id);
+    if (hdr == (XimProtoHdr *) NULL)
+        return;
+    /*endif*/
+    
+    memset (&call_data, 0, sizeof(IMProtocol));
+
+    call_data.major_code = hdr->major_opcode;
+    call_data.any.minor_code = hdr->minor_opcode;
+    call_data.any.connect_id = connect_id;
+
+    switch (call_data.major_code)
+    {
+    case XIM_CONNECT:
+#ifdef XIM_DEBUG
+       DebugLog("-- XIM_CONNECT\n");
+#endif
+        ConnectMessageProc (ims, &call_data, p1);
+        break;
+
+    case XIM_DISCONNECT:
+#ifdef XIM_DEBUG
+       DebugLog("-- XIM_DISCONNECT\n");
+#endif
+        DisConnectMessageProc (ims, &call_data);
+        break;
+
+    case XIM_OPEN:
+#ifdef XIM_DEBUG
+       DebugLog("-- XIM_OPEN\n");
+#endif
+        OpenMessageProc (ims, &call_data, p1);
+        break;
+
+    case XIM_CLOSE:
+#ifdef XIM_DEBUG
+       DebugLog("-- XIM_CLOSE\n");
+#endif
+        CloseMessageProc (ims, &call_data, p1);
+        break;
+
+    case XIM_QUERY_EXTENSION:
+#ifdef XIM_DEBUG
+       DebugLog("-- XIM_QUERY_EXTENSION\n");
+#endif
+        QueryExtensionMessageProc (ims, &call_data, p1);
+        break;
+
+    case XIM_GET_IM_VALUES:
+#ifdef XIM_DEBUG
+       DebugLog("-- XIM_GET_IM_VALUES\n");
+#endif
+        GetIMValuesMessageProc (ims, &call_data, p1);
+        break;
+
+    case XIM_CREATE_IC:
+#ifdef XIM_DEBUG
+       DebugLog("-- XIM_CREATE_IC\n");
+#endif
+        CreateICMessageProc (ims, &call_data, p1);
+        break;
+
+    case XIM_SET_IC_VALUES:
+#ifdef XIM_DEBUG
+       DebugLog("-- XIM_SET_IC_VALUES\n");
+#endif
+        SetICValuesMessageProc (ims, &call_data, p1);
+        break;
+
+    case XIM_GET_IC_VALUES:
+#ifdef XIM_DEBUG
+       DebugLog("-- XIM_GET_IC_VALUES\n");
+#endif
+        GetICValuesMessageProc (ims, &call_data, p1);
+        break;
+
+    case XIM_SET_IC_FOCUS:
+#ifdef XIM_DEBUG
+       DebugLog("-- XIM_SET_IC_FOCUS\n");
+#endif
+        SetICFocusMessageProc (ims, &call_data, p1);
+        break;
+
+    case XIM_UNSET_IC_FOCUS:
+#ifdef XIM_DEBUG
+       DebugLog("-- XIM_UNSET_IC_FOCUS\n");
+#endif
+        UnsetICFocusMessageProc (ims, &call_data, p1);
+        break;
+
+    case XIM_DESTROY_IC:
+#ifdef XIM_DEBUG
+       DebugLog("-- XIM_DESTROY_IC\n");
+#endif
+        DestroyICMessageProc (ims, &call_data, p1);
+        break;
+
+    case XIM_RESET_IC:
+#ifdef XIM_DEBUG
+       DebugLog("-- XIM_RESET_IC\n");
+#endif
+        ResetICMessageProc (ims, &call_data, p1);
+        break;
+
+    case XIM_FORWARD_EVENT:
+#ifdef XIM_DEBUG
+       DebugLog("-- XIM_FORWARD_EVENT\n");
+#endif
+        if (client->sync == True)
+        {
+            AddQueue (client, p);
+            *delete = False;
+        }
+        else
+        {
+            ForwardEventMessageProc (ims, &call_data, p1);
+        }
+        break;
+
+    case XIM_EXTENSION:
+#ifdef XIM_DEBUG
+       DebugLog("-- XIM_EXTENSION\n");
+#endif
+        ExtensionMessageProc (ims, &call_data, p1);
+        break;
+
+    case XIM_SYNC:
+#ifdef XIM_DEBUG
+       DebugLog("-- XIM_SYNC\n");
+#endif
+        break;
+
+    case XIM_SYNC_REPLY:
+#ifdef XIM_DEBUG
+       DebugLog("-- XIM_SYNC_REPLY\n");
+#endif
+        SyncReplyMessageProc (ims, &call_data, p1);
+        ProcessQueue (ims, connect_id);
+        break;
+
+    case XIM_TRIGGER_NOTIFY:
+#ifdef XIM_DEBUG
+       DebugLog("-- XIM_TRIGGER_NOTIFY\n");
+#endif
+        TriggerNotifyMessageProc (ims, &call_data, p1);
+        break;
+
+    case XIM_ENCODING_NEGOTIATION:
+#ifdef XIM_DEBUG
+       DebugLog("-- XIM_ENCODING_NEGOTIATION\n");
+#endif
+        EncodingNegotiatonMessageProc (ims, &call_data, p1);
+        break;
+
+    case XIM_PREEDIT_START_REPLY:
+#ifdef XIM_DEBUG
+       DebugLog("-- XIM_PREEDIT_START_REPLY\n");
+#endif
+        PreeditStartReplyMessageProc (ims, &call_data, p1);
+        break;
+
+    case XIM_PREEDIT_CARET_REPLY:
+#ifdef XIM_DEBUG
+       DebugLog("-- XIM_PREEDIT_CARET_REPLY\n");
+#endif
+        PreeditCaretReplyMessageProc (ims, &call_data, p1);
+        break;
+
+    case XIM_STR_CONVERSION_REPLY:
+#ifdef XIM_DEBUG
+       DebugLog("-- XIM_STR_CONVERSION_REPLY\n");
+#endif
+        StrConvReplyMessageProc (ims, &call_data, p1);
+        break;
+    }
+    /*endswitch*/
+}
diff --git a/wrapper/xim/IMdkit/i18nUtil.c b/wrapper/xim/IMdkit/i18nUtil.c
new file mode 100644 (file)
index 0000000..c07de48
--- /dev/null
@@ -0,0 +1,277 @@
+/******************************************************************
+         Copyright 1994, 1995 by Sun Microsystems, Inc.
+         Copyright 1993, 1994 by Hewlett-Packard Company
+Permission to use, copy, modify, distribute, and sell this software
+and its documentation for any purpose is hereby granted without fee,
+provided that the above copyright notice appear in all copies and
+that both that copyright notice and this permission notice appear
+in supporting documentation, and that the name of Sun Microsystems, Inc.
+and Hewlett-Packard not be used in advertising or publicity pertaining to
+distribution of the software without specific, written prior permission.
+Sun Microsystems, Inc. and Hewlett-Packard make no representations about
+the suitability of this software for any purpose.  It is provided "as is"
+without express or implied warranty.
+SUN MICROSYSTEMS INC. AND HEWLETT-PACKARD COMPANY DISCLAIMS ALL
+WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
+SUN MICROSYSTEMS, INC. AND HEWLETT-PACKARD COMPANY BE LIABLE FOR ANY
+SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
+RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
+CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
+IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+  Author: Hidetoshi Tajima(tajima@Eng.Sun.COM) Sun Microsystems, Inc.
+
+    This version tidied and debugged by Steve Underwood May 1999
+******************************************************************/
+
+#include <X11/Xlib.h>
+#include "IMdkit.h"
+#include "Xi18n.h"
+#include "FrameMgr.h"
+#include "XimFunc.h"
+
+Xi18nClient *_Xi18nFindClient (Xi18n, CARD16);
+
+int
+_Xi18nNeedSwap (Xi18n i18n_core, CARD16 connect_id)
+{
+    CARD8 im_byteOrder = i18n_core->address.im_byteOrder;
+    Xi18nClient *client = _Xi18nFindClient (i18n_core, connect_id);
+
+    return (client->byte_order != im_byteOrder);
+}
+
+Xi18nClient *_Xi18nNewClient(Xi18n i18n_core)
+{
+    static CARD16 connect_id = 0;
+    int new_connect_id;
+    Xi18nClient *client;
+
+    if (i18n_core->address.free_clients)
+    {
+        client = i18n_core->address.free_clients;
+        i18n_core->address.free_clients = client->next;
+       new_connect_id = client->connect_id;
+    }
+    else
+    {
+        client = (Xi18nClient *) malloc (sizeof (Xi18nClient));
+       new_connect_id = ++connect_id;
+    }
+    /*endif*/
+    memset (client, 0, sizeof (Xi18nClient));
+    client->connect_id = new_connect_id;
+    client->pending = (XIMPending *) NULL;
+    client->sync = False;
+    client->byte_order = '?';  /* initial value */
+    memset (&client->pending, 0, sizeof (XIMPending *));
+    client->property_offset = 0;
+    client->next = i18n_core->address.clients;
+    i18n_core->address.clients = client;
+
+    return (Xi18nClient *) client;
+}
+
+Xi18nClient *_Xi18nFindClient (Xi18n i18n_core, CARD16 connect_id)
+{
+    Xi18nClient *client = i18n_core->address.clients;
+
+    while (client)
+    {
+        if (client->connect_id == connect_id)
+            return client;
+        /*endif*/
+        client = client->next;
+    }
+    /*endwhile*/
+    return NULL;
+}
+
+void _Xi18nDeleteClient (Xi18n i18n_core, CARD16 connect_id)
+{
+    Xi18nClient *target = _Xi18nFindClient (i18n_core, connect_id);
+    Xi18nClient *ccp;
+    Xi18nClient *ccp0;
+
+    for (ccp = i18n_core->address.clients, ccp0 = NULL;
+         ccp != NULL;
+         ccp0 = ccp, ccp = ccp->next)
+    {
+        if (ccp == target)
+        {
+            if (ccp0 == NULL)
+                i18n_core->address.clients = ccp->next;
+            else
+                ccp0->next = ccp->next;
+            /*endif*/
+            /* put it back to free list */
+            target->next = i18n_core->address.free_clients;
+            i18n_core->address.free_clients = target;
+            return;
+        }
+        /*endif*/
+    }
+    /*endfor*/
+}
+
+void _Xi18nSendMessage (XIMS ims,
+                        CARD16 connect_id,
+                        CARD8 major_opcode,
+                        CARD8 minor_opcode,
+                        unsigned char *data,
+                        long length)
+{
+    Xi18n i18n_core = ims->protocol;
+    FrameMgr fm;
+    extern XimFrameRec packet_header_fr[];
+    unsigned char *reply_hdr = NULL;
+    int header_size;
+    unsigned char *reply = NULL;
+    unsigned char *replyp;
+    int reply_length;
+    long p_len = length/4;
+
+    fm = FrameMgrInit (packet_header_fr,
+                       NULL,
+                       _Xi18nNeedSwap (i18n_core, connect_id));
+
+    header_size = FrameMgrGetTotalSize (fm);
+    reply_hdr = (unsigned char *) malloc (header_size);
+    if (reply_hdr == NULL)
+    {
+        _Xi18nSendMessage (ims, connect_id, XIM_ERROR, 0, 0, 0);
+        return;
+    }
+    /*endif*/
+    FrameMgrSetBuffer (fm, reply_hdr);
+
+    /* put data */
+    FrameMgrPutToken (fm, major_opcode);
+    FrameMgrPutToken (fm, minor_opcode);
+    FrameMgrPutToken (fm, p_len);
+
+    reply_length = header_size + length;
+    reply = (unsigned char *) malloc (reply_length);
+    replyp = reply;
+    memmove (reply, reply_hdr, header_size);
+    replyp += header_size;
+    memmove (replyp, data, length);
+
+    i18n_core->methods.send (ims, connect_id, reply, reply_length);
+
+    XFree (reply);
+    XFree (reply_hdr);
+    FrameMgrFree (fm);
+}
+
+void _Xi18nSendTriggerKey (XIMS ims, CARD16 connect_id)
+{
+    Xi18n i18n_core = ims->protocol;
+    FrameMgr fm;
+    extern XimFrameRec register_triggerkeys_fr[];
+    XIMTriggerKey *on_keys = i18n_core->address.on_keys.keylist;
+    XIMTriggerKey *off_keys = i18n_core->address.off_keys.keylist;
+    int on_key_num = i18n_core->address.on_keys.count_keys;
+    int off_key_num = i18n_core->address.off_keys.count_keys;
+    unsigned char *reply = NULL;
+    register int i, total_size;
+    CARD16 im_id;
+
+    if (on_key_num == 0  &&  off_key_num == 0)
+        return;
+    /*endif*/
+    
+    fm = FrameMgrInit (register_triggerkeys_fr,
+                       NULL,
+                       _Xi18nNeedSwap (i18n_core, connect_id));
+
+    /* set iteration count for on-keys list */
+    FrameMgrSetIterCount (fm, on_key_num);
+    /* set iteration count for off-keys list */
+    FrameMgrSetIterCount (fm, off_key_num);
+
+    /* get total_size */
+    total_size = FrameMgrGetTotalSize (fm);
+
+    reply = (unsigned char *) malloc (total_size);
+    if (!reply)
+        return;
+    /*endif*/
+    memset (reply, 0, total_size);
+    FrameMgrSetBuffer (fm, reply);
+
+    /* Right now XIM_OPEN_REPLY hasn't been sent to this new client, so
+       the input-method-id is still invalid, and should be set to zero...
+       Reter to $(XC)/lib/X11/imDefLkup.c:_XimRegisterTriggerKeysCallback
+     */
+    im_id = 0;
+    FrameMgrPutToken (fm, im_id);  /* input-method-id */
+    for (i = 0;  i < on_key_num;  i++)
+    {
+        FrameMgrPutToken (fm, on_keys[i].keysym);
+        FrameMgrPutToken (fm, on_keys[i].modifier);
+        FrameMgrPutToken (fm, on_keys[i].modifier_mask);
+    }
+    /*endfor*/
+    for (i = 0;  i < off_key_num;  i++)
+    {
+        FrameMgrPutToken (fm, off_keys[i].keysym);
+        FrameMgrPutToken (fm, off_keys[i].modifier);
+        FrameMgrPutToken (fm, off_keys[i].modifier_mask);
+    }
+    /*endfor*/
+    _Xi18nSendMessage (ims,
+                       connect_id,
+                       XIM_REGISTER_TRIGGERKEYS,
+                       0,
+                       reply,
+                       total_size);
+    FrameMgrFree (fm);
+    XFree(reply);
+}
+
+void _Xi18nSetEventMask (XIMS ims,
+                         CARD16 connect_id,
+                         CARD16 im_id,
+                         CARD16 ic_id,
+                         CARD32 forward_mask,
+                         CARD32 sync_mask)
+{
+    Xi18n i18n_core = ims->protocol;
+    FrameMgr fm;
+    extern XimFrameRec set_event_mask_fr[];
+    unsigned char *reply = NULL;
+    register int total_size;
+
+    fm = FrameMgrInit (set_event_mask_fr,
+                       NULL,
+                       _Xi18nNeedSwap (i18n_core, connect_id));
+
+    total_size = FrameMgrGetTotalSize (fm);
+    reply = (unsigned char *) malloc (total_size);
+    if (!reply)
+        return;
+    /*endif*/
+    memset (reply, 0, total_size);
+    FrameMgrSetBuffer (fm, reply);
+
+    FrameMgrPutToken (fm, im_id);      /* input-method-id */
+    FrameMgrPutToken (fm, ic_id);      /* input-context-id */
+    FrameMgrPutToken (fm, forward_mask);
+    FrameMgrPutToken (fm, sync_mask);
+
+    _Xi18nSendMessage (ims,
+                       connect_id,
+                       XIM_SET_EVENT_MASK,
+                       0,
+                       reply,
+                       total_size);
+
+    FrameMgrFree (fm);
+    XFree(reply);
+}
diff --git a/wrapper/xim/IMdkit/i18nX.c b/wrapper/xim/IMdkit/i18nX.c
new file mode 100644 (file)
index 0000000..a47e2a5
--- /dev/null
@@ -0,0 +1,524 @@
+/******************************************************************
+
+         Copyright 1994, 1995 by Sun Microsystems, Inc.
+         Copyright 1993, 1994 by Hewlett-Packard Company
+
+Permission to use, copy, modify, distribute, and sell this software
+and its documentation for any purpose is hereby granted without fee,
+provided that the above copyright notice appear in all copies and
+that both that copyright notice and this permission notice appear
+in supporting documentation, and that the name of Sun Microsystems, Inc.
+and Hewlett-Packard not be used in advertising or publicity pertaining to
+distribution of the software without specific, written prior permission.
+Sun Microsystems, Inc. and Hewlett-Packard make no representations about
+the suitability of this software for any purpose.  It is provided "as is"
+without express or implied warranty.
+
+SUN MICROSYSTEMS INC. AND HEWLETT-PACKARD COMPANY DISCLAIMS ALL
+WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
+SUN MICROSYSTEMS, INC. AND HEWLETT-PACKARD COMPANY BE LIABLE FOR ANY
+SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
+RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
+CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
+IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+  Author: Hidetoshi Tajima(tajima@Eng.Sun.COM) Sun Microsystems, Inc.
+
+    This version tidied and debugged by Steve Underwood May 1999
+
+******************************************************************/
+
+#include <limits.h>
+#include <X11/Xlib.h>
+#include <X11/Xatom.h>
+#include "FrameMgr.h"
+#include "IMdkit.h"
+#include "Xi18n.h"
+#include "Xi18nX.h"
+#include "XimFunc.h"
+
+extern Xi18nClient *_Xi18nFindClient(Xi18n, CARD16);
+extern Xi18nClient *_Xi18nNewClient(Xi18n);
+extern void _Xi18nDeleteClient(Xi18n, CARD16);
+static Bool WaitXConnectMessage(Display*, Window,
+                                XEvent*, XPointer);
+static Bool WaitXIMProtocol(Display*, Window, XEvent*, XPointer);
+
+static XClient *NewXClient (Xi18n i18n_core, Window new_client)
+{
+    Display *dpy = i18n_core->address.dpy;
+    Xi18nClient *client = _Xi18nNewClient (i18n_core);
+    XClient *x_client;
+
+    x_client = (XClient *) malloc (sizeof (XClient));
+    x_client->client_win = new_client;
+    x_client->accept_win = XCreateSimpleWindow (dpy,
+                                                DefaultRootWindow(dpy),
+                                                0,
+                                                0,
+                                                1,
+                                                1,
+                                                1,
+                                                0,
+                                                0);
+    client->trans_rec = x_client;
+    return ((XClient *) x_client);
+}
+
+static unsigned char *ReadXIMMessage (XIMS ims,
+                                      XClientMessageEvent *ev,
+                                      int *connect_id)
+{
+    Xi18n i18n_core = ims->protocol;
+    Xi18nClient *client = i18n_core->address.clients;
+    XClient *x_client = NULL;
+    FrameMgr fm;
+    extern XimFrameRec packet_header_fr[];
+    unsigned char *p = NULL;
+    unsigned char *p1;
+
+    while (client != NULL) {
+        x_client = (XClient *) client->trans_rec;
+        if (x_client->accept_win == ev->window) {
+            *connect_id = client->connect_id;
+            break;
+        }
+        client = client->next;
+    }
+
+    if (ev->format == 8) {
+        /* ClientMessage only */
+        XimProtoHdr *hdr = (XimProtoHdr *) ev->data.b;
+        unsigned char *rec = (unsigned char *) (hdr + 1);
+        register int total_size;
+        CARD8 major_opcode;
+        CARD8 minor_opcode;
+        CARD16 length;
+        extern int _Xi18nNeedSwap (Xi18n, CARD16);
+
+        if (client->byte_order == '?')
+        {
+            if (hdr->major_opcode != XIM_CONNECT)
+                return (unsigned char *) NULL; /* can do nothing */
+            client->byte_order = (CARD8) rec[0];
+        }
+
+        fm = FrameMgrInit (packet_header_fr,
+                           (char *) hdr,
+                           _Xi18nNeedSwap (i18n_core, *connect_id));
+        total_size = FrameMgrGetTotalSize (fm);
+        /* get data */
+        FrameMgrGetToken (fm, major_opcode);
+        FrameMgrGetToken (fm, minor_opcode);
+        FrameMgrGetToken (fm, length);
+        FrameMgrFree (fm);
+
+        if ((p = (unsigned char *) malloc (total_size + length * 4)) == NULL)
+            return (unsigned char *) NULL;
+
+        p1 = p;
+        memmove (p1, &major_opcode, sizeof (CARD8));
+        p1 += sizeof (CARD8);
+        memmove (p1, &minor_opcode, sizeof (CARD8));
+        p1 += sizeof (CARD8);
+        memmove (p1, &length, sizeof (CARD16));
+        p1 += sizeof (CARD16);
+        memmove (p1, rec, length * 4);
+    }
+    else if (ev->format == 32) {
+        /* ClientMessage and WindowProperty */
+        unsigned long length = (unsigned long) ev->data.l[0];
+        unsigned long get_length;
+        Atom atom = (Atom) ev->data.l[1];
+        int return_code;
+        Atom actual_type_ret;
+        int actual_format_ret;
+        unsigned long bytes_after_ret;
+        unsigned char *prop;
+        unsigned long nitems;
+
+        /* Round up length to next 4 byte value. */
+        get_length = length + 3;
+        if (get_length > LONG_MAX)
+            get_length = LONG_MAX;
+        get_length /= 4;
+        if (get_length == 0) {
+            fprintf(stderr, "%s: invalid length 0\n", __func__);
+            return NULL;
+        }
+        return_code = XGetWindowProperty (i18n_core->address.dpy,
+                                          x_client->accept_win,
+                                          atom,
+                                          client->property_offset / 4,
+                                          get_length,
+                                          True,
+                                          AnyPropertyType,
+                                          &actual_type_ret,
+                                          &actual_format_ret,
+                                          &nitems,
+                                          &bytes_after_ret,
+                                          &prop);
+        if (return_code != Success || actual_format_ret == 0 || nitems == 0) {
+            if (return_code == Success)
+                XFree (prop);
+            client->property_offset = 0;
+            return (unsigned char *) NULL;
+        }
+        /* Update the offset to read next time as needed */
+        if (bytes_after_ret > 0)
+            client->property_offset += length;
+        else
+            client->property_offset = 0;
+        switch (actual_format_ret) {
+        case 8:
+        case 16:
+        case 32:
+            length = nitems * actual_format_ret / 8;
+            break;
+        default:
+            fprintf(stderr, "%s: unknown property return format: %d\n",
+                        __func__, actual_format_ret);
+            XFree(prop);
+            client->property_offset = 0;
+            return NULL;
+        }
+        /* if hit, it might be an error */
+        if ((p = (unsigned char *) malloc (length)) == NULL)
+            return (unsigned char *) NULL;
+
+        memmove (p, prop, length);
+        XFree (prop);
+    }
+    return (unsigned char *) p;
+}
+
+static void ReadXConnectMessage (XIMS ims, XClientMessageEvent *ev)
+{
+    Xi18n i18n_core = ims->protocol;
+    XSpecRec *spec = (XSpecRec *) i18n_core->address.connect_addr;
+    XEvent event;
+    Display *dpy = i18n_core->address.dpy;
+    Window new_client = ev->data.l[0];
+    CARD32 major_version = ev->data.l[1];
+    CARD32 minor_version = ev->data.l[2];
+    XClient *x_client = NewXClient (i18n_core, new_client);
+
+    if (ev->window != i18n_core->address.im_window)
+        return; /* incorrect connection request */
+    /*endif*/
+    if (major_version != 0  ||  minor_version != 0)
+    {
+        major_version =
+        minor_version = 0;
+        /* Only supporting only-CM & Property-with-CM method */
+    }
+    /*endif*/
+    _XRegisterFilterByType (dpy,
+                            x_client->accept_win,
+                            ClientMessage,
+                            ClientMessage,
+                            WaitXIMProtocol,
+                            (XPointer)ims);
+    event.xclient.type = ClientMessage;
+    event.xclient.display = dpy;
+    event.xclient.window = new_client;
+    event.xclient.message_type = spec->connect_request;
+    event.xclient.format = 32;
+    event.xclient.data.l[0] = x_client->accept_win;
+    event.xclient.data.l[1] = major_version;
+    event.xclient.data.l[2] = minor_version;
+    event.xclient.data.l[3] = XCM_DATA_LIMIT;
+
+    XSendEvent (dpy,
+                new_client,
+                False,
+                NoEventMask,
+                &event);
+    XFlush (dpy);
+}
+
+static Bool Xi18nXBegin (XIMS ims)
+{
+    Xi18n i18n_core = ims->protocol;
+    Display *dpy = i18n_core->address.dpy;
+    XSpecRec *spec = (XSpecRec *) i18n_core->address.connect_addr;
+
+    spec->xim_request = XInternAtom (i18n_core->address.dpy,
+                                     _XIM_PROTOCOL,
+                                     False);
+    spec->connect_request = XInternAtom (i18n_core->address.dpy,
+                                         _XIM_XCONNECT,
+                                         False);
+
+    _XRegisterFilterByType (dpy,
+                            i18n_core->address.im_window,
+                            ClientMessage,
+                            ClientMessage,
+                            WaitXConnectMessage,
+                            (XPointer)ims);
+    return True;
+}
+
+static Bool Xi18nXEnd(XIMS ims)
+{
+    Xi18n i18n_core = ims->protocol;
+    Display *dpy = i18n_core->address.dpy;
+
+    _XUnregisterFilter (dpy,
+                        i18n_core->address.im_window,
+                        WaitXConnectMessage,
+                        (XPointer)ims);
+    return True;
+}
+
+static char *MakeNewAtom (CARD16 connect_id, char *atomName)
+{
+    static int sequence = 0;
+
+    sprintf (atomName,
+             "_server%d_%d",
+             connect_id,
+             ((sequence > 20)  ?  (sequence = 0)  :  sequence++));
+    return atomName;
+}
+
+static Bool Xi18nXSend (XIMS ims,
+                        CARD16 connect_id,
+                        unsigned char *reply,
+                        long length)
+{
+    Xi18n i18n_core = ims->protocol;
+    Xi18nClient *client = _Xi18nFindClient (i18n_core, connect_id);
+    XSpecRec *spec = (XSpecRec *) i18n_core->address.connect_addr;
+    XClient *x_client = (XClient *) client->trans_rec;
+    XEvent event;
+
+    memset(&event, 0, sizeof(XEvent));
+    event.type = ClientMessage;
+    event.xclient.serial = 0;
+    event.xclient.send_event = True;
+    event.xclient.display = i18n_core->address.dpy;
+    event.xclient.window = x_client->client_win;
+    event.xclient.message_type = spec->xim_request;
+
+    if (length > XCM_DATA_LIMIT)
+    {
+        Atom atom;
+        char atomName[16];
+        Atom actual_type_ret;
+        int actual_format_ret;
+        int return_code;
+        unsigned long nitems_ret;
+        unsigned long bytes_after_ret;
+        unsigned char *win_data;
+
+        event.xclient.format = 32;
+        atom = XInternAtom (i18n_core->address.dpy,
+                            MakeNewAtom (connect_id, atomName),
+                            False);
+        return_code = XGetWindowProperty (i18n_core->address.dpy,
+                                          x_client->client_win,
+                                          atom,
+                                          0L,
+                                          10000L,
+                                          False,
+                                          XA_STRING,
+                                          &actual_type_ret,
+                                          &actual_format_ret,
+                                          &nitems_ret,
+                                          &bytes_after_ret,
+                                          &win_data);
+        if (return_code != Success)
+            return False;
+        /*endif*/
+        if (win_data)
+            XFree ((char *) win_data);
+        /*endif*/
+        XChangeProperty (i18n_core->address.dpy,
+                         x_client->client_win,
+                         atom,
+                         XA_STRING,
+                         8,
+                         PropModeAppend,
+                         (unsigned char *) reply,
+                         length);
+        event.xclient.data.l[0] = length;
+        event.xclient.data.l[1] = atom;
+    }
+    else
+    {
+        unsigned char buffer[XCM_DATA_LIMIT];
+        int i;
+
+        event.xclient.format = 8;
+
+        /* Clear unused field with NULL */
+        memmove(buffer, reply, length);
+        for (i = length; i < XCM_DATA_LIMIT; i++)
+            buffer[i] = (char) 0;
+        /*endfor*/
+        length = XCM_DATA_LIMIT;
+        memmove (event.xclient.data.b, buffer, length);
+    }
+    XSendEvent (i18n_core->address.dpy,
+                x_client->client_win,
+                False,
+                NoEventMask,
+                &event);
+    XFlush (i18n_core->address.dpy);
+    return True;
+}
+
+static Bool CheckCMEvent (Display *display, XEvent *event, XPointer xi18n_core)
+{
+    Xi18n i18n_core = (Xi18n) ((void *) xi18n_core);
+    XSpecRec *spec = (XSpecRec *) i18n_core->address.connect_addr;
+
+    if ((event->type == ClientMessage)
+        &&
+        (event->xclient.message_type == spec->xim_request))
+    {
+        return  True;
+    }
+    /*endif*/
+    return  False;
+}
+
+static Bool Xi18nXWait (XIMS ims,
+                        CARD16 connect_id,
+                        CARD8 major_opcode,
+                        CARD8 minor_opcode)
+{
+    Xi18n i18n_core = ims->protocol;
+    XEvent event;
+    Xi18nClient *client = _Xi18nFindClient (i18n_core, connect_id);
+    XClient *x_client = (XClient *) client->trans_rec;
+
+    for (;;)
+    {
+        unsigned char *packet;
+        XimProtoHdr *hdr;
+        int connect_id_ret;
+
+        XIfEvent (i18n_core->address.dpy,
+                  &event,
+                  CheckCMEvent,
+                  (XPointer) i18n_core);
+        if (event.xclient.window == x_client->accept_win)
+        {
+            if ((packet = ReadXIMMessage (ims,
+                                          (XClientMessageEvent *) & event,
+                                          &connect_id_ret))
+                == (unsigned char*) NULL)
+            {
+                return False;
+            }
+            /*endif*/
+            hdr = (XimProtoHdr *)packet;
+
+            if ((hdr->major_opcode == major_opcode)
+                &&
+                (hdr->minor_opcode == minor_opcode))
+            {
+                return True;
+            }
+            else if (hdr->major_opcode == XIM_ERROR)
+            {
+                return False;
+            }
+            /*endif*/
+        }
+        /*endif*/
+    }
+    /*endfor*/
+}
+
+static Bool Xi18nXDisconnect (XIMS ims, CARD16 connect_id)
+{
+    Xi18n i18n_core = ims->protocol;
+    Display *dpy = i18n_core->address.dpy;
+    Xi18nClient *client = _Xi18nFindClient (i18n_core, connect_id);
+    XClient *x_client = (XClient *) client->trans_rec;
+
+    XDestroyWindow (dpy, x_client->accept_win);
+    _XUnregisterFilter (dpy,
+                        x_client->accept_win,
+                        WaitXIMProtocol,
+                        (XPointer)ims);
+    XFree (x_client);
+    _Xi18nDeleteClient (i18n_core, connect_id);
+    return True;
+}
+
+Bool _Xi18nCheckXAddress (Xi18n i18n_core,
+                          TransportSW *transSW,
+                          char *address)
+{
+    XSpecRec *spec;
+
+    if (!(spec = (XSpecRec *) malloc (sizeof (XSpecRec))))
+        return False;
+    /*endif*/
+
+    i18n_core->address.connect_addr = (XSpecRec *) spec;
+    i18n_core->methods.begin = Xi18nXBegin;
+    i18n_core->methods.end = Xi18nXEnd;
+    i18n_core->methods.send = Xi18nXSend;
+    i18n_core->methods.wait = Xi18nXWait;
+    i18n_core->methods.disconnect = Xi18nXDisconnect;
+    return True;
+}
+
+static Bool WaitXConnectMessage (Display *dpy,
+                                 Window win,
+                                 XEvent *ev,
+                                 XPointer client_data)
+{
+    XIMS ims = (XIMS)client_data;
+    Xi18n i18n_core = ims->protocol;
+    XSpecRec *spec = (XSpecRec *) i18n_core->address.connect_addr;
+
+    if (((XClientMessageEvent *) ev)->message_type
+        == spec->connect_request)
+    {
+        ReadXConnectMessage (ims, (XClientMessageEvent *) ev);
+        return True;
+    }
+    /*endif*/
+    return False;
+}
+
+static Bool WaitXIMProtocol (Display *dpy,
+                             Window win,
+                             XEvent *ev,
+                             XPointer client_data)
+{
+    extern void _Xi18nMessageHandler (XIMS, CARD16, unsigned char *, Bool *);
+    XIMS ims = (XIMS) client_data;
+    Xi18n i18n_core = ims->protocol;
+    XSpecRec *spec = (XSpecRec *) i18n_core->address.connect_addr;
+    Bool delete = True;
+    unsigned char *packet;
+    int connect_id;
+
+    if (((XClientMessageEvent *) ev)->message_type
+        == spec->xim_request)
+    {
+        if ((packet = ReadXIMMessage (ims,
+                                      (XClientMessageEvent *) ev,
+                                      &connect_id))
+            == (unsigned char *)  NULL)
+        {
+            return False;
+        }
+        /*endif*/
+        _Xi18nMessageHandler (ims, connect_id, packet, &delete);
+        if (delete == True)
+            XFree (packet);
+        /*endif*/
+        return True;
+    }
+    /*endif*/
+    return False;
+}
diff --git a/wrapper/xim/LGPL.LICENSE b/wrapper/xim/LGPL.LICENSE
new file mode 100644 (file)
index 0000000..5b9dd3b
--- /dev/null
@@ -0,0 +1,516 @@
+                 GNU LESSER GENERAL PUBLIC LICENSE
+                      Version 2.1, February 1999
+
+ Copyright (C) 1991, 1999 Free Software Foundation, Inc.
+ 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the Lesser GPL.  It also counts
+ as the successor of the GNU Library Public License, version 2, hence
+ the version number 2.1.]
+
+                           Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+  This license, the Lesser General Public License, applies to some
+specially designated software packages--typically libraries--of the
+Free Software Foundation and other authors who decide to use it.  You
+can use it too, but we suggest you first think carefully about whether
+this license or the ordinary General Public License is the better
+strategy to use in any particular case, based on the explanations below.
+
+  When we speak of free software, we are referring to freedom of use,
+not price.  Our General Public Licenses are designed to make sure that
+you have the freedom to distribute copies of free software (and charge
+for this service if you wish); that you receive source code or can get
+it if you want it; that you can change the software and use pieces of
+it in new free programs; and that you are informed that you can do
+these things.
+
+  To protect your rights, we need to make restrictions that forbid
+distributors to deny you these rights or to ask you to surrender these
+rights.  These restrictions translate to certain responsibilities for
+you if you distribute copies of the library or if you modify it.
+
+  For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you.  You must make sure that they, too, receive or can get the source
+code.  If you link other code with the library, you must provide
+complete object files to the recipients, so that they can relink them
+with the library after making changes to the library and recompiling
+it.  And you must show them these terms so they know their rights.
+
+  We protect your rights with a two-step method: (1) we copyright the
+library, and (2) we offer you this license, which gives you legal
+permission to copy, distribute and/or modify the library.
+
+  To protect each distributor, we want to make it very clear that
+there is no warranty for the free library.  Also, if the library is
+modified by someone else and passed on, the recipients should know
+that what they have is not the original version, so that the original
+author's reputation will not be affected by problems that might be
+introduced by others.
+\f
+  Finally, software patents pose a constant threat to the existence of
+any free program.  We wish to make sure that a company cannot
+effectively restrict the users of a free program by obtaining a
+restrictive license from a patent holder.  Therefore, we insist that
+any patent license obtained for a version of the library must be
+consistent with the full freedom of use specified in this license.
+
+  Most GNU software, including some libraries, is covered by the
+ordinary GNU General Public License.  This license, the GNU Lesser
+General Public License, applies to certain designated libraries, and
+is quite different from the ordinary General Public License.  We use
+this license for certain libraries in order to permit linking those
+libraries into non-free programs.
+
+  When a program is linked with a library, whether statically or using
+a shared library, the combination of the two is legally speaking a
+combined work, a derivative of the original library.  The ordinary
+General Public License therefore permits such linking only if the
+entire combination fits its criteria of freedom.  The Lesser General
+Public License permits more lax criteria for linking other code with
+the library.
+
+  We call this license the "Lesser" General Public License because it
+does Less to protect the user's freedom than the ordinary General
+Public License.  It also provides other free software developers Less
+of an advantage over competing non-free programs.  These disadvantages
+are the reason we use the ordinary General Public License for many
+libraries.  However, the Lesser license provides advantages in certain
+special circumstances.
+
+  For example, on rare occasions, there may be a special need to
+encourage the widest possible use of a certain library, so that it becomes
+a de-facto standard.  To achieve this, non-free programs must be
+allowed to use the library.  A more frequent case is that a free
+library does the same job as widely used non-free libraries.  In this
+case, there is little to gain by limiting the free library to free
+software only, so we use the Lesser General Public License.
+
+  In other cases, permission to use a particular library in non-free
+programs enables a greater number of people to use a large body of
+free software.  For example, permission to use the GNU C Library in
+non-free programs enables many more people to use the whole GNU
+operating system, as well as its variant, the GNU/Linux operating
+system.
+
+  Although the Lesser General Public License is Less protective of the
+users' freedom, it does ensure that the user of a program that is
+linked with the Library has the freedom and the wherewithal to run
+that program using a modified version of the Library.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.  Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library".  The
+former contains code derived from the library, whereas the latter must
+be combined with the library in order to run.
+\f
+                 GNU LESSER GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License Agreement applies to any software library or other
+program which contains a notice placed by the copyright holder or
+other authorized party saying it may be distributed under the terms of
+this Lesser General Public License (also called "this License").
+Each licensee is addressed as "you".
+
+  A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+  The "Library", below, refers to any such software library or work
+which has been distributed under these terms.  A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language.  (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+  "Source code" for a work means the preferred form of the work for
+making modifications to it.  For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+  Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it).  Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+  
+  1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+  You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+\f
+  2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) The modified work must itself be a software library.
+
+    b) You must cause the files modified to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    c) You must cause the whole of the work to be licensed at no
+    charge to all third parties under the terms of this License.
+
+    d) If a facility in the modified Library refers to a function or a
+    table of data to be supplied by an application program that uses
+    the facility, other than as an argument passed when the facility
+    is invoked, then you must make a good faith effort to ensure that,
+    in the event an application does not supply such function or
+    table, the facility still operates, and performs whatever part of
+    its purpose remains meaningful.
+
+    (For example, a function in a library to compute square roots has
+    a purpose that is entirely well-defined independent of the
+    application.  Therefore, Subsection 2d requires that any
+    application-supplied function or table used by this function must
+    be optional: if the application does not supply it, the square
+    root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library.  To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License.  (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.)  Do not make any other change in
+these notices.
+\f
+  Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+  This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+  4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+  If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library".  Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+  However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library".  The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+  When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library.  The
+threshold for this to be true is not precisely defined by law.
+
+  If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work.  (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+  Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+\f
+  6. As an exception to the Sections above, you may also combine or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+  You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License.  You must supply a copy of this License.  If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License.  Also, you must do one
+of these things:
+
+    a) Accompany the work with the complete corresponding
+    machine-readable source code for the Library including whatever
+    changes were used in the work (which must be distributed under
+    Sections 1 and 2 above); and, if the work is an executable linked
+    with the Library, with the complete machine-readable "work that
+    uses the Library", as object code and/or source code, so that the
+    user can modify the Library and then relink to produce a modified
+    executable containing the modified Library.  (It is understood
+    that the user who changes the contents of definitions files in the
+    Library will not necessarily be able to recompile the application
+    to use the modified definitions.)
+
+    b) Use a suitable shared library mechanism for linking with the
+    Library.  A suitable mechanism is one that (1) uses at run time a
+    copy of the library already present on the user's computer system,
+    rather than copying library functions into the executable, and (2)
+    will operate properly with a modified version of the library, if
+    the user installs one, as long as the modified version is
+    interface-compatible with the version that the work was made with.
+
+    c) Accompany the work with a written offer, valid for at
+    least three years, to give the same user the materials
+    specified in Subsection 6a, above, for a charge no more
+    than the cost of performing this distribution.
+
+    d) If distribution of the work is made by offering access to copy
+    from a designated place, offer equivalent access to copy the above
+    specified materials from the same place.
+
+    e) Verify that the user has already received a copy of these
+    materials or that you have already sent this user a copy.
+
+  For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it.  However, as a special exception,
+the materials to be distributed need not include anything that is
+normally distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+  It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system.  Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+\f
+  7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+    a) Accompany the combined library with a copy of the same work
+    based on the Library, uncombined with any other library
+    facilities.  This must be distributed under the terms of the
+    Sections above.
+
+    b) Give prominent notice with the combined library of the fact
+    that part of it is a work based on the Library, and explaining
+    where to find the accompanying uncombined form of the same work.
+
+  8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License.  Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License.  However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+  9. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Library or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+  10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties with
+this License.
+\f
+  11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded.  In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+  13. The Free Software Foundation may publish revised and/or new
+versions of the Lesser General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation.  If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+\f
+  14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission.  For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this.  Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+                           NO WARRANTY
+
+  15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU.  SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+  16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+                    END OF TERMS AND CONDITIONS
+\f
+           How to Apply These Terms to Your New Libraries
+
+  If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change.  You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+  To apply these terms, attach the following notices to the library.  It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the library's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with this library; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the
+  library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+  <signature of Ty Coon>, 1 April 1990
+  Ty Coon, President of Vice
+
+That's all there is to it!
+
+--------------------------------------------------------------------
+
+NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND
+DISTRIBUTION LICENSE (CDDL)
+
+For Covered Software in this distribution, this License shall
+be governed by the laws of the State of California (excluding
+conflict-of-law provisions).
+
+Any litigation relating to this License shall be subject to the
+jurisdiction of the Federal Courts of the Northern District of
+California and the state courts of the State of California, with
+venue lying in Santa Clara County, California.
diff --git a/wrapper/xim/OPENSOLARIS.LICENSE b/wrapper/xim/OPENSOLARIS.LICENSE
new file mode 100644 (file)
index 0000000..d838932
--- /dev/null
@@ -0,0 +1,377 @@
+COMMON DEVELOPMENT AND DISTRIBUTION LICENSE Version 1.0
+
+1. Definitions.
+
+    1.1. "Contributor" means each individual or entity that creates
+         or contributes to the creation of Modifications.
+
+    1.2. "Contributor Version" means the combination of the Original
+         Software, prior Modifications used by a Contributor (if any),
+         and the Modifications made by that particular Contributor.
+
+    1.3. "Covered Software" means (a) the Original Software, or (b)
+         Modifications, or (c) the combination of files containing
+         Original Software with files containing Modifications, in
+         each case including portions thereof.
+
+    1.4. "Executable" means the Covered Software in any form other
+         than Source Code.
+
+    1.5. "Initial Developer" means the individual or entity that first
+         makes Original Software available under this License.
+
+    1.6. "Larger Work" means a work which combines Covered Software or
+         portions thereof with code not governed by the terms of this
+         License.
+
+    1.7. "License" means this document.
+
+    1.8. "Licensable" means having the right to grant, to the maximum
+         extent possible, whether at the time of the initial grant or
+         subsequently acquired, any and all of the rights conveyed
+         herein.
+
+    1.9. "Modifications" means the Source Code and Executable form of
+         any of the following:
+
+        A. Any file that results from an addition to, deletion from or
+           modification of the contents of a file containing Original
+           Software or previous Modifications;
+
+        B. Any new file that contains any part of the Original
+           Software or previous Modifications; or
+
+        C. Any new file that is contributed or otherwise made
+           available under the terms of this License.
+
+    1.10. "Original Software" means the Source Code and Executable
+          form of computer software code that is originally released
+          under this License.
+
+    1.11. "Patent Claims" means any patent claim(s), now owned or
+          hereafter acquired, including without limitation, method,
+          process, and apparatus claims, in any patent Licensable by
+          grantor.
+
+    1.12. "Source Code" means (a) the common form of computer software
+          code in which modifications are made and (b) associated
+          documentation included in or with such code.
+
+    1.13. "You" (or "Your") means an individual or a legal entity
+          exercising rights under, and complying with all of the terms
+          of, this License.  For legal entities, "You" includes any
+          entity which controls, is controlled by, or is under common
+          control with You.  For purposes of this definition,
+          "control" means (a) the power, direct or indirect, to cause
+          the direction or management of such entity, whether by
+          contract or otherwise, or (b) ownership of more than fifty
+          percent (50%) of the outstanding shares or beneficial
+          ownership of such entity.
+
+2. License Grants.
+
+    2.1. The Initial Developer Grant.
+
+    Conditioned upon Your compliance with Section 3.1 below and
+    subject to third party intellectual property claims, the Initial
+    Developer hereby grants You a world-wide, royalty-free,
+    non-exclusive license:
+
+        (a) under intellectual property rights (other than patent or
+            trademark) Licensable by Initial Developer, to use,
+            reproduce, modify, display, perform, sublicense and
+            distribute the Original Software (or portions thereof),
+            with or without Modifications, and/or as part of a Larger
+            Work; and
+
+        (b) under Patent Claims infringed by the making, using or
+            selling of Original Software, to make, have made, use,
+            practice, sell, and offer for sale, and/or otherwise
+            dispose of the Original Software (or portions thereof).
+
+        (c) The licenses granted in Sections 2.1(a) and (b) are
+            effective on the date Initial Developer first distributes
+            or otherwise makes the Original Software available to a
+            third party under the terms of this License.
+
+        (d) Notwithstanding Section 2.1(b) above, no patent license is
+            granted: (1) for code that You delete from the Original
+            Software, or (2) for infringements caused by: (i) the
+            modification of the Original Software, or (ii) the
+            combination of the Original Software with other software
+            or devices.
+
+    2.2. Contributor Grant.
+
+    Conditioned upon Your compliance with Section 3.1 below and
+    subject to third party intellectual property claims, each
+    Contributor hereby grants You a world-wide, royalty-free,
+    non-exclusive license:
+
+        (a) under intellectual property rights (other than patent or
+            trademark) Licensable by Contributor to use, reproduce,
+            modify, display, perform, sublicense and distribute the
+            Modifications created by such Contributor (or portions
+            thereof), either on an unmodified basis, with other
+            Modifications, as Covered Software and/or as part of a
+            Larger Work; and
+
+        (b) under Patent Claims infringed by the making, using, or
+            selling of Modifications made by that Contributor either
+            alone and/or in combination with its Contributor Version
+            (or portions of such combination), to make, use, sell,
+            offer for sale, have made, and/or otherwise dispose of:
+            (1) Modifications made by that Contributor (or portions
+            thereof); and (2) the combination of Modifications made by
+            that Contributor with its Contributor Version (or portions
+            of such combination).
+
+        (c) The licenses granted in Sections 2.2(a) and 2.2(b) are
+            effective on the date Contributor first distributes or
+            otherwise makes the Modifications available to a third
+            party.
+
+        (d) Notwithstanding Section 2.2(b) above, no patent license is
+            granted: (1) for any code that Contributor has deleted
+            from the Contributor Version; (2) for infringements caused
+            by: (i) third party modifications of Contributor Version,
+            or (ii) the combination of Modifications made by that
+            Contributor with other software (except as part of the
+            Contributor Version) or other devices; or (3) under Patent
+            Claims infringed by Covered Software in the absence of
+            Modifications made by that Contributor.
+
+3. Distribution Obligations.
+
+    3.1. Availability of Source Code.
+
+    Any Covered Software that You distribute or otherwise make
+    available in Executable form must also be made available in Source
+    Code form and that Source Code form must be distributed only under
+    the terms of this License.  You must include a copy of this
+    License with every copy of the Source Code form of the Covered
+    Software You distribute or otherwise make available.  You must
+    inform recipients of any such Covered Software in Executable form
+    as to how they can obtain such Covered Software in Source Code
+    form in a reasonable manner on or through a medium customarily
+    used for software exchange.
+
+    3.2. Modifications.
+
+    The Modifications that You create or to which You contribute are
+    governed by the terms of this License.  You represent that You
+    believe Your Modifications are Your original creation(s) and/or
+    You have sufficient rights to grant the rights conveyed by this
+    License.
+
+    3.3. Required Notices.
+
+    You must include a notice in each of Your Modifications that
+    identifies You as the Contributor of the Modification.  You may
+    not remove or alter any copyright, patent or trademark notices
+    contained within the Covered Software, or any notices of licensing
+    or any descriptive text giving attribution to any Contributor or
+    the Initial Developer.
+
+    3.4. Application of Additional Terms.
+
+    You may not offer or impose any terms on any Covered Software in
+    Source Code form that alters or restricts the applicable version
+    of this License or the recipients' rights hereunder.  You may
+    choose to offer, and to charge a fee for, warranty, support,
+    indemnity or liability obligations to one or more recipients of
+    Covered Software.  However, you may do so only on Your own behalf,
+    and not on behalf of the Initial Developer or any Contributor.
+    You must make it absolutely clear that any such warranty, support,
+    indemnity or liability obligation is offered by You alone, and You
+    hereby agree to indemnify the Initial Developer and every
+    Contributor for any liability incurred by the Initial Developer or
+    such Contributor as a result of warranty, support, indemnity or
+    liability terms You offer.
+
+    3.5. Distribution of Executable Versions.
+
+    You may distribute the Executable form of the Covered Software
+    under the terms of this License or under the terms of a license of
+    Your choice, which may contain terms different from this License,
+    provided that You are in compliance with the terms of this License
+    and that the license for the Executable form does not attempt to
+    limit or alter the recipient's rights in the Source Code form from
+    the rights set forth in this License.  If You distribute the
+    Covered Software in Executable form under a different license, You
+    must make it absolutely clear that any terms which differ from
+    this License are offered by You alone, not by the Initial
+    Developer or Contributor.  You hereby agree to indemnify the
+    Initial Developer and every Contributor for any liability incurred
+    by the Initial Developer or such Contributor as a result of any
+    such terms You offer.
+
+    3.6. Larger Works.
+
+    You may create a Larger Work by combining Covered Software with
+    other code not governed by the terms of this License and
+    distribute the Larger Work as a single product.  In such a case,
+    You must make sure the requirements of this License are fulfilled
+    for the Covered Software.
+
+4. Versions of the License.
+
+    4.1. New Versions.
+
+    Sun Microsystems, Inc. is the initial license steward and may
+    publish revised and/or new versions of this License from time to
+    time.  Each version will be given a distinguishing version number.
+    Except as provided in Section 4.3, no one other than the license
+    steward has the right to modify this License.
+
+    4.2. Effect of New Versions.
+
+    You may always continue to use, distribute or otherwise make the
+    Covered Software available under the terms of the version of the
+    License under which You originally received the Covered Software.
+    If the Initial Developer includes a notice in the Original
+    Software prohibiting it from being distributed or otherwise made
+    available under any subsequent version of the License, You must
+    distribute and make the Covered Software available under the terms
+    of the version of the License under which You originally received
+    the Covered Software.  Otherwise, You may also choose to use,
+    distribute or otherwise make the Covered Software available under
+    the terms of any subsequent version of the License published by
+    the license steward.
+
+    4.3. Modified Versions.
+
+    When You are an Initial Developer and You want to create a new
+    license for Your Original Software, You may create and use a
+    modified version of this License if You: (a) rename the license
+    and remove any references to the name of the license steward
+    (except to note that the license differs from this License); and
+    (b) otherwise make it clear that the license contains terms which
+    differ from this License.
+
+5. DISCLAIMER OF WARRANTY.
+
+    COVERED SOFTWARE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS"
+    BASIS, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED,
+    INCLUDING, WITHOUT LIMITATION, WARRANTIES THAT THE COVERED
+    SOFTWARE IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR
+    PURPOSE OR NON-INFRINGING.  THE ENTIRE RISK AS TO THE QUALITY AND
+    PERFORMANCE OF THE COVERED SOFTWARE IS WITH YOU.  SHOULD ANY
+    COVERED SOFTWARE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT THE
+    INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE COST OF ANY
+    NECESSARY SERVICING, REPAIR OR CORRECTION.  THIS DISCLAIMER OF
+    WARRANTY CONSTITUTES AN ESSENTIAL PART OF THIS LICENSE.  NO USE OF
+    ANY COVERED SOFTWARE IS AUTHORIZED HEREUNDER EXCEPT UNDER THIS
+    DISCLAIMER.
+
+6. TERMINATION.
+
+    6.1. This License and the rights granted hereunder will terminate
+    automatically if You fail to comply with terms herein and fail to
+    cure such breach within 30 days of becoming aware of the breach.
+    Provisions which, by their nature, must remain in effect beyond
+    the termination of this License shall survive.
+
+    6.2. If You assert a patent infringement claim (excluding
+    declaratory judgment actions) against Initial Developer or a
+    Contributor (the Initial Developer or Contributor against whom You
+    assert such claim is referred to as "Participant") alleging that
+    the Participant Software (meaning the Contributor Version where
+    the Participant is a Contributor or the Original Software where
+    the Participant is the Initial Developer) directly or indirectly
+    infringes any patent, then any and all rights granted directly or
+    indirectly to You by such Participant, the Initial Developer (if
+    the Initial Developer is not the Participant) and all Contributors
+    under Sections 2.1 and/or 2.2 of this License shall, upon 60 days
+    notice from Participant terminate prospectively and automatically
+    at the expiration of such 60 day notice period, unless if within
+    such 60 day period You withdraw Your claim with respect to the
+    Participant Software against such Participant either unilaterally
+    or pursuant to a written agreement with Participant.
+
+    6.3. In the event of termination under Sections 6.1 or 6.2 above,
+    all end user licenses that have been validly granted by You or any
+    distributor hereunder prior to termination (excluding licenses
+    granted to You by any distributor) shall survive termination.
+
+7. LIMITATION OF LIABILITY.
+
+    UNDER NO CIRCUMSTANCES AND UNDER NO LEGAL THEORY, WHETHER TORT
+    (INCLUDING NEGLIGENCE), CONTRACT, OR OTHERWISE, SHALL YOU, THE
+    INITIAL DEVELOPER, ANY OTHER CONTRIBUTOR, OR ANY DISTRIBUTOR OF
+    COVERED SOFTWARE, OR ANY SUPPLIER OF ANY OF SUCH PARTIES, BE
+    LIABLE TO ANY PERSON FOR ANY INDIRECT, SPECIAL, INCIDENTAL, OR
+    CONSEQUENTIAL DAMAGES OF ANY CHARACTER INCLUDING, WITHOUT
+    LIMITATION, DAMAGES FOR LOST PROFITS, LOSS OF GOODWILL, WORK
+    STOPPAGE, COMPUTER FAILURE OR MALFUNCTION, OR ANY AND ALL OTHER
+    COMMERCIAL DAMAGES OR LOSSES, EVEN IF SUCH PARTY SHALL HAVE BEEN
+    INFORMED OF THE POSSIBILITY OF SUCH DAMAGES.  THIS LIMITATION OF
+    LIABILITY SHALL NOT APPLY TO LIABILITY FOR DEATH OR PERSONAL
+    INJURY RESULTING FROM SUCH PARTY'S NEGLIGENCE TO THE EXTENT
+    APPLICABLE LAW PROHIBITS SUCH LIMITATION.  SOME JURISDICTIONS DO
+    NOT ALLOW THE EXCLUSION OR LIMITATION OF INCIDENTAL OR
+    CONSEQUENTIAL DAMAGES, SO THIS EXCLUSION AND LIMITATION MAY NOT
+    APPLY TO YOU.
+
+8. U.S. GOVERNMENT END USERS.
+
+    The Covered Software is a "commercial item," as that term is
+    defined in 48 C.F.R. 2.101 (Oct. 1995), consisting of "commercial
+    computer software" (as that term is defined at 48
+    C.F.R. 252.227-7014(a)(1)) and "commercial computer software
+    documentation" as such terms are used in 48 C.F.R. 12.212
+    (Sept. 1995).  Consistent with 48 C.F.R. 12.212 and 48
+    C.F.R. 227.7202-1 through 227.7202-4 (June 1995), all
+    U.S. Government End Users acquire Covered Software with only those
+    rights set forth herein.  This U.S. Government Rights clause is in
+    lieu of, and supersedes, any other FAR, DFAR, or other clause or
+    provision that addresses Government rights in computer software
+    under this License.
+
+9. MISCELLANEOUS.
+
+    This License represents the complete agreement concerning subject
+    matter hereof.  If any provision of this License is held to be
+    unenforceable, such provision shall be reformed only to the extent
+    necessary to make it enforceable.  This License shall be governed
+    by the law of the jurisdiction specified in a notice contained
+    within the Original Software (except to the extent applicable law,
+    if any, provides otherwise), excluding such jurisdiction's
+    conflict-of-law provisions.  Any litigation relating to this
+    License shall be subject to the jurisdiction of the courts located
+    in the jurisdiction and venue specified in a notice contained
+    within the Original Software, with the losing party responsible
+    for costs, including, without limitation, court costs and
+    reasonable attorneys' fees and expenses.  The application of the
+    United Nations Convention on Contracts for the International Sale
+    of Goods is expressly excluded.  Any law or regulation which
+    provides that the language of a contract shall be construed
+    against the drafter shall not apply to this License.  You agree
+    that You alone are responsible for compliance with the United
+    States export administration regulations (and the export control
+    laws and regulation of any other countries) when You use,
+    distribute or otherwise make available any Covered Software.
+
+10. RESPONSIBILITY FOR CLAIMS.
+
+    As between Initial Developer and the Contributors, each party is
+    responsible for claims and damages arising, directly or
+    indirectly, out of its utilization of rights under this License
+    and You agree to work with Initial Developer and Contributors to
+    distribute such responsibility on an equitable basis.  Nothing
+    herein is intended or shall be deemed to constitute any admission
+    of liability.
+
+--------------------------------------------------------------------
+
+NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND
+DISTRIBUTION LICENSE (CDDL)
+
+For Covered Software in this distribution, this License shall
+be governed by the laws of the State of California (excluding
+conflict-of-law provisions).
+
+Any litigation relating to this License shall be subject to the
+jurisdiction of the Federal Courts of the Northern District of
+California and the state courts of the State of California, with
+venue lying in Santa Clara County, California.
diff --git a/wrapper/xim/README b/wrapper/xim/README
new file mode 100644 (file)
index 0000000..563449a
--- /dev/null
@@ -0,0 +1,4 @@
+xsunpinyin
+===
+
+xsunpinyin is a standalone XIM server that uses SunPinyin input methord. 
diff --git a/wrapper/xim/SConstruct b/wrapper/xim/SConstruct
new file mode 100644 (file)
index 0000000..495871d
--- /dev/null
@@ -0,0 +1,151 @@
+import os
+
+sources = ['ic.c',
+           'ic_gtk.c',
+           'ic_skin.c',
+           'skin.c',
+           'ui.c',
+           'main.c',
+           'settings.c',
+           'sunpinyin_preedit.cc',
+           'sunpinyin_preedit_gtk.cc',
+           'sunpinyin_preedit_skin.cc',
+           'xim.c',
+           'xim_trigger.c',
+           'xmisc.c']
+
+preferences_sources = ['preferences.c',
+                       'settings.c',
+                       'xmisc.c']
+
+imdkit_sources = ['IMdkit/FrameMgr.c',
+                  'IMdkit/i18nAttr.c',
+                  'IMdkit/i18nClbk.c',
+                  'IMdkit/i18nIc.c',
+                  'IMdkit/i18nIMProto.c',
+                  'IMdkit/i18nMethod.c',
+                  'IMdkit/i18nPtHdr.c',
+                  'IMdkit/i18nUtil.c',
+                  'IMdkit/i18nX.c',
+                  'IMdkit/IMConn.c',
+                  'IMdkit/IMMethod.c',
+                  'IMdkit/IMValues.c']
+
+
+cflags='-O2 -g -pipe '
+
+# options
+AddOption('--prefix', dest='prefix', type='string', nargs=1, action='store',
+          metavar='DIR', help='installation prefix')
+AddOption('--rpath', dest='rpath', type='string', nargs=1, action='store',
+          metavar='DIR', help='encode rpath in the executables')
+
+# save the options
+opts = Variables('configure.conf')
+opts.Add('PREFIX', default='/usr/local')
+
+def PassVariables(envvar, env):
+    for (x, y) in envvar:
+        if x in os.environ:
+            print 'Warning: you\'ve set %s in the environmental variable!' % x
+            env[y] = os.environ[x]
+
+env = Environment(ENV=os.environ,
+                  CFLAGS=cflags, CXXFLAGS=cflags,
+                  CPPPATH=['.', 'IMdkit'])
+opts.Update(env)
+
+
+if GetOption('prefix') is not None:
+    env['PREFIX'] = GetOption('prefix')
+
+opts.Save('configure.conf', env)
+
+envvar = [('CC', 'CC'),
+          ('CXX', 'CXX'),
+          ('CFLAGS', 'CFLAGS'),
+          ('CXXFLAGS', 'CXXFLAGS'),
+          ('LDFLAGS', 'LINKFLAGS')]
+PassVariables(envvar, env)
+
+bin_dir = env['PREFIX'] + '/bin'
+data_dir = '%s/share/xsunpinyin/' % env['PREFIX']
+icon_dir = data_dir + 'icons/'
+
+extra_cflags =  ' -DSUNPINYIN_XIM_ICON_DIR=\\"%s\\"' % icon_dir
+extra_cflags += ' -DSUNPINYIN_XIM_SETTING_DIR=\\"%s\\"' % data_dir
+
+env.Append(CFLAGS=extra_cflags)
+env.Append(CXXFLAGS=extra_cflags)
+env.Append(LINKFLAGS=' -export-dynamic')
+
+# set rpath
+if GetOption('rpath') is not None:
+    env.Append(LINKFLAGS=' -Wl,-R -Wl,%s' % GetOption('rpath'))
+
+#
+#==============================configure================================
+#
+def CheckPKGConfig(context, version='0.12.0'):
+    context.Message( 'Checking for pkg-config... ' )
+    ret = context.TryAction('pkg-config --atleast-pkgconfig-version=%s' % version)[0]
+    context.Result(ret)
+    return ret
+
+def CheckPKG(context, name):
+    context.Message( 'Checking for %s... ' % name )
+    ret = context.TryAction('pkg-config --exists \'%s\'' % name)[0]
+    context.Result(ret)
+    return ret
+
+conf = Configure(env, custom_tests={'CheckPKGConfig' : CheckPKGConfig,
+                                    'CheckPKG' : CheckPKG })
+def DoConfigure():
+    if GetOption('clean'):
+        return
+
+    if not conf.CheckPKGConfig():
+        Exit(1)
+
+    if not conf.CheckPKG('gtk+-2.0'):
+        Exit(1)
+
+    if not conf.CheckPKG('x11'):
+        Exit(1)
+
+    if not conf.CheckPKG('sunpinyin-2.0'):
+        Exit(1)
+
+    env = conf.Finish()
+    env.ParseConfig('pkg-config gtk+-2.0 x11 sunpinyin-2.0 --libs --cflags')
+
+DoConfigure()
+
+env.Append(LIBS=env.Library('IMdkit', source=imdkit_sources))
+env.Program('xsunpinyin', source=sources)
+env.Program('xsunpinyin-preferences', source=preferences_sources)
+
+
+def DoInstall():
+    bin_target = env.Install(bin_dir,
+                             ['xsunpinyin', 'xsunpinyin-preferences'])
+    icon_target = env.Install(icon_dir,
+                              ['data/chnpunc.png',
+                               'data/han.png',
+                               'data/eng.png',
+                               'data/han.svg',
+                               'data/eng.svg',
+                               'data/engpunc.png',
+                               'data/full.png',
+                               'data/half.png',
+                               'data/sunpinyin-logo-big.png',
+                               'data/sunpinyin-logo.png'])
+    data_target = env.Install(data_dir, ['data/settings_ui.xml'])
+    data_target += env.Install(data_dir + 'skins/', Glob('data/skins/*'))
+    env.Alias('install-bin', bin_target)
+    env.Alias('install-data', [icon_target, data_target])
+
+DoInstall()
+env.Alias('install', ['install-bin', 'install-data'])
+
+
diff --git a/wrapper/xim/common.h b/wrapper/xim/common.h
new file mode 100644 (file)
index 0000000..4e2c5cf
--- /dev/null
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2010 Mike Qin <mikeandmore@gmail.com>
+ *
+ * The contents of this file are subject to the terms of either the GNU Lesser
+ * General Public License Version 2.1 only ("LGPL") or the Common Development and
+ * Distribution License ("CDDL")(collectively, the "License"). You may not use this
+ * file except in compliance with the License. You can obtain a copy of the CDDL at
+ * http://www.opensource.org/licenses/cddl1.php and a copy of the LGPLv2.1 at
+ * http://www.opensource.org/licenses/lgpl-license.php. See the License for the
+ * specific language governing permissions and limitations under the License. When
+ * distributing the software, include this License Header Notice in each file and
+ * include the full text of the License in the License file as well as the
+ * following notice:
+ *
+ * NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND DISTRIBUTION LICENSE
+ * (CDDL)
+ * For Covered Software in this distribution, this License shall be governed by the
+ * laws of the State of California (excluding conflict-of-law provisions).
+ * Any litigation relating to this License shall be subject to the jurisdiction of
+ * the Federal Courts of the Northern District of California and the state courts
+ * of the State of California, with venue lying in Santa Clara County, California.
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by only the CDDL or only
+ * the LGPL Version 2.1, indicate your decision by adding "[Contributor]" elects to
+ * include this software in this distribution under the [CDDL or LGPL Version 2.1]
+ * license." If you don't indicate a single choice of license, a recipient has the
+ * option to distribute your version of this file under either the CDDL or the LGPL
+ * Version 2.1, or to extend the choice of license to its licensees as provided
+ * above. However, if you add LGPL Version 2.1 code and therefore, elected the LGPL
+ * Version 2 license, then the option applies only if the new code is made subject
+ * to such option by the copyright holder.
+ */
+
+#ifndef _COMMON_H_
+#define _COMMON_H_
+
+#include <stdio.h>
+#include <stdbool.h>
+
+#ifdef __cplusplus
+ # ifndef __BEGIN_DECLS
+ # define __BEGIN_DECLS extern "C" {
+ # endif
+ # ifndef __END_DECLS
+ # define __END_DECLS }
+ # endif
+#else
+ # ifndef __BEGIN_DECLS
+ # define __BEGIN_DECLS
+ # endif
+ # ifndef __END_DECLS
+ # define __END_DECLS
+ # endif
+#endif
+
+
+#ifdef __cplusplus
+#define __EXPORT_API extern "C"
+#else
+#define __EXPORT_API
+#endif
+
+#ifdef LOG_ENABLED
+
+
+#define __PRINT(label, ...)                             \
+    do {                                                \
+        fprintf(stderr, "[%s] %s at %s: ", label,       \
+                __FILE__, __FUNCTION__);                \
+        fprintf(stderr, __VA_ARGS__);                   \
+        fprintf(stderr, "\n");                          \
+    } while (0)                                         \
+
+#define LOG(...) __PRINT("log",  __VA_ARGS__)
+#define DEBUG(...) __PRINT("debug",  __VA_ARGS__)
+#else
+#define LOG(...)
+#define DEBUG(...)
+#endif
+
+#define XIM_VERSION "2.0.3"
+#define XIM_PROGRAM_NAME "SunPinyin-XIM"
+#define XIM_WEBSITE "http://mike.struct.cn/sunpinyin-xim"
+#define XIM_COMMENTS "a XIM front-end for SunPinyin."
+
+
+#endif /* _COMMON_H_ */
diff --git a/wrapper/xim/data/chnpunc.png b/wrapper/xim/data/chnpunc.png
new file mode 100644 (file)
index 0000000..382c0f2
Binary files /dev/null and b/wrapper/xim/data/chnpunc.png differ
diff --git a/wrapper/xim/data/eng.png b/wrapper/xim/data/eng.png
new file mode 100644 (file)
index 0000000..b66bf35
Binary files /dev/null and b/wrapper/xim/data/eng.png differ
diff --git a/wrapper/xim/data/eng.svg b/wrapper/xim/data/eng.svg
new file mode 100644 (file)
index 0000000..16f9b35
--- /dev/null
@@ -0,0 +1,190 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:xlink="http://www.w3.org/1999/xlink"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="48"
+   height="48"
+   id="svg2"
+   version="1.1"
+   inkscape:version="0.47pre4 r22446"
+   sodipodi:docname="eng.svg">
+  <defs
+     id="defs4">
+    <linearGradient
+       id="linearGradient3742">
+      <stop
+         style="stop-color:#78c50f;stop-opacity:1;"
+         offset="0"
+         id="stop3744" />
+      <stop
+         style="stop-color:#cbf288;stop-opacity:1;"
+         offset="1"
+         id="stop3746" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient3726">
+      <stop
+         style="stop-color:#70c837;stop-opacity:1;"
+         offset="0"
+         id="stop3728" />
+      <stop
+         style="stop-color:#c1ea97;stop-opacity:1;"
+         offset="1"
+         id="stop3730" />
+    </linearGradient>
+    <inkscape:perspective
+       sodipodi:type="inkscape:persp3d"
+       inkscape:vp_x="0 : 526.18109 : 1"
+       inkscape:vp_y="0 : 1000 : 0"
+       inkscape:vp_z="744.09448 : 526.18109 : 1"
+       inkscape:persp3d-origin="372.04724 : 350.78739 : 1"
+       id="perspective10" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3742"
+       id="linearGradient3748"
+       x1="39.336147"
+       y1="1042.4371"
+       x2="14.555259"
+       y2="1010.7102"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="translate(2,3.0004875)" />
+    <inkscape:perspective
+       id="perspective4284"
+       inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
+       inkscape:vp_z="1 : 0.5 : 1"
+       inkscape:vp_y="0 : 1000 : 0"
+       inkscape:vp_x="0 : 0.5 : 1"
+       sodipodi:type="inkscape:persp3d" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3742-6"
+       id="linearGradient3748-7"
+       x1="39.336147"
+       y1="1042.4371"
+       x2="14.555259"
+       y2="1010.7102"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="translate(0,1.0004875)" />
+    <linearGradient
+       id="linearGradient3742-6">
+      <stop
+         style="stop-color:#78c50f;stop-opacity:1;"
+         offset="0"
+         id="stop3744-1" />
+      <stop
+         style="stop-color:#cbf288;stop-opacity:1;"
+         offset="1"
+         id="stop3746-8" />
+    </linearGradient>
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3742-6"
+       id="linearGradient4292"
+       x1="39.336147"
+       y1="1042.4371"
+       x2="14.555259"
+       y2="1010.7102"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="translate(0,1.0004875)" />
+    <linearGradient
+       id="linearGradient4294">
+      <stop
+         style="stop-color:#78c50f;stop-opacity:1;"
+         offset="0"
+         id="stop4296" />
+      <stop
+         style="stop-color:#cbf288;stop-opacity:1;"
+         offset="1"
+         id="stop4298" />
+    </linearGradient>
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3742"
+       id="linearGradient4337"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="translate(0,1.0004875)"
+       x1="39.336147"
+       y1="1042.4371"
+       x2="14.555259"
+       y2="1010.7102" />
+  </defs>
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     inkscape:pageopacity="0.0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="8.5416667"
+     inkscape:cx="16.474094"
+     inkscape:cy="21.182163"
+     inkscape:document-units="px"
+     inkscape:current-layer="layer1"
+     showgrid="false"
+     inkscape:window-width="1280"
+     inkscape:window-height="747"
+     inkscape:window-x="0"
+     inkscape:window-y="0"
+     inkscape:window-maximized="1" />
+  <metadata
+     id="metadata7">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:title />
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     inkscape:label="Layer 1"
+     inkscape:groupmode="layer"
+     id="layer1"
+     transform="translate(0,-1004.3622)">
+    <text
+       xml:space="preserve"
+       style="font-size:40px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;fill:#456c09;fill-opacity:1;stroke:#456c09;stroke-width:0.50000000000000000;stroke-opacity:1;font-family:'文泉驿正黑';-inkscape-font-specification:'文泉驿正黑 Bold'"
+       x="5.5660625"
+       y="1040.5483"
+       id="text3682"
+       sodipodi:linespacing="125%"><tspan
+         sodipodi:role="line"
+         id="tspan3684"
+         x="5.5660625"
+         y="1040.5483"
+         style="font-size:40px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;fill:#456c09;fill-opacity:1;stroke:#456c09;stroke-width:0.50000000000000000;stroke-opacity:1;font-family:'文泉驿正黑';-inkscape-font-specification:'文泉驿正黑 Bold'">英</tspan></text>
+    <path
+       sodipodi:type="arc"
+       style="fill:#000000;fill-opacity:0.14035088;stroke:none"
+       id="path4329"
+       sodipodi:cx="23.297562"
+       sodipodi:cy="43.37561"
+       sodipodi:rx="10.653659"
+       sodipodi:ry="1.697561"
+       d="m 33.951221,43.37561 c 0,0.937537 -4.769806,1.697561 -10.653659,1.697561 -5.883854,0 -10.653659,-0.760024 -10.653659,-1.697561 0,-0.937537 4.769805,-1.697561 10.653659,-1.697561 5.883853,0 10.653659,0.760024 10.653659,1.697561 z"
+       transform="matrix(1.6978022,0,0,1.4827586,-15.847333,984.54957)" />
+    <text
+       sodipodi:linespacing="125%"
+       id="text4333"
+       y="1039.548"
+       x="4.5658541"
+       style="font-size:40px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;fill:url(#linearGradient4337);fill-opacity:1;stroke:#76bd0c;stroke-width:0.5;stroke-opacity:1;font-family:'文泉驿正黑';-inkscape-font-specification:'文泉驿正黑 Bold'"
+       xml:space="preserve"><tspan
+         style="font-size:40px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;fill:url(#linearGradient4337);fill-opacity:1;stroke:#76bd0c;stroke-width:0.5;stroke-opacity:1;font-family:'文泉驿正黑';-inkscape-font-specification:'文泉驿正黑 Bold'"
+         y="1039.548"
+         x="4.5658541"
+         id="tspan4335"
+         sodipodi:role="line">英</tspan></text>
+  </g>
+</svg>
diff --git a/wrapper/xim/data/engpunc.png b/wrapper/xim/data/engpunc.png
new file mode 100644 (file)
index 0000000..dd8b3b9
Binary files /dev/null and b/wrapper/xim/data/engpunc.png differ
diff --git a/wrapper/xim/data/full.png b/wrapper/xim/data/full.png
new file mode 100644 (file)
index 0000000..90cbf35
Binary files /dev/null and b/wrapper/xim/data/full.png differ
diff --git a/wrapper/xim/data/half.png b/wrapper/xim/data/half.png
new file mode 100644 (file)
index 0000000..2e8e36c
Binary files /dev/null and b/wrapper/xim/data/half.png differ
diff --git a/wrapper/xim/data/han.png b/wrapper/xim/data/han.png
new file mode 100644 (file)
index 0000000..88e589e
Binary files /dev/null and b/wrapper/xim/data/han.png differ
diff --git a/wrapper/xim/data/han.svg b/wrapper/xim/data/han.svg
new file mode 100644 (file)
index 0000000..aed9615
--- /dev/null
@@ -0,0 +1,141 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:xlink="http://www.w3.org/1999/xlink"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="48"
+   height="48"
+   id="svg2"
+   version="1.1"
+   inkscape:version="0.47pre4 r22446"
+   sodipodi:docname="han.svg">
+  <defs
+     id="defs4">
+    <linearGradient
+       id="linearGradient3742">
+      <stop
+         style="stop-color:#78c50f;stop-opacity:1;"
+         offset="0"
+         id="stop3744" />
+      <stop
+         style="stop-color:#cbf288;stop-opacity:1;"
+         offset="1"
+         id="stop3746" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient3726">
+      <stop
+         style="stop-color:#70c837;stop-opacity:1;"
+         offset="0"
+         id="stop3728" />
+      <stop
+         style="stop-color:#c1ea97;stop-opacity:1;"
+         offset="1"
+         id="stop3730" />
+    </linearGradient>
+    <inkscape:perspective
+       sodipodi:type="inkscape:persp3d"
+       inkscape:vp_x="0 : 526.18109 : 1"
+       inkscape:vp_y="0 : 1000 : 0"
+       inkscape:vp_z="744.09448 : 526.18109 : 1"
+       inkscape:persp3d-origin="372.04724 : 350.78739 : 1"
+       id="perspective10" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3742"
+       id="linearGradient3748"
+       x1="39.336147"
+       y1="1042.4371"
+       x2="14.555259"
+       y2="1010.7102"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="translate(0.99989593,2.0009639)" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3742"
+       id="linearGradient4343"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="translate(0,1.0004875)"
+       x1="39.336147"
+       y1="1042.4371"
+       x2="14.555259"
+       y2="1010.7102" />
+  </defs>
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     inkscape:pageopacity="0.0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="8.5416667"
+     inkscape:cx="16.474094"
+     inkscape:cy="24"
+     inkscape:document-units="px"
+     inkscape:current-layer="layer1"
+     showgrid="false"
+     inkscape:window-width="1280"
+     inkscape:window-height="747"
+     inkscape:window-x="0"
+     inkscape:window-y="0"
+     inkscape:window-maximized="1" />
+  <metadata
+     id="metadata7">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:title />
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     inkscape:label="Layer 1"
+     inkscape:groupmode="layer"
+     id="layer1"
+     transform="translate(0,-1004.3622)">
+    <text
+       xml:space="preserve"
+       style="font-size:40px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;fill:#456c09;fill-opacity:1;stroke:#456c09;stroke-width:0.50000000000000000;stroke-opacity:1;font-family:'文泉驿正黑';-inkscape-font-specification:'文泉驿正黑 Bold'"
+       x="5.5657501"
+       y="1040.5485"
+       id="text3682"
+       sodipodi:linespacing="125%"><tspan
+         sodipodi:role="line"
+         id="tspan3684"
+         x="5.5657501"
+         y="1040.5485"
+         style="font-size:40px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;fill:#456c09;fill-opacity:1;stroke:#456c09;stroke-width:0.50000000000000000;stroke-opacity:1;font-family:'文泉驿正黑';-inkscape-font-specification:'文泉驿正黑 Bold'">中</tspan></text>
+    <path
+       sodipodi:type="arc"
+       style="fill:#000000;fill-opacity:0.14117648;stroke:none"
+       id="path4329"
+       sodipodi:cx="23.297562"
+       sodipodi:cy="43.37561"
+       sodipodi:rx="10.653659"
+       sodipodi:ry="1.697561"
+       d="m 33.951221,43.37561 c 0,0.937537 -4.769806,1.697561 -10.653659,1.697561 -5.883854,0 -10.653659,-0.760024 -10.653659,-1.697561 0,-0.937537 4.769805,-1.697561 10.653659,-1.697561 5.883853,0 10.653659,0.760024 10.653659,1.697561 z"
+       transform="matrix(1.6978022,0,0,1.4827586,-15.847333,984.54957)" />
+    <text
+       sodipodi:linespacing="125%"
+       id="text4339"
+       y="1039.548"
+       x="4.5658541"
+       style="font-size:40px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;fill:url(#linearGradient4343);fill-opacity:1;stroke:#76bd0c;stroke-width:0.5;stroke-opacity:1;font-family:'文泉驿正黑';-inkscape-font-specification:'文泉驿正黑 Bold'"
+       xml:space="preserve"><tspan
+         style="font-size:40px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;fill:url(#linearGradient4343);fill-opacity:1;stroke:#76bd0c;stroke-width:0.5;stroke-opacity:1;font-family:'文泉驿正黑';-inkscape-font-specification:'文泉驿正黑 Bold'"
+         y="1039.548"
+         x="4.5658541"
+         id="tspan4341"
+         sodipodi:role="line">中</tspan></text>
+  </g>
+</svg>
diff --git a/wrapper/xim/data/settings_ui.xml b/wrapper/xim/data/settings_ui.xml
new file mode 100644 (file)
index 0000000..5950d40
--- /dev/null
@@ -0,0 +1,806 @@
+<?xml version="1.0"?>
+<interface>
+  <requires lib="gtk+" version="2.16"/>
+  <!-- interface-naming-policy project-wide -->
+  <object class="GtkDialog" id="settings_dialog">
+    <property name="border_width">5</property>
+    <property name="title" translatable="yes">XSunpinyin Preferences</property>
+    <property name="resizable">False</property>
+    <property name="window_position">center</property>
+    <property name="icon_name">preferences-desktop</property>
+    <property name="type_hint">dialog</property>
+    <signal name="close" handler="gtk_main_quit"/>
+    <signal name="response" handler="gtk_main_quit"/>
+    <child internal-child="vbox">
+      <object class="GtkVBox" id="dialog-vbox1">
+        <property name="visible">True</property>
+        <property name="spacing">2</property>
+        <child>
+          <object class="GtkNotebook" id="notebook1">
+            <property name="visible">True</property>
+            <property name="can_focus">True</property>
+            <child>
+              <object class="GtkTable" id="table1">
+                <property name="visible">True</property>
+                <property name="n_rows">8</property>
+                <property name="n_columns">2</property>
+                <property name="row_spacing">7</property>
+                <child>
+                  <object class="GtkLabel" id="label3">
+                    <property name="visible">True</property>
+                    <property name="xalign">1</property>
+                    <property name="xpad">8</property>
+                    <property name="label" translatable="yes">Trigger Key</property>
+                  </object>
+                  <packing>
+                    <property name="x_options">GTK_FILL</property>
+                    <property name="y_options">GTK_FILL</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkLabel" id="label4">
+                    <property name="visible">True</property>
+                    <property name="xalign">1</property>
+                    <property name="xpad">8</property>
+                    <property name="label" translatable="yes">Switch to English</property>
+                  </object>
+                  <packing>
+                    <property name="top_attach">1</property>
+                    <property name="bottom_attach">2</property>
+                    <property name="x_options">GTK_FILL</property>
+                    <property name="y_options">GTK_FILL</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkLabel" id="label9">
+                    <property name="visible">True</property>
+                    <property name="xalign">1</property>
+                    <property name="xpad">8</property>
+                    <property name="label" translatable="yes">Number of Candidates</property>
+                  </object>
+                  <packing>
+                    <property name="top_attach">2</property>
+                    <property name="bottom_attach">3</property>
+                    <property name="y_options">GTK_FILL</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkHBox" id="hbox1">
+                    <property name="visible">True</property>
+                    <child>
+                      <object class="GtkCheckButton" id="trigger_ctrl_check">
+                        <property name="label" translatable="yes">Control</property>
+                        <property name="visible">True</property>
+                        <property name="can_focus">True</property>
+                        <property name="receives_default">False</property>
+                        <property name="draw_indicator">True</property>
+                        <signal name="toggled" handler="state_changed"/>
+                      </object>
+                      <packing>
+                        <property name="position">0</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkCheckButton" id="trigger_shift_check">
+                        <property name="label" translatable="yes">Shift</property>
+                        <property name="visible">True</property>
+                        <property name="can_focus">True</property>
+                        <property name="receives_default">False</property>
+                        <property name="draw_indicator">True</property>
+                        <signal name="toggled" handler="state_changed"/>
+                      </object>
+                      <packing>
+                        <property name="position">1</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkComboBox" id="trigger_combo">
+                        <property name="visible">True</property>
+                        <property name="model">keysym</property>
+                        <signal name="changed" handler="state_changed"/>
+                        <child>
+                          <object class="GtkCellRendererText" id="cellrenderertext1"/>
+                          <attributes>
+                            <attribute name="text">0</attribute>
+                          </attributes>
+                        </child>
+                      </object>
+                      <packing>
+                        <property name="position">2</property>
+                      </packing>
+                    </child>
+                  </object>
+                  <packing>
+                    <property name="left_attach">1</property>
+                    <property name="right_attach">2</property>
+                    <property name="y_options">GTK_FILL</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkHBox" id="hbox2">
+                    <property name="visible">True</property>
+                    <child>
+                      <object class="GtkCheckButton" id="english_ctrl_check">
+                        <property name="label" translatable="yes">Control</property>
+                        <property name="visible">True</property>
+                        <property name="can_focus">True</property>
+                        <property name="receives_default">False</property>
+                        <property name="draw_indicator">True</property>
+                        <signal name="toggled" handler="state_changed"/>
+                      </object>
+                      <packing>
+                        <property name="position">0</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkCheckButton" id="english_shift_check">
+                        <property name="label" translatable="yes">Shift</property>
+                        <property name="visible">True</property>
+                        <property name="can_focus">True</property>
+                        <property name="receives_default">False</property>
+                        <property name="draw_indicator">True</property>
+                        <signal name="toggled" handler="state_changed"/>
+                      </object>
+                      <packing>
+                        <property name="position">1</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkComboBox" id="english_combo">
+                        <property name="visible">True</property>
+                        <property name="model">keysym</property>
+                        <signal name="changed" handler="state_changed"/>
+                        <child>
+                          <object class="GtkCellRendererText" id="cellrenderertext2"/>
+                          <attributes>
+                            <attribute name="text">0</attribute>
+                          </attributes>
+                        </child>
+                      </object>
+                      <packing>
+                        <property name="position">2</property>
+                      </packing>
+                    </child>
+                  </object>
+                  <packing>
+                    <property name="left_attach">1</property>
+                    <property name="right_attach">2</property>
+                    <property name="top_attach">1</property>
+                    <property name="bottom_attach">2</property>
+                    <property name="y_options">GTK_FILL</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkHScale" id="hscale1">
+                    <property name="visible">True</property>
+                    <property name="can_focus">True</property>
+                    <property name="update_policy">delayed</property>
+                    <property name="adjustment">ncandidates</property>
+                    <property name="digits">0</property>
+                  </object>
+                  <packing>
+                    <property name="left_attach">1</property>
+                    <property name="right_attach">2</property>
+                    <property name="top_attach">2</property>
+                    <property name="bottom_attach">3</property>
+                    <property name="y_options"></property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkCheckButton" id="fuzzy_seg_check">
+                    <property name="label" translatable="yes">Fuzzy Segmentation</property>
+                    <property name="visible">True</property>
+                    <property name="can_focus">True</property>
+                    <property name="receives_default">False</property>
+                    <property name="draw_indicator">True</property>
+                    <signal name="toggled" handler="state_changed"/>
+                  </object>
+                  <packing>
+                    <property name="left_attach">1</property>
+                    <property name="right_attach">2</property>
+                    <property name="top_attach">5</property>
+                    <property name="bottom_attach">6</property>
+                    <property name="y_options">GTK_FILL</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkHBox" id="hbox3">
+                    <property name="visible">True</property>
+                    <child>
+                      <object class="GtkCheckButton" id="minus_plus_check">
+                        <property name="label" translatable="yes">- / =</property>
+                        <property name="visible">True</property>
+                        <property name="can_focus">True</property>
+                        <property name="receives_default">False</property>
+                        <property name="draw_indicator">True</property>
+                        <signal name="toggled" handler="state_changed"/>
+                      </object>
+                      <packing>
+                        <property name="position">0</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkCheckButton" id="comma_period_check">
+                        <property name="label" translatable="yes">, / .</property>
+                        <property name="visible">True</property>
+                        <property name="can_focus">True</property>
+                        <property name="receives_default">False</property>
+                        <property name="draw_indicator">True</property>
+                        <signal name="toggled" handler="state_changed"/>
+                      </object>
+                      <packing>
+                        <property name="position">1</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkCheckButton" id="paren_check">
+                        <property name="label" translatable="yes">[ / ]</property>
+                        <property name="visible">True</property>
+                        <property name="can_focus">True</property>
+                        <property name="receives_default">False</property>
+                        <property name="draw_indicator">True</property>
+                        <signal name="toggled" handler="state_changed"/>
+                      </object>
+                      <packing>
+                        <property name="position">2</property>
+                      </packing>
+                    </child>
+                  </object>
+                  <packing>
+                    <property name="left_attach">1</property>
+                    <property name="right_attach">2</property>
+                    <property name="top_attach">4</property>
+                    <property name="bottom_attach">5</property>
+                    <property name="y_options"></property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkLabel" id="label10">
+                    <property name="visible">True</property>
+                    <property name="xalign">1</property>
+                    <property name="xpad">8</property>
+                    <property name="label" translatable="yes">Page Up/Page Down</property>
+                  </object>
+                  <packing>
+                    <property name="top_attach">4</property>
+                    <property name="bottom_attach">5</property>
+                    <property name="y_options">GTK_FILL</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkLabel" id="label11">
+                    <property name="visible">True</property>
+                    <property name="xalign">1</property>
+                    <property name="xpad">8</property>
+                    <property name="label" translatable="yes">Backspace Behavior</property>
+                  </object>
+                  <packing>
+                    <property name="top_attach">3</property>
+                    <property name="bottom_attach">4</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkHBox" id="hbox4">
+                    <property name="visible">True</property>
+                    <child>
+                      <object class="GtkRadioButton" id="cancel_on_backspace_check">
+                        <property name="label" translatable="yes">Cancel Selection</property>
+                        <property name="visible">True</property>
+                        <property name="can_focus">True</property>
+                        <property name="receives_default">False</property>
+                        <property name="draw_indicator">True</property>
+                        <signal name="toggled" handler="state_changed"/>
+                      </object>
+                      <packing>
+                        <property name="position">0</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkRadioButton" id="remove_on_backspace_check">
+                        <property name="label" translatable="yes">Remove PinYin</property>
+                        <property name="visible">True</property>
+                        <property name="can_focus">True</property>
+                        <property name="receives_default">False</property>
+                        <property name="draw_indicator">True</property>
+                        <property name="group">cancel_on_backspace_check</property>
+                        <signal name="toggled" handler="state_changed"/>
+                      </object>
+                      <packing>
+                        <property name="position">1</property>
+                      </packing>
+                    </child>
+                  </object>
+                  <packing>
+                    <property name="left_attach">1</property>
+                    <property name="right_attach">2</property>
+                    <property name="top_attach">3</property>
+                    <property name="bottom_attach">4</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkCheckButton" id="smart_punct_check">
+                    <property name="label" translatable="yes">Smart Punctuation</property>
+                    <property name="visible">True</property>
+                    <property name="can_focus">True</property>
+                    <property name="receives_default">False</property>
+                    <property name="draw_indicator">True</property>
+                    <signal name="toggled" handler="state_changed"/>
+                  </object>
+                  <packing>
+                    <property name="left_attach">1</property>
+                    <property name="right_attach">2</property>
+                    <property name="top_attach">7</property>
+                    <property name="bottom_attach">8</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkCheckButton" id="fuzzy_inner_seg_check">
+                    <property name="label" translatable="yes">Fuzzy Segmentation on Inner Pinyin</property>
+                    <property name="visible">True</property>
+                    <property name="can_focus">True</property>
+                    <property name="receives_default">False</property>
+                    <property name="draw_indicator">True</property>
+                    <signal name="toggled" handler="state_changed"/>
+                  </object>
+                  <packing>
+                    <property name="left_attach">1</property>
+                    <property name="right_attach">2</property>
+                    <property name="top_attach">6</property>
+                    <property name="bottom_attach">7</property>
+                  </packing>
+                </child>
+                <child>
+                  <placeholder/>
+                </child>
+                <child>
+                  <placeholder/>
+                </child>
+                <child>
+                  <placeholder/>
+                </child>
+              </object>
+            </child>
+            <child type="tab">
+              <object class="GtkLabel" id="label5">
+                <property name="visible">True</property>
+                <property name="label" translatable="yes">Common</property>
+              </object>
+              <packing>
+                <property name="tab_fill">False</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkTable" id="table3">
+                <property name="visible">True</property>
+                <property name="n_rows">3</property>
+                <property name="n_columns">2</property>
+                <child>
+                  <object class="GtkRadioButton" id="pinyin_check">
+                    <property name="label" translatable="yes">PinYin</property>
+                    <property name="visible">True</property>
+                    <property name="can_focus">True</property>
+                    <property name="receives_default">False</property>
+                    <property name="draw_indicator">True</property>
+                    <signal name="toggled" handler="state_changed"/>
+                  </object>
+                  <packing>
+                    <property name="right_attach">2</property>
+                    <property name="y_options">GTK_FILL</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkRadioButton" id="shuangpin_check">
+                    <property name="label" translatable="yes">ShuangPin</property>
+                    <property name="visible">True</property>
+                    <property name="can_focus">True</property>
+                    <property name="receives_default">False</property>
+                    <property name="draw_indicator">True</property>
+                    <property name="group">pinyin_check</property>
+                    <signal name="toggled" handler="state_changed"/>
+                  </object>
+                  <packing>
+                    <property name="top_attach">1</property>
+                    <property name="bottom_attach">2</property>
+                    <property name="y_options">GTK_FILL</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkLabel" id="label13">
+                    <property name="visible">True</property>
+                    <property name="yalign">0.40000000596046448</property>
+                    <property name="ypad">9</property>
+                    <property name="label" translatable="yes">Note: &lt;i&gt;Switching to PinYin or QuanPin 
+requires restart or relogin to take effect,&lt;/i&gt;</property>
+                    <property name="use_markup">True</property>
+                    <property name="wrap">True</property>
+                  </object>
+                  <packing>
+                    <property name="right_attach">2</property>
+                    <property name="top_attach">2</property>
+                    <property name="bottom_attach">3</property>
+                    <property name="y_options"></property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkComboBox" id="shuangpin_combo">
+                    <property name="visible">True</property>
+                    <property name="model">shuangpin_scheme</property>
+                    <property name="active">0</property>
+                    <signal name="changed" handler="state_changed"/>
+                    <child>
+                      <object class="GtkCellRendererText" id="cellrenderertext3"/>
+                      <attributes>
+                        <attribute name="text">0</attribute>
+                      </attributes>
+                    </child>
+                  </object>
+                  <packing>
+                    <property name="left_attach">1</property>
+                    <property name="right_attach">2</property>
+                    <property name="top_attach">1</property>
+                    <property name="bottom_attach">2</property>
+                    <property name="y_options">GTK_FILL</property>
+                  </packing>
+                </child>
+              </object>
+              <packing>
+                <property name="position">1</property>
+              </packing>
+            </child>
+            <child type="tab">
+              <object class="GtkLabel" id="label1">
+                <property name="visible">True</property>
+                <property name="label" translatable="yes">PinYin Scheme</property>
+              </object>
+              <packing>
+                <property name="position">1</property>
+                <property name="tab_fill">False</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkTable" id="table2">
+                <property name="visible">True</property>
+                <property name="n_rows">8</property>
+                <property name="n_columns">2</property>
+                <property name="row_spacing">7</property>
+                <child>
+                  <object class="GtkLabel" id="label12">
+                    <property name="visible">True</property>
+                    <property name="xalign">1</property>
+                    <property name="xpad">8</property>
+                    <property name="label" translatable="yes">Preedit Opacity</property>
+                  </object>
+                  <packing>
+                    <property name="top_attach">7</property>
+                    <property name="bottom_attach">8</property>
+                    <property name="x_options">GTK_FILL</property>
+                    <property name="y_options">GTK_FILL</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkHScale" id="opacity_scale">
+                    <property name="visible">True</property>
+                    <property name="can_focus">True</property>
+                    <property name="update_policy">delayed</property>
+                    <property name="adjustment">opacity_value</property>
+                    <property name="digits">2</property>
+                  </object>
+                  <packing>
+                    <property name="left_attach">1</property>
+                    <property name="right_attach">2</property>
+                    <property name="top_attach">7</property>
+                    <property name="bottom_attach">8</property>
+                    <property name="y_options">GTK_FILL</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkLabel" id="label8">
+                    <property name="visible">True</property>
+                    <property name="xalign">1</property>
+                    <property name="xpad">8</property>
+                    <property name="label" translatable="yes">Preedit Font Color</property>
+                  </object>
+                  <packing>
+                    <property name="top_attach">6</property>
+                    <property name="bottom_attach">7</property>
+                    <property name="x_options">GTK_FILL</property>
+                    <property name="y_options">GTK_FILL</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkColorButton" id="font_color_btn">
+                    <property name="visible">True</property>
+                    <property name="can_focus">True</property>
+                    <property name="receives_default">True</property>
+                    <property name="color">#000000000000</property>
+                    <signal name="color_set" handler="state_changed"/>
+                  </object>
+                  <packing>
+                    <property name="left_attach">1</property>
+                    <property name="right_attach">2</property>
+                    <property name="top_attach">6</property>
+                    <property name="bottom_attach">7</property>
+                    <property name="y_options">GTK_FILL</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkLabel" id="label7">
+                    <property name="visible">True</property>
+                    <property name="xalign">1</property>
+                    <property name="xpad">8</property>
+                    <property name="label" translatable="yes">Preedit Font</property>
+                  </object>
+                  <packing>
+                    <property name="top_attach">5</property>
+                    <property name="bottom_attach">6</property>
+                    <property name="x_options">GTK_FILL</property>
+                    <property name="y_options">GTK_FILL</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkFontButton" id="font_btn">
+                    <property name="visible">True</property>
+                    <property name="can_focus">True</property>
+                    <property name="receives_default">True</property>
+                    <signal name="font_set" handler="state_changed"/>
+                  </object>
+                  <packing>
+                    <property name="left_attach">1</property>
+                    <property name="right_attach">2</property>
+                    <property name="top_attach">5</property>
+                    <property name="bottom_attach">6</property>
+                    <property name="y_options">GTK_FILL</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkLabel" id="label6">
+                    <property name="visible">True</property>
+                    <property name="xalign">1</property>
+                    <property name="xpad">8</property>
+                    <property name="label" translatable="yes">Preedit Background Color</property>
+                  </object>
+                  <packing>
+                    <property name="top_attach">4</property>
+                    <property name="bottom_attach">5</property>
+                    <property name="x_options">GTK_FILL</property>
+                    <property name="y_options">GTK_FILL</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkColorButton" id="background_color_btn">
+                    <property name="visible">True</property>
+                    <property name="can_focus">True</property>
+                    <property name="receives_default">True</property>
+                    <property name="color">#000000000000</property>
+                    <signal name="color_set" handler="state_changed"/>
+                  </object>
+                  <packing>
+                    <property name="left_attach">1</property>
+                    <property name="right_attach">2</property>
+                    <property name="top_attach">4</property>
+                    <property name="bottom_attach">5</property>
+                    <property name="y_options">GTK_FILL</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkLabel" id="label14">
+                    <property name="visible">True</property>
+                    <property name="xalign">0</property>
+                    <property name="xpad">16</property>
+                    <property name="label" translatable="yes">Classic Skin</property>
+                    <attributes>
+                      <attribute name="weight" value="bold"/>
+                    </attributes>
+                  </object>
+                  <packing>
+                    <property name="right_attach">2</property>
+                    <property name="top_attach">3</property>
+                    <property name="bottom_attach">4</property>
+                    <property name="y_options"></property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkLabel" id="label15">
+                    <property name="visible">True</property>
+                    <property name="xalign">1</property>
+                    <property name="xpad">8</property>
+                    <property name="label" translatable="yes">Skin:</property>
+                  </object>
+                  <packing>
+                    <property name="top_attach">2</property>
+                    <property name="bottom_attach">3</property>
+                    <property name="y_options"></property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkComboBox" id="skin_combo">
+                    <property name="visible">True</property>
+                    <property name="model">skin_list</property>
+                    <signal name="changed" handler="state_changed"/>
+                    <child>
+                      <object class="GtkCellRendererText" id="cellrenderertext4"/>
+                      <attributes>
+                        <attribute name="text">0</attribute>
+                      </attributes>
+                    </child>
+                  </object>
+                  <packing>
+                    <property name="left_attach">1</property>
+                    <property name="right_attach">2</property>
+                    <property name="top_attach">2</property>
+                    <property name="bottom_attach">3</property>
+                    <property name="y_options"></property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkLabel" id="label17">
+                    <property name="visible">True</property>
+                    <property name="xalign">1</property>
+                    <property name="xpad">8</property>
+                  </object>
+                  <packing>
+                    <property name="top_attach">1</property>
+                    <property name="bottom_attach">2</property>
+                    <property name="y_options"></property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkCheckButton" id="hide_icbar_check">
+                    <property name="label" translatable="yes">Hide Context Bar</property>
+                    <property name="visible">True</property>
+                    <property name="can_focus">True</property>
+                    <property name="receives_default">False</property>
+                    <property name="draw_indicator">True</property>
+                    <signal name="toggled" handler="state_changed"/>
+                  </object>
+                  <packing>
+                    <property name="left_attach">1</property>
+                    <property name="right_attach">2</property>
+                    <property name="top_attach">1</property>
+                    <property name="bottom_attach">2</property>
+                    <property name="y_options">GTK_FILL</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkLabel" id="label16">
+                    <property name="visible">True</property>
+                    <property name="xalign">0</property>
+                    <property name="xpad">16</property>
+                    <property name="label" translatable="yes">Common</property>
+                    <attributes>
+                      <attribute name="weight" value="bold"/>
+                    </attributes>
+                  </object>
+                  <packing>
+                    <property name="right_attach">2</property>
+                    <property name="y_options"></property>
+                  </packing>
+                </child>
+              </object>
+              <packing>
+                <property name="position">2</property>
+              </packing>
+            </child>
+            <child type="tab">
+              <object class="GtkLabel" id="label2">
+                <property name="visible">True</property>
+                <property name="label" translatable="yes">Look and Feel</property>
+              </object>
+              <packing>
+                <property name="position">2</property>
+                <property name="tab_fill">False</property>
+              </packing>
+            </child>
+          </object>
+          <packing>
+            <property name="position">1</property>
+          </packing>
+        </child>
+        <child internal-child="action_area">
+          <object class="GtkHButtonBox" id="dialog-action_area1">
+            <property name="visible">True</property>
+            <property name="layout_style">end</property>
+            <child>
+              <placeholder/>
+            </child>
+            <child>
+              <object class="GtkButton" id="button2">
+                <property name="label">gtk-close</property>
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">True</property>
+                <property name="use_stock">True</property>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">False</property>
+                <property name="position">1</property>
+              </packing>
+            </child>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="pack_type">end</property>
+            <property name="position">0</property>
+          </packing>
+        </child>
+      </object>
+    </child>
+    <action-widgets>
+      <action-widget response="0">button2</action-widget>
+    </action-widgets>
+  </object>
+  <object class="GtkAdjustment" id="opacity_value">
+    <property name="value">0.01</property>
+    <property name="lower">0.01</property>
+    <property name="upper">1.01</property>
+    <property name="step_increment">0.10000000000000001</property>
+    <property name="page_increment">0.01</property>
+    <property name="page_size">0.01</property>
+    <signal name="value_changed" handler="state_changed"/>
+  </object>
+  <object class="GtkListStore" id="keysym">
+    <columns>
+      <!-- column-name text -->
+      <column type="gchararray"/>
+    </columns>
+    <data>
+      <row>
+        <col id="0" translatable="yes">Space</col>
+      </row>
+      <row>
+        <col id="0" translatable="yes">Control_L</col>
+      </row>
+      <row>
+        <col id="0" translatable="yes">Control_R</col>
+      </row>
+      <row>
+        <col id="0" translatable="yes">Shift_L</col>
+      </row>
+      <row>
+        <col id="0" translatable="yes">Shift_R</col>
+      </row>
+    </data>
+  </object>
+  <object class="GtkAdjustment" id="ncandidates">
+    <property name="value">10</property>
+    <property name="lower">3</property>
+    <property name="upper">11</property>
+    <property name="step_increment">1</property>
+    <property name="page_increment">1</property>
+    <property name="page_size">1</property>
+    <signal name="value_changed" handler="state_changed"/>
+  </object>
+  <object class="GtkListStore" id="shuangpin_scheme">
+    <columns>
+      <!-- column-name text -->
+      <column type="gchararray"/>
+    </columns>
+    <data>
+      <row>
+        <col id="0" translatable="yes">MS2003</col>
+      </row>
+      <row>
+        <col id="0" translatable="yes">ABC</col>
+      </row>
+      <row>
+        <col id="0" translatable="yes">ZiRanMa</col>
+      </row>
+      <row>
+        <col id="0" translatable="yes">PinYin++</col>
+      </row>
+      <row>
+        <col id="0" translatable="yes">ZiGuang</col>
+      </row>
+      <row>
+        <col id="0" translatable="yes">XiaoHe</col>
+      </row>
+    </data>
+  </object>
+  <object class="GtkListStore" id="skin_list">
+    <columns>
+      <!-- column-name text -->
+      <column type="gchararray"/>
+    </columns>
+  </object>
+</interface>
diff --git a/wrapper/xim/data/skins/modern/eng-hover.png b/wrapper/xim/data/skins/modern/eng-hover.png
new file mode 100644 (file)
index 0000000..c5042bc
Binary files /dev/null and b/wrapper/xim/data/skins/modern/eng-hover.png differ
diff --git a/wrapper/xim/data/skins/modern/eng-press.png b/wrapper/xim/data/skins/modern/eng-press.png
new file mode 100644 (file)
index 0000000..024f388
Binary files /dev/null and b/wrapper/xim/data/skins/modern/eng-press.png differ
diff --git a/wrapper/xim/data/skins/modern/eng-punc-hover.png b/wrapper/xim/data/skins/modern/eng-punc-hover.png
new file mode 100644 (file)
index 0000000..2ac1aa8
Binary files /dev/null and b/wrapper/xim/data/skins/modern/eng-punc-hover.png differ
diff --git a/wrapper/xim/data/skins/modern/eng-punc-press.png b/wrapper/xim/data/skins/modern/eng-punc-press.png
new file mode 100644 (file)
index 0000000..0819b6e
Binary files /dev/null and b/wrapper/xim/data/skins/modern/eng-punc-press.png differ
diff --git a/wrapper/xim/data/skins/modern/eng-punc.png b/wrapper/xim/data/skins/modern/eng-punc.png
new file mode 100644 (file)
index 0000000..dd8b3b9
Binary files /dev/null and b/wrapper/xim/data/skins/modern/eng-punc.png differ
diff --git a/wrapper/xim/data/skins/modern/eng.png b/wrapper/xim/data/skins/modern/eng.png
new file mode 100644 (file)
index 0000000..b66bf35
Binary files /dev/null and b/wrapper/xim/data/skins/modern/eng.png differ
diff --git a/wrapper/xim/data/skins/modern/full-hover.png b/wrapper/xim/data/skins/modern/full-hover.png
new file mode 100644 (file)
index 0000000..ad6b36b
Binary files /dev/null and b/wrapper/xim/data/skins/modern/full-hover.png differ
diff --git a/wrapper/xim/data/skins/modern/full-press.png b/wrapper/xim/data/skins/modern/full-press.png
new file mode 100644 (file)
index 0000000..ca663fe
Binary files /dev/null and b/wrapper/xim/data/skins/modern/full-press.png differ
diff --git a/wrapper/xim/data/skins/modern/full.png b/wrapper/xim/data/skins/modern/full.png
new file mode 100644 (file)
index 0000000..90cbf35
Binary files /dev/null and b/wrapper/xim/data/skins/modern/full.png differ
diff --git a/wrapper/xim/data/skins/modern/half-hover.png b/wrapper/xim/data/skins/modern/half-hover.png
new file mode 100644 (file)
index 0000000..549f7f9
Binary files /dev/null and b/wrapper/xim/data/skins/modern/half-hover.png differ
diff --git a/wrapper/xim/data/skins/modern/half-press.png b/wrapper/xim/data/skins/modern/half-press.png
new file mode 100644 (file)
index 0000000..f012d6f
Binary files /dev/null and b/wrapper/xim/data/skins/modern/half-press.png differ
diff --git a/wrapper/xim/data/skins/modern/half.png b/wrapper/xim/data/skins/modern/half.png
new file mode 100644 (file)
index 0000000..2e8e36c
Binary files /dev/null and b/wrapper/xim/data/skins/modern/half.png differ
diff --git a/wrapper/xim/data/skins/modern/han-hover.png b/wrapper/xim/data/skins/modern/han-hover.png
new file mode 100644 (file)
index 0000000..657d453
Binary files /dev/null and b/wrapper/xim/data/skins/modern/han-hover.png differ
diff --git a/wrapper/xim/data/skins/modern/han-press.png b/wrapper/xim/data/skins/modern/han-press.png
new file mode 100644 (file)
index 0000000..a4978ad
Binary files /dev/null and b/wrapper/xim/data/skins/modern/han-press.png differ
diff --git a/wrapper/xim/data/skins/modern/han-punc-hover.png b/wrapper/xim/data/skins/modern/han-punc-hover.png
new file mode 100644 (file)
index 0000000..4a8737e
Binary files /dev/null and b/wrapper/xim/data/skins/modern/han-punc-hover.png differ
diff --git a/wrapper/xim/data/skins/modern/han-punc-press.png b/wrapper/xim/data/skins/modern/han-punc-press.png
new file mode 100644 (file)
index 0000000..491552b
Binary files /dev/null and b/wrapper/xim/data/skins/modern/han-punc-press.png differ
diff --git a/wrapper/xim/data/skins/modern/han-punc.png b/wrapper/xim/data/skins/modern/han-punc.png
new file mode 100644 (file)
index 0000000..382c0f2
Binary files /dev/null and b/wrapper/xim/data/skins/modern/han-punc.png differ
diff --git a/wrapper/xim/data/skins/modern/han.png b/wrapper/xim/data/skins/modern/han.png
new file mode 100644 (file)
index 0000000..88e589e
Binary files /dev/null and b/wrapper/xim/data/skins/modern/han.png differ
diff --git a/wrapper/xim/data/skins/modern/icbar.png b/wrapper/xim/data/skins/modern/icbar.png
new file mode 100644 (file)
index 0000000..2418936
Binary files /dev/null and b/wrapper/xim/data/skins/modern/icbar.png differ
diff --git a/wrapper/xim/data/skins/modern/info b/wrapper/xim/data/skins/modern/info
new file mode 100644 (file)
index 0000000..0ca4070
--- /dev/null
@@ -0,0 +1,9 @@
+52 29 74 29 96 29
+6 6
+Sans 10
+1.0 1.0 1.0 1.0
+6 25
+Sans 10
+1.0 1.0 1.0 1.0
+6 0
+6 6 12 12
diff --git a/wrapper/xim/data/skins/modern/preedit.png b/wrapper/xim/data/skins/modern/preedit.png
new file mode 100644 (file)
index 0000000..f4fda8a
Binary files /dev/null and b/wrapper/xim/data/skins/modern/preedit.png differ
diff --git a/wrapper/xim/data/sunpinyin-logo-big.png b/wrapper/xim/data/sunpinyin-logo-big.png
new file mode 100644 (file)
index 0000000..1f2eab1
Binary files /dev/null and b/wrapper/xim/data/sunpinyin-logo-big.png differ
diff --git a/wrapper/xim/data/sunpinyin-logo.png b/wrapper/xim/data/sunpinyin-logo.png
new file mode 100644 (file)
index 0000000..e4ce4b9
Binary files /dev/null and b/wrapper/xim/data/sunpinyin-logo.png differ
diff --git a/wrapper/xim/data/xim_config_default b/wrapper/xim/data/xim_config_default
new file mode 100644 (file)
index 0000000..e67763b
--- /dev/null
@@ -0,0 +1,7 @@
+trigger_key=Control+space
+eng_key=Shift_L
+icbar_pos=1180,730
+preedit_opacity=1.00
+preedit_color=#FFFFB3
+preedit_font=Sans 10
+preedit_font_color=#000000
diff --git a/wrapper/xim/ic.c b/wrapper/xim/ic.c
new file mode 100644 (file)
index 0000000..8b2f5b7
--- /dev/null
@@ -0,0 +1,343 @@
+/*
+ * Copyright (c) 2010 Mike Qin <mikeandmore@gmail.com>
+ *
+ * The contents of this file are subject to the terms of either the GNU Lesser
+ * General Public License Version 2.1 only ("LGPL") or the Common Development and
+ * Distribution License ("CDDL")(collectively, the "License"). You may not use this
+ * file except in compliance with the License. You can obtain a copy of the CDDL at
+ * http://www.opensource.org/licenses/cddl1.php and a copy of the LGPLv2.1 at
+ * http://www.opensource.org/licenses/lgpl-license.php. See the License for the
+ * specific language governing permissions and limitations under the License. When
+ * distributing the software, include this License Header Notice in each file and
+ * include the full text of the License in the License file as well as the
+ * following notice:
+ *
+ * NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND DISTRIBUTION LICENSE
+ * (CDDL)
+ * For Covered Software in this distribution, this License shall be governed by the
+ * laws of the State of California (excluding conflict-of-law provisions).
+ * Any litigation relating to this License shall be subject to the jurisdiction of
+ * the Federal Courts of the Northern District of California and the state courts
+ * of the State of California, with venue lying in Santa Clara County, California.
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by only the CDDL or only
+ * the LGPL Version 2.1, indicate your decision by adding "[Contributor]" elects to
+ * include this software in this distribution under the [CDDL or LGPL Version 2.1]
+ * license." If you don't indicate a single choice of license, a recipient has the
+ * option to distribute your version of this file under either the CDDL or the LGPL
+ * Version 2.1, or to extend the choice of license to its licensees as provided
+ * above. However, if you add LGPL Version 2.1 code and therefore, elected the LGPL
+ * Version 2 license, then the option applies only if the new code is made subject
+ * to such option by the copyright holder.
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include <X11/Xlib.h>
+#include <X11/Xos.h>
+#include <X11/Xfuncs.h>
+#include <X11/Xutil.h>
+#include <X11/Xatom.h>
+
+#include "common.h"
+#include "settings.h"
+#include "ic.h"
+#include "xmisc.h"
+#include "xim.h"
+
+static IC* icmaps[MAX_IC_NUM];
+static IC ics[MAX_IC_NUM];
+
+static size_t free_stack_sz = 0;
+static IC* free_stack[MAX_IC_NUM];
+
+static IC* current_ic;
+
+// check if this ic is available
+static int
+__find_application_pid(Window w)
+{
+    if (w == DefaultRootWindow(dpy))
+        return 0;
+
+    Atom actual_type;
+    int actual_format;
+    unsigned long nitems;
+    unsigned long bytes;
+    unsigned char* prop;
+    int status = XGetWindowProperty(
+        dpy, w, XInternAtom(dpy, "_NET_WM_PID", True), 0,
+        1024L, False, AnyPropertyType, &actual_type, &actual_format, &nitems,
+        &bytes, (unsigned char**) &prop);
+    if (status != 0) {
+        if (status == BadRequest)
+            return 0;
+        return -1;
+    }
+    if (!prop) {
+        Window parent;
+        Window root;
+        Window* children = NULL;
+        unsigned int sz = 0;
+        status = XQueryTree(dpy, w, &root, &parent, &children, &sz);
+        if (status != 0) {
+            if (status == BadRequest)
+                return 0;
+            return -1;
+        }
+        if (children)
+            XFree(children);
+        return __find_application_pid(parent);
+    } else {
+        // TODO: is this portable?
+        return prop[1] * 256 + prop[0];
+    }
+}
+
+static bool
+__ic_available(IC* ic)
+{
+    int pid = __find_application_pid(ic->client_window);
+    if (pid == -1)
+        return false;
+    if (pid == 0)
+        return true;
+    // verify if a process is running
+    char path[256];
+    snprintf(path, 255, "/proc/%d", pid);
+    struct stat buf;
+    if (stat(path, &buf) != 0) {
+        LOG("GC can't catch the process %d", pid);
+        return false;
+    }
+    if (!S_ISDIR(buf.st_mode)) {
+        LOG("GC can't catch the process %d", pid);
+        return false;
+    }
+    return true;
+}
+
+static void
+__scan_all_ic()
+{
+    int i = 0;
+    for (i = 0; i < MAX_IC_NUM; i++) {
+        IC* ic = icmaps[i];
+        if (ic == NULL)
+            continue;
+
+        if (__ic_available(ic) == false) {
+            LOG("GC detected garbage %d", ic->icid);
+            icmgr_destroy_ic(i);
+        }
+    }
+}
+
+static void
+__reset_ic(IC* ic)
+{
+    int id = ic->icid;
+    memset(ic, 0, sizeof(IC));
+    ic->icid = id;
+    ic->is_chn_punc = true;
+}
+
+void
+icmgr_init(void)
+{
+    memset(ics, 0, sizeof(IC) * MAX_IC_NUM);
+    int i;
+    for (i = 0; i < MAX_IC_NUM; i++) {
+        ics[i].icid = i;
+        __reset_ic(&ics[i]);
+
+        free_stack[free_stack_sz] = &ics[i];
+        free_stack_sz++;
+    }
+    current_ic = NULL;
+
+    icmgr_ui_init();
+}
+
+void
+icmgr_finalize(void)
+{
+    memset(icmaps, 0, sizeof(IC*) * MAX_IC_NUM);
+    current_ic = NULL;
+}
+
+
+IC*
+icmgr_create_ic(int connect_id)
+{
+    static int created_cnt = 0;
+
+    created_cnt++;
+    if (created_cnt == GC_THRESHOLD || free_stack_sz < MAX_IC_NUM / 3) {
+        __scan_all_ic();
+        created_cnt = 0;
+    }
+
+    if (free_stack_sz == 0) {
+        LOG("Error free stack empty!!");
+        return NULL;
+    }
+
+    free_stack_sz--;
+    IC* ic = free_stack[free_stack_sz];
+
+    icmaps[ic->icid] = ic;
+    __reset_ic(ic);
+
+    /* icmgr_set_current(ic->icid); */
+
+    ic->connect_id = connect_id;
+
+    /* current_ic = ic; */
+    return ic;
+}
+
+void
+icmgr_destroy_ic(int icid)
+{
+    IC* ic = icmaps[icid];
+    if (ic == NULL)
+        return;
+
+    memset(ic, 0, sizeof(IC));
+    ic->icid = icid;
+
+    icmaps[icid] = NULL;
+
+    // return to free stack
+    free_stack[free_stack_sz] = ic;
+    free_stack_sz++;
+
+    current_ic = NULL;
+}
+
+bool
+icmgr_set_current(int icid)
+{
+    IC* ic = icmaps[icid];
+    if (ic == NULL)
+        return false;
+    current_ic = ic;
+    return true;
+}
+
+IC*
+icmgr_get_current(void)
+{
+    return current_ic;
+}
+
+void
+icmgr_toggle_english(void)
+{
+    if (current_ic) {
+        current_ic->is_english = !current_ic->is_english;
+    }
+}
+
+void
+icmgr_toggle_full(void)
+{
+    if (current_ic) {
+        current_ic->is_full = !current_ic->is_full;
+    }
+}
+
+void
+icmgr_toggle_punc(void)
+{
+    if (current_ic) {
+        current_ic->is_chn_punc = !current_ic->is_chn_punc;
+    }
+}
+
+IC*
+icmgr_get(int icid)
+{
+    return icmaps[icid];
+}
+
+void
+icmgr_clear_current(void)
+{
+    current_ic = NULL;
+}
+
+void
+icmgr_refresh(void)
+{
+    if (current_ic == NULL) {
+        icmgr_ui_refresh();
+        return;
+    }
+
+    /* refresh preedit */
+    if (current_ic->is_enabled) {
+        if (current_ic->is_english && preedit_status())
+            preedit_pause();
+        else if (!current_ic->is_english && !preedit_status())
+            preedit_go_on();
+
+        preedit_set_full(current_ic->is_full);
+        preedit_set_chinese_punc(current_ic->is_chn_punc);
+    } else {
+        preedit_pause();
+    }
+    icmgr_ui_refresh();
+}
+
+extern IC_UI icmgr_gtk;
+extern IC_UI icmgr_skin;
+
+static IC_UI* current_icmgr_ui = NULL;
+
+static void
+init_front_end()
+{
+    varchar skin_name;
+    settings_get(SKIN_NAME, skin_name);
+    if (strcmp(skin_name, "classic") == 0) {
+        current_icmgr_ui = &icmgr_gtk;
+    } else {
+        current_icmgr_ui = &icmgr_skin;
+    }
+
+    if (!current_icmgr_ui->init(skin_name)) {
+        fprintf(stderr, "Error init front end!\n");
+        exit(-1);
+    }
+}
+
+void
+icmgr_ui_init(void)
+{
+    ui_tray_init();
+    init_front_end();
+}
+
+void
+icmgr_ui_refresh(void)
+{
+    ui_tray_refresh();
+    if (current_icmgr_ui != NULL) {
+        varchar skin_name;
+        settings_get(SKIN_NAME, skin_name);
+        if (strcmp(skin_name, current_icmgr_ui->get_name()) != 0) {
+            current_icmgr_ui->dispose();
+            init_front_end();
+        }
+        current_icmgr_ui->refresh();
+    } else {
+        init_front_end();
+    }
+}
+
diff --git a/wrapper/xim/ic.h b/wrapper/xim/ic.h
new file mode 100644 (file)
index 0000000..cb69ee4
--- /dev/null
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 2010 Mike Qin <mikeandmore@gmail.com>
+ *
+ * The contents of this file are subject to the terms of either the GNU Lesser
+ * General Public License Version 2.1 only ("LGPL") or the Common Development and
+ * Distribution License ("CDDL")(collectively, the "License"). You may not use this
+ * file except in compliance with the License. You can obtain a copy of the CDDL at
+ * http://www.opensource.org/licenses/cddl1.php and a copy of the LGPLv2.1 at
+ * http://www.opensource.org/licenses/lgpl-license.php. See the License for the
+ * specific language governing permissions and limitations under the License. When
+ * distributing the software, include this License Header Notice in each file and
+ * include the full text of the License in the License file as well as the
+ * following notice:
+ *
+ * NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND DISTRIBUTION LICENSE
+ * (CDDL)
+ * For Covered Software in this distribution, this License shall be governed by the
+ * laws of the State of California (excluding conflict-of-law provisions).
+ * Any litigation relating to this License shall be subject to the jurisdiction of
+ * the Federal Courts of the Northern District of California and the state courts
+ * of the State of California, with venue lying in Santa Clara County, California.
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by only the CDDL or only
+ * the LGPL Version 2.1, indicate your decision by adding "[Contributor]" elects to
+ * include this software in this distribution under the [CDDL or LGPL Version 2.1]
+ * license." If you don't indicate a single choice of license, a recipient has the
+ * option to distribute your version of this file under either the CDDL or the LGPL
+ * Version 2.1, or to extend the choice of license to its licensees as provided
+ * above. However, if you add LGPL Version 2.1 code and therefore, elected the LGPL
+ * Version 2 license, then the option applies only if the new code is made subject
+ * to such option by the copyright holder.
+ */
+
+#ifndef _IC_H_
+#define _IC_H_
+
+#include <gtk/gtk.h>
+#include <X11/Xproto.h>
+#include <X11/Xlib.h>
+#include <X11/keysym.h>
+#include <X11/Xutil.h>
+
+#include "common.h"
+
+__BEGIN_DECLS
+
+
+#define MAX_IC_NUM 0x7fff
+#define GC_THRESHOLD 4096
+
+/* input context */
+typedef struct _IC {
+    Window client_window;
+    bool   is_enabled;
+    bool   is_english;
+    bool   is_full;
+    bool   is_chn_punc;
+    int    icid;
+    int    connect_id;
+    int    offset_x;
+    int    offset_y;
+} IC;
+
+typedef struct _IC_UI {
+    gboolean (*init)    (const char* name);
+    void (*refresh) (void);
+    void (*dispose) (void);
+    const char* (*get_name) (void);
+} IC_UI;
+
+/* input context manager */
+
+void icmgr_init       (void);
+void icmgr_finalize   (void);
+
+IC*  icmgr_create_ic  (int connect_id);
+void icmgr_destroy_ic (int icid);
+bool icmgr_set_current(int icid);
+IC*  icmgr_get        (int icid);
+
+void icmgr_toggle_english (void);
+void icmgr_toggle_full    (void);
+void icmgr_toggle_punc    (void);
+
+IC*  icmgr_get_current  (void);
+void icmgr_clear_current(void);
+void icmgr_refresh      (void);
+
+void icmgr_ui_init      (void);
+void icmgr_ui_refresh   (void);
+
+__END_DECLS
+
+#endif /* _IC_H_ */
diff --git a/wrapper/xim/ic_gtk.c b/wrapper/xim/ic_gtk.c
new file mode 100644 (file)
index 0000000..2cb141f
--- /dev/null
@@ -0,0 +1,235 @@
+/*
+ * Copyright (c) 2010 Mike Qin <mikeandmore@gmail.com>
+ *
+ * The contents of this file are subject to the terms of either the GNU Lesser
+ * General Public License Version 2.1 only ("LGPL") or the Common Development and
+ * Distribution License ("CDDL")(collectively, the "License"). You may not use this
+ * file except in compliance with the License. You can obtain a copy of the CDDL at
+ * http://www.opensource.org/licenses/cddl1.php and a copy of the LGPLv2.1 at
+ * http://www.opensource.org/licenses/lgpl-license.php. See the License for the
+ * specific language governing permissions and limitations under the License. When
+ * distributing the software, include this License Header Notice in each file and
+ * include the full text of the License in the License file as well as the
+ * following notice:
+ *
+ * NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND DISTRIBUTION LICENSE
+ * (CDDL)
+ * For Covered Software in this distribution, this License shall be governed by the
+ * laws of the State of California (excluding conflict-of-law provisions).
+ * Any litigation relating to this License shall be subject to the jurisdiction of
+ * the Federal Courts of the Northern District of California and the state courts
+ * of the State of California, with venue lying in Santa Clara County, California.
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by only the CDDL or only
+ * the LGPL Version 2.1, indicate your decision by adding "[Contributor]" elects to
+ * include this software in this distribution under the [CDDL or LGPL Version 2.1]
+ * license." If you don't indicate a single choice of license, a recipient has the
+ * option to distribute your version of this file under either the CDDL or the LGPL
+ * Version 2.1, or to extend the choice of license to its licensees as provided
+ * above. However, if you add LGPL Version 2.1 code and therefore, elected the LGPL
+ * Version 2 license, then the option applies only if the new code is made subject
+ * to such option by the copyright holder.
+ */
+
+#include <gtk/gtk.h>
+#include "ic.h"
+#include "ui.h"
+#include "common.h"
+#include "settings.h"
+
+static GtkWidget* icbar_window;
+static GtkWidget* icbar_status_btn;
+static GtkWidget* icbar_full_btn;
+static GtkWidget* icbar_chn_punc_btn;
+
+static GtkStatusIcon* icbar_tray;
+static GtkWidget* popup_menu;
+
+#define LOGO_FILE SUNPINYIN_XIM_ICON_DIR"/sunpinyin-logo.png"
+#define ENG_ICON_PNG SUNPINYIN_XIM_ICON_DIR"/eng.png"
+#define HAN_ICON_PNG SUNPINYIN_XIM_ICON_DIR"/han.png"
+#define FULL_ICON_PNG SUNPINYIN_XIM_ICON_DIR"/full.png"
+#define HALF_ICON_PNG SUNPINYIN_XIM_ICON_DIR"/half.png"
+#define CHN_PUNC_ICON_PNG SUNPINYIN_XIM_ICON_DIR"/chnpunc.png"
+#define ENG_PUNC_ICON_PNG SUNPINYIN_XIM_ICON_DIR"/engpunc.png"
+
+
+static void
+toggle_english(GtkToggleButton* btn, gpointer userdata)
+{
+    icmgr_toggle_english();
+    icmgr_refresh();
+}
+
+static void
+toggle_full(GtkToggleButton* btn, gpointer userdata)
+{
+    icmgr_toggle_full();
+    icmgr_refresh();
+}
+
+static void
+toggle_chn_punc(GtkToggleButton* btn, gpointer userdata)
+{
+    icmgr_toggle_punc();
+    icmgr_refresh();
+}
+
+static bool begin_drag = false;
+static int drag_offset_x = -1;
+static int drag_offset_y = -1;
+
+static void
+icbar_on_button_press(GtkWidget* wnd, GdkEventButton* evt, gpointer data)
+{
+    if (evt->button == 1) {
+        begin_drag = true;
+        drag_offset_x = (int) evt->x;
+        drag_offset_y = (int) evt->y;
+    }
+}
+
+static void
+icbar_on_button_release(GtkWidget* wnd, GdkEventButton* evt, gpointer data)
+{
+    if (evt->button == 1) {
+        begin_drag = false;
+        position_t pos;
+        gtk_window_get_position(GTK_WINDOW(icbar_window),
+                                &(pos.x), &(pos.y));
+        settings_set(ICBAR_POS, &pos);
+    }
+}
+
+static void
+icbar_on_motion(GtkWidget* wnd, GdkEventMotion* evt, gpointer data)
+{
+    if (begin_drag) {
+        gtk_window_move(GTK_WINDOW(icbar_window),
+                        (int) evt->x_root - drag_offset_x,
+                        (int) evt->y_root - drag_offset_y);
+    }
+}
+
+static void
+__toggle_mode(gboolean mode, GtkWidget* btn,
+              const char* img_path1, const char* img_path2)
+{
+    GtkWidget* img_wid = gtk_tool_button_get_icon_widget(
+        GTK_TOOL_BUTTON(btn));
+    const char* img_path = NULL;
+
+    if (mode) {
+        img_path = img_path1;
+    } else {
+        img_path = img_path2;
+    }
+    gtk_image_set_from_file(GTK_IMAGE(img_wid), img_path);
+    gtk_image_set_pixel_size(GTK_IMAGE(img_wid), 20);
+}
+
+static GtkWidget*
+__create_btn(bool stock, const char* img_path, GCallback cb)
+{
+    GtkWidget* img_wid;
+    if (stock) {
+        img_wid = gtk_image_new_from_icon_name(img_path, GTK_ICON_SIZE_MENU);
+    } else {
+        img_wid = gtk_image_new_from_file(ENG_ICON_PNG);
+    }
+    gtk_image_set_pixel_size(GTK_IMAGE(img_wid), 20);
+    GtkWidget* res = GTK_WIDGET(gtk_tool_button_new(img_wid, ""));
+    g_signal_connect(res, "clicked", cb, NULL);
+    return res;
+}
+
+static gboolean
+icmgr_gtk_init(const char* name)
+{
+    icbar_window = ui_create_window();
+
+    gtk_widget_add_events(icbar_window,
+                          GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK
+                          | GDK_POINTER_MOTION_MASK);
+    g_signal_connect(icbar_window, "button-press-event",
+                     G_CALLBACK(icbar_on_button_press), NULL);
+    g_signal_connect(icbar_window, "motion-notify-event",
+                     G_CALLBACK(icbar_on_motion), NULL);
+    g_signal_connect(icbar_window, "button-release-event",
+                     G_CALLBACK(icbar_on_button_release), NULL);
+
+    icbar_status_btn = __create_btn(false, ENG_ICON_PNG,
+                                    G_CALLBACK(toggle_english));
+    icbar_full_btn = __create_btn(false, FULL_ICON_PNG,
+                                  G_CALLBACK(toggle_full));
+    icbar_chn_punc_btn = __create_btn(false, CHN_PUNC_ICON_PNG,
+                                      G_CALLBACK(toggle_chn_punc));
+
+    GtkWidget* logo = gtk_image_new_from_file(LOGO_FILE);
+    gtk_widget_add_events(logo,
+                          GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK);
+
+    GtkWidget* box = gtk_hbox_new(false, 1);
+
+    gtk_box_pack_start(GTK_BOX(box), logo, false, false, 1);
+    gtk_box_pack_start(GTK_BOX(box), icbar_status_btn, false, false, 1);
+    gtk_box_pack_start(GTK_BOX(box), icbar_full_btn, false, false, 1);
+    gtk_box_pack_start(GTK_BOX(box), icbar_chn_punc_btn, false, false, 1);
+
+    gtk_container_add(GTK_CONTAINER(icbar_window), box);
+
+    gtk_widget_show_all(box);
+    return TRUE;
+}
+
+static void
+icmgr_gtk_refresh(void)
+{
+    if (settings_get_int(HIDE_ICBAR)) {
+        gtk_widget_hide(icbar_window);
+        return;
+    }
+    IC* ic = icmgr_get_current();
+    if (ic == NULL || !ic->is_enabled) {
+        gtk_widget_hide(icbar_window);
+        return;
+    }
+
+    __toggle_mode(ic->is_english, icbar_status_btn,
+                  ENG_ICON_PNG, HAN_ICON_PNG);
+    __toggle_mode(ic->is_full, icbar_full_btn,
+                  FULL_ICON_PNG, HALF_ICON_PNG);
+    __toggle_mode(ic->is_chn_punc, icbar_chn_punc_btn,
+                  CHN_PUNC_ICON_PNG, ENG_PUNC_ICON_PNG);
+
+    position_t pos;
+    int width, height;
+    gtk_window_get_size(GTK_WINDOW(icbar_window), &width, &height);
+    settings_get(ICBAR_POS, &pos);
+    adjust_position(&(pos.x), &(pos.y), width, height);
+    settings_set(ICBAR_POS, &pos);
+
+    gtk_window_move(GTK_WINDOW(icbar_window), pos.x, pos.y);
+    gtk_widget_show(icbar_window);
+}
+
+static void
+icmgr_gtk_dispose(void)
+{
+    gtk_widget_destroy(icbar_window);
+}
+
+static const char*
+icmgr_gtk_get_name(void)
+{
+    return "classic";
+}
+
+IC_UI icmgr_gtk = {
+    .get_name = icmgr_gtk_get_name,
+    .init = icmgr_gtk_init,
+    .refresh = icmgr_gtk_refresh,
+    .dispose = icmgr_gtk_dispose,
+};
diff --git a/wrapper/xim/ic_skin.c b/wrapper/xim/ic_skin.c
new file mode 100644 (file)
index 0000000..8cecbb9
--- /dev/null
@@ -0,0 +1,184 @@
+/*
+ * Copyright (c) 2010 Mike Qin <mikeandmore@gmail.com>
+ *
+ * The contents of this file are subject to the terms of either the GNU Lesser
+ * General Public License Version 2.1 only ("LGPL") or the Common Development and
+ * Distribution License ("CDDL")(collectively, the "License"). You may not use this
+ * file except in compliance with the License. You can obtain a copy of the CDDL at
+ * http://www.opensource.org/licenses/cddl1.php and a copy of the LGPLv2.1 at
+ * http://www.opensource.org/licenses/lgpl-license.php. See the License for the
+ * specific language governing permissions and limitations under the License. When
+ * distributing the software, include this License Header Notice in each file and
+ * include the full text of the License in the License file as well as the
+ * following notice:
+ *
+ * NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND DISTRIBUTION LICENSE
+ * (CDDL)
+ * For Covered Software in this distribution, this License shall be governed by the
+ * laws of the State of California (excluding conflict-of-law provisions).
+ * Any litigation relating to this License shall be subject to the jurisdiction of
+ * the Federal Courts of the Northern District of California and the state courts
+ * of the State of California, with venue lying in Santa Clara County, California.
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by only the CDDL or only
+ * the LGPL Version 2.1, indicate your decision by adding "[Contributor]" elects to
+ * include this software in this distribution under the [CDDL or LGPL Version 2.1]
+ * license." If you don't indicate a single choice of license, a recipient has the
+ * option to distribute your version of this file under either the CDDL or the LGPL
+ * Version 2.1, or to extend the choice of license to its licensees as provided
+ * above. However, if you add LGPL Version 2.1 code and therefore, elected the LGPL
+ * Version 2 license, then the option applies only if the new code is made subject
+ * to such option by the copyright holder.
+ */
+
+#include <gtk/gtk.h>
+#include "ic.h"
+#include "ui.h"
+#include "skin.h"
+#include "common.h"
+#include "settings.h"
+
+static skin_info_t* info;
+static char* skin_name;
+static skin_window_t* icbar_wind;
+static skin_button_t* icbar_status_btn;
+static skin_button_t* icbar_full_btn;
+static skin_button_t* icbar_punc_btn;
+
+static void
+toggle_english(GtkWidget* wid, GdkEventButton* evt, void* userdata)
+{
+    icmgr_toggle_english();
+    icmgr_refresh();
+}
+
+static void
+toggle_full(GtkWidget* wid, GdkEventButton* evt, void* userdata)
+{
+    icmgr_toggle_full();
+    icmgr_refresh();
+}
+
+static void
+toggle_punc(GtkWidget* wid, GdkEventButton* evt, void* userdata)
+{
+    icmgr_toggle_punc();
+    icmgr_refresh();
+}
+
+static void
+icbar_on_release(GtkWidget* wid, GdkEventMotion* evt, void* userdata)
+{
+    position_t pos;
+    gtk_window_get_position(GTK_WINDOW(wid), &(pos.x), &(pos.y));
+    settings_set(ICBAR_POS, &pos);
+}
+
+static gboolean
+icmgr_skin_init(const char* name)
+{
+    info = ui_skin_new(name);
+    if (!info) return FALSE;
+    skin_name = strdup(name);
+    icbar_wind = skin_window_new(GTK_WINDOW(ui_create_window()),
+                                 info->icbar_background,
+                                 0, 0, 0, 0, 1);
+    skin_window_set_drag_to_move(icbar_wind, TRUE);
+
+    skin_window_set_release_cb(icbar_wind, G_CALLBACK(icbar_on_release), NULL);
+
+    /* creating the buttons */
+    icbar_status_btn = skin_button_new(info->eng_btn.normal1,
+                                       info->eng_btn.highlight1,
+                                       info->eng_btn.pressdown1);
+    icbar_full_btn = skin_button_new(info->full_btn.normal1,
+                                     info->full_btn.highlight1,
+                                     info->full_btn.pressdown1);
+    icbar_punc_btn = skin_button_new(info->punc_btn.normal1,
+                                     info->punc_btn.highlight1,
+                                     info->punc_btn.pressdown1);
+
+    /* setting up events */
+    skin_button_set_release_cb(icbar_status_btn,
+                               G_CALLBACK(toggle_english), NULL);
+    skin_button_set_release_cb(icbar_full_btn,
+                               G_CALLBACK(toggle_full), NULL);
+    skin_button_set_release_cb(icbar_punc_btn,
+                               G_CALLBACK(toggle_punc), NULL);
+
+    /* adding the buttons to the icbar */
+    skin_window_add_button(icbar_wind, icbar_status_btn, info->eng_btn.x,
+                           info->eng_btn.y);
+    skin_window_add_button(icbar_wind, icbar_full_btn, info->full_btn.x,
+                           info->full_btn.y);
+    skin_window_add_button(icbar_wind, icbar_punc_btn, info->punc_btn.x,
+                           info->punc_btn.y);
+    return TRUE;
+}
+
+static void
+toggle_mode(gboolean mode, skin_button_t* btn, skin_button_info_t* info)
+{
+    if (mode) {
+        skin_button_set_image(btn, info->normal1, info->highlight1,
+                              info->pressdown1);
+    } else {
+        skin_button_set_image(btn, info->normal2, info->highlight2,
+                              info->pressdown2);
+    }
+}
+
+static void
+icmgr_skin_refresh(void)
+{
+    if (settings_get_int(HIDE_ICBAR)) {
+        gtk_widget_hide(icbar_wind->widget);
+        return;
+    }
+    IC* ic = icmgr_get_current();
+    if (ic == NULL || !ic->is_enabled) {
+        gtk_widget_hide(GTK_WIDGET(icbar_wind->widget));
+        return;
+    }
+    toggle_mode(ic->is_english, icbar_status_btn, &(info->eng_btn));
+    toggle_mode(ic->is_full, icbar_full_btn, &(info->full_btn));
+    toggle_mode(ic->is_chn_punc, icbar_punc_btn, &(info->punc_btn));
+
+    position_t pos;
+    int width, height;
+    gtk_window_get_size(GTK_WINDOW(icbar_wind->widget), &width, &height);
+    settings_get(ICBAR_POS, &pos);
+    adjust_position(&(pos.x), &(pos.y), width, height);
+    /* write back the adjustion */
+    settings_set(ICBAR_POS, &pos);
+
+    gtk_window_move(GTK_WINDOW(icbar_wind->widget), pos.x, pos.y);
+    gtk_widget_show(icbar_wind->widget);
+}
+
+static void
+icmgr_skin_dispose(void)
+{
+    ui_skin_destroy(info);
+    free(skin_name);
+    skin_button_destroy(icbar_status_btn);
+    skin_button_destroy(icbar_full_btn);
+    skin_button_destroy(icbar_punc_btn);
+    skin_window_destroy(icbar_wind);
+}
+
+static const char*
+icmgr_skin_get_name(void)
+{
+    return skin_name;
+}
+
+IC_UI icmgr_skin = {
+    .get_name = icmgr_skin_get_name,
+    .init = icmgr_skin_init,
+    .refresh = icmgr_skin_refresh,
+    .dispose = icmgr_skin_dispose,
+};
+
diff --git a/wrapper/xim/im-switch/xsunpinyin b/wrapper/xim/im-switch/xsunpinyin
new file mode 100644 (file)
index 0000000..c4d16ed
--- /dev/null
@@ -0,0 +1,5 @@
+XIM=xsunpinyin
+XIM_ARGS=-d
+XIM_PROGRAM=/usr/bin/xsunpinyin
+GTK_IM_MODULE=xim
+QT_IM_MODULE=xim
diff --git a/wrapper/xim/main.c b/wrapper/xim/main.c
new file mode 100644 (file)
index 0000000..9beb7de
--- /dev/null
@@ -0,0 +1,119 @@
+/*
+ * Copyright (c) 2010 Mike Qin <mikeandmore@gmail.com>
+ *
+ * The contents of this file are subject to the terms of either the GNU Lesser
+ * General Public License Version 2.1 only ("LGPL") or the Common Development and
+ * Distribution License ("CDDL")(collectively, the "License"). You may not use this
+ * file except in compliance with the License. You can obtain a copy of the CDDL at
+ * http://www.opensource.org/licenses/cddl1.php and a copy of the LGPLv2.1 at
+ * http://www.opensource.org/licenses/lgpl-license.php. See the License for the
+ * specific language governing permissions and limitations under the License. When
+ * distributing the software, include this License Header Notice in each file and
+ * include the full text of the License in the License file as well as the
+ * following notice:
+ *
+ * NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND DISTRIBUTION LICENSE
+ * (CDDL)
+ * For Covered Software in this distribution, this License shall be governed by the
+ * laws of the State of California (excluding conflict-of-law provisions).
+ * Any litigation relating to this License shall be subject to the jurisdiction of
+ * the Federal Courts of the Northern District of California and the state courts
+ * of the State of California, with venue lying in Santa Clara County, California.
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by only the CDDL or only
+ * the LGPL Version 2.1, indicate your decision by adding "[Contributor]" elects to
+ * include this software in this distribution under the [CDDL or LGPL Version 2.1]
+ * license." If you don't indicate a single choice of license, a recipient has the
+ * option to distribute your version of this file under either the CDDL or the LGPL
+ * Version 2.1, or to extend the choice of license to its licensees as provided
+ * above. However, if you add LGPL Version 2.1 code and therefore, elected the LGPL
+ * Version 2 license, then the option applies only if the new code is made subject
+ * to such option by the copyright holder.
+ */
+
+#include <gtk/gtk.h>
+#include <gdk/gdkx.h>
+#include <signal.h>
+#include <langinfo.h>
+
+#include "xim.h"
+#include "xmisc.h"
+#include "ic.h"
+#include "settings.h"
+
+#define XIM_NAME "xsunpinyin"
+
+static void
+finalize(void)
+{
+    preedit_finalize();
+    icmgr_finalize();
+    settings_save();
+    settings_destroy();
+}
+
+static void
+on_app_sig(int sig)
+{
+    if (sig == SIGUSR1) {
+        /* reload the settings */
+        settings_load();
+        preedit_reload();
+    } else {
+        exit(0);
+    }
+}
+
+#define ALL_LOCALES_STRING "ca,cs,en,es,et,eu,fr,zh,zu"
+
+int
+main(int argc, char* argv[])
+{
+    if (argc == 2 && strcmp(argv[1], "-d") == 0) {
+        int pid = fork();
+        if (pid < 0)
+            return -1;
+        else if (pid > 0)
+            return 0;
+    }
+
+    init_display(&argc, &argv);
+
+    settings_init();
+    settings_load();
+
+    preedit_init();
+
+    /* check if the codeset is utf-8 */
+    if (strcmp(nl_langinfo(CODESET), "UTF-8") != 0) {
+        fprintf(stderr, "Warning: using codeset %s might cause xsunpinyin unable to trigger.\n", nl_langinfo(CODESET));
+    }
+
+    /* guess the locale */
+    char* locale = getenv("LC_CTYPE");
+    if (locale == NULL) {
+        locale = getenv("LANG");
+        if (locale == NULL) {
+            fprintf(stderr, "Can't guess locale.\n");
+            return -1;
+        }
+    }
+    char final_locale[256];
+    snprintf(final_locale, 256, "%s,%s", ALL_LOCALES_STRING, locale);
+
+    XIMHandle* hdl = create_xim_server(XIM_NAME, final_locale);
+    preedit_set_handle(hdl);
+    preedit_reload();
+
+    signal(SIGUSR1, on_app_sig);
+    signal(SIGHUP, on_app_sig);
+    signal(SIGINT, on_app_sig);
+    signal(SIGTERM, on_app_sig);
+
+    atexit(finalize);
+    gtk_main();
+
+    return 0;
+}
diff --git a/wrapper/xim/preferences.c b/wrapper/xim/preferences.c
new file mode 100644 (file)
index 0000000..6b83ab7
--- /dev/null
@@ -0,0 +1,394 @@
+/*
+ * Copyright (c) 2010 Mike Qin <mikeandmore@gmail.com>
+ *
+ * The contents of this file are subject to the terms of either the GNU Lesser
+ * General Public License Version 2.1 only ("LGPL") or the Common Development and
+ * Distribution License ("CDDL")(collectively, the "License"). You may not use this
+ * file except in compliance with the License. You can obtain a copy of the CDDL at
+ * http://www.opensource.org/licenses/cddl1.php and a copy of the LGPLv2.1 at
+ * http://www.opensource.org/licenses/lgpl-license.php. See the License for the
+ * specific language governing permissions and limitations under the License. When
+ * distributing the software, include this License Header Notice in each file and
+ * include the full text of the License in the License file as well as the
+ * following notice:
+ *
+ * NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND DISTRIBUTION LICENSE
+ * (CDDL)
+ * For Covered Software in this distribution, this License shall be governed by the
+ * laws of the State of California (excluding conflict-of-law provisions).
+ * Any litigation relating to this License shall be subject to the jurisdiction of
+ * the Federal Courts of the Northern District of California and the state courts
+ * of the State of California, with venue lying in Santa Clara County, California.
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by only the CDDL or only
+ * the LGPL Version 2.1, indicate your decision by adding "[Contributor]" elects to
+ * include this software in this distribution under the [CDDL or LGPL Version 2.1]
+ * license." If you don't indicate a single choice of license, a recipient has the
+ * option to distribute your version of this file under either the CDDL or the LGPL
+ * Version 2.1, or to extend the choice of license to its licensees as provided
+ * above. However, if you add LGPL Version 2.1 code and therefore, elected the LGPL
+ * Version 2 license, then the option applies only if the new code is made subject
+ * to such option by the copyright holder.
+ */
+
+#include <gtk/gtk.h>
+
+#include <X11/X.h>
+#include <X11/Xproto.h>
+#include <X11/Xlib.h>
+#include <X11/keysym.h>
+#include <X11/Xutil.h>
+
+#include <unistd.h>
+#include <dirent.h>
+#include <sys/types.h>
+
+#include "settings.h"
+#include "xmisc.h"
+
+#define UI_FILE SUNPINYIN_XIM_SETTING_DIR"/settings_ui.xml"
+
+static GtkWidget* main_wnd = NULL;
+static GtkToggleButton* trigger_ctrl_check = NULL;
+static GtkToggleButton* english_ctrl_check = NULL;
+static GtkToggleButton* trigger_shift_check = NULL;
+static GtkToggleButton* english_shift_check = NULL;
+static GtkComboBox* trigger_combo = NULL;
+static GtkComboBox* english_combo = NULL;
+static GtkColorButton* background_color_btn = NULL;
+static GtkFontButton* font_btn = NULL;
+static GtkColorButton* font_color_btn = NULL;
+static GtkAdjustment* opacity_value = NULL;
+static GtkAdjustment* ncandidates = NULL;
+static GtkToggleButton* minus_plus_check = NULL;
+static GtkToggleButton* comma_period_check = NULL;
+static GtkToggleButton* paren_check = NULL;
+static GtkToggleButton* fuzzy_seg_check = NULL;
+static GtkToggleButton* fuzzy_inner_seg_check = NULL;
+static GtkToggleButton* cancel_on_backspace_check = NULL;
+static GtkToggleButton* smart_punct_check = NULL;
+static GtkToggleButton* shuangpin_check = NULL;
+static GtkComboBox* shuangpin_combo = NULL;
+static GtkComboBox* skin_combo = NULL;
+static GtkToggleButton* hide_icbar_check = NULL;
+
+#define RETRIEVE(name, macro)                                   \
+    name = macro(gtk_builder_get_object(builder, # name))
+
+static const char* ui_shuangpin_schemes[] =
+{
+    "MS2003", "ABC", "ZiRanMa", "PinYin++", "ZiGuang", "XiaoHe",
+};
+
+#define UI_SHUANGPIN_SCHEMES_NUM 6
+
+static const int ui_keysym_model[] =
+{
+    XK_space, XK_Control_L, XK_Control_R, XK_Shift_L, XK_Shift_R
+};
+
+#define UI_KEYSYM_MODEL_NUM 5
+
+#define INIT_KEY_SETTING(prefix)                                        \
+    do {                                                                \
+        if (hk.modifiers & ControlMask) {                               \
+            gtk_toggle_button_set_active(prefix##_ctrl_check, TRUE);    \
+        }                                                               \
+        if (hk.modifiers & ShiftMask)                                   \
+            gtk_toggle_button_set_active(prefix##_shift_check, TRUE);   \
+        int i;                                                          \
+        for (i = 0; i < UI_KEYSYM_MODEL_NUM; i++) {                     \
+            if (hk.keysym == ui_keysym_model[i]) {                      \
+                gtk_combo_box_set_active(prefix##_combo, i);            \
+                break;                                                  \
+            }                                                           \
+        }                                                               \
+    } while(0)
+
+#define INIT_COLOR_SETTING(widget_name)                         \
+    do {                                                        \
+        GdkColor color;                                         \
+        gdk_color_parse(colorstr, &color);                      \
+        gtk_color_button_set_color((widget_name), &color);      \
+    } while(0)
+
+static int
+fill_skin_list(const char* dirpath, varchar names[], int idx)
+{
+    DIR* dir = opendir(dirpath);
+    if (!dir) {
+        mkdir(dirpath, 0644);
+        return idx;
+    }
+
+    struct dirent* ent = NULL;
+    while ((ent = readdir(dir))) {
+        if (ent->d_name[0] == '.') continue;
+        if (strcmp(ent->d_name, "classic") == 0) continue;
+
+        strncpy(names[idx], ent->d_name, sizeof(varchar));
+        idx++;
+    }
+    closedir(dir);
+    return idx;
+}
+
+#define SYSTEM_SKIN_DIR SUNPINYIN_XIM_SETTING_DIR"/skins"
+#define USER_SKIN_DIR "%s/.sunpinyin/xim_skins"
+#define MAX_SKINS 256
+
+static int
+list_skins(const char* current_skin_name)
+{
+    int idx_ret = 0;
+    int skin_count = 0;
+    varchar skins[MAX_SKINS];
+
+    GtkListStore* model = GTK_LIST_STORE(gtk_combo_box_get_model(skin_combo));
+    GtkTreeIter iter;
+    gtk_list_store_append(model, &iter);
+    gtk_list_store_set(model, &iter, 0, "classic", -1);
+
+    skin_count = fill_skin_list(SYSTEM_SKIN_DIR, skins, skin_count);
+    varchar dirpath;
+    snprintf(dirpath, sizeof(varchar), USER_SKIN_DIR, getenv("HOME"));
+    skin_count = fill_skin_list(dirpath, skins, skin_count);
+
+    /* sort and unique the names */
+    qsort(skins, skin_count, sizeof(varchar),
+          (int (*)(const void*, const void*)) strcmp);
+
+    int i, j, idx = 1;
+    for (i = 0; i < skin_count; i++) {
+        for (j = i + 1; j < skin_count; j++) {
+            if (strcmp(skins[i], skins[j]) == 0) {
+                i = j;
+            } else {
+                break;
+            }
+        }
+        if (strcmp(skins[i], current_skin_name) == 0) {
+            idx_ret = idx;
+        }
+        gtk_list_store_append(model, &iter);
+        gtk_list_store_set(model, &iter, 0, skins[i], -1);
+        idx++;
+    }
+
+    return idx_ret;
+}
+
+static void
+init_settings(void)
+{
+    settings_init();
+    settings_load();
+
+    hotkey_t hk;
+    settings_get(TRIGGER_KEY, &hk);
+    INIT_KEY_SETTING(trigger);
+
+    settings_get(ENG_KEY, &hk);
+    INIT_KEY_SETTING(english);
+
+    varchar colorstr;
+    settings_get(PREEDIT_COLOR, colorstr);
+    INIT_COLOR_SETTING(background_color_btn);
+
+    settings_get(PREEDIT_FONT_COLOR, colorstr);
+    INIT_COLOR_SETTING(font_color_btn);
+
+    varchar fontstr;
+    settings_get(PREEDIT_FONT, fontstr);
+    gtk_font_button_set_font_name(font_btn, fontstr);
+
+
+    gtk_adjustment_set_value(opacity_value,
+                             settings_get_double(PREEDIT_OPACITY));
+
+    gtk_adjustment_set_value(ncandidates, settings_get_int(CANDIDATES_SIZE));
+
+    gtk_toggle_button_set_active(minus_plus_check,
+                                 settings_get_int(PAGE_MINUS_PLUS));
+    gtk_toggle_button_set_active(comma_period_check,
+                                 settings_get_int(PAGE_COMMA_PERIOD));
+    gtk_toggle_button_set_active(paren_check,
+                                 settings_get_int(PAGE_PAREN));
+
+    gtk_toggle_button_set_active(fuzzy_seg_check,
+                                 settings_get_int(FUZZY_SEGMENTATION));
+    gtk_toggle_button_set_active(fuzzy_inner_seg_check,
+                                 settings_get_int(FUZZY_INNER_SEGMENTATION));
+
+    gtk_toggle_button_set_active(cancel_on_backspace_check,
+                                 settings_get_int(CANCEL_ON_BACKSPACE));
+
+    gtk_toggle_button_set_active(smart_punct_check,
+                                 settings_get_int(SMART_PUNCT));
+
+    gtk_toggle_button_set_active(shuangpin_check,
+                                 settings_get_int(SHUANGPIN));
+    varchar scheme;
+    int i;
+    settings_get(SHUANGPIN_SCHEME, scheme);
+    for (i = 0; i < UI_SHUANGPIN_SCHEMES_NUM; i++) {
+        if (strcmp(ui_shuangpin_schemes[i], scheme) == 0) {
+            gtk_combo_box_set_active(shuangpin_combo, i);
+            break;
+        }
+    }
+
+    /* skin */
+    varchar skin_name;
+    settings_get(SKIN_NAME, skin_name);
+    int idx = list_skins(skin_name);
+    gtk_combo_box_set_active(skin_combo, idx);
+
+    gtk_toggle_button_set_active(hide_icbar_check,
+                                 settings_get_int(HIDE_ICBAR));
+}
+
+static void
+init(void)
+{
+    GtkBuilder* builder = gtk_builder_new();
+    gtk_builder_add_from_file(builder, UI_FILE, NULL);
+    main_wnd = GTK_WIDGET(gtk_builder_get_object(builder, "settings_dialog"));
+
+    RETRIEVE(trigger_ctrl_check, GTK_TOGGLE_BUTTON);
+    RETRIEVE(english_ctrl_check, GTK_TOGGLE_BUTTON);
+    RETRIEVE(trigger_shift_check, GTK_TOGGLE_BUTTON);
+    RETRIEVE(english_shift_check, GTK_TOGGLE_BUTTON);
+    RETRIEVE(trigger_combo, GTK_COMBO_BOX);
+    RETRIEVE(english_combo, GTK_COMBO_BOX);
+    RETRIEVE(background_color_btn, GTK_COLOR_BUTTON);
+    RETRIEVE(font_btn, GTK_FONT_BUTTON);
+    RETRIEVE(font_color_btn, GTK_COLOR_BUTTON);
+    RETRIEVE(opacity_value, GTK_ADJUSTMENT);
+    RETRIEVE(ncandidates, GTK_ADJUSTMENT);
+    RETRIEVE(minus_plus_check, GTK_TOGGLE_BUTTON);
+    RETRIEVE(comma_period_check, GTK_TOGGLE_BUTTON);
+    RETRIEVE(paren_check, GTK_TOGGLE_BUTTON);
+    RETRIEVE(fuzzy_seg_check, GTK_TOGGLE_BUTTON);
+    RETRIEVE(fuzzy_inner_seg_check, GTK_TOGGLE_BUTTON);
+    RETRIEVE(cancel_on_backspace_check, GTK_TOGGLE_BUTTON);
+    RETRIEVE(smart_punct_check, GTK_TOGGLE_BUTTON);
+    RETRIEVE(shuangpin_check, GTK_TOGGLE_BUTTON);
+    RETRIEVE(shuangpin_combo, GTK_COMBO_BOX);
+    RETRIEVE(skin_combo, GTK_COMBO_BOX);
+    RETRIEVE(hide_icbar_check, GTK_TOGGLE_BUTTON);
+
+    init_settings();
+
+    gtk_builder_connect_signals(builder, NULL);
+
+    g_object_unref(builder);
+}
+
+#define REFRESH_KEY_SETTING(prefix)                                     \
+    do {                                                                \
+        hk.modifiers = hk.keysym = 0;                                   \
+        if (gtk_toggle_button_get_active(prefix##_ctrl_check)) {        \
+            hk.modifiers |= ControlMask;                                \
+        }                                                               \
+        if (gtk_toggle_button_get_active(prefix##_shift_check)) {       \
+            hk.modifiers |= ShiftMask;                                  \
+        }                                                               \
+        int idx = gtk_combo_box_get_active(prefix##_combo);             \
+        if (idx >= 0)                                                   \
+            hk.keysym = ui_keysym_model[idx];                           \
+    } while (0)
+
+#define REFRESH_COLOR_SETTING(widget_name)                              \
+    do {                                                                \
+        GdkColor color;                                                 \
+        gtk_color_button_get_color((widget_name), &color);              \
+        snprintf(colorstr, sizeof(varchar), "#%.2X%.2X%.2X",            \
+                 color.red >> 8, color.green >> 8, color.blue >> 8);    \
+    } while(0)
+
+static void
+send_reload()
+{
+    /* notify all running xsunpinyin with this user */
+    char cmd[256];
+    snprintf(cmd, 256, "/usr/bin/pkill -10 '^xsunpinyin$' -u %d", getuid());
+    system(cmd);
+}
+
+void
+state_changed()
+{
+    hotkey_t hk;
+    REFRESH_KEY_SETTING(trigger);
+    settings_set(TRIGGER_KEY, &hk);
+
+    REFRESH_KEY_SETTING(english);
+    settings_set(ENG_KEY, &hk);
+
+    varchar colorstr;
+    REFRESH_COLOR_SETTING(background_color_btn);
+    settings_set(PREEDIT_COLOR, colorstr);
+
+    REFRESH_COLOR_SETTING(font_color_btn);
+    settings_set(PREEDIT_FONT_COLOR, colorstr);
+
+    /* font and size information */
+    settings_set(PREEDIT_FONT, (void*) gtk_font_button_get_font_name(font_btn));
+
+    /* font color information */
+    settings_set_double(PREEDIT_OPACITY,
+                        gtk_adjustment_get_value(opacity_value));
+
+    settings_set_int(CANDIDATES_SIZE,
+                     gtk_adjustment_get_value(ncandidates));
+
+    /* page up and down trigger */
+    settings_set_int(PAGE_MINUS_PLUS,
+                     gtk_toggle_button_get_active(minus_plus_check));
+    settings_set_int(PAGE_COMMA_PERIOD,
+                     gtk_toggle_button_get_active(comma_period_check));
+    settings_set_int(PAGE_PAREN,
+                     gtk_toggle_button_get_active(paren_check));
+
+    /* fuzzy segmentation */
+    settings_set_int(FUZZY_SEGMENTATION,
+                     gtk_toggle_button_get_active(fuzzy_seg_check));
+    settings_set_int(FUZZY_INNER_SEGMENTATION,
+                     gtk_toggle_button_get_active(fuzzy_inner_seg_check));
+
+    /* cancel on backspace */
+    settings_set_int(CANCEL_ON_BACKSPACE,
+                     gtk_toggle_button_get_active(cancel_on_backspace_check));
+
+    /* smart punctuation */
+    settings_set_int(SMART_PUNCT,
+                     gtk_toggle_button_get_active(smart_punct_check));
+
+    settings_set_int(SHUANGPIN, gtk_toggle_button_get_active(shuangpin_check));
+    int sche_idx = gtk_combo_box_get_active(shuangpin_combo);
+    if (sche_idx < UI_SHUANGPIN_SCHEMES_NUM)
+        settings_set_string(SHUANGPIN_SCHEME, ui_shuangpin_schemes[sche_idx]);
+
+    /* skins */
+    settings_set_string(SKIN_NAME, gtk_combo_box_get_active_text(skin_combo));
+
+    /* whether hide icbar */
+    settings_set_int(HIDE_ICBAR, gtk_toggle_button_get_active(hide_icbar_check));
+
+    settings_save();
+    send_reload();
+}
+
+int main(int argc, char *argv[])
+{
+    init_display(&argc, &argv);
+    init();
+
+    gtk_widget_show(main_wnd);
+
+    gtk_main();
+    return 0;
+}
diff --git a/wrapper/xim/settings.c b/wrapper/xim/settings.c
new file mode 100644 (file)
index 0000000..91fd093
--- /dev/null
@@ -0,0 +1,438 @@
+/*
+ * Copyright (c) 2010 Mike Qin <mikeandmore@gmail.com>
+ *
+ * The contents of this file are subject to the terms of either the GNU Lesser
+ * General Public License Version 2.1 only ("LGPL") or the Common Development and
+ * Distribution License ("CDDL")(collectively, the "License"). You may not use this
+ * file except in compliance with the License. You can obtain a copy of the CDDL at
+ * http://www.opensource.org/licenses/cddl1.php and a copy of the LGPLv2.1 at
+ * http://www.opensource.org/licenses/lgpl-license.php. See the License for the
+ * specific language governing permissions and limitations under the License. When
+ * distributing the software, include this License Header Notice in each file and
+ * include the full text of the License in the License file as well as the
+ * following notice:
+ *
+ * NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND DISTRIBUTION LICENSE
+ * (CDDL)
+ * For Covered Software in this distribution, this License shall be governed by the
+ * laws of the State of California (excluding conflict-of-law provisions).
+ * Any litigation relating to this License shall be subject to the jurisdiction of
+ * the Federal Courts of the Northern District of California and the state courts
+ * of the State of California, with venue lying in Santa Clara County, California.
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by only the CDDL or only
+ * the LGPL Version 2.1, indicate your decision by adding "[Contributor]" elects to
+ * include this software in this distribution under the [CDDL or LGPL Version 2.1]
+ * license." If you don't indicate a single choice of license, a recipient has the
+ * option to distribute your version of this file under either the CDDL or the LGPL
+ * Version 2.1, or to extend the choice of license to its licensees as provided
+ * above. However, if you add LGPL Version 2.1 code and therefore, elected the LGPL
+ * Version 2 license, then the option applies only if the new code is made subject
+ * to such option by the copyright holder.
+ */
+
+#include <X11/X.h>
+#include <X11/Xproto.h>
+#include <X11/Xlib.h>
+#include <X11/keysym.h>
+#include <X11/Xutil.h>
+#include <sys/stat.h>
+
+#include "common.h"
+#include "xmisc.h"
+#include "settings.h"
+
+typedef void (*serialize_func_t)(char* str, void* data);
+
+static const char* setting_names[] = {
+    "trigger_key",
+    "eng_key",
+    "icbar_pos",
+    "preedit_opacity",
+    "preedit_color",
+    "preedit_font",
+    "preedit_font_color",
+    "shuangpin",
+    "shuangpin_scheme",
+    "candidates_size",
+    "page_minus_plus",
+    "page_comma_period",
+    "page_paren",
+    "fuzzy_inner_segmentation",
+    "fuzzy_segmentation",
+    "cancel_on_backspace",
+    "smart_punct",
+    "skin_name",
+    "hide_icbar",
+    NULL
+};
+
+static void*  setting_data[MAX_KEY];
+static size_t setting_size[MAX_KEY];
+
+static serialize_func_t setting_enc[MAX_KEY];
+static serialize_func_t setting_dec[MAX_KEY];
+
+static void
+__varchar_enc(char* str, void* data)
+{
+    strncpy(str, data, 128);
+}
+
+static void
+__varchar_dec(char* str, void* data)
+{
+    strncpy(data, str, 128);
+}
+
+static void
+__double_enc(char* str, void* data)
+{
+    double* ptr = data;
+    snprintf(str, 256, "%.2lf", *ptr);
+}
+
+static void
+__double_dec(char* str, void* data)
+{
+    double* ptr = data;
+    sscanf(str, "%lf", ptr);
+}
+
+static void
+__int_enc(char* str, void* data)
+{
+    int* ptr = data;
+    snprintf(str, 256, "%d", *ptr);
+}
+
+static void
+__int_dec(char* str, void* data)
+{
+    int* ptr = data;
+    sscanf(str, "%d", ptr);
+}
+
+static void
+__position_enc(char* str, void* data)
+{
+    position_t* pos = data;
+    snprintf(str, 256, "%d,%d", pos->x, pos->y);
+}
+
+static void
+__position_dec(char* str, void* data)
+{
+    position_t* pos = data;
+    sscanf(str, "%d,%d", &pos->x, &pos->y);
+}
+
+static const int kmap_keysym[] =
+{
+    XK_Shift_L, XK_Shift_R, XK_Control_L,
+    XK_Control_R, XK_Meta_L, XK_Meta_R,
+    XK_space,
+};
+
+static const char* kmap_text[] =
+{
+    "Shift_L", "Shift_R", "Control_L",
+    "Control_R", "Meta_L", "Meta_R", "space",
+};
+
+const int nkmap = 7;
+
+static void
+__hotkey_enc(char* str, void* data)
+{
+    hotkey_t* hk = data;
+    if (hk->modifiers & ControlMask) {
+        strncat(str, "Control+", 255);
+    }
+    if (hk->modifiers & ShiftMask) {
+        strncat(str, "Shift+", 255);
+    }
+
+    char keyname[256];
+    memset(keyname, 0, sizeof(char) * 256);
+    int i;
+    for (i = 0; i < nkmap + 1; i++) {
+        if (i == nkmap) {
+            keyname[0] = hk->keysym - 0x0020;
+            break;
+        } else if (hk->keysym == kmap_keysym[i]) {
+            strncpy(keyname, kmap_text[i], 255);
+            break;
+        }
+    }
+
+    strncat(str, keyname, 255);
+}
+
+static void
+__hotkey_dec(char* str, void* data)
+{
+    hotkey_t* hk = data;
+    hk->keysym = 0;
+    hk->modifiers = 0;
+
+    char* last_ptr = str;
+    char text[256];
+    while (1) {
+        char* ptr = strchr(last_ptr, '+');
+        memset(text, 0, sizeof(char) * 256);
+        if (ptr == NULL)
+            strcpy(text, last_ptr);
+        else
+            strncpy(text, last_ptr, (ptr - last_ptr) * sizeof(char));
+
+        if (ptr == NULL) {
+            int i;
+            for (i = 0; i < nkmap + 1; i++) {
+                if (i == nkmap) {
+                    hk->keysym = text[0] + 0x0020;
+                    break;
+                } else if (strcmp(text, kmap_text[i]) == 0) {
+                    hk->keysym = kmap_keysym[i];
+                    break;
+                }
+            }
+            break;
+        } else {
+            if (strcmp(text, "Control") == 0)
+                hk->modifiers |= ControlMask;
+            if (strcmp(text, "Shift") == 0)
+                hk->modifiers |= ShiftMask;
+        }
+        last_ptr = ptr + 1;
+    }
+}
+
+static void
+__init_default_values()
+{
+    hotkey_t hk;
+    position_t pos;
+    double d;
+    varchar str;
+    int i;
+
+    /* trigger key */
+    hk.modifiers = ControlMask;
+    hk.keysym = XK_space;
+    settings_set(TRIGGER_KEY, &hk);
+
+    /* eng key */
+    hk.modifiers = 0;
+    hk.keysym = XK_Shift_L;
+    settings_set(ENG_KEY, &hk);
+
+    get_screen_size(&(pos.x), &(pos.y));
+    pos.x -= 200;
+    pos.y -= 70;
+
+    settings_set(ICBAR_POS, &pos);
+
+    /* preedit opacity */
+    settings_set_double(PREEDIT_OPACITY, 1.0);
+
+    settings_set_string(PREEDIT_COLOR, "#FFFFB3");
+    settings_set_string(PREEDIT_FONT, "Sans 10");
+    settings_set_string(PREEDIT_FONT_COLOR, "#000000");
+
+    settings_set_int(SHUANGPIN, 0);
+    settings_set_string(SHUANGPIN_SCHEME, "MS2003");
+
+    settings_set_int(CANDIDATES_SIZE, 10);
+
+    /* page up and down trigger */
+    settings_set_int(PAGE_MINUS_PLUS, 1);
+    settings_set_int(PAGE_COMMA_PERIOD, 0);
+    settings_set_int(PAGE_PAREN, 0);
+
+    /* fuzzy segmentation */
+    settings_set_int(FUZZY_SEGMENTATION, 0);
+    settings_set_int(FUZZY_INNER_SEGMENTATION, 0);
+
+    /* cancel on backspace */
+    settings_set_int(CANCEL_ON_BACKSPACE, 1);
+
+    /* smart punctuation */
+    settings_set_int(SMART_PUNCT, 0);
+
+    /* skin support */
+    settings_set_string(SKIN_NAME, "classic");
+
+    /* whether hide icbar */
+    settings_set_int(HIDE_ICBAR, 0);
+}
+
+#define REGISTER(k, type, efunc, dfunc)               \
+    do {                                        \
+        setting_data[k] = malloc(sizeof(type)); \
+        setting_size[k] = sizeof(type);         \
+        setting_enc[k] = efunc;                 \
+        setting_dec[k] = dfunc;                 \
+    } while(0)                                  \
+
+void
+settings_init()
+{
+    memset(setting_data, 0, sizeof(void*) * MAX_KEY);
+
+    REGISTER(TRIGGER_KEY, hotkey_t, __hotkey_enc, __hotkey_dec);
+    REGISTER(ENG_KEY, hotkey_t, __hotkey_enc, __hotkey_dec);
+    REGISTER(ICBAR_POS, position_t, __position_enc, __position_dec);
+    REGISTER(PREEDIT_OPACITY, double, __double_enc, __double_dec);
+    REGISTER(PREEDIT_COLOR, varchar, __varchar_enc, __varchar_dec);
+    REGISTER(PREEDIT_FONT, varchar, __varchar_enc, __varchar_dec);
+    REGISTER(PREEDIT_FONT_COLOR, varchar, __varchar_enc, __varchar_dec);
+    REGISTER(SHUANGPIN, int, __int_enc, __int_dec);
+    REGISTER(SHUANGPIN_SCHEME, varchar, __varchar_enc, __varchar_dec);
+    REGISTER(CANDIDATES_SIZE, int, __int_enc, __int_dec);
+    REGISTER(PAGE_MINUS_PLUS, int, __int_enc, __int_dec);
+    REGISTER(PAGE_COMMA_PERIOD, int, __int_enc, __int_dec);
+    REGISTER(PAGE_PAREN, int, __int_enc, __int_dec);
+    REGISTER(FUZZY_SEGMENTATION, int, __int_enc, __int_dec);
+    REGISTER(FUZZY_INNER_SEGMENTATION, int, __int_enc, __int_dec);
+    REGISTER(CANCEL_ON_BACKSPACE, int, __int_enc, __int_dec);
+    REGISTER(SMART_PUNCT, int, __int_enc, __int_dec);
+    REGISTER(SKIN_NAME, varchar, __varchar_enc, __varchar_dec);
+    REGISTER(HIDE_ICBAR, int, __int_enc, __int_dec);
+
+    __init_default_values();
+}
+
+void
+settings_destroy()
+{
+    int i = 0;
+    while (setting_names[i] != NULL) {
+        if (setting_data[i] != NULL)
+            free(setting_data[i]);
+        i++;
+    }
+}
+
+#define SETTING_FILE ".sunpinyin/xim_config"
+#define DEFAULT_SETTING_FILE SUNPINYIN_XIM_SETTING_DIR"/xim_config_default"
+
+void
+settings_load()
+{
+    char path[256];
+    char line[256];
+    snprintf(path, 256, "%s/%s", getenv("HOME"), SETTING_FILE);
+    FILE *fp = fopen(path, "r");
+    if (fp == NULL) {
+        char config_dir[256];
+        snprintf(config_dir, 256, "%s/.sunpinyin", getenv("HOME"));
+        mkdir(config_dir, S_IRWXU);
+        settings_save();
+        if ((fp = fopen(path, "r")) == NULL)
+            return;
+    }
+    while (1) {
+        memset(line, 0, sizeof(char) * 256);
+        if (fgets(line, 256, fp) == NULL)
+            break;
+        if (line[0] == 0)
+            break;
+
+        /* strip the last \n */
+        line[strlen(line) - 1] = 0;
+
+        /* bypass the comment */
+        if (line[0] == '#')
+            continue;
+
+        char* ptr = strchr(line, '=');
+        int i = 0;
+        while (setting_names[i] != NULL) {
+            if (strncmp(line, setting_names[i], ptr - line) == 0) {
+                serialize_func_t func = setting_dec[i];
+                func(ptr + 1, setting_data[i]);
+            }
+            i++;
+        }
+    }
+    fclose(fp);
+}
+
+void
+settings_save()
+{
+    char path[256];
+    char line[256];
+    snprintf(path, 256, "%s/%s", getenv("HOME"), SETTING_FILE);
+    FILE *fp = fopen(path, "w");
+    if (fp == NULL) {
+        LOG("settings can't be saved");
+        return;
+    }
+    int i = 0;
+    while (setting_names[i] != NULL) {
+        memset(line, 0, sizeof(char) * 256);
+        serialize_func_t func = setting_enc[i];
+        func(line, setting_data[i]);
+        fprintf(fp, "%s=%s\n", setting_names[i], line);
+        i++;
+    }
+    fclose(fp);
+}
+
+int settings_get_int(setting_key_t key)
+{
+    int ret = 0;
+    settings_get(key, &ret);
+    return ret;
+}
+
+double settings_get_double(setting_key_t key)
+{
+    double ret = 0;
+    settings_get(key, &ret);
+    return ret;
+}
+
+void
+settings_get(setting_key_t key, void* data)
+{
+    if (setting_data[key] == NULL) {
+        LOG("invalid setting key %d to get", key);
+        return;
+    }
+    memcpy(data, setting_data[key], setting_size[key]);
+}
+
+void
+settings_set_int(setting_key_t key, int value)
+{
+    settings_set(key, &value);
+}
+
+void
+settings_set_double(setting_key_t key, double value)
+{
+    settings_set(key, &value);
+}
+
+void
+settings_set_string(setting_key_t key, const char* str)
+{
+    varchar vchar;
+    strncpy(vchar, str, sizeof(varchar));
+    settings_set(key, vchar);
+}
+
+void
+settings_set(setting_key_t key, void* data)
+{
+    if (setting_data[key] == NULL) {
+        LOG("invalid setting key %d to set", key);
+        return;
+    }
+    memcpy(setting_data[key], data, setting_size[key]);
+}
diff --git a/wrapper/xim/settings.h b/wrapper/xim/settings.h
new file mode 100644 (file)
index 0000000..0fdf8ad
--- /dev/null
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2010 Mike Qin <mikeandmore@gmail.com>
+ *
+ * The contents of this file are subject to the terms of either the GNU Lesser
+ * General Public License Version 2.1 only ("LGPL") or the Common Development and
+ * Distribution License ("CDDL")(collectively, the "License"). You may not use this
+ * file except in compliance with the License. You can obtain a copy of the CDDL at
+ * http://www.opensource.org/licenses/cddl1.php and a copy of the LGPLv2.1 at
+ * http://www.opensource.org/licenses/lgpl-license.php. See the License for the
+ * specific language governing permissions and limitations under the License. When
+ * distributing the software, include this License Header Notice in each file and
+ * include the full text of the License in the License file as well as the
+ * following notice:
+ *
+ * NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND DISTRIBUTION LICENSE
+ * (CDDL)
+ * For Covered Software in this distribution, this License shall be governed by the
+ * laws of the State of California (excluding conflict-of-law provisions).
+ * Any litigation relating to this License shall be subject to the jurisdiction of
+ * the Federal Courts of the Northern District of California and the state courts
+ * of the State of California, with venue lying in Santa Clara County, California.
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by only the CDDL or only
+ * the LGPL Version 2.1, indicate your decision by adding "[Contributor]" elects to
+ * include this software in this distribution under the [CDDL or LGPL Version 2.1]
+ * license." If you don't indicate a single choice of license, a recipient has the
+ * option to distribute your version of this file under either the CDDL or the LGPL
+ * Version 2.1, or to extend the choice of license to its licensees as provided
+ * above. However, if you add LGPL Version 2.1 code and therefore, elected the LGPL
+ * Version 2 license, then the option applies only if the new code is made subject
+ * to such option by the copyright holder.
+ */
+
+#ifndef _SETTINGS_H_
+#define _SETTINGS_H_
+
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <string.h>
+
+#include "common.h"
+
+__BEGIN_DECLS
+
+typedef struct {
+    int x;
+    int y;
+} position_t;
+
+typedef struct {
+    int modifiers;
+    int keysym;
+} hotkey_t;
+
+typedef char varchar[128];
+
+typedef enum {
+    TRIGGER_KEY = 0,
+    ENG_KEY,
+    ICBAR_POS,
+    PREEDIT_OPACITY,
+    PREEDIT_COLOR,
+    PREEDIT_FONT,
+    PREEDIT_FONT_COLOR,
+    SHUANGPIN,
+    SHUANGPIN_SCHEME,
+    CANDIDATES_SIZE,
+    PAGE_MINUS_PLUS,
+    PAGE_COMMA_PERIOD,
+    PAGE_PAREN,
+    FUZZY_SEGMENTATION,
+    FUZZY_INNER_SEGMENTATION,
+    CANCEL_ON_BACKSPACE,
+    SMART_PUNCT,
+    SKIN_NAME,
+    HIDE_ICBAR,
+} setting_key_t;
+
+#define MAX_KEY 0xFF
+
+void  settings_init();
+void  settings_destroy();
+
+void  settings_load();
+void  settings_save();
+
+void  settings_get(setting_key_t key, void* data);
+void  settings_set(setting_key_t key, void* data);
+
+void  settings_set_int(setting_key_t key, int value);
+void  settings_set_double(setting_key_t key, double value);
+void  settings_set_string(setting_key_t key, const char* str);
+
+int    settings_get_int(setting_key_t key);
+double settings_get_double(setting_key_t key);
+
+__END_DECLS
+
+#endif /* _SETTINGS_H_ */
diff --git a/wrapper/xim/skin.c b/wrapper/xim/skin.c
new file mode 100644 (file)
index 0000000..56b0793
--- /dev/null
@@ -0,0 +1,594 @@
+/*
+ * Copyright (c) 2010 Mike Qin <mikeandmore@gmail.com>
+ *
+ * The contents of this file are subject to the terms of either the GNU Lesser
+ * General Public License Version 2.1 only ("LGPL") or the Common Development and
+ * Distribution License ("CDDL")(collectively, the "License"). You may not use this
+ * file except in compliance with the License. You can obtain a copy of the CDDL at
+ * http://www.opensource.org/licenses/cddl1.php and a copy of the LGPLv2.1 at
+ * http://www.opensource.org/licenses/lgpl-license.php. See the License for the
+ * specific language governing permissions and limitations under the License. When
+ * distributing the software, include this License Header Notice in each file and
+ * include the full text of the License in the License file as well as the
+ * following notice:
+ *
+ * NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND DISTRIBUTION LICENSE
+ * (CDDL)
+ * For Covered Software in this distribution, this License shall be governed by the
+ * laws of the State of California (excluding conflict-of-law provisions).
+ * Any litigation relating to this License shall be subject to the jurisdiction of
+ * the Federal Courts of the Northern District of California and the state courts
+ * of the State of California, with venue lying in Santa Clara County, California.
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by only the CDDL or only
+ * the LGPL Version 2.1, indicate your decision by adding "[Contributor]" elects to
+ * include this software in this distribution under the [CDDL or LGPL Version 2.1]
+ * license." If you don't indicate a single choice of license, a recipient has the
+ * option to distribute your version of this file under either the CDDL or the LGPL
+ * Version 2.1, or to extend the choice of license to its licensees as provided
+ * above. However, if you add LGPL Version 2.1 code and therefore, elected the LGPL
+ * Version 2 license, then the option applies only if the new code is made subject
+ * to such option by the copyright holder.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include "skin.h"
+
+struct _skin_window_priv_t
+{
+    skin_label_t* labels;
+    skin_button_t* btns;
+
+    /* current expose environment */
+    skin_button_t* highlight_btn;
+    skin_button_t* pressdown_btn;
+
+    GCallback      press_cb;
+    GCallback      release_cb;
+    GCallback      motion_cb;
+
+    void*          press_cb_data;
+    void*          release_cb_data;
+    void*          motion_cb_data;
+
+    /* drag to move positions */
+    gboolean       enable_drag_to_move;
+    int            drag_init_x;
+    int            drag_init_y;
+    gboolean       drag_begin;
+};
+
+struct _skin_button_priv_t
+{
+    skin_button_t* next;
+    skin_window_t* parent;
+
+    GCallback press_cb;
+    GCallback release_cb;
+
+    void*     press_cb_data;
+    void*     release_cb_data;
+};
+
+struct _skin_label_priv_t
+{
+    skin_label_t*  next;
+    skin_window_t* wind;
+};
+
+static void
+zoom_and_composite(GdkPixbuf* src,
+                   GdkPixbuf* dst,
+                   int        x,
+                   int        y,
+                   int        width,
+                   int        height,
+                   int        dst_x,
+                   int        dst_y,
+                   int        dst_width,
+                   int        dst_height)
+{
+    if (width <= 0 || height <= 0 || dst_width <= 0 || dst_height <= 0)
+        return;
+    GdkPixbuf* sub = gdk_pixbuf_new_subpixbuf(src, x, y, width, height);
+    double x_scale = 1.0 * dst_width / width;
+    double y_scale = 1.0 * dst_height / height;
+
+    gdk_pixbuf_scale(sub, dst, dst_x, dst_y, dst_width, dst_height,
+                     dst_x, dst_y, x_scale, y_scale, GDK_INTERP_BILINEAR);
+    g_object_unref(sub);
+}
+
+static void
+cairo_paint_pixbuf(cairo_t*   cr,
+                   GdkPixbuf* buf,
+                   int        off_x,
+                   int        off_y)
+{
+    gdk_cairo_set_source_pixbuf(cr, buf, off_x, off_y);
+    cairo_paint(cr);
+}
+
+static void
+paint_background_with_mask(GtkWidget*      wid,
+                           skin_window_t*  wind)
+{
+    GdkPixbuf* bg = wind->background_image;
+    int width, height;
+    int bg_width, bg_height;
+    int top, left, bottom, right;
+
+    width = wid->allocation.width;
+    height = wid->allocation.height;
+    bg_width = gdk_pixbuf_get_width(bg);
+    bg_height = gdk_pixbuf_get_height(bg);
+
+    top = wind->margin_top;
+    left = wind->margin_left;
+    right = wind->margin_right;
+    bottom = wind->margin_bottom;
+
+    GdkPixbuf* newbg = gdk_pixbuf_new(GDK_COLORSPACE_RGB, TRUE, 8,
+                                       width, height);
+
+    // 4 corners
+    gdk_pixbuf_copy_area(bg, 0, 0, left, top, newbg, 0, 0);
+    gdk_pixbuf_copy_area(bg, bg_width - right, 0, right, top,
+                         newbg, width - right, 0);
+    gdk_pixbuf_copy_area(bg, 0, bg_height - bottom, left, bottom,
+                         newbg, 0, height - bottom);
+    gdk_pixbuf_copy_area(bg, bg_width - right, bg_height - bottom,
+                         right, bottom,
+                         newbg, width - right, height - bottom);
+
+    // 4 margins and the center area
+    int content_width = bg_width - left - right;
+    int content_height = bg_height - top - bottom;
+    int new_content_width = width - left - right;
+    int new_content_height = height - top - bottom;
+
+    // top
+    zoom_and_composite(bg, newbg, left, 0, content_width, top,
+                       left, 0, new_content_width, top);
+    // bottom
+    zoom_and_composite(bg, newbg,
+                       left, bg_height - bottom, content_width, bottom,
+                       left, height - bottom, new_content_width, bottom);
+    // left
+    zoom_and_composite(bg, newbg,
+                       0, top, left, content_height,
+                       0, top, left, new_content_height);
+    // right
+    zoom_and_composite(bg, newbg,
+                       bg_width - right, top, right, content_height,
+                       width - right, top, right, new_content_height);
+    // center
+    zoom_and_composite(bg, newbg,
+                       left, top, content_width, content_height,
+                       left, top, new_content_width, new_content_height);
+
+    gdk_window_clear(wid->window);
+    // paint it
+    cairo_t* cr = gdk_cairo_create(wid->window);
+    cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
+    cairo_set_source_rgba(cr, 0.0, 0.0, 0.0, 0.0);
+    cairo_paint(cr);
+    cairo_paint_pixbuf(cr, newbg, 0, 0);
+    cairo_destroy(cr);
+    // set the mask
+    GdkBitmap* mask;
+    gdk_pixbuf_render_pixmap_and_mask(newbg, NULL, &mask,
+                                      wind->alpha_mask_threshold);
+    gdk_window_shape_combine_mask(wid->window, mask, 0, 0);
+
+    g_object_unref(newbg);
+}
+
+static void
+paint_buttons(GtkWidget*     wid,
+              skin_window_t* wind)
+{
+    cairo_t* cr = gdk_cairo_create(wid->window);
+    skin_button_t* btn = wind->priv->btns;
+    for (; btn != NULL; btn = btn->priv->next) {
+        if (btn == wind->priv->pressdown_btn) {
+            cairo_paint_pixbuf(cr, btn->pressdown_image, btn->x, btn->y);
+        } else if (btn == wind->priv->highlight_btn) {
+            cairo_paint_pixbuf(cr, btn->highlight_image, btn->x, btn->y);
+        } else {
+            cairo_paint_pixbuf(cr, btn->normal_image, btn->x, btn->y);
+        }
+    }
+    cairo_destroy(cr);
+}
+
+static void
+paint_labels(GtkWidget*     wid,
+             skin_window_t* wind)
+{
+    cairo_t* cr = gdk_cairo_create(wid->window);
+    skin_label_t* label = wind->priv->labels;
+    for (; label != NULL; label = label->priv->next) {
+        cairo_set_source_rgba(cr, label->color_r, label->color_g,
+                              label->color_b, label->color_a);
+        if (label->layout == NULL) {
+            label->layout = pango_cairo_create_layout(cr);
+            pango_layout_set_font_description(
+                label->layout, pango_font_description_from_string(label->font));
+        }
+        pango_layout_set_text(label->layout, label->text, -1);
+        cairo_move_to(cr, label->x, label->y);
+        pango_cairo_layout_path(cr, label->layout);
+        cairo_fill(cr);
+    }
+    cairo_destroy(cr);
+}
+
+static gboolean
+window_on_expose(GtkWidget*      wid,
+                 GdkEventExpose* evt,
+                 skin_window_t*  wind)
+{
+    paint_background_with_mask(wid, wind);
+    paint_labels(wid, wind);
+    paint_buttons(wid, wind);
+    return TRUE;
+}
+
+static gboolean
+window_on_configure(GtkWidget*         wid,
+                    GdkEventConfigure* evt,
+                    skin_window_t*     wind)
+{
+    gtk_widget_queue_draw(wid);
+    return FALSE;
+}
+
+static skin_button_t*
+find_button(skin_window_t* wind, int pos_x, int pos_y)
+{
+    skin_button_t* btn = wind->priv->btns;
+    for (; btn != NULL; btn = btn->priv->next) {
+        int x = btn->x, y = btn->y, width = btn->width, height = btn->height;
+        if (pos_x > x && pos_y > y && pos_x < x + width && pos_y < y + height) {
+            return btn;
+        }
+    }
+    return NULL;
+}
+
+static gboolean
+set_expose_env(skin_window_t* wind,
+               skin_button_t* highlight,
+               skin_button_t* down)
+{
+    gboolean ret = FALSE;
+    if (wind->priv->highlight_btn != highlight) {
+        ret |= TRUE;
+        wind->priv->highlight_btn = highlight;
+    }
+    if (wind->priv->pressdown_btn != down) {
+        ret |= TRUE;
+        wind->priv->pressdown_btn = down;
+    }
+    return ret;
+}
+
+typedef gboolean (*motion_cb_t) (GtkWidget*, GdkEventMotion*, void*);
+typedef gboolean (*mouse_cb_t) (GtkWidget*, GdkEventButton*, void*);
+
+static gboolean
+window_on_motion(GtkWidget*      wid,
+                 GdkEventMotion* evt,
+                 skin_window_t*  wind)
+{
+    skin_button_t* btn = find_button(wind, evt->x, evt->y);
+    gboolean need_redraw = FALSE;
+    if (btn) {
+        if ((evt->state & GDK_BUTTON1_MASK) != 0
+            || (evt->state & GDK_BUTTON2_MASK) != 0
+            || (evt->state & GDK_BUTTON3_MASK) != 0) {
+            need_redraw = set_expose_env(wind, NULL, btn);
+        } else {
+            need_redraw = set_expose_env(wind, btn, NULL);
+        }
+    } else {
+        /* move it if drag */
+        if (wind->priv->enable_drag_to_move && wind->priv->drag_begin) {
+            gtk_window_move(GTK_WINDOW(wind->widget),
+                            evt->x_root - wind->priv->drag_init_x,
+                            evt->y_root - wind->priv->drag_init_y);
+        }
+        need_redraw = set_expose_env(wind, NULL, NULL);
+        motion_cb_t cb = (motion_cb_t) wind->priv->motion_cb;
+        if (cb) {
+            cb(wid, evt, wind->priv->motion_cb_data);
+        }
+    }
+    if (need_redraw) {
+        gtk_widget_queue_draw(wid);
+    }
+    return TRUE;
+}
+
+static gboolean
+window_on_press_or_release(GtkWidget*      wid,
+                           GdkEventButton* evt,
+                           skin_window_t*  wind,
+                           gboolean        press)
+{
+    skin_button_t* btn = find_button(wind, evt->x, evt->y);
+    gboolean need_redraw = FALSE;
+    skin_button_t* highlight_btn = NULL;
+    skin_button_t* pressdown_btn = NULL;
+    mouse_cb_t btncb = NULL;
+    mouse_cb_t wincb = NULL;
+
+    if (press) {
+        wincb = (mouse_cb_t) wind->priv->press_cb;
+        pressdown_btn = btn;
+        if (!btn) {
+            /* update drag init positions */
+            wind->priv->drag_init_x = evt->x;
+            wind->priv->drag_init_y = evt->y;
+            wind->priv->drag_begin = wind->priv->enable_drag_to_move;
+        } else {
+            btncb = (mouse_cb_t) btn->priv->press_cb;
+        }
+    } else {
+        wincb = (mouse_cb_t) wind->priv->release_cb;
+        highlight_btn = btn;
+        if (!btn) {
+            wind->priv->drag_begin = FALSE;
+        } else {
+            btncb = (mouse_cb_t) btn->priv->release_cb;
+        }
+    }
+
+    if (btn) {
+        need_redraw = set_expose_env(wind, highlight_btn, pressdown_btn);
+        if (btncb) {
+            btncb(wid, evt, btn->priv->press_cb_data);
+        }
+    } else {
+        if (wincb) {
+            wincb(wid, evt, wind->priv->press_cb_data);
+        }
+    }
+    if (need_redraw) {
+        gtk_widget_queue_draw(wid);
+    }
+    return TRUE;
+}
+
+static gboolean
+window_on_press(GtkWidget*      wid,
+                GdkEventButton* evt,
+                skin_window_t*  wind)
+{
+    return window_on_press_or_release(wid, evt, wind, TRUE);
+}
+
+static gboolean
+window_on_release(GtkWidget* wid,
+                  GdkEventButton* evt,
+                  skin_window_t* wind)
+{
+    return window_on_press_or_release(wid, evt, wind, FALSE);
+}
+
+skin_window_t*
+skin_window_new(GtkWindow* widget,
+                GdkPixbuf* background_image,
+                int        margin_top,
+                int        margin_left,
+                int        margin_bottom,
+                int        margin_right,
+                int        alpha_mask_threshold)
+{
+    skin_window_t* wind = malloc(sizeof(skin_window_t));
+    wind->widget = GTK_WIDGET(widget);
+    wind->background_image = background_image;
+    wind->margin_top = margin_top;
+    wind->margin_left = margin_left;
+    wind->margin_bottom = margin_bottom;
+    wind->margin_right = margin_right;
+    wind->alpha_mask_threshold = alpha_mask_threshold;
+    wind->priv = malloc(sizeof(skin_window_priv_t));
+    memset(wind->priv, 0, sizeof(skin_window_priv_t));
+    gtk_window_set_default_size(widget,
+                                gdk_pixbuf_get_width(background_image),
+                                gdk_pixbuf_get_height(background_image));
+
+    /* set rgba */
+    GdkScreen* screen = gdk_screen_get_default();
+    GdkColormap* cmap = gdk_screen_get_rgba_colormap(screen);
+    if (cmap) {
+        gtk_widget_set_colormap(wind->widget, cmap);
+    } else {
+        fprintf(stderr, "Cannot set rgba colormap!\n");
+    }
+
+    /* signal expose */
+    gtk_widget_set_events(wind->widget,
+                          GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK
+                          | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK);
+    gtk_widget_realize(wind->widget);
+
+    g_signal_connect(wind->widget, "expose-event",
+                     G_CALLBACK(window_on_expose), wind);
+    g_signal_connect(wind->widget, "configure-event",
+                     G_CALLBACK(window_on_configure), wind);
+    g_signal_connect(wind->widget, "motion-notify-event",
+                     G_CALLBACK(window_on_motion), wind);
+    g_signal_connect(wind->widget, "button-press-event",
+                     G_CALLBACK(window_on_press), wind);
+    g_signal_connect(wind->widget, "button-release-event",
+                     G_CALLBACK(window_on_release), wind);
+    return wind;
+}
+
+void
+skin_window_destroy(skin_window_t* wind)
+{
+    gtk_widget_destroy(wind->widget);
+    free(wind->priv);
+    free(wind);
+}
+
+void
+skin_window_add_button(skin_window_t* wind,
+                       skin_button_t* btn,
+                       int            x,
+                       int            y)
+{
+    /* append to the buttons list */
+    btn->priv->next = wind->priv->btns;
+    wind->priv->btns = btn;
+
+    btn->priv->parent = wind;
+    btn->x = x;
+    btn->y = y;
+}
+
+void
+skin_window_set_drag_to_move(skin_window_t* wind,
+                             gboolean       drag_to_move)
+{
+    wind->priv->enable_drag_to_move = drag_to_move;
+}
+
+skin_button_t*
+skin_button_new(GdkPixbuf* normal_image,
+                GdkPixbuf* highlight_image,
+                GdkPixbuf* pressdown_image)
+{
+    skin_button_t* btn = malloc(sizeof(skin_button_t));
+    btn->normal_image = normal_image;
+    btn->highlight_image = highlight_image;
+    btn->pressdown_image = pressdown_image;
+    btn->width = gdk_pixbuf_get_width(normal_image);
+    btn->height = gdk_pixbuf_get_height(normal_image);
+    btn->priv = malloc(sizeof(skin_button_priv_t));
+    memset(btn->priv, 0, sizeof(skin_button_priv_t));
+    return btn;
+}
+
+void
+skin_button_destroy(skin_button_t* btn)
+{
+    free(btn->priv);
+    free(btn);
+}
+
+void
+skin_button_set_image(skin_button_t* btn,
+                      GdkPixbuf* normal_image,
+                      GdkPixbuf* highlight_image,
+                      GdkPixbuf* pressdown_image)
+{
+    /* since we're redraw it, we'd better check if we really changed
+       the pixbuf. This can save a lot of time.
+    */
+    gboolean need_set = (btn->normal_image != normal_image) ||
+        (btn->highlight_image != highlight_image) ||
+        (btn->pressdown_image != pressdown_image);
+
+    if (!need_set)
+        return;
+
+    btn->normal_image = normal_image;
+    btn->highlight_image = highlight_image;
+    btn->pressdown_image = pressdown_image;
+    if (btn->priv->parent) {
+        gtk_widget_queue_draw(btn->priv->parent->widget);
+    }
+}
+
+skin_label_t*
+skin_label_new(char*  font,
+               char*  text,
+               double color_r,
+               double color_g,
+               double color_b,
+               double color_a)
+{
+    skin_label_t* label = malloc(sizeof(skin_label_t));
+    label->color_r = color_r;
+    label->color_g = color_g;
+    label->color_b = color_b;
+    label->color_a = color_a;
+    label->font = strdup(font);
+    if (text) {
+        label->text = strdup(text);
+    } else {
+        label->text = NULL;
+    }
+    label->layout = NULL;
+    label->priv = malloc(sizeof(skin_label_priv_t));
+    memset(label->priv, 0, sizeof(skin_label_priv_t));
+
+    return label;
+}
+
+void
+skin_label_destroy(skin_label_t* label)
+{
+    free(label->text);
+    free(label->font);
+    free(label->priv);
+    if (label->layout) {
+        g_object_unref(label->layout);
+    }
+    free(label);
+}
+
+void
+skin_window_add_label(skin_window_t* wind,
+                      skin_label_t*  label,
+                      int            x,
+                      int            y)
+{
+    label->x = x;
+    label->y = y;
+    label->priv->wind = wind;
+    label->priv->next = wind->priv->labels;
+    wind->priv->labels = label;
+
+    cairo_t* cr = gdk_cairo_create(wind->widget->window);
+    label->layout = pango_cairo_create_layout(cr);
+    pango_layout_set_font_description(
+        label->layout, pango_font_description_from_string(label->font));
+    cairo_destroy(cr);
+}
+
+void
+skin_label_set_text(skin_label_t* label, const char* text)
+{
+    free(label->text);
+    if (text) {
+        label->text = strdup(text);
+        pango_layout_set_text(label->layout, label->text, -1);
+    } else {
+        label->text = NULL;
+    }
+    if (label->layout && label->priv->wind) {
+        gtk_widget_queue_draw(label->priv->wind->widget);
+    }
+}
+
+#define SET_CB_IMPL(name, event)                                        \
+    void skin_##name##_set_##event##_cb(skin_##name##_t* wid,           \
+                                        GCallback        cb,            \
+                                        void*            data)          \
+    { wid->priv->event##_cb = cb; wid->priv->event##_cb_data = data; }  \
+
+
+SET_CB_IMPL(window, press);
+SET_CB_IMPL(window, release);
+SET_CB_IMPL(window, motion);
+SET_CB_IMPL(button, press);
+SET_CB_IMPL(button, release);
diff --git a/wrapper/xim/skin.h b/wrapper/xim/skin.h
new file mode 100644 (file)
index 0000000..bc8f8d6
--- /dev/null
@@ -0,0 +1,159 @@
+/*
+ * Copyright (c) 2010 Mike Qin <mikeandmore@gmail.com>
+ *
+ * The contents of this file are subject to the terms of either the GNU Lesser
+ * General Public License Version 2.1 only ("LGPL") or the Common Development and
+ * Distribution License ("CDDL")(collectively, the "License"). You may not use this
+ * file except in compliance with the License. You can obtain a copy of the CDDL at
+ * http://www.opensource.org/licenses/cddl1.php and a copy of the LGPLv2.1 at
+ * http://www.opensource.org/licenses/lgpl-license.php. See the License for the
+ * specific language governing permissions and limitations under the License. When
+ * distributing the software, include this License Header Notice in each file and
+ * include the full text of the License in the License file as well as the
+ * following notice:
+ *
+ * NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND DISTRIBUTION LICENSE
+ * (CDDL)
+ * For Covered Software in this distribution, this License shall be governed by the
+ * laws of the State of California (excluding conflict-of-law provisions).
+ * Any litigation relating to this License shall be subject to the jurisdiction of
+ * the Federal Courts of the Northern District of California and the state courts
+ * of the State of California, with venue lying in Santa Clara County, California.
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by only the CDDL or only
+ * the LGPL Version 2.1, indicate your decision by adding "[Contributor]" elects to
+ * include this software in this distribution under the [CDDL or LGPL Version 2.1]
+ * license." If you don't indicate a single choice of license, a recipient has the
+ * option to distribute your version of this file under either the CDDL or the LGPL
+ * Version 2.1, or to extend the choice of license to its licensees as provided
+ * above. However, if you add LGPL Version 2.1 code and therefore, elected the LGPL
+ * Version 2 license, then the option applies only if the new code is made subject
+ * to such option by the copyright holder.
+ */
+
+#ifndef _SKIN_H_
+#define _SKIN_H_
+
+#include <gtk/gtk.h>
+#include <cairo.h>
+#include "common.h"
+
+__BEGIN_DECLS
+
+typedef struct _skin_button_priv_t skin_button_priv_t;
+typedef struct _skin_button_t skin_button_t;
+
+typedef struct _skin_label_priv_t skin_label_priv_t;
+typedef struct _skin_label_t skin_label_t;
+
+typedef struct _skin_window_priv_t skin_window_priv_t;
+typedef struct _skin_window_t skin_window_t;
+
+struct _skin_button_t
+{
+    int x, y;
+    int width, height;
+
+    GdkPixbuf* normal_image;
+    GdkPixbuf* highlight_image;
+    GdkPixbuf* pressdown_image;
+
+    skin_button_priv_t* priv;
+};
+
+struct _skin_label_t
+{
+    int x, y;
+    double color_r, color_g, color_b, color_a;
+    char* font;
+    char* text;
+
+    PangoLayout* layout;
+
+    skin_label_priv_t* priv;
+};
+
+struct _skin_window_t
+{
+    GtkWidget* widget;
+    GdkPixbuf* background_image;
+    int        margin_top;
+    int        margin_left;
+    int        margin_bottom;
+    int        margin_right;
+    int        alpha_mask_threshold;
+
+    skin_window_priv_t* priv;
+
+};
+
+skin_window_t*   skin_window_new(GtkWindow* window,
+                                 GdkPixbuf* background_image,
+                                 int        margin_top,
+                                 int        margin_left,
+                                 int        margin_bottom,
+                                 int        margin_right,
+                                 int        alpha_mask_threshold);
+
+void             skin_window_destroy(skin_window_t* wind);
+
+void             skin_window_set_drag_to_move(skin_window_t* wind,
+                                              gboolean       drag_to_move);
+
+void             skin_window_add_button(skin_window_t* wind,
+                                        skin_button_t* btn,
+                                        int            x,
+                                        int            y);
+
+void             skin_window_add_label(skin_window_t* wind,
+                                       skin_label_t*  label,
+                                       int            x,
+                                       int            y);
+
+void             skin_window_set_motion_cb(skin_window_t*  wind,
+                                           GCallback       cb,
+                                           void*           data);
+
+void             skin_window_set_press_cb(skin_window_t*   wind,
+                                          GCallback        cb,
+                                          void*            data);
+
+void             skin_window_set_release_cb(skin_window_t* wind,
+                                            GCallback      cb,
+                                            void*          data);
+
+skin_button_t*   skin_button_new(GdkPixbuf* normal_image,
+                                 GdkPixbuf* highlight_image,
+                                 GdkPixbuf* down_image);
+
+void             skin_button_destroy(skin_button_t* btn);
+
+void             skin_button_set_image(skin_button_t* btn,
+                                       GdkPixbuf*     normal_image,
+                                       GdkPixbuf*     highlight_image,
+                                       GdkPixbuf*     pressdown_image);
+
+void             skin_button_set_press_cb(skin_button_t*   wind,
+                                          GCallback        cb,
+                                          void*            data);
+
+void             skin_button_set_release_cb(skin_button_t* wind,
+                                            GCallback      cb,
+                                            void*          data);
+
+skin_label_t*    skin_label_new(char*  font,
+                                char*  text,
+                                double color_r,
+                                double color_g,
+                                double color_b,
+                                double color_a);
+
+void             skin_label_destroy(skin_label_t* label);
+
+void             skin_label_set_text(skin_label_t* label, const char* text);
+
+__END_DECLS
+
+#endif /* _SKIN_H_ */
diff --git a/wrapper/xim/sunpinyin_preedit.cc b/wrapper/xim/sunpinyin_preedit.cc
new file mode 100644 (file)
index 0000000..4ceecf2
--- /dev/null
@@ -0,0 +1,393 @@
+/*
+ * Copyright (c) 2010 Mike Qin <mikeandmore@gmail.com>
+ *
+ * The contents of this file are subject to the terms of either the GNU Lesser
+ * General Public License Version 2.1 only ("LGPL") or the Common Development and
+ * Distribution License ("CDDL")(collectively, the "License"). You may not use this
+ * file except in compliance with the License. You can obtain a copy of the CDDL at
+ * http://www.opensource.org/licenses/cddl1.php and a copy of the LGPLv2.1 at
+ * http://www.opensource.org/licenses/lgpl-license.php. See the License for the
+ * specific language governing permissions and limitations under the License. When
+ * distributing the software, include this License Header Notice in each file and
+ * include the full text of the License in the License file as well as the
+ * following notice:
+ *
+ * NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND DISTRIBUTION LICENSE
+ * (CDDL)
+ * For Covered Software in this distribution, this License shall be governed by the
+ * laws of the State of California (excluding conflict-of-law provisions).
+ * Any litigation relating to this License shall be subject to the jurisdiction of
+ * the Federal Courts of the Northern District of California and the state courts
+ * of the State of California, with venue lying in Santa Clara County, California.
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by only the CDDL or only
+ * the LGPL Version 2.1, indicate your decision by adding "[Contributor]" elects to
+ * include this software in this distribution under the [CDDL or LGPL Version 2.1]
+ * license." If you don't indicate a single choice of license, a recipient has the
+ * option to distribute your version of this file under either the CDDL or the LGPL
+ * Version 2.1, or to extend the choice of license to its licensees as provided
+ * above. However, if you add LGPL Version 2.1 code and therefore, elected the LGPL
+ * Version 2 license, then the option applies only if the new code is made subject
+ * to such option by the copyright holder.
+ */
+#include <locale.h>
+
+#include <sunpinyin.h>
+#include <ime-core/imi_glibHandler.h>
+
+#include "xim.h"
+#include "common.h"
+#include "settings.h"
+#include "sunpinyin_preedit_ui.h"
+
+#define BUF_SIZE 4096
+
+class WindowHandler : public CIMIGlibHandler
+{
+protected:
+    virtual void updatePreedit(const IPreeditString* ppd);
+    virtual void updateCandidates(const ICandidateList* pcl);
+    virtual void updateStatus(int key, int value);
+    virtual void commit(const TWCHAR* str);
+
+private:
+    PreeditUI* ui_impl_;
+
+public:
+
+    WindowHandler();
+    virtual ~WindowHandler();
+
+    PreeditUI* preedit_ui_impl() { return ui_impl_; }
+    void       set_preedit_ui_impl(PreeditUI* ui_impl) {
+        ui_impl_ = ui_impl;
+    }
+
+    void set_xim_handle(XIMHandle* handle) {
+        handle_ = handle;
+    }
+
+    bool status() {
+        return status_;
+    }
+
+    void update_preedit_ui(const IPreeditString* ppd, const char* utf_str);
+    void update_candidates_ui(const ICandidateList* pcl, const char* utf_str);
+
+    void pause();
+    void move(int x, int y);
+    void go_on();
+    void reload_ui();
+
+private:
+    XIMHandle* handle_;
+
+    char* preedit_str_;
+    char* candidate_str_;
+
+    bool status_;
+    bool pause_;
+
+    int  x_, y_;
+};
+
+WindowHandler::WindowHandler()
+{
+    preedit_str_ = new char[BUF_SIZE];
+    candidate_str_ = new char[BUF_SIZE];
+    status_ = false;
+    pause_ = false;
+    ui_impl_ = NULL;
+    handle_ = NULL;
+    x_ = y_ = 0;
+}
+
+WindowHandler::~WindowHandler()
+{
+    delete [] preedit_str_;
+    delete [] candidate_str_;
+}
+
+void
+WindowHandler::reload_ui()
+{
+    ui_impl_->reload();
+    ui_impl_->update_preedit_string(preedit_str_);
+    ui_impl_->update_candidates_string(candidate_str_);
+    if (status_) {
+        ui_impl_->show();
+        ui_impl_->move(x_, y_);
+    } else {
+        ui_impl_->hide();
+    }
+}
+
+void
+WindowHandler::pause()
+{
+    if (status_) {
+        ui_impl_->hide();
+        status_ = false;
+        pause_ = true;
+    }
+}
+
+void
+WindowHandler::move(int x, int y)
+{
+    x_ = x;
+    y_ = y;
+    if (ui_impl_) {
+        ui_impl_->move(x, y);
+    }
+}
+
+void
+WindowHandler::go_on()
+{
+    if (!status_ && pause_) {
+        ui_impl_->show();
+        status_ = true;
+        pause_ = false;
+    }
+}
+
+void
+WindowHandler::update_candidates_ui(const ICandidateList* pcl, const char* utf_str)
+{
+    ui_impl_->update_candidates_string(utf_str);
+    if (status_) {
+        ui_impl_->show();
+    } else {
+        ui_impl_->hide();
+    }
+}
+
+void
+WindowHandler::update_preedit_ui(const IPreeditString* ppd, const char* utf_str)
+{
+    ui_impl_->update_preedit_string(utf_str);
+    if (ppd->size() == 0) {
+        status_ = false;
+    } else {
+        status_ = true;
+    }
+}
+
+void
+WindowHandler::updatePreedit(const IPreeditString* ppd)
+{
+    TIConvSrcPtr src = (TIConvSrcPtr) (ppd->string());
+    TWCHAR* front_src = new TWCHAR[BUF_SIZE];
+    TWCHAR* end_src = new TWCHAR[BUF_SIZE];
+
+    memset(front_src, 0, BUF_SIZE * sizeof(TWCHAR));
+    memset(end_src, 0, BUF_SIZE * sizeof(TWCHAR));
+
+    memcpy(front_src, src, ppd->caret() * sizeof(TWCHAR));
+    memcpy(end_src, src + ppd->caret() * sizeof(TWCHAR),
+           (ppd->size() - ppd->caret() + 1) * sizeof(TWCHAR));
+
+    memset(preedit_str_, 0, BUF_SIZE);
+
+    WCSTOMBS(preedit_str_, front_src, BUF_SIZE - 1);
+    preedit_str_[strlen(preedit_str_)] = '|';
+    WCSTOMBS(&preedit_str_[strlen(preedit_str_)], end_src, BUF_SIZE - 1);
+
+    // update within the ui provider
+    update_preedit_ui(ppd, preedit_str_);
+
+    delete [] front_src;
+    delete [] end_src;
+}
+
+void
+WindowHandler::updateCandidates(const ICandidateList* pcl)
+{
+    wstring cand_str;
+    for (int i = 0, sz = pcl->size(); i < sz; i++) {
+        const TWCHAR* pcand = pcl->candiString(i);
+        if (pcand == NULL) break;
+        cand_str += (i == 9) ? '0' : TWCHAR('1' + i);
+        cand_str += TWCHAR('.');
+        cand_str += pcand;
+        cand_str += TWCHAR(' ');
+    }
+
+    TIConvSrcPtr src = (TIConvSrcPtr)(cand_str.c_str());
+    WCSTOMBS(candidate_str_, (const TWCHAR*) src, BUF_SIZE - 1);
+
+    // update within the ui provider
+    update_candidates_ui(pcl, candidate_str_);
+}
+
+void
+WindowHandler::updateStatus(int key, int value)
+{}
+
+void
+WindowHandler::commit(const TWCHAR* str)
+{
+    char* buf = new char[BUF_SIZE];
+    memset(buf, 0, BUF_SIZE);
+    WCSTOMBS(buf, str, BUF_SIZE - 1);
+    if (handle_ != NULL) {
+        xim_commit_preedit(handle_, buf);
+    }
+    delete [] buf;
+}
+
+
+static PreeditUI* ui_impl = NULL;
+static WindowHandler* instance = NULL;
+static CIMIView* view = NULL;
+
+__EXPORT_API void
+preedit_init()
+{
+    CSunpinyinSessionFactory& fac = CSunpinyinSessionFactory::getFactory();
+    if (settings_get_int(SHUANGPIN)) {
+        fac.setPinyinScheme(CSunpinyinSessionFactory::SHUANGPIN);
+        // shuangpin schemes
+        varchar scheme;
+        settings_get(SHUANGPIN_SCHEME, scheme);
+        if (strcmp(scheme, "MS2003") == 0) {
+            AShuangpinSchemePolicy::instance().setShuangpinType(MS2003);
+        } else if (strcmp(scheme, "ABC") == 0) {
+            AShuangpinSchemePolicy::instance().setShuangpinType(ABC);
+        } else if (strcmp(scheme, "ZiRanMa") == 0) {
+            AShuangpinSchemePolicy::instance().setShuangpinType(ZIRANMA);
+        } else if (strcmp(scheme, "PinYin++") == 0) {
+            AShuangpinSchemePolicy::instance().setShuangpinType(PINYINJIAJIA);
+        } else if (strcmp(scheme, "ZiGuang") == 0) {
+            AShuangpinSchemePolicy::instance().setShuangpinType(ZIGUANG);
+        } else if (strcmp(scheme, "XiaoHe") == 0) {
+            AShuangpinSchemePolicy::instance().setShuangpinType(XIAOHE);
+        }
+    } else {
+        fac.setPinyinScheme(CSunpinyinSessionFactory::QUANPIN);
+    }
+    view = fac.createSession();
+
+    varchar skin_name;
+    settings_get(SKIN_NAME, skin_name);
+    ui_impl = create_preedit_ui(skin_name);
+
+    instance = new WindowHandler();
+    instance->set_preedit_ui_impl(ui_impl);
+    view->getIC()->setCharsetLevel(1);// GBK
+    view->attachWinHandler(instance);
+}
+
+__EXPORT_API void
+preedit_finalize(void)
+{
+    LOG("preedit_finalizing...");
+    CSunpinyinSessionFactory& fac = CSunpinyinSessionFactory::getFactory();
+    fac.destroySession(view);
+
+    delete ui_impl;
+    delete instance;
+}
+
+__EXPORT_API void
+preedit_reload(void)
+{
+    // number of candidates
+    view->setCandiWindowSize(settings_get_int(CANDIDATES_SIZE));
+
+    // page up/down key
+    CHotkeyProfile* prof = view->getHotkeyProfile();
+    prof->clear();
+    if (settings_get_int(PAGE_MINUS_PLUS)) {
+        prof->addPageUpKey(CKeyEvent(IM_VK_MINUS));
+        prof->addPageDownKey(CKeyEvent(IM_VK_EQUALS));
+    }
+    if (settings_get_int(PAGE_COMMA_PERIOD)) {
+        prof->addPageUpKey(CKeyEvent(IM_VK_COMMA));
+        prof->addPageDownKey(CKeyEvent(IM_VK_PERIOD));
+    }
+    if (settings_get_int(PAGE_PAREN)) {
+        prof->addPageUpKey(CKeyEvent('['));
+        prof->addPageDownKey(CKeyEvent(']'));
+    }
+
+    // fuzzy segmentation
+    bool enable_fuzzy = settings_get_int(FUZZY_SEGMENTATION);
+    bool enable_inner = settings_get_int(FUZZY_INNER_SEGMENTATION);
+    AQuanpinSchemePolicy::instance().setFuzzySegmentation(enable_fuzzy);
+    AQuanpinSchemePolicy::instance().setInnerFuzzySegmentation(enable_inner);
+
+    // cancel last selection on backspace
+    view->setCancelOnBackspace(settings_get_int(CANCEL_ON_BACKSPACE));
+
+    // do we need to change the skin?
+    varchar skin_name;
+    settings_get(SKIN_NAME, skin_name);
+    if (ui_impl->name() != skin_name) {
+        delete ui_impl;
+        ui_impl = create_preedit_ui(skin_name);
+        instance->set_preedit_ui_impl(ui_impl);
+    }
+
+    instance->reload_ui();
+}
+
+__EXPORT_API void
+preedit_set_handle(XIMHandle* handle)
+{
+    instance->set_xim_handle(handle);
+}
+
+__EXPORT_API void
+preedit_move(int x, int y)
+{
+    instance->move(x, y);
+}
+
+__EXPORT_API void
+preedit_pause(void)
+{
+    instance->pause();
+}
+
+__EXPORT_API void
+preedit_go_on(void)
+{
+    instance->go_on();
+}
+
+__EXPORT_API void
+preedit_on_key(XIMHandle* handle, unsigned int keycode, unsigned int state)
+{
+    if (keycode < 0x20 && keycode > 0x7E)
+        keycode = 0;
+    view->onKeyEvent(CKeyEvent(keycode, keycode, state));
+}
+
+__EXPORT_API bool
+preedit_status(void)
+{
+    return instance->status();
+}
+
+__EXPORT_API void
+preedit_set_full(bool full)
+{
+    view->setStatusAttrValue(CIMIWinHandler::STATUS_ID_FULLSYMBOL, full);
+}
+
+__EXPORT_API void
+preedit_set_chinese_punc(bool chn_punc)
+{
+    view->setStatusAttrValue(CIMIWinHandler::STATUS_ID_FULLPUNC, chn_punc);
+}
+
+__EXPORT_API void
+preedit_omit_next_punct()
+{
+    view->getIC()->omitNextPunct();
+}
+
diff --git a/wrapper/xim/sunpinyin_preedit_gtk.cc b/wrapper/xim/sunpinyin_preedit_gtk.cc
new file mode 100644 (file)
index 0000000..80e47b4
--- /dev/null
@@ -0,0 +1,144 @@
+/*
+ * Copyright (c) 2010 Mike Qin <mikeandmore@gmail.com>
+ *
+ * The contents of this file are subject to the terms of either the GNU Lesser
+ * General Public License Version 2.1 only ("LGPL") or the Common Development and
+ * Distribution License ("CDDL")(collectively, the "License"). You may not use this
+ * file except in compliance with the License. You can obtain a copy of the CDDL at
+ * http://www.opensource.org/licenses/cddl1.php and a copy of the LGPLv2.1 at
+ * http://www.opensource.org/licenses/lgpl-license.php. See the License for the
+ * specific language governing permissions and limitations under the License. When
+ * distributing the software, include this License Header Notice in each file and
+ * include the full text of the License in the License file as well as the
+ * following notice:
+ *
+ * NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND DISTRIBUTION LICENSE
+ * (CDDL)
+ * For Covered Software in this distribution, this License shall be governed by the
+ * laws of the State of California (excluding conflict-of-law provisions).
+ * Any litigation relating to this License shall be subject to the jurisdiction of
+ * the Federal Courts of the Northern District of California and the state courts
+ * of the State of California, with venue lying in Santa Clara County, California.
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by only the CDDL or only
+ * the LGPL Version 2.1, indicate your decision by adding "[Contributor]" elects to
+ * include this software in this distribution under the [CDDL or LGPL Version 2.1]
+ * license." If you don't indicate a single choice of license, a recipient has the
+ * option to distribute your version of this file under either the CDDL or the LGPL
+ * Version 2.1, or to extend the choice of license to its licensees as provided
+ * above. However, if you add LGPL Version 2.1 code and therefore, elected the LGPL
+ * Version 2 license, then the option applies only if the new code is made subject
+ * to such option by the copyright holder.
+ */
+
+#include "ui.h"
+#include "settings.h"
+#include "sunpinyin_preedit_ui.h"
+
+GtkPreeditUI::GtkPreeditUI()
+    : PreeditUI("classic")
+{
+    main_wnd_ = ui_create_window();
+    GtkWidget* box = gtk_vbox_new(FALSE, 1);
+    gtk_container_add(GTK_CONTAINER(main_wnd_), box);
+
+    preedit_area_ = gtk_label_new("");
+    candidate_area_ = gtk_label_new("");
+
+    gtk_misc_set_alignment(GTK_MISC(preedit_area_), 0, 0.5);
+    gtk_misc_set_alignment(GTK_MISC(candidate_area_), 0, 0.5);
+
+    gtk_box_pack_start(GTK_BOX(box), preedit_area_,
+                       FALSE, FALSE, 1);
+    gtk_box_pack_start(GTK_BOX(box), candidate_area_,
+                       FALSE, FALSE, 1);
+    gtk_widget_show_all(box);
+
+    // set the colormap before realized the window
+    GdkScreen* screen = gtk_widget_get_screen(main_wnd_);
+    GdkColormap* cmap = gdk_screen_get_rgba_colormap(screen);
+    if (cmap) {
+        gtk_widget_set_colormap(main_wnd_, cmap);
+    }
+    gtk_widget_realize(main_wnd_);
+}
+
+GtkPreeditUI::~GtkPreeditUI()
+{
+    gtk_widget_destroy(main_wnd_);
+}
+
+void
+GtkPreeditUI::show()
+{
+    gtk_widget_show(main_wnd_);
+}
+
+void
+GtkPreeditUI::hide()
+{
+    gtk_widget_hide(main_wnd_);
+}
+
+void
+GtkPreeditUI::move(int x, int y)
+{
+    int width = 0, height = 0;
+    gtk_window_get_size(GTK_WINDOW(main_wnd_), &width, &height);
+    adjust_position(&x, &y, width, height);
+    gtk_window_move(GTK_WINDOW(main_wnd_), x, y);
+}
+
+void
+GtkPreeditUI::reload()
+{
+    GdkColor color;
+    varchar value;
+    double opa = 1.0;
+
+    settings_get(PREEDIT_COLOR, value);
+    gdk_color_parse(value, &color);
+    gtk_widget_modify_bg(main_wnd_, GTK_STATE_NORMAL, &color);
+
+    settings_get(PREEDIT_FONT, value);
+    gtk_widget_modify_font(candidate_area_,
+                           pango_font_description_from_string(value));
+
+    settings_get(PREEDIT_FONT_COLOR, value);
+    gdk_color_parse(value, &color);
+    gtk_widget_modify_fg(candidate_area_, GTK_STATE_NORMAL, &color);
+    gtk_widget_modify_fg(preedit_area_, GTK_STATE_NORMAL, &color);
+
+    settings_get(PREEDIT_OPACITY, &opa);
+
+    // setting the opacity
+    if (opa > 1.0) opa = 1.0;
+    gtk_window_set_opacity(GTK_WINDOW(main_wnd_), opa);
+}
+
+void
+GtkPreeditUI::update_preedit_string(const char* utf_str)
+{
+    gtk_label_set_text(GTK_LABEL(preedit_area_), utf_str);
+}
+
+void
+GtkPreeditUI::update_candidates_string(const char* utf_str)
+{
+    gtk_label_set(GTK_LABEL(candidate_area_), utf_str);
+
+    PangoLayout* pre_lay = gtk_label_get_layout(GTK_LABEL(preedit_area_));
+    PangoLayout* can_lay = gtk_label_get_layout(GTK_LABEL(candidate_area_));
+    int x = 0, y = 0;
+    int pre_wid = -1, can_wid = -1;
+    pango_layout_get_pixel_size(pre_lay, &pre_wid, NULL);
+    pango_layout_get_pixel_size(can_lay, &can_wid, NULL);
+
+    gtk_window_resize(GTK_WINDOW(main_wnd_), MAX(pre_wid, can_wid) + 1, 1);
+
+    gtk_window_get_position(GTK_WINDOW(main_wnd_), &x, &y);
+    move(x, y);
+}
+
diff --git a/wrapper/xim/sunpinyin_preedit_skin.cc b/wrapper/xim/sunpinyin_preedit_skin.cc
new file mode 100644 (file)
index 0000000..7778ae9
--- /dev/null
@@ -0,0 +1,148 @@
+/*
+ * Copyright (c) 2010 Mike Qin <mikeandmore@gmail.com>
+ *
+ * The contents of this file are subject to the terms of either the GNU Lesser
+ * General Public License Version 2.1 only ("LGPL") or the Common Development and
+ * Distribution License ("CDDL")(collectively, the "License"). You may not use this
+ * file except in compliance with the License. You can obtain a copy of the CDDL at
+ * http://www.opensource.org/licenses/cddl1.php and a copy of the LGPLv2.1 at
+ * http://www.opensource.org/licenses/lgpl-license.php. See the License for the
+ * specific language governing permissions and limitations under the License. When
+ * distributing the software, include this License Header Notice in each file and
+ * include the full text of the License in the License file as well as the
+ * following notice:
+ *
+ * NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND DISTRIBUTION LICENSE
+ * (CDDL)
+ * For Covered Software in this distribution, this License shall be governed by the
+ * laws of the State of California (excluding conflict-of-law provisions).
+ * Any litigation relating to this License shall be subject to the jurisdiction of
+ * the Federal Courts of the Northern District of California and the state courts
+ * of the State of California, with venue lying in Santa Clara County, California.
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by only the CDDL or only
+ * the LGPL Version 2.1, indicate your decision by adding "[Contributor]" elects to
+ * include this software in this distribution under the [CDDL or LGPL Version 2.1]
+ * license." If you don't indicate a single choice of license, a recipient has the
+ * option to distribute your version of this file under either the CDDL or the LGPL
+ * Version 2.1, or to extend the choice of license to its licensees as provided
+ * above. However, if you add LGPL Version 2.1 code and therefore, elected the LGPL
+ * Version 2 license, then the option applies only if the new code is made subject
+ * to such option by the copyright holder.
+ */
+
+#include "ui.h"
+#include "settings.h"
+#include "sunpinyin_preedit_ui.h"
+#include "skin.h"
+
+SkinPreeditUI::SkinPreeditUI(std::string name) throw()
+    : PreeditUI(name)
+{
+    info_ = ui_skin_new(name.c_str());
+    if (!info_) {
+        throw SkinLoaderException();
+    }
+    main_wnd_ = skin_window_new(GTK_WINDOW(ui_create_window()),
+                                info_->preedit_background,
+                                info_->top, info_->left,
+                                info_->bottom, info_->right,
+                                1);
+    preedit_label_ = skin_label_new(info_->preedit_label.font, NULL,
+                                    info_->preedit_label.color_r,
+                                    info_->preedit_label.color_g,
+                                    info_->preedit_label.color_b,
+                                    info_->preedit_label.color_a);
+
+    candidate_label_ = skin_label_new(info_->candidate_label.font, NULL,
+                                      info_->candidate_label.color_r,
+                                      info_->candidate_label.color_g,
+                                      info_->candidate_label.color_b,
+                                      info_->candidate_label.color_a);
+
+    skin_window_add_label(main_wnd_, preedit_label_,
+                          info_->preedit_label.x, info_->preedit_label.y);
+    skin_window_add_label(main_wnd_, candidate_label_,
+                          info_->candidate_label.x, info_->candidate_label.y);
+}
+
+SkinPreeditUI::~SkinPreeditUI()
+{
+    ui_skin_destroy(info_);
+    skin_label_destroy(preedit_label_);
+    skin_label_destroy(candidate_label_);
+    skin_window_destroy(main_wnd_);
+}
+
+void
+SkinPreeditUI::show()
+{
+    gtk_widget_show(main_wnd_->widget);
+    adjust_size();
+}
+
+void
+SkinPreeditUI::hide()
+{
+    gtk_widget_hide(main_wnd_->widget);
+}
+
+void
+SkinPreeditUI::move(int x, int y)
+{
+    internal_move(x - info_->offset_x, y - info_->offset_y);
+}
+
+void SkinPreeditUI::internal_move(int x, int y)
+{
+    int width, height;
+    gtk_window_get_size(GTK_WINDOW(main_wnd_->widget), &width, &height);
+    adjust_position(&x, &y, width, height);
+    gtk_window_move(GTK_WINDOW(main_wnd_->widget), x, y);
+}
+
+void
+SkinPreeditUI::reload()
+{
+    // Nothing?
+}
+
+void
+SkinPreeditUI::update_preedit_string(const char* utf_str)
+{
+    skin_label_set_text(preedit_label_, utf_str);
+    adjust_size();
+}
+
+#define BUFSIZE (4096*2)
+
+void
+SkinPreeditUI::update_candidates_string(const char* utf_str)
+{
+    skin_label_set_text(candidate_label_, utf_str);
+    adjust_size();
+}
+
+void
+SkinPreeditUI::adjust_size()
+{
+    if (candidate_label_->layout && preedit_label_->layout) {
+        int x = 0, y = 0;
+        int can_wid = 0, pre_wid = 0, width = 0, height = 0;
+        int hmargin, vmargin;
+        hmargin = info_->candidate_label.x + info_->right;
+        vmargin = info_->candidate_label.y + info_->bottom;
+
+        pango_layout_get_pixel_size(preedit_label_->layout, &pre_wid, NULL);
+        pango_layout_get_pixel_size(candidate_label_->layout, &can_wid,
+                                    &height);
+        width = MAX(pre_wid, can_wid);
+
+        gtk_window_resize(GTK_WINDOW(main_wnd_->widget), width + hmargin,
+                          height + vmargin);
+        gtk_window_get_position(GTK_WINDOW(main_wnd_->widget), &x, &y);
+        internal_move(x, y);
+    }
+}
diff --git a/wrapper/xim/sunpinyin_preedit_ui.h b/wrapper/xim/sunpinyin_preedit_ui.h
new file mode 100644 (file)
index 0000000..f238388
--- /dev/null
@@ -0,0 +1,125 @@
+/* -*- mode: c++ -*- */
+/*
+ * Copyright (c) 2010 Mike Qin <mikeandmore@gmail.com>
+ *
+ * The contents of this file are subject to the terms of either the GNU Lesser
+ * General Public License Version 2.1 only ("LGPL") or the Common Development and
+ * Distribution License ("CDDL")(collectively, the "License"). You may not use this
+ * file except in compliance with the License. You can obtain a copy of the CDDL at
+ * http://www.opensource.org/licenses/cddl1.php and a copy of the LGPLv2.1 at
+ * http://www.opensource.org/licenses/lgpl-license.php. See the License for the
+ * specific language governing permissions and limitations under the License. When
+ * distributing the software, include this License Header Notice in each file and
+ * include the full text of the License in the License file as well as the
+ * following notice:
+ *
+ * NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND DISTRIBUTION LICENSE
+ * (CDDL)
+ * For Covered Software in this distribution, this License shall be governed by the
+ * laws of the State of California (excluding conflict-of-law provisions).
+ * Any litigation relating to this License shall be subject to the jurisdiction of
+ * the Federal Courts of the Northern District of California and the state courts
+ * of the State of California, with venue lying in Santa Clara County, California.
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by only the CDDL or only
+ * the LGPL Version 2.1, indicate your decision by adding "[Contributor]" elects to
+ * include this software in this distribution under the [CDDL or LGPL Version 2.1]
+ * license." If you don't indicate a single choice of license, a recipient has the
+ * option to distribute your version of this file under either the CDDL or the LGPL
+ * Version 2.1, or to extend the choice of license to its licensees as provided
+ * above. However, if you add LGPL Version 2.1 code and therefore, elected the LGPL
+ * Version 2 license, then the option applies only if the new code is made subject
+ * to such option by the copyright holder.
+ */
+
+#ifndef _SUNPINYIN_PREEDIT_H_
+#define _SUNPINYIN_PREEDIT_H_
+
+#include <string>
+#include <cstring>
+#include <exception>
+#include <gtk/gtk.h>
+#include "xmisc.h"
+#include "skin.h"
+#include "ui.h"
+
+class PreeditUI
+{
+    std::string name_;
+public:
+    PreeditUI(std::string name) throw() : name_(name) {}
+    virtual ~PreeditUI() {}
+
+    std::string name() { return name_; }
+
+    virtual void show() = 0;
+    virtual void hide() = 0;
+    virtual void move(int x, int y) = 0;
+    virtual void reload() = 0;
+    virtual void update_preedit_string(const char* utf_str) = 0;
+    virtual void update_candidates_string(const char* utf_str) = 0;
+};
+
+class GtkPreeditUI : public PreeditUI
+{
+public:
+    GtkPreeditUI();
+    virtual ~GtkPreeditUI();
+protected:
+    virtual void show();
+    virtual void hide();
+    virtual void move(int x, int y);
+    virtual void reload();
+    virtual void update_preedit_string(const char* utf_str);
+    virtual void update_candidates_string(const char* utf_str);
+private:
+    GtkWidget* main_wnd_;
+    GtkWidget* preedit_area_;
+    GtkWidget* candidate_area_;
+};
+
+class SkinLoaderException: public std::exception
+{
+public:
+    const char* what() const throw() { return "Cannot load skin!"; }
+};
+
+class SkinPreeditUI : public PreeditUI
+{
+public:
+    SkinPreeditUI(std::string name) throw();
+    virtual ~SkinPreeditUI();
+protected:
+    virtual void show();
+    virtual void hide();
+    virtual void move(int x, int y);
+    virtual void reload();
+    virtual void update_preedit_string(const char* utf_str);
+    virtual void update_candidates_string(const char* utf_str);
+private:
+    void adjust_size();
+    void internal_move(int x, int y);
+private:
+    skin_window_t* main_wnd_;
+    skin_label_t*  preedit_label_;
+    skin_label_t*  candidate_label_;
+    skin_info_t*   info_;
+};
+
+inline PreeditUI* create_preedit_ui(std::string name)
+{
+    if (name == "classic") {
+        return new GtkPreeditUI();
+    } else {
+        try {
+            return new SkinPreeditUI(name);
+        } catch (const SkinLoaderException& ex) {
+            fprintf(stderr, "%s\n", ex.what());
+            exit(-1);
+        }
+    }
+}
+
+#endif /* _SUNPINYIN_PREEDIT_H_ */
diff --git a/wrapper/xim/ui.c b/wrapper/xim/ui.c
new file mode 100644 (file)
index 0000000..9407902
--- /dev/null
@@ -0,0 +1,239 @@
+/*
+ * Copyright (c) 2010 Mike Qin <mikeandmore@gmail.com>
+ *
+ * The contents of this file are subject to the terms of either the GNU Lesser
+ * General Public License Version 2.1 only ("LGPL") or the Common Development and
+ * Distribution License ("CDDL")(collectively, the "License"). You may not use this
+ * file except in compliance with the License. You can obtain a copy of the CDDL at
+ * http://www.opensource.org/licenses/cddl1.php and a copy of the LGPLv2.1 at
+ * http://www.opensource.org/licenses/lgpl-license.php. See the License for the
+ * specific language governing permissions and limitations under the License. When
+ * distributing the software, include this License Header Notice in each file and
+ * include the full text of the License in the License file as well as the
+ * following notice:
+ *
+ * NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND DISTRIBUTION LICENSE
+ * (CDDL)
+ * For Covered Software in this distribution, this License shall be governed by the
+ * laws of the State of California (excluding conflict-of-law provisions).
+ * Any litigation relating to this License shall be subject to the jurisdiction of
+ * the Federal Courts of the Northern District of California and the state courts
+ * of the State of California, with venue lying in Santa Clara County, California.
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by only the CDDL or only
+ * the LGPL Version 2.1, indicate your decision by adding "[Contributor]" elects to
+ * include this software in this distribution under the [CDDL or LGPL Version 2.1]
+ * license." If you don't indicate a single choice of license, a recipient has the
+ * option to distribute your version of this file under either the CDDL or the LGPL
+ * Version 2.1, or to extend the choice of license to its licensees as provided
+ * above. However, if you add LGPL Version 2.1 code and therefore, elected the LGPL
+ * Version 2 license, then the option applies only if the new code is made subject
+ * to such option by the copyright holder.
+ */
+
+#include <gtk/gtk.h>
+#include "ic.h"
+#include "common.h"
+#include "ui.h"
+
+#define ENG_ICON SUNPINYIN_XIM_ICON_DIR"/eng.svg"
+#define HAN_ICON SUNPINYIN_XIM_ICON_DIR"/han.svg"
+#define LOGO_FILE_BIG SUNPINYIN_XIM_ICON_DIR"/sunpinyin-logo-big.png"
+
+#define SYSTEM_SKIN_DIR SUNPINYIN_XIM_SETTING_DIR"/skins"
+#define USER_SKIN_DIR "%s/.sunpinyin/xim_skins"
+
+
+static GtkStatusIcon* icbar_tray;
+static GtkWidget* popup_menu;
+
+static void
+show_ui_about(GtkWidget* wid, gpointer user_data)
+{
+    GError* error = NULL;
+    GdkPixbuf* logo_pixbuf =
+        gdk_pixbuf_new_from_file(LOGO_FILE_BIG, &error);
+
+    gtk_show_about_dialog(NULL,
+                          "program-name", XIM_PROGRAM_NAME,
+                          "logo", logo_pixbuf,
+                          "version", XIM_VERSION,
+                          "website", XIM_WEBSITE,
+                          "comments", XIM_COMMENTS,
+                          NULL);
+}
+
+static void
+launch_preferences(GtkWidget* wid, gpointer user_data)
+{
+    system("xsunpinyin-preferences&");
+}
+
+static void
+status_icon_popup_menu(GtkStatusIcon *status_icon, guint button,
+                       guint activate_time, gpointer user_data)
+{
+    gtk_widget_show_all(popup_menu);
+    gtk_menu_popup(GTK_MENU(popup_menu), NULL, NULL,
+                   gtk_status_icon_position_menu, status_icon,
+                   button, activate_time);
+}
+
+void
+ui_tray_init(void)
+{
+    icbar_tray = gtk_status_icon_new_from_file(ENG_ICON);
+    GtkWidget* setting_menu_item =
+        gtk_image_menu_item_new_from_stock(GTK_STOCK_PREFERENCES, NULL);
+    g_signal_connect(setting_menu_item, "activate",
+                     G_CALLBACK(launch_preferences), NULL);
+
+    GtkWidget* about_menu_item =
+        gtk_image_menu_item_new_from_stock(GTK_STOCK_ABOUT, NULL);
+    g_signal_connect(about_menu_item, "activate",
+                     G_CALLBACK(show_ui_about), NULL);
+
+    /* construct the popup menu */
+    popup_menu = gtk_menu_new();
+    gtk_menu_shell_append(GTK_MENU_SHELL(popup_menu), setting_menu_item);
+    gtk_menu_shell_append(GTK_MENU_SHELL(popup_menu), about_menu_item);
+
+    g_signal_connect(icbar_tray, "popup-menu",
+                     G_CALLBACK(status_icon_popup_menu), NULL);
+}
+
+void
+ui_tray_refresh(void)
+{
+    IC* ic = icmgr_get_current();
+    const char* filepath = HAN_ICON;
+    if (ic == NULL || !ic->is_enabled || ic->is_english) {
+        filepath = ENG_ICON;
+    }
+    gtk_status_icon_set_from_file(icbar_tray, filepath);
+}
+
+GtkWidget*
+ui_create_window()
+{
+    GtkWidget* window = gtk_window_new(GTK_WINDOW_POPUP);
+    gtk_window_set_decorated(GTK_WINDOW(window), false);
+    gtk_window_set_deletable(GTK_WINDOW(window), false);
+    gtk_window_set_accept_focus(GTK_WINDOW(window), false);
+    gtk_window_set_focus_on_map(GTK_WINDOW(window), false);
+    gtk_window_set_keep_above(GTK_WINDOW(window), true);
+    gtk_window_set_skip_pager_hint(GTK_WINDOW(window), true);
+    gtk_window_set_skip_taskbar_hint(GTK_WINDOW(window), true);
+    return window;
+}
+
+static GdkPixbuf*
+load_pixbuf(const char* skin_name, const char* filename, gboolean sys_dir)
+{
+    char filepath[256];
+    if (sys_dir) {
+        snprintf(filepath, 256, SYSTEM_SKIN_DIR"/%s/%s.png", skin_name,
+                 filename);
+    } else {
+        snprintf(filepath, 256, USER_SKIN_DIR"/%s/%s.png", getenv("HOME"),
+                 skin_name, filename);
+    }
+    return gdk_pixbuf_new_from_file(filepath, NULL);
+}
+
+#define FILL_PIXBUF(name)                       \
+    info->name = load_pixbuf(skin_name, name, sys_dir)
+
+static void
+fill_button_pixbuf(skin_button_info_t* info, const char* skin_name,
+                   gboolean sys_dir, const char* normal1, const char* normal2,
+                   const char* highlight1, const char* highlight2,
+                   const char* pressdown1, const char* pressdown2)
+{
+    FILL_PIXBUF(normal1);
+    FILL_PIXBUF(normal2);
+    FILL_PIXBUF(highlight1);
+    FILL_PIXBUF(highlight2);
+    FILL_PIXBUF(pressdown1);
+    FILL_PIXBUF(pressdown2);
+}
+
+static void
+fill_label_info(skin_label_info_t* info, FILE* fp)
+{
+    fscanf(fp, "%d %d\n", &(info->x), &(info->y));
+    fgets(info->font, 256, fp);
+    /* remove the last \n */
+    info->font[strlen(info->font) - 1] = 0;
+
+    fscanf(fp, "%lf %lf %lf %lf\n", &(info->color_r), &(info->color_g),
+           &(info->color_b), &(info->color_a));
+}
+
+skin_info_t*
+ui_skin_new(const char* skin_name)
+{
+    char filepath[256];
+    gboolean sys_dir = TRUE;
+    snprintf(filepath, 256, SYSTEM_SKIN_DIR"/%s/info", skin_name);
+    FILE* fp = fopen(filepath, "r");
+    if (!fp) {
+        sys_dir = FALSE;
+        snprintf(filepath, 256, USER_SKIN_DIR"/%s/info", getenv("HOME"),
+                 skin_name);
+        fp = fopen(filepath, "r");
+        if (!fp) {
+            fprintf(stderr, "Cannot open skin %s\n", skin_name);
+            return NULL;
+        }
+    }
+    skin_info_t* info = malloc(sizeof(skin_info_t));
+    fscanf(fp, "%d %d %d %d %d %d\n", &(info->eng_btn.x), &(info->eng_btn.y),
+           &(info->full_btn.x), &(info->full_btn.y),
+           &(info->punc_btn.x), &(info->punc_btn.y));
+
+    fill_label_info(&(info->preedit_label), fp);
+    fill_label_info(&(info->candidate_label), fp);
+
+    fscanf(fp, "%d %d\n", &(info->offset_x), &(info->offset_y));
+    fscanf(fp, "%d %d %d %d\n", &(info->top), &(info->left), &(info->bottom),
+           &(info->right));
+
+    fclose(fp);
+
+    fill_button_pixbuf(&(info->eng_btn), skin_name, sys_dir, "eng", "han",
+                       "eng-hover", "han-hover", "eng-press", "han-press");
+    fill_button_pixbuf(&(info->full_btn), skin_name, sys_dir, "full", "half",
+                       "full-hover", "half-hover", "full-press", "half-press");
+    fill_button_pixbuf(&(info->punc_btn), skin_name, sys_dir,
+                       "han-punc", "eng-punc",
+                       "han-punc-hover", "eng-punc-hover",
+                       "han-punc-press", "eng-punc-press");
+    info->icbar_background = load_pixbuf(skin_name, "icbar", sys_dir);
+    info->preedit_background = load_pixbuf(skin_name, "preedit", sys_dir);
+    return info;
+}
+
+static void
+free_button_info(skin_button_info_t* info)
+{
+    g_object_unref(info->normal1);
+    g_object_unref(info->highlight1);
+    g_object_unref(info->pressdown1);
+    g_object_unref(info->normal2);
+    g_object_unref(info->highlight2);
+    g_object_unref(info->pressdown2);
+}
+
+void
+ui_skin_destroy(skin_info_t* info)
+{
+    g_object_unref(info->icbar_background);
+    g_object_unref(info->preedit_background);
+
+    free_button_info(&(info->eng_btn));
+    free_button_info(&(info->full_btn));
+    free_button_info(&(info->punc_btn));
+}
diff --git a/wrapper/xim/ui.h b/wrapper/xim/ui.h
new file mode 100644 (file)
index 0000000..59183dd
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2010 Mike Qin <mikeandmore@gmail.com>
+ *
+ * The contents of this file are subject to the terms of either the GNU Lesser
+ * General Public License Version 2.1 only ("LGPL") or the Common Development and
+ * Distribution License ("CDDL")(collectively, the "License"). You may not use this
+ * file except in compliance with the License. You can obtain a copy of the CDDL at
+ * http://www.opensource.org/licenses/cddl1.php and a copy of the LGPLv2.1 at
+ * http://www.opensource.org/licenses/lgpl-license.php. See the License for the
+ * specific language governing permissions and limitations under the License. When
+ * distributing the software, include this License Header Notice in each file and
+ * include the full text of the License in the License file as well as the
+ * following notice:
+ *
+ * NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND DISTRIBUTION LICENSE
+ * (CDDL)
+ * For Covered Software in this distribution, this License shall be governed by the
+ * laws of the State of California (excluding conflict-of-law provisions).
+ * Any litigation relating to this License shall be subject to the jurisdiction of
+ * the Federal Courts of the Northern District of California and the state courts
+ * of the State of California, with venue lying in Santa Clara County, California.
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by only the CDDL or only
+ * the LGPL Version 2.1, indicate your decision by adding "[Contributor]" elects to
+ * include this software in this distribution under the [CDDL or LGPL Version 2.1]
+ * license." If you don't indicate a single choice of license, a recipient has the
+ * option to distribute your version of this file under either the CDDL or the LGPL
+ * Version 2.1, or to extend the choice of license to its licensees as provided
+ * above. However, if you add LGPL Version 2.1 code and therefore, elected the LGPL
+ * Version 2 license, then the option applies only if the new code is made subject
+ * to such option by the copyright holder.
+ */
+
+#ifndef _UI_H_
+#define _UI_H_
+
+#include "common.h"
+#include "settings.h"
+#include <gtk/gtk.h>
+
+__BEGIN_DECLS
+
+typedef struct _skin_button_info_t
+{
+    int        x, y;
+    GdkPixbuf* normal1;
+    GdkPixbuf* highlight1;
+    GdkPixbuf* pressdown1;
+    GdkPixbuf* normal2;
+    GdkPixbuf* highlight2;
+    GdkPixbuf* pressdown2;
+} skin_button_info_t;
+
+typedef struct _skin_label_info_t
+{
+    int        x, y;
+    char       font[256];
+    double     color_r, color_g, color_b, color_a;
+} skin_label_info_t;
+
+typedef struct _skin_info_t
+{
+    skin_button_info_t eng_btn, full_btn, punc_btn;
+    GdkPixbuf*         icbar_background;
+    skin_label_info_t  preedit_label;
+    skin_label_info_t  candidate_label;
+    GdkPixbuf*         preedit_background;
+    int                top, left, bottom, right; /* margins of preedit */
+    int                offset_x, offset_y; /* offset of preedit */
+} skin_info_t;
+
+void          ui_tray_init       (void);
+void          ui_tray_refresh    (void);
+GtkWidget*    ui_create_window   (void);
+skin_info_t*  ui_skin_new        (const char* name);
+void          ui_skin_destroy    (skin_info_t* info);
+
+__END_DECLS
+
+#endif /* _UI_H_ */
diff --git a/wrapper/xim/xim.c b/wrapper/xim/xim.c
new file mode 100644 (file)
index 0000000..19859d1
--- /dev/null
@@ -0,0 +1,388 @@
+/*
+ * Copyright (c) 2010 Mike Qin <mikeandmore@gmail.com>
+ *
+ * The contents of this file are subject to the terms of either the GNU Lesser
+ * General Public License Version 2.1 only ("LGPL") or the Common Development and
+ * Distribution License ("CDDL")(collectively, the "License"). You may not use this
+ * file except in compliance with the License. You can obtain a copy of the CDDL at
+ * http://www.opensource.org/licenses/cddl1.php and a copy of the LGPLv2.1 at
+ * http://www.opensource.org/licenses/lgpl-license.php. See the License for the
+ * specific language governing permissions and limitations under the License. When
+ * distributing the software, include this License Header Notice in each file and
+ * include the full text of the License in the License file as well as the
+ * following notice:
+ *
+ * NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND DISTRIBUTION LICENSE
+ * (CDDL)
+ * For Covered Software in this distribution, this License shall be governed by the
+ * laws of the State of California (excluding conflict-of-law provisions).
+ * Any litigation relating to this License shall be subject to the jurisdiction of
+ * the Federal Courts of the Northern District of California and the state courts
+ * of the State of California, with venue lying in Santa Clara County, California.
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by only the CDDL or only
+ * the LGPL Version 2.1, indicate your decision by adding "[Contributor]" elects to
+ * include this software in this distribution under the [CDDL or LGPL Version 2.1]
+ * license." If you don't indicate a single choice of license, a recipient has the
+ * option to distribute your version of this file under either the CDDL or the LGPL
+ * Version 2.1, or to extend the choice of license to its licensees as provided
+ * above. However, if you add LGPL Version 2.1 code and therefore, elected the LGPL
+ * Version 2 license, then the option applies only if the new code is made subject
+ * to such option by the copyright holder.
+ */
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdbool.h>
+#include <langinfo.h>
+#include <locale.h>
+#include <iconv.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <stdbool.h>
+
+#include "xim.h"
+#include "xmisc.h"
+#include "ic.h"
+#include "common.h"
+#include "settings.h"
+
+
+static int __preedit_x;
+static int __preedit_y;
+static int __input_style;
+static Window __client_window;
+static Window __focus_window;
+
+static int
+_xim_open(XIMHandle* handle, IMOpenStruct* proto)
+{
+    LOG("XIM_OPEN %d", proto->connect_id);
+    return 1;
+}
+
+static int
+_xim_close(XIMHandle* handle, IMCloseStruct* proto)
+{
+    LOG("XIM_CLOSE %d", proto->connect_id);
+    return 1;
+}
+
+static int
+__xim_ic_events(IMChangeICStruct* proto)
+{
+    XICAttribute* ic_attr = proto->ic_attr;
+    XICAttribute* pre_attr = proto->preedit_attr;
+
+    int i = 0;
+    for (i = 0; i < (int) proto->ic_attr_num; i++) {
+        if (strcmp(XNInputStyle, ic_attr[i].name) == 0) {
+            LOG("got input style %d", __input_style);
+            __input_style = * (int*) ic_attr[i].value;
+        } else if (strcmp(XNClientWindow, ic_attr[i].name) == 0) {
+            LOG("got client window");
+            __client_window = * (Window*) ic_attr[i].value;
+        } else if (strcmp(XNFocusWindow, ic_attr[i].name) == 0) {
+            LOG("got focus window");
+            __focus_window = * (Window*) ic_attr[i].value;
+        }
+    }
+    for (i = 0; i < (int) proto->preedit_attr_num; i++) {
+        if (strcmp(XNSpotLocation, pre_attr[i].name) == 0) {
+            XPoint* point = pre_attr[i].value;
+            __preedit_x = point->x;
+            __preedit_y = point->y;
+            LOG("position (%d, %d)", __preedit_x, __preedit_y);
+        }
+    }
+    return 1;
+}
+
+static int
+_xim_create_ic(XIMHandle* handle, IMChangeICStruct* proto)
+{
+    IC* ic = icmgr_create_ic(proto->connect_id);
+    __xim_ic_events(proto);
+    proto->icid = ic->icid;
+    ic->client_window = __client_window;
+    ic->offset_x = __preedit_x;
+    ic->offset_y = __preedit_y;
+    LOG("XIM_CREATE_IC %d", proto->icid);
+
+    return 1;
+}
+
+static int
+_xim_destroy_ic(XIMHandle* handle, IMChangeICStruct* proto)
+{
+    LOG("XIM_DESTROY_IC %d", proto->icid);
+    icmgr_destroy_ic(proto->icid);
+    icmgr_refresh();
+    return 1;
+}
+
+void
+__move_preedit(IC* ic)
+{
+    int root_x, root_y;
+    get_window_position(ic->client_window, &root_x, &root_y);
+    LOG("root: %d, %d offset: %d,%d", root_x, root_y,
+        ic->offset_x, ic->offset_y);
+    if (ic->offset_x <= 0 && ic->offset_y <= 0) {
+        int height;
+        get_window_size(ic->client_window, NULL, &height);
+        root_x += 4;
+        root_y += height;
+    } else {
+        root_x += ic->offset_x;
+        root_y += ic->offset_y;
+    }
+
+    preedit_move(root_x, root_y);
+}
+
+static int
+_xim_set_ic_values(XIMHandle* handle, IMChangeICStruct* proto)
+{
+    __xim_ic_events(proto);
+    IC* ic = icmgr_get(proto->icid);
+    /* some crapy swing application will have synchronization problems */
+    if (ic == NULL)
+        return 1;
+
+    LOG("XIM_SET_IC_VALUES %d", proto->icid);
+    ic->offset_x = __preedit_x;
+    ic->offset_y = __preedit_y;
+    IC* cur_ic = icmgr_get_current();
+
+    /* if we change the current ic position, we might wanna
+     * move it along the way
+     */
+    if (cur_ic != NULL && ic->icid == cur_ic->icid) {
+        __move_preedit(ic);
+    }
+    return 1;
+}
+
+static int
+_xim_get_ic_values(XIMHandle* handle, IMChangeICStruct* proto)
+{
+    LOG("XIM_GET_IC_VALUES %d", proto->icid);
+    XICAttribute* ic_attr = proto->ic_attr;
+
+    int i;
+    for (i = 0; i < (int) proto->ic_attr_num; i++) {
+        if (strcmp(XNFilterEvents, ic_attr[i].name) == 0) {
+            ic_attr[i].value = malloc(sizeof(CARD32));
+            *((CARD32*) ic_attr[i].value) = KeyPressMask | KeyPress;
+            ic_attr[i].value_length = sizeof(CARD32);
+        }
+    }
+    return 1;
+}
+
+static int
+_xim_trigger_notify(XIMHandle* handle, IMTriggerNotifyStruct* proto)
+{
+    LOG("trigger key pressed, %d", proto->icid);
+    IC* ic = icmgr_get(proto->icid);
+    if (ic == NULL)
+        return 1;
+
+    icmgr_set_current(proto->icid);
+    ic->is_enabled = true;
+    xim_start_preedit(handle);
+    icmgr_refresh();
+    return 1;
+}
+
+static int
+_xim_set_ic_focus(XIMHandle* handle, IMChangeFocusStruct* proto)
+{
+    DEBUG("%d", proto->icid);
+    LOG("set focus on ic %d %d", proto->icid, preedit_status());
+    /* if use didn't finish typing, we won't focus to new context */
+    if (preedit_status() == false) {
+        icmgr_set_current(proto->icid);
+    }
+    icmgr_refresh();
+
+    return 1;
+}
+
+static int
+_xim_unset_ic_focus(XIMHandle* handle, IMChangeFocusStruct* proto)
+{
+    LOG("unset focus on ic %d", proto->icid);
+
+    IC* ic = icmgr_get_current();
+    if (ic != NULL && ic->icid == proto->icid && preedit_status() == false) {
+        icmgr_clear_current();
+        icmgr_refresh();
+    }
+    return 1;
+}
+
+extern int _xim_forward_event(XIMHandle* handle,
+                              IMForwardEventStruct* proto);
+
+static int
+_imdkit_protocol_hanlder(XIMHandle* handle, IMProtocol* proto)
+{
+    assert(handle != NULL);
+    assert(proto != NULL);
+
+    switch (proto->major_code) {
+    case XIM_OPEN:
+        return _xim_open(handle, (IMOpenStruct *) proto);
+    case XIM_CLOSE:
+        return _xim_close(handle, (IMCloseStruct*) proto);
+    case XIM_CREATE_IC:
+        return _xim_create_ic(handle, (IMChangeICStruct*) proto);
+    case XIM_DESTROY_IC:
+        return _xim_destroy_ic(handle, (IMChangeICStruct*) proto);
+    case XIM_SET_IC_VALUES:
+        return _xim_set_ic_values(handle, (IMChangeICStruct*) proto);
+    case XIM_GET_IC_VALUES:
+        return _xim_get_ic_values(handle, (IMChangeICStruct*) proto);
+    case XIM_TRIGGER_NOTIFY:
+          return _xim_trigger_notify(handle, (IMTriggerNotifyStruct*) proto);
+    case XIM_FORWARD_EVENT:
+        return _xim_forward_event(handle, (IMForwardEventStruct *) proto);
+    case XIM_SET_IC_FOCUS:
+        return _xim_set_ic_focus(handle, (IMChangeFocusStruct *) proto);
+    case XIM_UNSET_IC_FOCUS:
+        return _xim_unset_ic_focus(handle, (IMChangeFocusStruct *) proto);
+    default:
+        LOG("unhandled major code %d", proto->major_code);
+        return 1;
+    }
+}
+
+static XIMHandle*
+_open_imdkit(const char* _server_name, const char* _locale)
+{
+    XIMStyle ims_styles_onspot [] = {
+        XIMPreeditPosition | XIMStatusArea,        //OverTheSpot
+        XIMPreeditPosition | XIMStatusNothing,     //OverTheSpot
+        XIMPreeditPosition | XIMStatusNone,        //OverTheSpot
+        XIMPreeditNothing  | XIMStatusNothing,     //Root
+        XIMPreeditNothing  | XIMStatusNone,        //Root
+        0
+    };
+    XIMEncoding ims_encodings[] = {
+        "COMPOUND_TEXT",
+        0
+    };
+
+    /* this is rarely documentated, the trigger condition is
+     *
+     * keycode == keysym && (state & modifier_mask) == modifier
+     *
+     * where keycode and state is the user pressed
+     */
+    hotkey_t hk;
+    settings_get(TRIGGER_KEY, &hk);
+    XIMTriggerKey trigger = {
+        .keysym = hk.keysym,
+        .modifier = hk.modifiers,
+        .modifier_mask = STATE_MASK
+    };
+
+    XIMTriggerKeys keys;
+    XIMStyles styles;
+    XIMEncodings encodings;
+
+    styles.count_styles =
+        sizeof (ims_styles_onspot)/sizeof (XIMStyle) - 1;
+    styles.supported_styles = ims_styles_onspot;
+
+    encodings.count_encodings =
+        sizeof (ims_encodings)/sizeof (XIMEncoding) - 1;
+    encodings.supported_encodings = ims_encodings;
+
+    keys.count_keys = 1;
+    keys.keylist = &trigger;
+
+    Window win = XCreateSimpleWindow(dpy, DefaultRootWindow(dpy),
+                                     0, 0, 1, 1, 1, 0, 0);
+    XSelectInput(dpy, win,
+                 ExposureMask | ButtonPressMask | ButtonReleaseMask
+                 | ButtonMotionMask | VisibilityChangeMask);
+
+    XIMHandle* handle =
+        IMOpenIM(dpy,
+                 IMModifiers, "Xi18n",
+                 IMServerWindow, win,
+                 IMServerName, _server_name,
+                 IMLocale, _locale,
+                 IMServerTransport, "X/",
+                 IMInputStyles, &styles,
+                 IMEncodingList, &encodings,
+                 IMProtocolHandler, _imdkit_protocol_hanlder,
+                 IMFilterEventMask, KeyPressMask | KeyReleaseMask,
+                 IMOnKeysList, &keys,
+                 NULL);
+    if (handle == NULL) {
+        fprintf(stderr, "Startup xim server failed.\n");
+        fprintf(stderr, "Your locale is %s, please file a bug.", _locale);
+    }
+    return handle;
+}
+
+XIMHandle*
+create_xim_server(const char* server_name, const char* locale)
+{
+    XIMHandle* handle = _open_imdkit(server_name, locale);
+    icmgr_init();
+    return handle;
+}
+
+void
+xim_start_preedit(XIMHandle* handle)
+{
+    IC* ic = icmgr_get_current();
+    if (ic == NULL)
+        return;
+
+    IMPreeditStateStruct ps;
+    ps.icid = ic->icid;
+    ps.connect_id = ic->connect_id;
+    IMPreeditStart(handle, (XPointer) &ps);
+}
+
+void
+xim_cancel_preedit(XIMHandle* handle)
+{
+    IC* ic = icmgr_get_current();
+    if (ic == NULL)
+        return;
+
+    IMPreeditStateStruct ps;
+    ps.icid = ic->icid;
+    ps.connect_id = ic->connect_id;
+    IMPreeditEnd(handle, (XPointer) &ps);
+}
+
+void
+xim_commit_preedit(XIMHandle* handle, const char* result_str)
+{
+    IC* ic = icmgr_get_current();
+    if (ic == NULL)
+        return;
+
+    XTextProperty tp;
+    IMCommitStruct cs;
+    Xutf8TextListToTextProperty(dpy, (char**) &result_str, 1,
+                                XCompoundTextStyle, &tp);
+    memset(&cs, 0, sizeof(IMCommitStruct));
+    cs.major_code = XIM_COMMIT;
+    cs.icid = ic->icid;
+    cs.connect_id = ic->connect_id;
+    cs.flag = XimLookupChars;
+    cs.commit_string = (char*) tp.value;
+    IMCommitString(handle, (XPointer) &cs);
+    XFree(tp.value);
+}
diff --git a/wrapper/xim/xim.h b/wrapper/xim/xim.h
new file mode 100644 (file)
index 0000000..f730fe3
--- /dev/null
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2010 Mike Qin <mikeandmore@gmail.com>
+ *
+ * The contents of this file are subject to the terms of either the GNU Lesser
+ * General Public License Version 2.1 only ("LGPL") or the Common Development and
+ * Distribution License ("CDDL")(collectively, the "License"). You may not use this
+ * file except in compliance with the License. You can obtain a copy of the CDDL at
+ * http://www.opensource.org/licenses/cddl1.php and a copy of the LGPLv2.1 at
+ * http://www.opensource.org/licenses/lgpl-license.php. See the License for the
+ * specific language governing permissions and limitations under the License. When
+ * distributing the software, include this License Header Notice in each file and
+ * include the full text of the License in the License file as well as the
+ * following notice:
+ *
+ * NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND DISTRIBUTION LICENSE
+ * (CDDL)
+ * For Covered Software in this distribution, this License shall be governed by the
+ * laws of the State of California (excluding conflict-of-law provisions).
+ * Any litigation relating to this License shall be subject to the jurisdiction of
+ * the Federal Courts of the Northern District of California and the state courts
+ * of the State of California, with venue lying in Santa Clara County, California.
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by only the CDDL or only
+ * the LGPL Version 2.1, indicate your decision by adding "[Contributor]" elects to
+ * include this software in this distribution under the [CDDL or LGPL Version 2.1]
+ * license." If you don't indicate a single choice of license, a recipient has the
+ * option to distribute your version of this file under either the CDDL or the LGPL
+ * Version 2.1, or to extend the choice of license to its licensees as provided
+ * above. However, if you add LGPL Version 2.1 code and therefore, elected the LGPL
+ * Version 2 license, then the option applies only if the new code is made subject
+ * to such option by the copyright holder.
+ */
+
+#ifndef _XIM_H_
+#define _XIM_H_
+
+#include <X11/X.h>
+#include <X11/Xproto.h>
+#include <X11/Xlib.h>
+#include <X11/keysym.h>
+#include <X11/Xutil.h>
+#include <XimProto.h>
+#include <IMdkit.h>
+#include <Xi18n.h>
+
+#include "common.h"
+
+__BEGIN_DECLS
+
+#define STATE_MASK 0x0D
+
+typedef struct _XIMS XIMHandle;
+
+XIMHandle* create_xim_server(const char* server_name, const char* locale);
+
+void      xim_start_preedit (XIMHandle* handle);
+void      xim_cancel_preedit(XIMHandle* handle);
+void      xim_commit_preedit(XIMHandle* handle, const char* result_str);
+
+/* provided by preedit backend */
+void      preedit_init(void);
+void      preedit_finalize(void);
+
+void      preedit_set_handle(XIMHandle* handle);
+void      preedit_reload(void);
+
+void      preedit_move(int x, int y);
+void      preedit_on_key(XIMHandle* handle, unsigned int keycode,
+                         unsigned int state);
+bool      preedit_status(void);
+void      preedit_pause(void);
+void      preedit_go_on(void);
+void      preedit_set_full(bool full);
+void      preedit_set_chinese_punc(bool chn_punc);
+void      preedit_omit_next_punct();
+
+__END_DECLS
+
+#endif /* _XIM_H_ */
diff --git a/wrapper/xim/xim_trigger.c b/wrapper/xim/xim_trigger.c
new file mode 100644 (file)
index 0000000..b308acc
--- /dev/null
@@ -0,0 +1,165 @@
+/*
+ * Copyright (c) 2010 Mike Qin <mikeandmore@gmail.com>
+ *
+ * The contents of this file are subject to the terms of either the GNU Lesser
+ * General Public License Version 2.1 only ("LGPL") or the Common Development and
+ * Distribution License ("CDDL")(collectively, the "License"). You may not use this
+ * file except in compliance with the License. You can obtain a copy of the CDDL at
+ * http://www.opensource.org/licenses/cddl1.php and a copy of the LGPLv2.1 at
+ * http://www.opensource.org/licenses/lgpl-license.php. See the License for the
+ * specific language governing permissions and limitations under the License. When
+ * distributing the software, include this License Header Notice in each file and
+ * include the full text of the License in the License file as well as the
+ * following notice:
+ *
+ * NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND DISTRIBUTION LICENSE
+ * (CDDL)
+ * For Covered Software in this distribution, this License shall be governed by the
+ * laws of the State of California (excluding conflict-of-law provisions).
+ * Any litigation relating to this License shall be subject to the jurisdiction of
+ * the Federal Courts of the Northern District of California and the state courts
+ * of the State of California, with venue lying in Santa Clara County, California.
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by only the CDDL or only
+ * the LGPL Version 2.1, indicate your decision by adding "[Contributor]" elects to
+ * include this software in this distribution under the [CDDL or LGPL Version 2.1]
+ * license." If you don't indicate a single choice of license, a recipient has the
+ * option to distribute your version of this file under either the CDDL or the LGPL
+ * Version 2.1, or to extend the choice of license to its licensees as provided
+ * above. However, if you add LGPL Version 2.1 code and therefore, elected the LGPL
+ * Version 2 license, then the option applies only if the new code is made subject
+ * to such option by the copyright holder.
+ */
+
+#include "xim.h"
+#include "ic.h"
+#include "common.h"
+#include "settings.h"
+
+#include <stdio.h>
+
+static void
+__toggle_preedit_status(XIMHandle* handle, bool flag)
+{
+    if (flag)
+        xim_start_preedit(handle);
+    else
+        xim_cancel_preedit(handle);
+}
+
+static bool last_shift_available = false;
+
+static bool
+__filter_forward_triger_key(XIMHandle* handle, IC* ic, XKeyEvent* evt)
+{
+    KeySym sym = 0;
+    hotkey_t hk;
+
+    settings_get(TRIGGER_KEY, &hk);
+    XLookupString(evt, NULL, 0, &sym, NULL);
+
+    unsigned int masked_state = (evt->state & STATE_MASK);
+
+    if (masked_state == hk.modifiers && sym == hk.keysym) {
+        if (evt->type == KeyRelease) return true;
+        ic->is_enabled = !ic->is_enabled;
+        __toggle_preedit_status(handle, ic->is_enabled);
+        icmgr_refresh();
+        return true;
+    }
+
+    settings_get(ENG_KEY, &hk);
+    if ((masked_state & hk.modifiers) == hk.modifiers && sym == hk.keysym) {
+        if (evt->type == KeyPress) {
+            last_shift_available = true;
+            return true;
+        } else if (evt->type == KeyRelease && last_shift_available) {
+            last_shift_available = false;
+            if (ic->is_enabled) {
+                ic->is_english = !ic->is_english;
+                icmgr_refresh();
+            }
+        }
+        return true;
+    } else {
+        last_shift_available = false;
+    }
+
+    return false;
+}
+
+static void
+__do_forward_event(XIMHandle* handle, IMForwardEventStruct* proto)
+{
+    /* by pass the event */
+    IMForwardEventStruct fe;
+    memset(&fe, 0, sizeof (fe));
+
+    fe.major_code = XIM_FORWARD_EVENT;
+    fe.icid = proto->icid;
+    fe.connect_id = proto->connect_id;
+    fe.sync_bit = 0;
+    fe.serial_number = 0L;
+    fe.event = proto->event;
+
+    IMForwardEvent(handle, (XPointer) &fe);
+}
+
+extern void __move_preedit(IC* ic);
+
+int
+_xim_forward_event(XIMHandle* handle, IMForwardEventStruct* proto)
+{
+    LOG("%d", proto->icid);
+    XKeyEvent* evt = (XKeyEvent*) &(proto->event);
+    IC* ic = icmgr_get_current();
+    if (ic == NULL) {
+        icmgr_set_current(proto->icid);
+        ic = icmgr_get_current();
+        if (ic == NULL)
+            return 1;
+    }
+
+    /* some of swing applications like netbeans won't set focus,
+     * we have to set focus ourself
+     */
+    if (ic->icid != proto->icid || preedit_status() == false) {
+        icmgr_set_current(proto->icid);
+        ic = icmgr_get_current();
+        icmgr_refresh();
+    }
+
+    if (!__filter_forward_triger_key(handle, ic, evt)) {
+        int masked_state = evt->state & STATE_MASK;
+        if (masked_state != ShiftMask && masked_state != 0) {
+            __do_forward_event(handle, proto);
+        } else if (!ic->is_enabled || ic->is_english) {
+            __do_forward_event(handle, proto);
+        } else {
+            KeySym sym;
+            XLookupString(evt, NULL, 0, &sym, NULL);
+            if ((sym <= 0x20 || sym > 0x7E) && preedit_status() == false) {
+                __do_forward_event(handle, proto);
+            } else if (sym >= 0x30 && sym <= 0x39
+                       && preedit_status() == false) {
+                // digit key pressed
+                if (settings_get_int(SMART_PUNCT) && evt->type == KeyPress) {
+                    preedit_omit_next_punct();
+                }
+
+                __do_forward_event(handle, proto);
+            } else {
+                if (evt->type == KeyPress) {
+                    __move_preedit(ic);
+                    preedit_on_key(handle, sym, evt->state);
+                } else {
+                    LOG("ignore");
+                }
+                return 0;
+            }
+        }
+    }
+    return 1;
+}
diff --git a/wrapper/xim/xmisc.c b/wrapper/xim/xmisc.c
new file mode 100644 (file)
index 0000000..174cdea
--- /dev/null
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 2010 Mike Qin <mikeandmore@gmail.com>
+ *
+ * The contents of this file are subject to the terms of either the GNU Lesser
+ * General Public License Version 2.1 only ("LGPL") or the Common Development and
+ * Distribution License ("CDDL")(collectively, the "License"). You may not use this
+ * file except in compliance with the License. You can obtain a copy of the CDDL at
+ * http://www.opensource.org/licenses/cddl1.php and a copy of the LGPLv2.1 at
+ * http://www.opensource.org/licenses/lgpl-license.php. See the License for the
+ * specific language governing permissions and limitations under the License. When
+ * distributing the software, include this License Header Notice in each file and
+ * include the full text of the License in the License file as well as the
+ * following notice:
+ *
+ * NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND DISTRIBUTION LICENSE
+ * (CDDL)
+ * For Covered Software in this distribution, this License shall be governed by the
+ * laws of the State of California (excluding conflict-of-law provisions).
+ * Any litigation relating to this License shall be subject to the jurisdiction of
+ * the Federal Courts of the Northern District of California and the state courts
+ * of the State of California, with venue lying in Santa Clara County, California.
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by only the CDDL or only
+ * the LGPL Version 2.1, indicate your decision by adding "[Contributor]" elects to
+ * include this software in this distribution under the [CDDL or LGPL Version 2.1]
+ * license." If you don't indicate a single choice of license, a recipient has the
+ * option to distribute your version of this file under either the CDDL or the LGPL
+ * Version 2.1, or to extend the choice of license to its licensees as provided
+ * above. However, if you add LGPL Version 2.1 code and therefore, elected the LGPL
+ * Version 2 license, then the option applies only if the new code is made subject
+ * to such option by the copyright holder.
+ */
+
+#include <gdk/gdkx.h>
+
+#include "xmisc.h"
+
+void
+get_window_position(Window w, int* x, int* y)
+{
+    int tx = 0, ty = 0;
+    Window child;
+    if (XTranslateCoordinates(dpy, w, DefaultRootWindow(dpy),
+                              0, 0,
+                              &tx, &ty, &child) < 0) {
+        printf("ERROR\n");
+        return;
+    }
+    if (x != NULL)
+        (*x) = tx;
+    if (y != NULL)
+        (*y) = ty;
+}
+
+void
+get_window_size(Window w, int* width, int* height)
+{
+    XWindowAttributes attrs;
+    if (XGetWindowAttributes(dpy, w, &attrs) < 0) {
+        printf("ERROR\n");
+    }
+    if (width != NULL)
+        (*width) = attrs.width;
+    if (height != NULL)
+        (*height) = attrs.height;
+}
+
+void
+get_screen_size(int* width, int* height)
+{
+    get_window_size(DefaultRootWindow(dpy), width, height);
+}
+
+Display* dpy = NULL;
+
+void
+init_display(int* argc, char*** argv)
+{
+    gtk_init(argc, argv);
+    dpy = GDK_DISPLAY();
+}
+
+static int
+in_range(int x, int min, int max)
+{
+    if (x < min) x = min;
+    if (x > max) x = max;
+    return x;
+}
+
+void
+adjust_position(int* x, int* y, int width, int height)
+{
+    int screen_width, screen_height;
+    get_screen_size(&screen_width, &screen_height);
+    *x = in_range(*x, 0, screen_width - width);
+    *y = in_range(*y, 0, screen_height - height);
+}
diff --git a/wrapper/xim/xmisc.h b/wrapper/xim/xmisc.h
new file mode 100644 (file)
index 0000000..001126c
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2010 Mike Qin <mikeandmore@gmail.com>
+ *
+ * The contents of this file are subject to the terms of either the GNU Lesser
+ * General Public License Version 2.1 only ("LGPL") or the Common Development and
+ * Distribution License ("CDDL")(collectively, the "License"). You may not use this
+ * file except in compliance with the License. You can obtain a copy of the CDDL at
+ * http://www.opensource.org/licenses/cddl1.php and a copy of the LGPLv2.1 at
+ * http://www.opensource.org/licenses/lgpl-license.php. See the License for the
+ * specific language governing permissions and limitations under the License. When
+ * distributing the software, include this License Header Notice in each file and
+ * include the full text of the License in the License file as well as the
+ * following notice:
+ *
+ * NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND DISTRIBUTION LICENSE
+ * (CDDL)
+ * For Covered Software in this distribution, this License shall be governed by the
+ * laws of the State of California (excluding conflict-of-law provisions).
+ * Any litigation relating to this License shall be subject to the jurisdiction of
+ * the Federal Courts of the Northern District of California and the state courts
+ * of the State of California, with venue lying in Santa Clara County, California.
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by only the CDDL or only
+ * the LGPL Version 2.1, indicate your decision by adding "[Contributor]" elects to
+ * include this software in this distribution under the [CDDL or LGPL Version 2.1]
+ * license." If you don't indicate a single choice of license, a recipient has the
+ * option to distribute your version of this file under either the CDDL or the LGPL
+ * Version 2.1, or to extend the choice of license to its licensees as provided
+ * above. However, if you add LGPL Version 2.1 code and therefore, elected the LGPL
+ * Version 2 license, then the option applies only if the new code is made subject
+ * to such option by the copyright holder.
+ */
+
+#ifndef _XMISC_H_
+#define _XMISC_H_
+
+#include <X11/Xproto.h>
+#include <X11/Xlib.h>
+#include <X11/keysym.h>
+#include <X11/Xutil.h>
+
+#include "common.h"
+
+__BEGIN_DECLS
+
+void get_window_position(Window w, int* x, int* y);
+void get_window_size(Window w, int* width, int* height);
+void get_screen_size(int* width, int* height);
+
+void init_display(int* argc, char*** argv);
+void adjust_position(int* x, int* y, int width, int height);
+
+extern Display* dpy;
+
+__END_DECLS
+
+#endif /* _XMISC_H_ */