[pypy-svn] r73301 - in pypy/branch/cpython-extension/pypy/module/cpyext: . include test
fijal at codespeak.net
fijal at codespeak.net
Fri Apr 2 17:42:55 CEST 2010
Author: fijal
Date: Fri Apr 2 17:42:53 2010
New Revision: 73301
Added:
pypy/branch/cpython-extension/pypy/module/cpyext/include/stringobject.c
Modified:
pypy/branch/cpython-extension/pypy/module/cpyext/api.py
pypy/branch/cpython-extension/pypy/module/cpyext/include/Python.h
pypy/branch/cpython-extension/pypy/module/cpyext/include/modsupport.c
pypy/branch/cpython-extension/pypy/module/cpyext/include/pyerrors.c
pypy/branch/cpython-extension/pypy/module/cpyext/include/pyerrors.h
pypy/branch/cpython-extension/pypy/module/cpyext/include/stringobject.h
pypy/branch/cpython-extension/pypy/module/cpyext/modsupport.py
pypy/branch/cpython-extension/pypy/module/cpyext/stringobject.py
pypy/branch/cpython-extension/pypy/module/cpyext/stubgen.py
pypy/branch/cpython-extension/pypy/module/cpyext/stubs.py
pypy/branch/cpython-extension/pypy/module/cpyext/test/test_stringobject.py
Log:
Expose a bit more of API from .c files. Requires a bit of tests here
and there, will fix this (and implement missing functionality).
Modified: pypy/branch/cpython-extension/pypy/module/cpyext/api.py
==============================================================================
--- pypy/branch/cpython-extension/pypy/module/cpyext/api.py (original)
+++ pypy/branch/cpython-extension/pypy/module/cpyext/api.py Fri Apr 2 17:42:53 2010
@@ -230,7 +230,7 @@
}
for exc_name in ['TypeError', 'ValueError', 'KeyError', 'Exception',
- 'BaseException']:
+ 'BaseException', 'SystemError']:
GLOBALS['PyExc_' + exc_name] = ('PyObject*', 'space.w_' + exc_name)
for cpyname, pypyexpr in {"Type": "space.w_type",
@@ -254,6 +254,9 @@
PyVarObjectFields = PyObjectFields + (("ob_size", Py_ssize_t), )
cpython_struct('struct _object', PyObjectFields, PyObjectStruct)
+# a pointer to PyObject
+PyObjectP = rffi.CArrayPtr(PyObject)
+
PyStringObjectStruct = lltype.ForwardReference()
PyStringObject = lltype.Ptr(PyStringObjectStruct)
PyStringObjectFields = PyObjectFields + \
@@ -540,7 +543,8 @@
separate_module_files=[include_dir / "varargwrapper.c",
include_dir / "pyerrors.c",
include_dir / "modsupport.c",
- include_dir / "getargs.c"],
+ include_dir / "getargs.c",
+ include_dir / "stringobject.c"],
separate_module_sources = [code],
export_symbols=export_symbols_eci,
**kwds
Modified: pypy/branch/cpython-extension/pypy/module/cpyext/include/Python.h
==============================================================================
--- pypy/branch/cpython-extension/pypy/module/cpyext/include/Python.h (original)
+++ pypy/branch/cpython-extension/pypy/module/cpyext/include/Python.h Fri Apr 2 17:42:53 2010
@@ -1,6 +1,15 @@
#ifndef Py_PYTHON_H
#define Py_PYTHON_H
+// XXX this should be in pyconfig.h
+
+#define HAVE_LONG_LONG 1
+#define HAVE_STDARG_PROTOTYPES 1
+#define PY_FORMAT_LONG_LONG "ll"
+#define PY_LONG_LONG long long
+#define SIZEOF_LONG_LONG sizeof(PY_LONG_LONG)
+#define PY_FORMAT_SIZE_T "z"
+
/* Compat stuff */
#ifndef _WIN32
# include <inttypes.h>
@@ -18,6 +27,16 @@
#endif
#define Py_ssize_t long
+/* Convert a possibly signed character to a nonnegative int */
+/* XXX This assumes characters are 8 bits wide */
+#ifdef __CHAR_UNSIGNED__
+#define Py_CHARMASK(c) (c)
+#else
+#define Py_CHARMASK(c) ((unsigned char)((c) & 0xff))
+#endif
+
+#define Py_MEMCPY memcpy
+
#include <pypy_macros.h>
#include "patchlevel.h"
@@ -28,6 +47,8 @@
#include <stdio.h>
#include <string.h>
#include <assert.h>
+#include <locale.h>
+#include <ctype.h>
#include "boolobject.h"
#include "floatobject.h"
Modified: pypy/branch/cpython-extension/pypy/module/cpyext/include/modsupport.c
==============================================================================
--- pypy/branch/cpython-extension/pypy/module/cpyext/include/modsupport.c (original)
+++ pypy/branch/cpython-extension/pypy/module/cpyext/include/modsupport.c Fri Apr 2 17:42:53 2010
@@ -1,6 +1,5 @@
#include <Python.h>
-#if 0
-unsupported functions in it
+
int
PyModule_AddObject(PyObject *m, const char *name, PyObject *o)
{
@@ -29,4 +28,4 @@
Py_DECREF(o);
return 0;
}
-#endif
+
Modified: pypy/branch/cpython-extension/pypy/module/cpyext/include/pyerrors.c
==============================================================================
--- pypy/branch/cpython-extension/pypy/module/cpyext/include/pyerrors.c (original)
+++ pypy/branch/cpython-extension/pypy/module/cpyext/include/pyerrors.c Fri Apr 2 17:42:53 2010
@@ -1,5 +1,25 @@
#include <Python.h>
#include <string.h>
+
+PyObject *
+PyErr_Format(PyObject *exception, const char *format, ...)
+{
+ va_list vargs;
+ PyObject* string;
+
+#ifdef HAVE_STDARG_PROTOTYPES
+ va_start(vargs, format);
+#else
+ va_start(vargs);
+#endif
+
+ string = PyString_FromFormatV(format, vargs);
+ PyErr_SetObject(exception, string);
+ Py_XDECREF(string);
+ va_end(vargs);
+ return NULL;
+}
+
#if 0
depends on unavailable functions
@@ -52,4 +72,6 @@
Py_XDECREF(modulename);
return result;
}
+
+
#endif
Modified: pypy/branch/cpython-extension/pypy/module/cpyext/include/pyerrors.h
==============================================================================
--- pypy/branch/cpython-extension/pypy/module/cpyext/include/pyerrors.h (original)
+++ pypy/branch/cpython-extension/pypy/module/cpyext/include/pyerrors.h Fri Apr 2 17:42:53 2010
@@ -8,6 +8,7 @@
#endif
PyObject *PyErr_NewException(char *name, PyObject *base, PyObject *dict);
+PyObject *PyErr_Format(PyObject *exception, const char *format, ...);
#ifdef __cplusplus
}
Added: pypy/branch/cpython-extension/pypy/module/cpyext/include/stringobject.c
==============================================================================
--- (empty file)
+++ pypy/branch/cpython-extension/pypy/module/cpyext/include/stringobject.c Fri Apr 2 17:42:53 2010
@@ -0,0 +1,233 @@
+
+#include "Python.h"
+
+PyObject *
+PyString_FromFormatV(const char *format, va_list vargs)
+{
+ va_list count;
+ Py_ssize_t n = 0;
+ const char* f;
+ char *s;
+ PyObject* string;
+
+#ifdef VA_LIST_IS_ARRAY
+ Py_MEMCPY(count, vargs, sizeof(va_list));
+#else
+#ifdef __va_copy
+ __va_copy(count, vargs);
+#else
+ count = vargs;
+#endif
+#endif
+ /* step 1: figure out how large a buffer we need */
+ for (f = format; *f; f++) {
+ if (*f == '%') {
+#ifdef HAVE_LONG_LONG
+ int longlongflag = 0;
+#endif
+ const char* p = f;
+ while (*++f && *f != '%' && !isalpha(Py_CHARMASK(*f)))
+ ;
+
+ /* skip the 'l' or 'z' in {%ld, %zd, %lu, %zu} since
+ * they don't affect the amount of space we reserve.
+ */
+ if (*f == 'l') {
+ if (f[1] == 'd' || f[1] == 'u') {
+ ++f;
+ }
+#ifdef HAVE_LONG_LONG
+ else if (f[1] == 'l' &&
+ (f[2] == 'd' || f[2] == 'u')) {
+ longlongflag = 1;
+ f += 2;
+ }
+#endif
+ }
+ else if (*f == 'z' && (f[1] == 'd' || f[1] == 'u')) {
+ ++f;
+ }
+
+ switch (*f) {
+ case 'c':
+ (void)va_arg(count, int);
+ /* fall through... */
+ case '%':
+ n++;
+ break;
+ case 'd': case 'u': case 'i': case 'x':
+ (void) va_arg(count, int);
+#ifdef HAVE_LONG_LONG
+ /* Need at most
+ ceil(log10(256)*SIZEOF_LONG_LONG) digits,
+ plus 1 for the sign. 53/22 is an upper
+ bound for log10(256). */
+ if (longlongflag)
+ n += 2 + (SIZEOF_LONG_LONG*53-1) / 22;
+ else
+#endif
+ /* 20 bytes is enough to hold a 64-bit
+ integer. Decimal takes the most
+ space. This isn't enough for
+ octal. */
+ n += 20;
+
+ break;
+ case 's':
+ s = va_arg(count, char*);
+ n += strlen(s);
+ break;
+ case 'p':
+ (void) va_arg(count, int);
+ /* maximum 64-bit pointer representation:
+ * 0xffffffffffffffff
+ * so 19 characters is enough.
+ * XXX I count 18 -- what's the extra for?
+ */
+ n += 19;
+ break;
+ default:
+ /* if we stumble upon an unknown
+ formatting code, copy the rest of
+ the format string to the output
+ string. (we cannot just skip the
+ code, since there's no way to know
+ what's in the argument list) */
+ n += strlen(p);
+ goto expand;
+ }
+ } else
+ n++;
+ }
+ expand:
+ /* step 2: fill the buffer */
+ /* Since we've analyzed how much space we need for the worst case,
+ use sprintf directly instead of the slower PyOS_snprintf. */
+ string = PyString_FromStringAndSize(NULL, n);
+ if (!string)
+ return NULL;
+
+ s = PyString_AsString(string);
+
+ for (f = format; *f; f++) {
+ if (*f == '%') {
+ const char* p = f++;
+ Py_ssize_t i;
+ int longflag = 0;
+#ifdef HAVE_LONG_LONG
+ int longlongflag = 0;
+#endif
+ int size_tflag = 0;
+ /* parse the width.precision part (we're only
+ interested in the precision value, if any) */
+ n = 0;
+ while (isdigit(Py_CHARMASK(*f)))
+ n = (n*10) + *f++ - '0';
+ if (*f == '.') {
+ f++;
+ n = 0;
+ while (isdigit(Py_CHARMASK(*f)))
+ n = (n*10) + *f++ - '0';
+ }
+ while (*f && *f != '%' && !isalpha(Py_CHARMASK(*f)))
+ f++;
+ /* Handle %ld, %lu, %lld and %llu. */
+ if (*f == 'l') {
+ if (f[1] == 'd' || f[1] == 'u') {
+ longflag = 1;
+ ++f;
+ }
+#ifdef HAVE_LONG_LONG
+ else if (f[1] == 'l' &&
+ (f[2] == 'd' || f[2] == 'u')) {
+ longlongflag = 1;
+ f += 2;
+ }
+#endif
+ }
+ /* handle the size_t flag. */
+ else if (*f == 'z' && (f[1] == 'd' || f[1] == 'u')) {
+ size_tflag = 1;
+ ++f;
+ }
+
+ switch (*f) {
+ case 'c':
+ *s++ = va_arg(vargs, int);
+ break;
+ case 'd':
+ if (longflag)
+ sprintf(s, "%ld", va_arg(vargs, long));
+#ifdef HAVE_LONG_LONG
+ else if (longlongflag)
+ sprintf(s, "%" PY_FORMAT_LONG_LONG "d",
+ va_arg(vargs, PY_LONG_LONG));
+#endif
+ else if (size_tflag)
+ sprintf(s, "%" PY_FORMAT_SIZE_T "d",
+ va_arg(vargs, Py_ssize_t));
+ else
+ sprintf(s, "%d", va_arg(vargs, int));
+ s += strlen(s);
+ break;
+ case 'u':
+ if (longflag)
+ sprintf(s, "%lu",
+ va_arg(vargs, unsigned long));
+#ifdef HAVE_LONG_LONG
+ else if (longlongflag)
+ sprintf(s, "%" PY_FORMAT_LONG_LONG "u",
+ va_arg(vargs, PY_LONG_LONG));
+#endif
+ else if (size_tflag)
+ sprintf(s, "%" PY_FORMAT_SIZE_T "u",
+ va_arg(vargs, size_t));
+ else
+ sprintf(s, "%u",
+ va_arg(vargs, unsigned int));
+ s += strlen(s);
+ break;
+ case 'i':
+ sprintf(s, "%i", va_arg(vargs, int));
+ s += strlen(s);
+ break;
+ case 'x':
+ sprintf(s, "%x", va_arg(vargs, int));
+ s += strlen(s);
+ break;
+ case 's':
+ p = va_arg(vargs, char*);
+ i = strlen(p);
+ if (n > 0 && i > n)
+ i = n;
+ Py_MEMCPY(s, p, i);
+ s += i;
+ break;
+ case 'p':
+ sprintf(s, "%p", va_arg(vargs, void*));
+ /* %p is ill-defined: ensure leading 0x. */
+ if (s[1] == 'X')
+ s[1] = 'x';
+ else if (s[1] != 'x') {
+ memmove(s+2, s, strlen(s)+1);
+ s[0] = '0';
+ s[1] = 'x';
+ }
+ s += strlen(s);
+ break;
+ case '%':
+ *s++ = '%';
+ break;
+ default:
+ strcpy(s, p);
+ s += strlen(s);
+ goto end;
+ }
+ } else
+ *s++ = *f;
+ }
+
+ end:
+ _PyString_Resize(&string, s - PyString_AS_STRING(string));
+ return string;
+}
Modified: pypy/branch/cpython-extension/pypy/module/cpyext/include/stringobject.h
==============================================================================
--- pypy/branch/cpython-extension/pypy/module/cpyext/include/stringobject.h (original)
+++ pypy/branch/cpython-extension/pypy/module/cpyext/include/stringobject.h Fri Apr 2 17:42:53 2010
@@ -7,12 +7,17 @@
extern "C" {
#endif
+#define PyString_AS_STRING(op) PyString_AsString(op)
+
typedef struct {
PyObject_HEAD
char* buffer;
Py_ssize_t size;
} PyStringObject;
+PyObject *
+PyString_FromFormatV(const char *format, va_list vargs);
+
#ifdef __cplusplus
}
#endif
Modified: pypy/branch/cpython-extension/pypy/module/cpyext/modsupport.py
==============================================================================
--- pypy/branch/cpython-extension/pypy/module/cpyext/modsupport.py (original)
+++ pypy/branch/cpython-extension/pypy/module/cpyext/modsupport.py Fri Apr 2 17:42:53 2010
@@ -91,3 +91,13 @@
else:
PyErr_BadInternalCall(space)
+ at cpython_api([PyObject], rffi.CCHARP, error=0)
+def PyModule_GetName(space, module):
+ """
+
+
+
+ Return module's __name__ value. If the module does not provide one,
+ or if it is not a string, SystemError is raised and NULL is returned."""
+ raise NotImplementedError
+
Modified: pypy/branch/cpython-extension/pypy/module/cpyext/stringobject.py
==============================================================================
--- pypy/branch/cpython-extension/pypy/module/cpyext/stringobject.py (original)
+++ pypy/branch/cpython-extension/pypy/module/cpyext/stringobject.py Fri Apr 2 17:42:53 2010
@@ -1,7 +1,8 @@
from pypy.rpython.lltypesystem import rffi, lltype
from pypy.module.cpyext.api import (cpython_api, PyVarObjectFields,
PyStringObject, Py_ssize_t, cpython_struct,
- CANNOT_FAIL, build_type_checkers)
+ CANNOT_FAIL, build_type_checkers,
+ PyObjectP)
from pypy.module.cpyext.pyobject import PyObject, make_ref, from_ref
@@ -48,3 +49,19 @@
else:
w_obj = from_ref(space, ref)
return space.int_w(space.len(w_obj))
+
+ at cpython_api([PyObjectP, Py_ssize_t], rffi.INT_real, error=-1)
+def _PyString_Resize(space, string, newsize):
+ """A way to resize a string object even though it is "immutable". Only use this to
+ build up a brand new string object; don't use this if the string may already be
+ known in other parts of the code. It is an error to call this function if the
+ refcount on the input string object is not one. Pass the address of an existing
+ string object as an lvalue (it may be written into), and the new size desired.
+ On success, *string holds the resized string object and 0 is returned;
+ the address in *string may differ from its input value. If the reallocation
+ fails, the original string object at *string is deallocated, *string is
+ set to NULL, a memory exception is set, and -1 is returned.
+
+ This function used an int type for newsize. This might
+ require changes in your code for properly supporting 64-bit systems."""
+ raise NotImplementedError
Modified: pypy/branch/cpython-extension/pypy/module/cpyext/stubgen.py
==============================================================================
--- pypy/branch/cpython-extension/pypy/module/cpyext/stubgen.py (original)
+++ pypy/branch/cpython-extension/pypy/module/cpyext/stubgen.py Fri Apr 2 17:42:53 2010
@@ -19,6 +19,7 @@
"PyVarObject*": "PyObject",
"const char*": "rffi.CCHARP",
"PyObject*": "PyObject",
+ "PyObject**": "PyObjectP",
"char*": "rffi.CCHARP",
"PyMethodDef*": "PyMethodDef",
"Py_ssize_t": "Py_ssize_t",
Modified: pypy/branch/cpython-extension/pypy/module/cpyext/stubs.py
==============================================================================
--- pypy/branch/cpython-extension/pypy/module/cpyext/stubs.py (original)
+++ pypy/branch/cpython-extension/pypy/module/cpyext/stubs.py Fri Apr 2 17:42:53 2010
@@ -4033,16 +4033,6 @@
raise NotImplementedError
@cpython_api([PyObject], rffi.CCHARP)
-def PyModule_GetName(space, module):
- """
-
-
-
- Return module's __name__ value. If the module does not provide one,
- or if it is not a string, SystemError is raised and NULL is returned."""
- raise NotImplementedError
-
- at cpython_api([PyObject], rffi.CCHARP)
def PyModule_GetFilename(space, module):
"""
Modified: pypy/branch/cpython-extension/pypy/module/cpyext/test/test_stringobject.py
==============================================================================
--- pypy/branch/cpython-extension/pypy/module/cpyext/test/test_stringobject.py (original)
+++ pypy/branch/cpython-extension/pypy/module/cpyext/test/test_stringobject.py Fri Apr 2 17:42:53 2010
@@ -44,8 +44,7 @@
("test_is_string", "METH_VARARGS",
"""
return PyBool_FromLong(PyString_Check(PyTuple_GetItem(args, 0)));
- """),
- ])
+ """)])
assert module.get_hello1() == 'Hello world'
assert module.get_hello2() == 'Hello world'
assert module.test_Size()
@@ -96,3 +95,16 @@
])
s = module.getstring()
assert s == 'test'
+
+ def test_format_v(self):
+ skip("unsupported yet, think how to fak va_list")
+ module = self.import_extension('foo', [
+ ("test_string_format_v", "METH_VARARGS",
+ '''
+ return PyString_FromFormatV("bla %d ble %s",
+ PyInt_AsLong(PyTuple_GetItem(args, 0)),
+ PyString_AsString(PyTuple_GetItem(args, 1)));
+ '''
+ )
+ ])
+ pass
More information about the Pypy-commit
mailing list