280 lines
8.7 KiB
C
280 lines
8.7 KiB
C
/* 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 zlib 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. */
|
|
|
|
#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(text, width)\n\n\nReturn a list of two-tuple, the first int is the starting position of the line and the second is its end.");
|
|
|
|
static PyObject *poopt_cut_text(PyObject *self, PyObject *args)
|
|
{
|
|
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;
|
|
|
|
int w = width; /* this is a width that increases to make the length of char
|
|
of colors attribute be ignored */
|
|
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) >= w)
|
|
{
|
|
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;
|
|
}
|
|
w = width;
|
|
}
|
|
if (buffer[bpos] == 25) /* \x19 */
|
|
{
|
|
while (buffer[bpos] &&
|
|
buffer[bpos] != 'u' &&
|
|
buffer[bpos] != 'b' &&
|
|
buffer[bpos] != 'o' &&
|
|
buffer[bpos] != '}')
|
|
{
|
|
bpos++;
|
|
spos++;
|
|
w++;
|
|
}
|
|
bpos++;
|
|
w++;
|
|
}
|
|
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;
|
|
}
|