#include // ptrdiff_t
#include "parts.h"
#include "util.h"
/* Test PyUnicode_New() */
static PyObject *
unicode_new(PyObject *self, PyObject *args)
{
Py_ssize_t size;
unsigned int maxchar;
PyObject *result;
if (!PyArg_ParseTuple(args, "nI", &size, &maxchar)) {
return NULL;
}
result = PyUnicode_New(size, (Py_UCS4)maxchar);
if (!result) {
return NULL;
}
if (size > 0 && maxchar tp_alloc(type, 0);
if (!self) {
return NULL;
}
self->writer = NULL;
return (PyObject*)self;
}
static int
writer_init(PyObject *self_raw, PyObject *args, PyObject *kwargs)
{
WriterObject *self = (WriterObject *)self_raw;
Py_ssize_t size;
if (!PyArg_ParseTuple(args, "n", &size)) {
return -1;
}
if (self->writer) {
PyUnicodeWriter_Discard(self->writer);
}
self->writer = PyUnicodeWriter_Create(size);
if (self->writer == NULL) {
return -1;
}
return 0;
}
static void
writer_dealloc(PyObject *self_raw)
{
WriterObject *self = (WriterObject *)self_raw;
PyTypeObject *tp = Py_TYPE(self);
if (self->writer) {
PyUnicodeWriter_Discard(self->writer);
}
tp->tp_free(self);
Py_DECREF(tp);
}
static inline int
writer_check(WriterObject *self)
{
if (self->writer == NULL) {
PyErr_SetString(PyExc_ValueError, "operation on finished writer");
return -1;
}
return 0;
}
static PyObject*
writer_write_char(PyObject *self_raw, PyObject *args)
{
WriterObject *self = (WriterObject *)self_raw;
if (writer_check(self) < 0) {
return NULL;
}
unsigned int ch;
if (!PyArg_ParseTuple(args, "I", &ch)) {
return NULL;
}
if (PyUnicodeWriter_WriteChar(self->writer, (Py_UCS4)ch) < 0) {
return NULL;
}
Py_RETURN_NONE;
}
static PyObject*
writer_write_utf8(PyObject *self_raw, PyObject *args)
{
WriterObject *self = (WriterObject *)self_raw;
if (writer_check(self) < 0) {
return NULL;
}
const char *str;
Py_ssize_t bsize, size;
if (!PyArg_ParseTuple(args, "z#n", &str, &bsize, &size)) {
return NULL;
}
if (PyUnicodeWriter_WriteUTF8(self->writer, str, size) < 0) {
return NULL;
}
Py_RETURN_NONE;
}
static PyObject*
writer_write_ascii(PyObject *self_raw, PyObject *args)
{
WriterObject *self = (WriterObject *)self_raw;
if (writer_check(self) < 0) {
return NULL;
}
const char *str;
Py_ssize_t bsize, size;
if (!PyArg_ParseTuple(args, "z#n", &str, &bsize, &size)) {
return NULL;
}
if (PyUnicodeWriter_WriteASCII(self->writer, str, size) < 0) {
return NULL;
}
Py_RETURN_NONE;
}
static PyObject*
writer_write_widechar(PyObject *self_raw, PyObject *args)
{
WriterObject *self = (WriterObject *)self_raw;
if (writer_check(self) < 0) {
return NULL;
}
const char *s;
Py_ssize_t bsize;
Py_ssize_t size = -100;
if (!PyArg_ParseTuple(args, "z#|n", &s, &bsize, &size)) {
return NULL;
}
if (size == -100) {
if (bsize % SIZEOF_WCHAR_T) {
PyErr_SetString(PyExc_AssertionError,
"invalid size in writer.write_widechar()");
return NULL;
}
size = bsize / SIZEOF_WCHAR_T;
}
int res = PyUnicodeWriter_WriteWideChar(self->writer, (const wchar_t *)s, size);
if (res < 0) {
return NULL;
}
Py_RETURN_NONE;
}
static PyObject*
writer_write_ucs4(PyObject *self_raw, PyObject *args)
{
WriterObject *self = (WriterObject *)self_raw;
if (writer_check(self) < 0) {
return NULL;
}
const char *s;
Py_ssize_t bsize;
Py_ssize_t size = -100;
if (!PyArg_ParseTuple(args, "z#|n", &s, &bsize, &size)) {
return NULL;
}
if (size == -100) {
if (bsize % sizeof(Py_UCS4)) {
PyErr_SetString(PyExc_AssertionError,
"invalid size in writer.write_ucs4()");
return NULL;
}
size = bsize / sizeof(Py_UCS4);
}
int res = PyUnicodeWriter_WriteUCS4(self->writer, (const Py_UCS4 *)s, size);
if (res < 0) {
return NULL;
}
Py_RETURN_NONE;
}
static PyObject*
writer_write_str(PyObject *self_raw, PyObject *obj)
{
WriterObject *self = (WriterObject *)self_raw;
if (writer_check(self) < 0) {
return NULL;
}
NULLABLE(obj);
if (PyUnicodeWriter_WriteStr(self->writer, obj) < 0) {
return NULL;
}
Py_RETURN_NONE;
}
static PyObject*
writer_write_repr(PyObject *self_raw, PyObject *obj)
{
WriterObject *self = (WriterObject *)self_raw;
if (writer_check(self) < 0) {
return NULL;
}
NULLABLE(obj);
if (PyUnicodeWriter_WriteRepr(self->writer, obj) < 0) {
return NULL;
}
Py_RETURN_NONE;
}
// write_repr(None) calls PyUnicodeWriter_WriteRepr(writer, NULL), so add
// a specialized function calling PyUnicodeWriter_WriteRepr(writer, Py_None).
static PyObject*
writer_write_repr_none(PyObject *self_raw, PyObject *Py_UNUSED(arg))
{
WriterObject *self = (WriterObject *)self_raw;
if (writer_check(self) < 0) {
return NULL;
}
if (PyUnicodeWriter_WriteRepr(self->writer, Py_None) < 0) {
return NULL;
}
Py_RETURN_NONE;
}
static PyObject*
writer_write_substring(PyObject *self_raw, PyObject *args)
{
WriterObject *self = (WriterObject *)self_raw;
if (writer_check(self) < 0) {
return NULL;
}
PyObject *str;
Py_ssize_t start, end;
if (!PyArg_ParseTuple(args, "Onn", &str, &start, &end)) {
return NULL;
}
NULLABLE(str);
if (PyUnicodeWriter_WriteSubstring(self->writer, str, start, end) < 0) {
return NULL;
}
Py_RETURN_NONE;
}
static PyObject*
writer_write_latin1(PyObject *self_raw, PyObject *args)
{
WriterObject *self = (WriterObject *)self_raw;
if (writer_check(self) < 0) {
return NULL;
}
const char *str;
Py_ssize_t bsize, size;
if (!PyArg_ParseTuple(args, "z#n", &str, &bsize, &size)) {
return NULL;
}
_PyUnicodeWriter *writer = (_PyUnicodeWriter*)self->writer;
_Py_COMP_DIAG_PUSH
_Py_COMP_DIAG_IGNORE_DEPR_DECLS
if (_PyUnicodeWriter_WriteLatin1String(writer, str, size) < 0) {
return NULL;
}
_Py_COMP_DIAG_POP
Py_RETURN_NONE;
}
static PyObject*
writer_decodeutf8stateful(PyObject *self_raw, PyObject *args)
{
WriterObject *self = (WriterObject *)self_raw;
if (writer_check(self) < 0) {
return NULL;
}
const char *str;
Py_ssize_t bsize, len;
const char *errors;
int use_consumed = 0;
if (!PyArg_ParseTuple(args, "z#nz#|p", &str, &bsize, &len, &errors, &bsize, &use_consumed)) {
return NULL;
}
Py_ssize_t consumed = 12345;
Py_ssize_t *pconsumed = use_consumed ? &consumed : NULL;
if (PyUnicodeWriter_DecodeUTF8Stateful(self->writer, str, len,
errors, pconsumed) < 0) {
if (use_consumed) {
assert(consumed == 0);
}
return NULL;
}
if (use_consumed) {
return PyLong_FromSsize_t(consumed);
}
Py_RETURN_NONE;
}
static PyObject*
writer_get_pointer(PyObject *self_raw, PyObject *args)
{
WriterObject *self = (WriterObject *)self_raw;
if (writer_check(self) < 0) {
return NULL;
}
return PyLong_FromVoidPtr(self->writer);
}
static PyObject*
writer_get_buffer(PyObject *self_raw, PyObject *args)
{
WriterObject *self = (WriterObject *)self_raw;
if (writer_check(self) < 0) {
return NULL;
}
_PyUnicodeWriter *writer = (_PyUnicodeWriter*)self->writer;
PyObject *allocated;
Py_UCS4 maxchar;
if (writer->buffer) {
allocated = PyLong_FromSsize_t(PyUnicode_GET_LENGTH(writer->buffer));
maxchar = PyUnicode_MAX_CHAR_VALUE(writer->buffer);
}
else {
allocated = Py_None;
maxchar = writer->min_char;
}
return Py_BuildValue("(NkN)",
allocated, (unsigned long)maxchar,
PyBool_FromLong(writer->readonly));
}
static PyObject*
writer_finish(PyObject *self_raw, PyObject *Py_UNUSED(args))
{
WriterObject *self = (WriterObject *)self_raw;
if (writer_check(self) < 0) {
return NULL;
}
PyObject *str = PyUnicodeWriter_Finish(self->writer);
self->writer = NULL;
return str;
}
static PyObject*
writer_finish_with_size(PyObject *self_raw, PyObject *args)
{
PyAPI_FUNC(PyObject*) _PyUnicodeWriter_FinishWithSize(
_PyUnicodeWriter *writer,
Py_ssize_t size);
WriterObject *self = (WriterObject *)self_raw;
if (writer_check(self) < 0) {
return NULL;
}
Py_ssize_t size;
if (!PyArg_ParseTuple(args, "n", &size)) {
return NULL;
}
_PyUnicodeWriter *writer = (_PyUnicodeWriter*)self->writer;
PyObject *str = _PyUnicodeWriter_FinishWithSize(writer, size);
PyUnicodeWriter_Discard(self->writer);
self->writer = NULL;
return str;
}
static PyMethodDef writer_methods[] = {
{"write_char", _PyCFunction_CAST(writer_write_char), METH_VARARGS},
{"write_utf8", _PyCFunction_CAST(writer_write_utf8), METH_VARARGS},
{"write_ascii", _PyCFunction_CAST(writer_write_ascii), METH_VARARGS},
{"write_widechar", _PyCFunction_CAST(writer_write_widechar), METH_VARARGS},
{"write_ucs4", _PyCFunction_CAST(writer_write_ucs4), METH_VARARGS},
{"write_str", _PyCFunction_CAST(writer_write_str), METH_O},
{"write_repr", _PyCFunction_CAST(writer_write_repr), METH_O},
{"write_repr_none", _PyCFunction_CAST(writer_write_repr_none), METH_NOARGS},
{"write_substring", _PyCFunction_CAST(writer_write_substring), METH_VARARGS},
{"write_latin1", _PyCFunction_CAST(writer_write_latin1), METH_VARARGS},
{"decodeutf8stateful", _PyCFunction_CAST(writer_decodeutf8stateful), METH_VARARGS},
{"get_pointer", _PyCFunction_CAST(writer_get_pointer), METH_VARARGS},
{"get_buffer", _PyCFunction_CAST(writer_get_buffer), METH_VARARGS},
{"finish", _PyCFunction_CAST(writer_finish), METH_NOARGS},
{"finish_with_size", _PyCFunction_CAST(writer_finish_with_size), METH_VARARGS},
{NULL, NULL} /* sentinel */
};
static PyType_Slot Writer_Type_slots[] = {
{Py_tp_new, writer_new},
{Py_tp_init, writer_init},
{Py_tp_dealloc, writer_dealloc},
{Py_tp_methods, writer_methods},
{0, 0}, /* sentinel */
};
static PyType_Spec Writer_spec = {
.name = "_testcapi.PyUnicodeWriter",
.basicsize = sizeof(WriterObject),
.flags = Py_TPFLAGS_DEFAULT,
.slots = Writer_Type_slots,
};
static PyMethodDef TestMethods[] = {
{"unicode_new", unicode_new, METH_VARARGS},
{"unicode_fill", _PyCFunction_CAST(unicode_fill), METH_VARARGS | METH_KEYWORDS},
{"unicode_fromkindanddata", unicode_fromkindanddata, METH_VARARGS},
{"unicode_asucs4", unicode_asucs4, METH_VARARGS},
{"unicode_asucs4copy", unicode_asucs4copy, METH_VARARGS},
{"unicode_asutf8", unicode_asutf8, METH_VARARGS},
{"unicode_copycharacters", _PyCFunction_CAST(unicode_copycharacters), METH_VARARGS | METH_KEYWORDS},
{"unicode_GET_CACHED_HASH", unicode_GET_CACHED_HASH, METH_O},
{"test_py_identifier", test_py_identifier, METH_NOARGS},
{"corrupt_unicode", corrupt_unicode, METH_VARARGS},
{"unicode_read_char", unicode_read_char, METH_VARARGS},
{"unicode_read", unicode_read, METH_VARARGS},
{"unicode_write", unicode_write, METH_VARARGS},
{"unicode_kind", unicode_kind, METH_O},
{"unicode_max_char_value", unicode_max_char_value, METH_O},
{"unicode_getlength_macro", unicode_getlength_macro, METH_O},
{"unicode_equal", unicode_equal, METH_VARARGS},
{"unicode_check_interned", unicode_check_interned, METH_O},
{"unicode_is_ascii", unicode_is_ascii, METH_O},
{"unicode_is_compact", unicode_is_compact, METH_O},
{"unicode_is_compact_ascii", unicode_is_compact_ascii, METH_O},
{NULL},
};
int
_PyTestCapi_Init_Unicode(PyObject *m) {
if (PyModule_AddFunctions(m, TestMethods) < 0) {
return -1;
}
PyTypeObject *writer_type = (PyTypeObject *)PyType_FromSpec(&Writer_spec);
if (writer_type == NULL) {
return -1;
}
if (PyModule_AddType(m, writer_type) < 0) {
Py_DECREF(writer_type);
return -1;
}
Py_DECREF(writer_type);
return 0;
}