A C implementation of the htmltext type. (quixote/src/_c_htmltext.c)
Neil Schemenauer <nascheme-fVcApmY9cLvQ3/1i3zOLAti2O/[email protected]> Wed, 08 Jan 2003 14:44:05 -0500
| Newsgroups | gmane.comp.web.quixote.cvs |
|---|---|
| Message-ID | <[email protected]> |
Update of /home/cvs/quixote/src
In directory hewson:/tmp/cvs-serv20117/src
Added Files:
_c_htmltext.c
Log Message:
A C implementation of the htmltext type.
--- NEW FILE: _c_htmltext.c ---
/* htmltext type and the htmlescape function */
#include "Python.h"
#include "structmember.h"
typedef struct {
PyObject_HEAD
PyStringObject *s;
} htmltextObject;
static PyTypeObject htmltext_Type;
#define htmltextObject_Check(v) ((v)->ob_type == &htmltext_Type)
#define htmltext_STR(v) ((PyObject *)(((htmltextObject *)v)->s))
typedef struct {
PyObject_HEAD
PyObject *obj;
} QuoteWrapperObject;
static PyTypeObject QuoteWrapper_Type;
#define QuoteWrapper_Check(v) ((v)->ob_type == &QuoteWrapper_Type)
static PyObject *
type_error(const char *msg)
{
PyErr_SetString(PyExc_TypeError, msg);
return NULL;
}
static PyObject *
escape_string(PyObject *s)
{
PyObject *new_s;
char *ss, *new_ss;
int i, j, extra_space, size, new_size;
if (!PyString_Check(s))
return type_error("str object required");
ss = PyString_AS_STRING(s);
size = PyString_GET_SIZE(s);
extra_space = 0;
for (i=0; i < size; i++) {
switch (ss[i]) {
case '&':
extra_space += 4;
break;
case '<':
case '>':
extra_space += 3;
break;
case '"':
extra_space += 5;
break;
}
}
if (extra_space == 0) {
Py_INCREF(s);
return (PyObject *)s;
}
new_size = size + extra_space;
new_ss = PyMem_MALLOC(new_size);
if (new_ss == NULL)
return NULL;
for (i=0, j=0; i < size; i++) {
switch (ss[i]) {
case '&':
new_ss[j] = '&';
new_ss[j+1] = 'a';
new_ss[j+2] = 'm';
new_ss[j+3] = 'p';
new_ss[j+4] = ';';
j += 5;
break;
case '<':
new_ss[j] = '&';
new_ss[j+1] = 'l';
new_ss[j+2] = 't';
new_ss[j+3] = ';';
j += 4;
break;
case '>':
new_ss[j] = '&';
new_ss[j+1] = 'g';
new_ss[j+2] = 't';
new_ss[j+3] = ';';
j += 4;
break;
case '"':
new_ss[j] = '&';
new_ss[j+1] = 'q';
new_ss[j+2] = 'u';
new_ss[j+3] = 'o';
new_ss[j+4] = 't';
new_ss[j+5] = ';';
j += 6;
break;
default:
new_ss[j] = ss[i];
j += 1;
break;
}
}
assert (j == new_size);
new_s = PyString_FromStringAndSize(new_ss, new_size);
PyMem_FREE(new_ss);
return (PyObject *)new_s;
}
static PyObject *
quote_wrapper_new(PyObject *o)
{
QuoteWrapperObject *self;
self = PyObject_New(QuoteWrapperObject, &QuoteWrapper_Type);
if (self == NULL)
return NULL;
Py_INCREF(o);
self->obj = o;
return (PyObject *)self;
}
static void
quote_wrapper_dealloc(QuoteWrapperObject *self)
{
Py_DECREF(self->obj);
PyObject_Del(self);
}
static PyObject *
quote_wrapper_repr(QuoteWrapperObject *self)
{
PyObject *s = PyObject_Repr(self->obj);
if (htmltextObject_Check(self->obj)) {
return s;
}
else {
PyObject *qs = escape_string(s);
Py_DECREF(s);
return qs;
}
}
static PyObject *
quote_wrapper_str(QuoteWrapperObject *self)
{
PyObject *s = PyObject_Str(self->obj);
if (s == NULL)
return NULL;
if (htmltextObject_Check(self->obj)) {
return s;
}
else {
PyObject *qs = escape_string(s);
Py_DECREF(s);
return qs;
}
}
static PyObject *
quote_wrapper_int(QuoteWrapperObject *self)
{
return PyNumber_Int(self->obj);
}
static PyObject *
quote_wrapper_float(QuoteWrapperObject *self)
{
return PyNumber_Float(self->obj);
}
static PyObject *
htmltext_from_string(PyObject *s)
{
/* note, this takes a reference */
PyObject *self;
if (s == NULL)
return NULL;
assert (PyString_Check(s));
self = PyType_GenericAlloc(&htmltext_Type, 0);
if (self == NULL) {
return NULL;
}
((htmltextObject *)self)->s = (PyStringObject *)s;
return self;
}
static PyObject *
htmltext_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
{
htmltextObject *self;
PyObject *s;
static char *kwlist[] = {"s", 0};
if (!PyArg_ParseTupleAndKeywords(args, kwds, "O:htmltext", kwlist,
&s))
return NULL;
s = PyObject_Str(s);
if (s == NULL)
return NULL;
self = (htmltextObject *)type->tp_alloc(type, 0);
if (self == NULL) {
Py_DECREF(s);
return NULL;
}
self->s = (PyStringObject *)s;
return (PyObject *)self;
}
/* htmltext methods */
static void
htmltext_dealloc(htmltextObject *self)
{
Py_DECREF(self->s);
self->ob_type->tp_free((PyObject *)self);
}
static long
htmltext_hash(PyObject *self)
{
return PyObject_Hash(htmltext_STR(self));
}
static PyObject *
htmltext_str(htmltextObject *self)
{
Py_INCREF(self->s);
return (PyObject *)self->s;
}
static PyObject *
htmltext_repr(htmltextObject *self)
{
PyObject *sr, *rv;
sr = PyObject_Repr((PyObject *)self->s);
if (sr == NULL)
return NULL;
rv = PyString_FromFormat("<htmltext %s>", PyString_AsString(sr));
Py_DECREF(sr);
return rv;
}
static PyObject *
htmltext_richcompare(PyObject *a, PyObject *b, int op)
{
PyObject *sa, *sb;
if (PyString_Check(a)) {
sa = a;
} else if (htmltextObject_Check(a)) {
sa = htmltext_STR(a);
} else {
goto out;
}
if (PyString_Check(b)) {
sb = b;
} else if (htmltextObject_Check(b)) {
sb = htmltext_STR(b);
} else {
goto out;
}
return sa->ob_type->tp_richcompare(sa, sb, op);
out:
Py_INCREF(Py_NotImplemented);
return Py_NotImplemented;
}
static long
htmltext_length(htmltextObject *self)
{
return ((PyStringObject *)self->s)->ob_size;
}
static PyObject *
wrap_arg(PyObject *arg)
{
PyObject *warg;
if (htmltextObject_Check(arg)) {
/* don't bother with wrapper object */
warg = arg;
Py_INCREF(arg);
} else {
warg = quote_wrapper_new(arg);
}
return warg;
}
static PyObject *
htmltext_format(htmltextObject *self, PyObject *args)
{
/* wrap the format arguments with QuoteWrapperObject */
int do_dict = 0;
PyObject *rv, *wargs;
if (args->ob_type->tp_as_mapping && !PyTuple_Check(args) &&
!PyString_Check(args)) {
char *fmt = PyString_AS_STRING(htmltext_STR(self));
int i, n = PyString_GET_SIZE(htmltext_STR(self));
char last = 0;
/* second check necessary since '%s' % {} => '{}' */
for (i=0; i < n; i++) {
if (last == '%' && fmt[i] == '(') {
do_dict = 1;
break;
}
last = fmt[i];
}
}
if (do_dict) {
int pos = 0;
PyObject *key, *value;
wargs = PyDict_New();
while (PyDict_Next(args, &pos, &key, &value)) {
PyObject *wvalue = wrap_arg(value);
if (wvalue == NULL) {
Py_DECREF(wargs);
return NULL;
}
if (PyDict_SetItem(wargs, key, wvalue) < 0) {
Py_DECREF(wargs);
return NULL;
}
Py_DECREF(wvalue);
}
}
else if (PyTuple_Check(args)) {
int i, n = PyTuple_GET_SIZE(args);
wargs = PyTuple_New(n);
for (i=0; i < n; i++) {
PyObject *wvalue = wrap_arg(PyTuple_GET_ITEM(args, i));
if (wvalue == NULL) {
Py_DECREF(wargs);
return NULL;
}
PyTuple_SetItem(wargs, i, wvalue);
}
}
else {
wargs = wrap_arg(args);
if (wargs == NULL) {
return NULL;
}
}
rv = PyString_Format((PyObject *)self->s, wargs);
Py_DECREF(wargs);
return htmltext_from_string(rv);
}
static PyObject *
htmltext_add(PyObject *v, PyObject *w)
{
PyObject *qv, *qw;
if (htmltextObject_Check(v) && htmltextObject_Check(w)) {
qv = htmltext_STR(v);
qw = htmltext_STR(w);
Py_INCREF(qv);
Py_INCREF(qw);
}
else if (PyString_Check(w)) {
assert (htmltextObject_Check(v));
qv = htmltext_STR(v);
qw = escape_string(w);
if (qw == NULL)
return NULL;
Py_INCREF(qv);
}
else if (PyString_Check(v)) {
assert (htmltextObject_Check(w));
qv = escape_string(v);
if (qv == NULL)
return NULL;
qw = htmltext_STR(w);
Py_INCREF(qw);
}
else {
Py_INCREF(Py_NotImplemented);
return Py_NotImplemented;
}
PyString_ConcatAndDel(&qv, qw);
return htmltext_from_string(qv);
}
static PyObject *
htmltext_repeat(htmltextObject *self, int n)
{
PyObject *s = PySequence_Repeat(htmltext_STR(self), n);
if (s == NULL)
return NULL;
return htmltext_from_string(s);
}
static PyObject *
htmltext_join(PyObject *self, PyObject *args)
{
int i;
PyObject *qargs, *rv;
if (!PySequence_Check(args)) {
return type_error("argument must be a sequence");
}
qargs = PyList_New(PySequence_Size(args));
if (qargs == NULL)
return NULL;
for (i=0; i < PySequence_Size(args); i++) {
PyObject *value, *qvalue;
value = PySequence_GetItem(args, i);
if (value == NULL) {
goto error;
}
if (htmltextObject_Check(value)) {
qvalue = htmltext_STR(value);
Py_INCREF(qvalue);
Py_DECREF(value);
}
else if (PyString_Check(value)) {
qvalue = escape_string(value);
Py_DECREF(value);
}
else {
Py_DECREF(value);
type_error("join requires a list of strings");
goto error;
}
if (PyList_SetItem(qargs, i, qvalue) < 0) {
goto error;
}
}
rv = _PyString_Join(htmltext_STR(self), qargs);
Py_DECREF(qargs);
return htmltext_from_string(rv);
error:
Py_DECREF(qargs);
return NULL;
}
static PyObject *
quote_arg(PyObject *s)
{
PyObject *ss;
if (PyString_Check(s)) {
ss = escape_string(s);
if (ss == NULL)
return NULL;
}
else if (htmltextObject_Check(s)) {
ss = htmltext_STR(s);
Py_INCREF(ss);
}
else {
return type_error("string object required");
}
return ss;
}
static PyObject *
htmltext_call_method1(PyObject *self, PyObject *s, char *method)
{
PyObject *ss, *rv;
ss = quote_arg(s);
if (ss == NULL)
return NULL;
rv = PyObject_CallMethod(htmltext_STR(self), method, "O", ss);
Py_DECREF(ss);
return rv;
}
static PyObject *
htmltext_startswith(PyObject *self, PyObject *s)
{
return htmltext_call_method1(self, s, "startswith");
}
static PyObject *
htmltext_endswith(PyObject *self, PyObject *s)
{
return htmltext_call_method1(self, s, "endswith");
}
static PyObject *
htmltext_replace(PyObject *self, PyObject *args)
{
PyObject *old, *new, *q_old, *q_new, *rv;
int maxsplit = -1;
if (!PyArg_ParseTuple(args,"OO|i:replace", &old, &new, &maxsplit))
return NULL;
q_old = quote_arg(old);
if (q_old == NULL)
return NULL;
q_new = quote_arg(new);
if (q_new == NULL) {
Py_DECREF(q_old);
return NULL;
}
rv = PyObject_CallMethod(htmltext_STR(self), "replace", "OOi",
q_old, q_new, maxsplit);
Py_DECREF(q_old);
Py_DECREF(q_new);
return htmltext_from_string(rv);
}
static PyObject *
htmltext_lower(PyObject *self)
{
return htmltext_from_string(PyObject_CallMethod(htmltext_STR(self),
"lower", ""));
}
static PyObject *
htmltext_upper(PyObject *self)
{
return htmltext_from_string(PyObject_CallMethod(htmltext_STR(self),
"upper", ""));
}
static PyObject *
htmltext_capitalize(PyObject *self)
{
return htmltext_from_string(PyObject_CallMethod(htmltext_STR(self),
"capitalize", ""));
}
static PyMethodDef htmltext_methods[] = {
{"join", (PyCFunction)htmltext_join, METH_O, ""},
{"startswith", (PyCFunction)htmltext_startswith, METH_O, ""},
{"endswith", (PyCFunction)htmltext_endswith, METH_O, ""},
{"replace", (PyCFunction)htmltext_replace, METH_VARARGS, ""},
{"lower", (PyCFunction)htmltext_lower, METH_NOARGS, ""},
{"upper", (PyCFunction)htmltext_upper, METH_NOARGS, ""},
{"capitalize", (PyCFunction)htmltext_capitalize, METH_NOARGS, ""},
{NULL, NULL}
};
static PyMemberDef htmltext_members[] = {
{"s", T_OBJECT, offsetof(htmltextObject, s), READONLY, "the string"},
{NULL},
};
static PySequenceMethods htmltext_as_sequence = {
(inquiry)htmltext_length, /*sq_length*/
0, /*sq_concat*/
(intargfunc)htmltext_repeat, /*sq_repeat*/
0, /*sq_item*/
0, /*sq_slice*/
0, /*sq_ass_item*/
0, /*sq_ass_slice*/
0, /*sq_contains*/
};
static PyNumberMethods htmltext_as_number = {
(binaryfunc)htmltext_add, /*nb_add*/
0, /*nb_subtract*/
0, /*nb_multiply*/
0, /*nb_divide*/
(binaryfunc)htmltext_format, /*nb_remainder*/
0, /*nb_divmod*/
0, /*nb_power*/
0, /*nb_negative*/
0, /*nb_positive*/
0, /*nb_absolute*/
0, /*nb_nonzero*/
0, /*nb_invert*/
0, /*nb_lshift*/
0, /*nb_rshift*/
0, /*nb_and*/
0, /*nb_xor*/
0, /*nb_or*/
0, /*nb_coerce*/
0, /*nb_int*/
0, /*nb_long*/
0, /*nb_float*/
};
static PyTypeObject htmltext_Type = {
PyObject_HEAD_INIT(&PyType_Type)
0, /*ob_size*/
"htmltext", /*tp_name*/
sizeof(htmltextObject), /*tp_basicsize*/
0, /*tp_itemsize*/
/* methods */
(destructor)htmltext_dealloc, /*tp_dealloc*/
0, /*tp_print*/
0, /*tp_getattr*/
0, /*tp_setattr*/
0, /*tp_compare*/
(unaryfunc)htmltext_repr,/*tp_repr*/
&htmltext_as_number, /*tp_as_number*/
&htmltext_as_sequence, /*tp_as_sequence*/
0, /*tp_as_mapping*/
htmltext_hash, /*tp_hash*/
0, /*tp_call*/
(unaryfunc)htmltext_str,/*tp_str*/
PyObject_GenericGetAttr,/*tp_getattro*/
0, /*tp_setattro*/
0, /*tp_as_buffer*/
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE \
| Py_TPFLAGS_CHECKTYPES, /*tp_flags*/
0, /*tp_doc*/
0, /*tp_traverse*/
0, /*tp_clear*/
htmltext_richcompare, /*tp_richcompare*/
0, /*tp_weaklistoffset*/
0, /*tp_iter*/
0, /*tp_iternext*/
htmltext_methods, /*tp_methods*/
htmltext_members, /*tp_members*/
0, /*tp_getset*/
0, /*tp_base*/
0, /*tp_dict*/
0, /*tp_descr_get*/
0, /*tp_descr_set*/
0, /*tp_dictoffset*/
0, /*tp_init*/
PyType_GenericAlloc, /*tp_alloc*/
htmltext_new, /*tp_new*/
_PyObject_Del, /*tp_free*/
0, /*tp_is_gc*/
};
static PyNumberMethods quote_wrapper_as_number = {
0, /*nb_add*/
0, /*nb_subtract*/
0, /*nb_multiply*/
0, /*nb_divide*/
0, /*nb_remainder*/
0, /*nb_divmod*/
0, /*nb_power*/
0, /*nb_negative*/
0, /*nb_positive*/
0, /*nb_absolute*/
0, /*nb_nonzero*/
0, /*nb_invert*/
0, /*nb_lshift*/
0, /*nb_rshift*/
0, /*nb_and*/
0, /*nb_xor*/
0, /*nb_or*/
0, /*nb_coerce*/
(unaryfunc)quote_wrapper_int, /*nb_int*/
0, /*nb_long*/
(unaryfunc)quote_wrapper_float, /*nb_float*/
};
static PyTypeObject QuoteWrapper_Type = {
PyObject_HEAD_INIT(&PyType_Type)
0, /*ob_size*/
"QuoteWrapper", /*tp_name*/
sizeof(QuoteWrapperObject), /*tp_basicsize*/
0, /*tp_itemsize*/
/* methods */
(destructor)quote_wrapper_dealloc, /*tp_dealloc*/
0, /*tp_print*/
0, /*tp_getattr*/
0, /*tp_setattr*/
0, /*tp_compare*/
(unaryfunc)quote_wrapper_repr,/*tp_repr*/
"e_wrapper_as_number,/*tp_as_number*/
0, /*tp_as_sequence*/
0, /*tp_as_mapping*/
0, /*tp_hash*/
0, /*tp_call*/
(unaryfunc)quote_wrapper_str, /*tp_str*/
};
/* --------------------------------------------------------------------- */
static PyObject *
html_escape(PyObject *self, PyObject *o)
{
if (htmltextObject_Check(o)) {
Py_INCREF(o);
return o;
}
else {
PyObject *rv;
PyObject *s = PyObject_Str(o);
if (s == NULL)
return NULL;
rv = escape_string(s);
Py_DECREF(s);
return htmltext_from_string(rv);
}
}
static PyObject *
py_escape_string(PyObject *self, PyObject *o)
{
PyObject *rv;
if (!PyString_Check(o))
return type_error("string required");
rv = escape_string(o);
return rv;
}
/* List of functions defined in the module */
static PyMethodDef htmltext_module_methods[] = {
{"htmlescape", (PyCFunction)html_escape, METH_O},
{"_escape_string", (PyCFunction)py_escape_string, METH_O},
{NULL, NULL}
};
static char module_doc[] = "htmltext string type";
void
init_c_htmltext(void)
{
PyObject *m;
/* Initialize the type of the new type object here; doing it here
* is required for portability to Windows without requiring C++. */
htmltext_Type.ob_type = &PyType_Type;
/* Create the module and add the functions */
m = Py_InitModule4("_c_htmltext", htmltext_module_methods, module_doc,
NULL, PYTHON_API_VERSION);
Py_INCREF((PyObject *)&htmltext_Type);
Py_INCREF((PyObject *)&QuoteWrapper_Type);
PyModule_AddObject(m, "htmltext", (PyObject *)&htmltext_Type);
}