source: pymigemo/trunk/pymigemo.c @ 227

Revision 227, 13.2 KB checked in by atzm, 11 years ago (diff)
  • fixed handle value bytes to unicode
  • Property svn:keywords set to Id
RevLine 
[21]1/*
[37]2 * pymigemo.c - C/Migemo Python binding
[225]3 * Copyright(C) 2005-2012, Atzm WATANABE <atzm@atzm.org>
[21]4 *
5 * $Id$
6 */
7
8#include <Python.h>
[30]9#include <structmember.h>
10#include <migemo.h>
[34]11#include <stdbool.h>
[30]12#include <string.h>
[40]13#include <stdlib.h>
[36]14#include <errno.h>
15#include <sys/types.h>
16#include <sys/stat.h>
17#include <fcntl.h>
18#include <unistd.h>
[21]19
[225]20#define PYMIGEMO_VERSION "0.4"
[21]21
[225]22#if (PY_MAJOR_VERSION == 3 && PY_MINOR_VERSION >= 1) || PY_MAJOR_VERSION > 3
23#  define PYTHON3
24#endif
25
26#ifndef Py_TYPE
27#  define Py_TYPE(ob) (((PyObject *)(ob))->ob_type)
28#endif
29
[21]30/* for dereference migemo object members */
[30]31struct _migemo {
32    int   enable;
33    void *mtree;
34    int   charset;
35    void *roma2hira;
36    void *hira2kata;
37    void *han2zen;
38    void *zen2han;
39    void *rx;
40    void *addword;
41    void *char2int;
[21]42};
43
44typedef struct {
[30]45    PyObject_HEAD
46    migemo *migemo_obj;
[21]47} Migemo;
48
[34]49static bool
[227]50get_encoding(unsigned char *encoding, size_t size, int charset)
[34]51{
[227]52    unsigned char *enc;
[34]53
54    switch(charset) {
55    case 1:
56        enc = "cp932";
57        break;
58    case 2:
59        enc = "euc_jp";
60        break;
61    case 3:
62        enc = "utf_8";
63        break;
64    default:
65        enc = "ascii";
66    }
67
68    if (strlen(enc) < size) {
69        strcpy(encoding, enc);
70        return true;
71    }
72
73    return false;
74}
75
[227]76static unsigned char *
77trans_string(PyObject *pystr, const unsigned char *encoding)
78{
79    unsigned char *str;
80
81    if (PyUnicode_Check(pystr)) {
82        PyObject *tmp = PyUnicode_AsEncodedString(pystr, encoding, "strict");
83
84        if (tmp == NULL) {
85            return NULL;
86        }
87
88        str = strdup(PyBytes_AS_STRING(tmp));
89        Py_DECREF(tmp);
90
91        if (str == NULL) {
92            PyErr_NoMemory();
93            return NULL;
94        }
95        return str;
96    }
97
98    if (PyBytes_Check(pystr)) {
99        if ((str = strdup(PyBytes_AS_STRING(pystr))) == NULL) {
100            PyErr_NoMemory();
101            return NULL;
102        }
103        return str;
104    }
105
106    PyErr_SetString(PyExc_TypeError, "argument must be string");
107    return NULL;
108}
109
[36]110static int
[227]111isloadable(const unsigned char *path)
[36]112{
113    struct stat st;
[227]114
[36]115    int ret = 0;
116    int fd  = open(path, O_RDONLY);
117
118    if (fd < 0) {
119        return errno;
120    }
121
122    if (fstat(fd, &st) < 0) {
123        ret = errno;
124        goto isloadable_end;
125    }
126    if (S_ISDIR(st.st_mode)) {
127        ret = EISDIR;
128        goto isloadable_end;
129    }
130
131  isloadable_end:
132    if (close(fd) < 0) {
133        ret = errno;
134    }
135    return ret;
136}
137
[21]138static void
139Migemo_dealloc(Migemo *self)
140{
[30]141    if (self->migemo_obj) {
142        migemo_close(self->migemo_obj);
143    }
[21]144
[225]145    Py_TYPE(self)->tp_free((PyObject *)self);
[21]146}
147
148static PyObject *
149Migemo_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
150{
[227]151    Migemo *self = (Migemo *)type->tp_alloc(type, 0);
[21]152
[30]153    if (self != NULL) {
154        self->migemo_obj = NULL;
155    }
156
157    return (PyObject *)self;
[21]158}
159
160static int
161Migemo_init(Migemo *self, PyObject *args, PyObject *kwds)
162{
[227]163    migemo        *migemo_obj;
164    unsigned char *dictionary;
[21]165
[30]166    static char *kwlist[] = {"dictionary", NULL};
[21]167
[30]168    if (!PyArg_ParseTupleAndKeywords(args, kwds, "s", kwlist, &dictionary)) {
169        return -1;
170    }
[21]171
[30]172    if (dictionary) {
[36]173        int ret = isloadable(dictionary);
174
175        if (ret != 0) {
[227]176            PyErr_SetString(PyExc_OSError, strerror(ret));
[36]177            return -1;
178        }
179
[30]180        if (self->migemo_obj) {
181            migemo_close(self->migemo_obj);
182        }
[21]183
[30]184        migemo_obj = migemo_open(dictionary);
[21]185
[30]186        if (migemo_obj) {
187            self->migemo_obj = migemo_obj;
188        }
189        else {
[34]190            PyErr_SetString(PyExc_AssertionError, "migemo_open() failed");
[30]191            return -1;
192        }
193    }
194
195    return 0;
[21]196}
197
198static PyObject *
199Migemo_get_encoding(Migemo *self)
200{
[227]201    unsigned char encoding[7];
[30]202
203    if (!get_encoding(encoding, sizeof(encoding), self->migemo_obj->charset)) {
[34]204        PyErr_SetString(PyExc_AssertionError, "get_encoding() failed");
[30]205        return NULL;
206    }
207
[227]208    return PyUnicode_FromString(encoding);
[21]209}
210
211static PyObject *
212Migemo_query(Migemo *self, PyObject *args, PyObject *kwds)
213{
[34]214    PyObject      *result, *pyquery, *pyrestr;
[227]215    unsigned char *query, *regex, encoding[7];
[21]216
[30]217    static char *kwlist[] = {"query", NULL};
[21]218
[34]219    if (!PyArg_ParseTupleAndKeywords(args, kwds, "O", kwlist, &pyquery)) {
[30]220        return NULL;
221    }
[21]222
[30]223    if (!get_encoding(encoding, sizeof(encoding), self->migemo_obj->charset)) {
[34]224        PyErr_SetString(PyExc_AssertionError, "get_encoding() failed");
[30]225        return NULL;
226    }
[21]227
[227]228    if ((query = trans_string(pyquery, encoding)) == NULL) {
[30]229        return NULL;
230    }
[21]231
[34]232    regex = migemo_query(self->migemo_obj, query);
[40]233    free(query);
[34]234    if (regex == NULL) {
235        PyErr_SetString(PyExc_AssertionError, "migemo_query() failed");
236        return NULL;
[21]237    }
238
[225]239    pyrestr = PyBytes_FromString(regex);
[34]240    migemo_release(self->migemo_obj, regex);
241    if (pyrestr == NULL) {
[30]242        return NULL;
243    }
[21]244
[34]245    result = PyUnicode_FromEncodedObject(pyrestr, encoding, "strict");
246    Py_DECREF(pyrestr);
[30]247    return result;
[21]248}
249
250static PyObject *
251Migemo_set_operator(Migemo *self, PyObject *args, PyObject *kwds)
252{
[227]253    PyObject      *result, *pyop;
254    unsigned char *op, encoding[7];
255    int            index;
[21]256 
[30]257    static char *kwlist[] = {"index", "op", NULL};
[21]258
[227]259    if (!PyArg_ParseTupleAndKeywords(args, kwds, "iO", kwlist, &index, &pyop)) {
[30]260        return NULL;
261    }
[21]262
[227]263    if (!get_encoding(encoding, sizeof(encoding), self->migemo_obj->charset)) {
264        PyErr_SetString(PyExc_AssertionError, "get_encoding() failed");
265        return NULL;
[30]266    }
[21]267
[227]268    if ((op = trans_string(pyop, encoding)) == NULL) {
269        return NULL;
270    }
271
272    result = PyBool_FromLong((long)migemo_set_operator(self->migemo_obj, index, op));
273    free(op);
[30]274    return result;
[21]275}
276
277static PyObject *
278Migemo_get_operator(Migemo *self, PyObject *args, PyObject *kwds)
279{
[227]280    PyObject            *result;
[34]281    const unsigned char *op;
[227]282    unsigned char        encoding[7];
[34]283    int                  index;
[21]284 
[30]285    static char *kwlist[] = {"index", NULL};
[21]286
[30]287    if (!PyArg_ParseTupleAndKeywords(args, kwds, "i", kwlist, &index)) {
288        return NULL;
289    }
[21]290
[227]291    if (!get_encoding(encoding, sizeof(encoding), self->migemo_obj->charset)) {
292        PyErr_SetString(PyExc_AssertionError, "get_encoding() failed");
293        return NULL;
294    }
295
[30]296    if (op = migemo_get_operator(self->migemo_obj, index)) {
[227]297        PyObject *tmp = PyBytes_FromString(op);
298
299        if (tmp == NULL) {
300            return NULL;
301        }
302
303        result = PyUnicode_FromEncodedObject(tmp, encoding, "strict");
304        Py_DECREF(tmp);
305        return result;
[30]306    }
307
[227]308    PyErr_SetString(PyExc_ValueError, "invalid opindex");
309    return NULL;
[21]310}
311
312static PyObject *
313Migemo_load(Migemo *self, PyObject *args, PyObject *kwds)
314{
[227]315    unsigned char *dict_file;
316    int            dict_id;
[21]317 
[30]318    static char *kwlist[] = {"dict_id", "dict_file", NULL};
[21]319
[30]320    if (!PyArg_ParseTupleAndKeywords(args, kwds, "is", kwlist, &dict_id, &dict_file)) {
321        return NULL;
322    }
[21]323
[30]324    if (dict_file) {
[36]325        int ret = isloadable(dict_file);
326
327        if (ret != 0) {
[227]328            PyErr_SetString(PyExc_OSError, strerror(ret));
[36]329            return NULL;
330        }
331
[227]332        return PyLong_FromLong((long)migemo_load(self->migemo_obj, dict_id, dict_file));
[30]333    }
[21]334
[227]335    PyErr_SetString(PyExc_AssertionError, "dict_file is NULL");
336    return NULL;
[21]337}
338
339static PyObject *
340Migemo_is_enable(Migemo *self)
341{
[34]342    return PyBool_FromLong((long)migemo_is_enable(self->migemo_obj));
[21]343}
344
345static PyMethodDef Migemo_methods[] = {
[225]346    {"query", (PyCFunction)Migemo_query, METH_VARARGS | METH_KEYWORDS,
[227]347     "return regex from string\n\
[21]348\n\
349def query(query)\n\
[227]350  query: string\n\
[21]351\n\
[227]352  returns: regex string"},
[225]353    {"set_operator", (PyCFunction)Migemo_set_operator, METH_VARARGS | METH_KEYWORDS,
[30]354     "set operator string as the meta character of regex\n\
[21]355\n\
356def set_operator(index, op):\n\
357  index: (OPINDEX_NEST_IN|OPINDEX_NEST_OUT|OPINDEX_NEWLINE|\n\
358          OPINDEX_OR|OPINDEX_SELECT_IN|OPINDEX_SELECT_OUT)\n\
[227]359  op: operator string\n\
[21]360\n\
361  returns: boolean value"},
[225]362    {"get_operator", (PyCFunction)Migemo_get_operator, METH_VARARGS | METH_KEYWORDS,
[30]363     "get operator string as the meta character of regex\n\
[21]364\n\
365def get_operator(index)\n\
366  index: (OPINDEX_NEST_IN|OPINDEX_NEST_OUT|OPINDEX_NEWLINE|\n\
367          OPINDEX_OR|OPINDEX_SELECT_IN|OPINDEX_SELECT_OUT)\n\
368\n\
[227]369  returns: operator string"},
[225]370    {"load", (PyCFunction)Migemo_load, METH_VARARGS | METH_KEYWORDS,
[30]371     "add dictionary to Migemo object\n\
[21]372\n\
373def load(dict_id, dict_file)\n\
374  dict_id: (DICTID_HAN2ZEN|DICTID_HIRA2KATA|DICTID_MIGEMO|\n\
375            DICTID_ROMA2HIRA|DICTID_ZEN2HAN)\n\
[227]376  dict_file: path to dictionary file\n\
[21]377\n\
[37]378  returns: ID of loaded dictionary"},
[30]379    {"is_enable", (PyCFunction)Migemo_is_enable, METH_NOARGS,
380     "check internal migemo_dict\n\
[21]381\n\
382def is_enable()\n\
383  returns: boolean value"},
[30]384    {"get_encoding", (PyCFunction)Migemo_get_encoding, METH_NOARGS,
385     "get dictionary encoding\n\
[21]386\n\
387def get_encoding()\n\
[227]388  returns: encoding string"},
[30]389    {NULL} /* Sentinel */
[21]390};
391
392static PyMemberDef Migemo_members[] = {
[30]393    {NULL} /* Sentinel */
[21]394};
395
[225]396#ifndef PyVarObject_HEAD_INIT
397#  define PyVarObject_HEAD_INIT(type, size) PyObject_HEAD_INIT(type) size,
398#endif
399
[21]400static PyTypeObject MigemoType = {
[225]401    PyVarObject_HEAD_INIT(NULL, 0)
[30]402    "migemo.Migemo",            /*tp_name*/
403    sizeof(Migemo),             /*tp_basicsize*/
404    0,                          /*tp_itemsize*/
405    (destructor)Migemo_dealloc, /*tp_dealloc*/
406    0,                          /*tp_print*/
407    0,                          /*tp_getattr*/
408    0,                          /*tp_setattr*/
409    0,                          /*tp_compare*/
410    0,                          /*tp_repr*/
411    0,                          /*tp_as_number*/
412    0,                          /*tp_as_sequence*/
413    0,                          /*tp_as_mapping*/
414    0,                          /*tp_hash */
415    0,                          /*tp_call*/
416    0,                          /*tp_str*/
417    0,                          /*tp_getattro*/
418    0,                          /*tp_setattro*/
419    0,                          /*tp_as_buffer*/
420    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
[37]421    "",                         /* tp_doc */
[30]422    0,                          /* tp_traverse */
423    0,                          /* tp_clear */
424    0,                          /* tp_richcompare */
425    0,                          /* tp_weaklistoffset */
426    0,                          /* tp_iter */
427    0,                          /* tp_iternext */
428    Migemo_methods,             /* tp_methods */
429    Migemo_members,             /* tp_members */
430    0,                          /* tp_getset */
431    0,                          /* tp_base */
432    0,                          /* tp_dict */
433    0,                          /* tp_descr_get */
434    0,                          /* tp_descr_set */
435    0,                          /* tp_dictoffset */
436    (initproc)Migemo_init,      /* tp_init */
437    0,                          /* tp_alloc */
438    Migemo_new,                 /* tp_new */
[21]439};
440
[225]441#define PYMIGEMO_MODULEDOC "C/Migemo Python binding"
442
[21]443static PyMethodDef module_methods[] = {
[30]444    {NULL} /* Sentinel */
[21]445};
446
[225]447#ifdef PYTHON3
448static struct PyModuleDef moduledef = {
449    PyModuleDef_HEAD_INIT,
450    "migemo",            /* m_name */
451    PYMIGEMO_MODULEDOC,  /* m_doc */
452    -1,                  /* m_size */
453    module_methods,      /* m_methods */
454    NULL,                /* m_reload */
455    NULL,                /* m_traverse */
456    NULL,                /* m_clear */
457    NULL,                /* m_free */
458};
[21]459#endif
[225]460
461#ifdef PYTHON3
462#  define MOD_INIT(name) PyObject *PyInit_##name(void)
463#else
464#  define MOD_INIT(name) void init##name(void)
465#endif
466
467MOD_INIT(migemo)
[21]468{
[30]469    PyObject* m;
[21]470
[30]471    if (PyType_Ready(&MigemoType) < 0)
472        return;
[21]473
[225]474#ifdef PYTHON3
475    m = PyModule_Create(&moduledef);
476#else
477    m = Py_InitModule3("migemo", module_methods, PYMIGEMO_MODULEDOC);
478#endif
[21]479
[225]480    if (m == NULL) {
481#ifdef PYTHON3
482        return NULL;
483#else
484        return;
485#endif
486    }
487
[30]488    Py_INCREF(&MigemoType);
489    PyModule_AddObject(m, "Migemo", (PyObject *)&MigemoType);
490    PyModule_AddObject(m, "PYMIGEMO_VERSION", Py_BuildValue("s", PYMIGEMO_VERSION));
[21]491
[30]492    PyModule_AddObject(m, "MIGEMO_VERSION", Py_BuildValue("s", MIGEMO_VERSION));
[21]493
[30]494    PyModule_AddObject(m, "DICTID_INVALID", Py_BuildValue("i", MIGEMO_DICTID_INVALID));
495    PyModule_AddObject(m, "DICTID_MIGEMO", Py_BuildValue("i", MIGEMO_DICTID_MIGEMO));
496    PyModule_AddObject(m, "DICTID_ROMA2HIRA", Py_BuildValue("i", MIGEMO_DICTID_ROMA2HIRA));
497    PyModule_AddObject(m, "DICTID_HIRA2KATA", Py_BuildValue("i", MIGEMO_DICTID_HIRA2KATA));
498    PyModule_AddObject(m, "DICTID_HAN2ZEN", Py_BuildValue("i", MIGEMO_DICTID_HAN2ZEN));
499    PyModule_AddObject(m, "DICTID_ZEN2HAN", Py_BuildValue("i", MIGEMO_DICTID_ZEN2HAN));
[21]500
[30]501    PyModule_AddObject(m, "OPINDEX_OR", Py_BuildValue("i", MIGEMO_OPINDEX_OR));
502    PyModule_AddObject(m, "OPINDEX_NEST_IN", Py_BuildValue("i", MIGEMO_OPINDEX_NEST_IN));
503    PyModule_AddObject(m, "OPINDEX_NEST_OUT", Py_BuildValue("i", MIGEMO_OPINDEX_NEST_OUT));
504    PyModule_AddObject(m, "OPINDEX_SELECT_IN", Py_BuildValue("i", MIGEMO_OPINDEX_SELECT_IN));
505    PyModule_AddObject(m, "OPINDEX_SELECT_OUT", Py_BuildValue("i", MIGEMO_OPINDEX_SELECT_OUT));
506    PyModule_AddObject(m, "OPINDEX_NEWLINE", Py_BuildValue("i", MIGEMO_OPINDEX_NEWLINE));
[225]507
508#ifdef PYTHON3
509    return m;
510#endif
[21]511}
Note: See TracBrowser for help on using the repository browser.