diff options
Diffstat (limited to 'src/pooptmodule.c')
-rw-r--r-- | src/pooptmodule.c | 279 |
1 files changed, 279 insertions, 0 deletions
diff --git a/src/pooptmodule.c b/src/pooptmodule.c new file mode 100644 index 00000000..289313f3 --- /dev/null +++ b/src/pooptmodule.c @@ -0,0 +1,279 @@ +/* Copyright 2010-2011 Florent Le Coz <louiz@louiz.org> */ + +/* This file is part of Poezio. */ + +/* Poezio is free software: you can redistribute it and/or modify */ +/* it under the terms of the MIT license. See the COPYING file. */ + +/** The poopt python3 module +**/ + +/* This file is a python3 module for poezio, used to replace some time-critical +python functions that are too slow. If compiled, poezio will use this module, +otherwise it will just use the equivalent python functions. */ + +#define PY_SSIZE_T_CLEAN + +#include "Python.h" + +PyObject *ErrorObject; + +/*** + The module functions + ***/ + +/* cut_text: takes a string and returns a tuple of int. + Each two int tuple is a line, represented by the ending position it (where it should be cut). + Not that this position is calculed using the position of the python string characters, + not just the individual bytes. + For example, poopt_cut_text("vivent les frigidaires", 6); + will return [(0, 6), (7, 10), (11, 17), (17, 22)], meaning that the lines are + "vivent", "les", "frigid" and "aires" +*/ +PyDoc_STRVAR(poopt_cut_text_doc, "cut_text(width, text)\n\n\nReturn the list of strings, cut according to the given size."); + +static PyObject *poopt_cut_text(PyObject *self, PyObject *args) +{ + /* int length; */ + unsigned char *buffer; + int width; + + if (PyArg_ParseTuple(args, "si", &buffer, &width) == 0) + return NULL; + + int bpos = 0; /* the real position in the char* */ + int spos = 0; /* the position, considering UTF-8 chars */ + int last_space = -1; + int start_pos = 0; + + PyObject* retlist = PyList_New(0); + + while (buffer[bpos]) + { + if (buffer[bpos] == ' ') + last_space = spos; + else if (buffer[bpos] == '\n') + { + if (PyList_Append(retlist, Py_BuildValue("ii", start_pos, spos)) == -1) + return NULL; + start_pos = spos + 1; + last_space = -1; + } + else if ((spos - start_pos) >= width) + { + if (last_space == -1) + { + if (PyList_Append(retlist, Py_BuildValue("ii", start_pos, spos)) == -1) + return NULL; + start_pos = spos; + } + else + { + if (PyList_Append(retlist, Py_BuildValue("ii", start_pos, last_space)) == -1) + return NULL; + start_pos = last_space + 1; + last_space = -1; + } + } + if (buffer[bpos] == 25) /* \x19 */ + { + spos++; + bpos += 2; + } + else + if (buffer[bpos] <= 127) /* ASCII char on one byte */ + bpos += 1; + else if (buffer[bpos] >= 194 && buffer[bpos] <= 223) + bpos += 2; + else if (buffer[bpos] >= 224 && buffer[bpos] <= 239) + bpos += 3; + else if (buffer[bpos] >= 240 && buffer[bpos] <= 244) + bpos += 4; + else + return NULL; + spos++; + } + if (PyList_Append(retlist, Py_BuildValue("(i,i)", start_pos, spos)) == -1) + return NULL; + return retlist; +} + +/*** + Module initialization. Just taken from the xxmodule.c template from the python sources. + ***/ +static PyTypeObject Str_Type = { + PyVarObject_HEAD_INIT(NULL, 0) + "pooptmodule.Str", /*tp_name*/ + 0, /*tp_basicsize*/ + 0, /*tp_itemsize*/ + /* methods */ + 0, /*tp_dealloc*/ + 0, /*tp_print*/ + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_reserved*/ + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash*/ + 0, /*tp_call*/ + 0, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/ + 0, /*tp_doc*/ + 0, /*tp_traverse*/ + 0, /*tp_clear*/ + 0, /*tp_richcompare*/ + 0, /*tp_weaklistoffset*/ + 0, /*tp_iter*/ + 0, /*tp_iternext*/ + 0, /*tp_methods*/ + 0, /*tp_members*/ + 0, /*tp_getset*/ + 0, /* see PyInit_xx */ /*tp_base*/ + 0, /*tp_dict*/ + 0, /*tp_descr_get*/ + 0, /*tp_descr_set*/ + 0, /*tp_dictoffset*/ + 0, /*tp_init*/ + 0, /*tp_alloc*/ + 0, /*tp_new*/ + 0, /*tp_free*/ + 0, /*tp_is_gc*/ +}; + +/* ---------- */ + +static PyObject * +null_richcompare(PyObject *self, PyObject *other, int op) +{ + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; +} + +static PyTypeObject Null_Type = { + PyVarObject_HEAD_INIT(NULL, 0) + "pooptmodule.Null", /*tp_name*/ + 0, /*tp_basicsize*/ + 0, /*tp_itemsize*/ + /* methods */ + 0, /*tp_dealloc*/ + 0, /*tp_print*/ + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_reserved*/ + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash*/ + 0, /*tp_call*/ + 0, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/ + 0, /*tp_doc*/ + 0, /*tp_traverse*/ + 0, /*tp_clear*/ + null_richcompare, /*tp_richcompare*/ + 0, /*tp_weaklistoffset*/ + 0, /*tp_iter*/ + 0, /*tp_iternext*/ + 0, /*tp_methods*/ + 0, /*tp_members*/ + 0, /*tp_getset*/ + 0, /* see PyInit_xx */ /*tp_base*/ + 0, /*tp_dict*/ + 0, /*tp_descr_get*/ + 0, /*tp_descr_set*/ + 0, /*tp_dictoffset*/ + 0, /*tp_init*/ + 0, /*tp_alloc*/ + 0, /* see PyInit_xx */ /*tp_new*/ + 0, /*tp_free*/ + 0, /*tp_is_gc*/ +}; + + +/* List of functions defined in the module */ + +static PyMethodDef poopt_methods[] = { + {"cut_text", poopt_cut_text, METH_VARARGS, + poopt_cut_text_doc}, + {NULL, NULL} /* sentinel */ +}; + +PyDoc_STRVAR(module_doc, + "This is a template module just for instruction. And poopt."); + +/* Initialization function for the module (*must* be called PyInit_xx) */ + +static struct PyModuleDef pooptmodule = { + PyModuleDef_HEAD_INIT, + "poopt", + module_doc, + -1, + poopt_methods, + NULL, + NULL, + NULL, + NULL +}; + +PyMODINIT_FUNC +PyInit_poopt(void) +{ + PyObject *m = NULL; + + /* Due to cross platform compiler issues the slots must be filled + * here. It's required for portability to Windows without requiring + * C++. */ + Null_Type.tp_base = &PyBaseObject_Type; + Null_Type.tp_new = PyType_GenericNew; + Str_Type.tp_base = &PyUnicode_Type; + + /* Finalize the type object including setting type of the new type + * object; doing it here is required for portability, too. */ + /* if (PyType_Ready(&Xxo_Type) < 0) */ + /* goto fail; */ + + /* Create the module and add the functions */ + m = PyModule_Create(&pooptmodule); + if (m == NULL) + goto fail; + + /* Add some symbolic constants to the module */ + if (ErrorObject == NULL) { + ErrorObject = PyErr_NewException("poopt.error", NULL, NULL); + if (ErrorObject == NULL) + goto fail; + } + Py_INCREF(ErrorObject); + PyModule_AddObject(m, "error", ErrorObject); + + /* Add Str */ + if (PyType_Ready(&Str_Type) < 0) + goto fail; + PyModule_AddObject(m, "Str", (PyObject *)&Str_Type); + + /* Add Null */ + if (PyType_Ready(&Null_Type) < 0) + goto fail; + PyModule_AddObject(m, "Null", (PyObject *)&Null_Type); + return m; + fail: + Py_XDECREF(m); + return NULL; +} + +/* /\* test function *\/ */ +/* int main(void) */ +/* { */ +/* char coucou[] = "vive le foutre, le beurre et le caca boudin"; */ + +/* cut_text(coucou, 8); */ +/* } */ |