From b3ca22dc339ca18873079bd96bbb19dd00bc8f0a Mon Sep 17 00:00:00 2001 From: William S Fulton Date: Sun, 26 May 2013 22:34:07 +0100 Subject: [PATCH] Fix Python examples to compile and run under Python 3 --- Examples/python/index.html | 17 ++--------- Examples/python/multimap/example.i | 47 +++++++++++++++++++++++------- Examples/python/varargs/example.i | 10 +++++-- Examples/python/varargs/runme.py | 7 +++-- 4 files changed, 51 insertions(+), 30 deletions(-) diff --git a/Examples/python/index.html b/Examples/python/index.html index 8443a85e1..37f4b55af 100644 --- a/Examples/python/index.html +++ b/Examples/python/index.html @@ -89,21 +89,10 @@ to look at the distutils

Compatibility

-The examples have been extensively tested on the following platforms: - - - -All of the examples were last tested with the following configuration (9/1/2000): - - +For Python 3, set the environment variable PY3=1. +This will ensure the 2to3 program is run prior to running any example. +

Your mileage may vary. If you experience a problem, please let us know by contacting us on the mailing lists. diff --git a/Examples/python/multimap/example.i b/Examples/python/multimap/example.i index f1c4d9990..3f6fc3db3 100644 --- a/Examples/python/multimap/example.i +++ b/Examples/python/multimap/example.i @@ -38,27 +38,44 @@ extern int gcd(int x, int y); } %#if PY_VERSION_HEX >= 0x03000000 { - int l; - $2[i] = PyUnicode_AsStringAndSize(s, &l); + PyObject *utf8str = PyUnicode_AsUTF8String(s); + const char *cstr = PyBytes_AsString(utf8str); + $2[i] = strdup(cstr); + Py_DECREF(utf8str); } %#else $2[i] = PyString_AsString(s); %#endif - } $2[i] = 0; } +%typemap(freearg) (int argc, char *argv[]) { +%#if PY_VERSION_HEX >= 0x03000000 + int i; + for (i = 0; i < $1; i++) { + free($2[i]); + } +%#endif +} + extern int gcdmain(int argc, char *argv[]); %typemap(in) (char *bytes, int len) { %#if PY_VERSION_HEX >= 0x03000000 + char *cstr; + Py_ssize_t len; + PyObject *utf8str; if (!PyUnicode_Check($input)) { PyErr_SetString(PyExc_ValueError,"Expected a string"); return NULL; } - $1 = PyUnicode_AsStringAndSize($input, &$2); + utf8str = PyUnicode_AsUTF8String($input); + PyBytes_AsStringAndSize(utf8str, &cstr, &len); + $1 = strndup(cstr, (size_t)len); + $2 = (int)len; + Py_DECREF(utf8str); %#else if (!PyString_Check($input)) { PyErr_SetString(PyExc_ValueError,"Expected a string"); @@ -69,6 +86,12 @@ extern int gcdmain(int argc, char *argv[]); %#endif } +%typemap(freearg) (char *bytes, int len) { +%#if PY_VERSION_HEX >= 0x03000000 + free($1); +%#endif +} + extern int count(char *bytes, int len, char c); @@ -79,13 +102,17 @@ extern int count(char *bytes, int len, char c); %typemap(in) (char *str, int len) { %#if PY_VERSION_HEX >= 0x03000000 - $2 = PyUnicode_GetSize($input); - $1 = (char *) malloc($2+1); - memmove($1,PyUnicode_AsString($input),$2); + char *cstr; + Py_ssize_t len; + PyObject *utf8str = PyUnicode_AsUTF8String($input); + PyBytes_AsStringAndSize(utf8str, &cstr, &len); + $1 = strndup(cstr, (size_t)len); + $2 = (int)len; + Py_DECREF(utf8str); %#else - $2 = PyString_Size($input); - $1 = (char *) malloc($2+1); - memmove($1,PyString_AsString($input),$2); + $2 = PyString_Size($input); + $1 = (char *) malloc($2+1); + memmove($1,PyString_AsString($input),$2); %#endif } diff --git a/Examples/python/varargs/example.i b/Examples/python/varargs/example.i index 6cb88f5f4..a581bca5d 100644 --- a/Examples/python/varargs/example.i +++ b/Examples/python/varargs/example.i @@ -32,9 +32,6 @@ int printf(const char *fmt, ...); } #endif -/* Typemap just to make the example work */ -%typemap(in) FILE * "$1 = PyFile_AsFile($input);"; - int fprintf(FILE *, const char *fmt, ...); /* Here is somewhat different example. A variable length argument @@ -48,6 +45,13 @@ int fprintf(FILE *, const char *fmt, ...); %varargs(20, char *x = NULL) printv; %inline %{ + +/* In Python 2 we could use PyFile_AsFile for converting Python sys.stdout to C's stdout. + This API disappeared in Python 3, so instead we use a helper function to get stdout */ +FILE * stdout_stream(void) { + return stdout; +} + void printv(char *s, ...) { va_list ap; char *x; diff --git a/Examples/python/varargs/runme.py b/Examples/python/varargs/runme.py index a01cb6769..8eab77041 100644 --- a/Examples/python/varargs/runme.py +++ b/Examples/python/varargs/runme.py @@ -13,13 +13,14 @@ for i in range(0,10): # This will probably be garbled because %d is interpreted by C example.printf("The value is %d\n") +stdout = example.stdout_stream() # Call fprintf -example.fprintf(sys.stdout,"Hello World. I'm fprintf\n") +example.fprintf(stdout,"Hello World. I'm fprintf\n") for i in range(0,10): - example.fprintf(sys.stdout,"i is %d\n" % i) + example.fprintf(stdout,"i is %d\n" % i) # This won't be garbled since %d is not interpreted -example.fprintf(sys.stdout,"The value is %d\n") +example.fprintf(stdout,"The value is %d\n") # This function calls our NULL-terminated function