source: pymigemo/trunk/pymigemo.c @ 225

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