[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