2
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
4
* Copyright (c) 2007 Sun Microsystems, Inc. All Rights Reserved.
6
* The contents of this file are subject to the terms of either the GNU Lesser
7
* General Public License Version 2.1 only ("LGPL") or the Common Development and
8
* Distribution License ("CDDL")(collectively, the "License"). You may not use this
9
* file except in compliance with the License. You can obtain a copy of the CDDL at
10
* http://www.opensource.org/licenses/cddl1.php and a copy of the LGPLv2.1 at
11
* http://www.opensource.org/licenses/lgpl-license.php. See the License for the
12
* specific language governing permissions and limitations under the License. When
13
* distributing the software, include this License Header Notice in each file and
14
* include the full text of the License in the License file as well as the
17
* NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND DISTRIBUTION LICENSE
19
* For Covered Software in this distribution, this License shall be governed by the
20
* laws of the State of California (excluding conflict-of-law provisions).
21
* Any litigation relating to this License shall be subject to the jurisdiction of
22
* the Federal Courts of the Northern District of California and the state courts
23
* of the State of California, with venue lying in Santa Clara County, California.
27
* If you wish your version of this file to be governed by only the CDDL or only
28
* the LGPL Version 2.1, indicate your decision by adding "[Contributor]" elects to
29
* include this software in this distribution under the [CDDL or LGPL Version 2.1]
30
* license." If you don't indicate a single choice of license, a recipient has the
31
* option to distribute your version of this file under either the CDDL or the LGPL
32
* Version 2.1, or to extend the choice of license to its licensees as provided
33
* above. However, if you add LGPL Version 2.1 code and therefore, elected the LGPL
34
* Version 2 license, then the option applies only if the new code is made subject
35
* to such option by the copyright holder.
42
#include "portability.h"
43
#include "imi_plugin.h"
45
CIMIPlugin::CIMIPlugin(TPluginTypeEnum pluginType)
46
: m_pluginType(pluginType)
49
CIMIPlugin::~CIMIPlugin()
52
class CIMIPythonPlugin : public CIMIPlugin
55
CIMIPythonPlugin(std::string filename);
56
virtual ~CIMIPythonPlugin();
58
virtual std::string getName() { return m_name; }
59
virtual std::string getAuthor() { return m_author; }
60
virtual std::string getDescription() { return m_description; }
62
virtual TPluginCandidates provide_candidates(const TPluginPreedit& str,
64
virtual TPluginCandidate translate_candidate(const TPluginCandidate& candi,
68
PyObject* m_provide_method;
69
PyObject* m_trans_method;
73
std::string m_description;
76
CIMIPythonPlugin::CIMIPythonPlugin(std::string filename)
77
: CIMIPlugin(CIMI_PLUGIN_PYTHON), m_module(NULL), m_provide_method(NULL),
80
// filename always ends with .py
81
std::string module_name = filename.substr(0, filename.length() - 3);
82
CIMIPluginManager& manager = AIMIPluginManager::instance();
83
PyObject* dict = NULL;
84
PyObject* name = NULL;
85
PyObject* author = NULL;
86
PyObject* description = NULL;
88
m_module = PyImport_ImportModule(module_name.c_str());
89
if (m_module == NULL) {
92
dict = PyModule_GetDict(m_module);
96
m_provide_method = PyDict_GetItemString(dict, "provide_candidates");
97
m_trans_method = PyDict_GetItemString(dict, "translate_candidate");
98
name = PyDict_GetItemString(dict, "__NAME__");
99
author = PyDict_GetItemString(dict, "__AUTHOR__");
100
description = PyDict_GetItemString(dict, "__DESCRIPTION__");
102
if (name != NULL && PyString_Check(name)) {
103
m_name = PyString_AsString(name);
105
if (author != NULL && PyString_Check(author)) {
106
m_author = PyString_AsString(author);
108
if (description != NULL && PyString_Check(description)) {
109
m_description = PyString_AsString(description);
113
manager.setLastError("Error when loading Python module");
117
CIMIPythonPlugin::~CIMIPythonPlugin()
119
Py_XDECREF(m_module);
123
Py_Call1(PyObject* method, PyObject* obj)
125
PyObject* args = PyTuple_Pack(1, obj);
126
PyObject* ret = PyObject_CallObject(method, args);
134
static const size_t TWCharBufferSize = 2048;
137
PyUnicode_AsWString(PyObject* obj)
139
TWCHAR* wide_str_buf = new TWCHAR[TWCharBufferSize];
141
memset(wide_str_buf, 0, sizeof(TWCHAR) * TWCharBufferSize);
143
Py_ssize_t size = PyUnicode_AsWideChar((PyUnicodeObject*) obj,
144
(wchar_t*) wide_str_buf,
147
res = wstring(wide_str_buf);
149
delete [] wide_str_buf;
154
ExtractSequence(TPluginCandidates& result, PyObject* py_seq)
156
Py_ssize_t len = PySequence_Length(py_seq);
157
for (Py_ssize_t i = 0; i < len; i++) {
158
PyObject* tuple_item_obj = PySequence_GetItem(py_seq, i);
159
if (!PyTuple_Check(tuple_item_obj)) {
162
PyObject* rank_obj = PyTuple_GetItem(tuple_item_obj, 0);
163
PyObject* candi_obj = PyTuple_GetItem(tuple_item_obj, 1);
164
if (rank_obj == NULL || !PyInt_Check(rank_obj) || candi_obj == NULL
165
|| !PyUnicode_Check(candi_obj)) {
169
result.push_back(TPluginCandidateItem((int) PyInt_AsLong(rank_obj),
170
PyUnicode_AsWString(candi_obj)));
175
CIMIPythonPlugin::provide_candidates(const TPluginPreedit& str,
178
TPluginCandidates res;
181
if (m_provide_method == NULL) {
186
PyObject* str_obj = PyUnicode_FromWideChar((wchar_t*) str.c_str(),
188
PyObject* ret_obj = Py_Call1(m_provide_method, str_obj);
190
if (ret_obj == NULL) {
192
} else if (PyInt_Check(ret_obj)) {
193
*waitTime = (int) PyInt_AsLong(ret_obj);
194
} else if (PyTuple_Check(ret_obj) && PyTuple_Size(ret_obj) == 2) {
195
PyObject* time_obj = PyTuple_GetItem(ret_obj, 0);
196
PyObject* seq_obj = PyTuple_GetItem(ret_obj, 1);
197
if (PyInt_Check(time_obj) && PyList_Check(seq_obj)) {
198
*waitTime = (int) PyInt_AsLong(time_obj);
199
ExtractSequence(res, seq_obj);
201
} else if (PyList_Check(ret_obj)) {
202
// extract all items inside this sequence.
203
ExtractSequence(res, ret_obj);
211
CIMIPythonPlugin::translate_candidate(const TPluginCandidate& candi,
214
TPluginCandidate res;
217
if (m_trans_method == NULL) {
222
PyObject* str_obj = PyUnicode_FromWideChar((wchar_t*) candi.c_str(),
224
PyObject* ret_obj = Py_Call1(m_trans_method, str_obj);
225
if (ret_obj == NULL) {
227
} else if (PyInt_Check(ret_obj)) {
228
*waitTime = (int) PyInt_AsLong(ret_obj);
229
} else if (PyUnicode_Check(ret_obj)) {
230
res = TPluginCandidate(PyUnicode_AsWString(ret_obj));
240
if (Py_IsInitialized())
242
std::stringstream eval_str;
244
// append plugin module path to default load path
246
signal(SIGINT, SIG_DFL);
248
PyRun_SimpleString("import sys");
249
eval_str << "sys.path.append(r'" << getenv("HOME")
250
<< "/.sunpinyin/plugins/" << "')";
251
PyRun_SimpleString(eval_str.str().c_str());
254
#define PLUGIN_LIST_FILE "/.sunpinyin/plugins.list";
255
#define PLUGIN_NAME_LEN 128
257
CIMIPluginManager::CIMIPluginManager()
258
: m_hasError(false), m_waitTime(0)
263
CIMIPluginManager::~CIMIPluginManager()
265
for (size_t i = 0; i < m_plugins.size(); i++) {
271
CIMIPluginManager::initializePlugins()
273
// load configuration file which list all needed plugins
274
std::string plugin_list_path = getenv("HOME");
275
plugin_list_path += PLUGIN_LIST_FILE;
276
FILE* fp = fopen(plugin_list_path.c_str(), "r");
281
char plugin_name[PLUGIN_NAME_LEN];
282
memset(plugin_name, 0, PLUGIN_NAME_LEN);
283
fgets(plugin_name, PLUGIN_NAME_LEN, fp);
284
if (strlen(plugin_name) == 0) {
287
if (strlen(plugin_name) == 1) {
290
plugin_name[strlen(plugin_name) - 1] = 0; // remove the \n at the end
291
if (loadPlugin(plugin_name) == NULL) {
292
fprintf(stderr, "Error! Cannot load plugin %s\n", plugin_name);
299
CIMIPluginManager::detectPluginType(std::string filename)
301
if (filename.length() >= 3
302
&& filename.substr(filename.length() - 3) == ".py") {
303
return CIMI_PLUGIN_PYTHON;
305
return CIMI_PLUGIN_UNKNOWN;
310
CIMIPluginManager::loadPlugin(std::string filename)
312
TPluginTypeEnum type = detectPluginType(filename);
313
CIMIPlugin* plugin = createPlugin(filename, type);
314
std::stringstream error;
316
if (plugin == NULL) {
319
if (hasLastError()) {
324
for (size_t i = 0; i < m_plugins.size(); i++) {
325
if (m_plugins[i]->getName() == plugin->getName()) {
326
error << "Plugin " << plugin->getName() << " has already loaded!";
327
setLastError(error.str());
328
delete plugin; // Reject duplicate plugins
332
m_plugins.push_back(plugin);
337
CIMIPluginManager::createPlugin(std::string filename,
338
TPluginTypeEnum pluginType)
340
std::stringstream error;
343
switch (pluginType) {
344
case CIMI_PLUGIN_PYTHON:
345
return new CIMIPythonPlugin(filename);
346
case CIMI_PLUGIN_UNKNOWN:
348
error << "Cannot detect type for " << filename;
349
setLastError(error.str());
355
CIMIPluginManager::setLastError(std::string desc)
362
CIMIPluginManager::clearLastError()
369
CIMIPluginManager::markWaitTime(int waitTime)
374
if (m_waitTime == 0) {
375
m_waitTime = waitTime;
376
} else if (waitTime < m_waitTime) {
377
m_waitTime = waitTime;