diff options
| author | mattip <matti.picus@gmail.com> | 2012-08-22 22:20:49 +0300 |
|---|---|---|
| committer | mattip <matti.picus@gmail.com> | 2012-08-22 22:20:49 +0300 |
| commit | a7d6d37ac1caf3740d6e544bf8675ea832891a61 (patch) | |
| tree | c50ce9a4029eff7b89aa6adff862d5bf6dc7bd5a | |
| parent | 9b16704262e25c478989dc9732c17ae3cc1c2741 (diff) | |
| parent | ba63b2188158712097b5b6f2bc76db47cd63d77d (diff) | |
| download | cffi-win32.tar.gz | |
merge default into branchwin32
| -rw-r--r-- | c/_cffi_backend.c | 8 | ||||
| -rw-r--r-- | c/misc_win32.h | 22 | ||||
| -rw-r--r-- | c/test_c.py | 5 | ||||
| -rw-r--r-- | cffi/cparser.py | 31 | ||||
| -rw-r--r-- | testing/test_parsing.py | 14 |
5 files changed, 73 insertions, 7 deletions
diff --git a/c/_cffi_backend.c b/c/_cffi_backend.c index cf8ac37..138e2fb 100644 --- a/c/_cffi_backend.c +++ b/c/_cffi_backend.c @@ -197,6 +197,8 @@ static void init_errno(void) { } # else # include "misc_thread.h" # endif +# define save_errno_only save_errno +# define restore_errno_only restore_errno #endif #ifdef HAVE_WCHAR_H @@ -3182,7 +3184,7 @@ static ffi_type *fb_fill_type(struct funcbuilder_s *fb, CTypeDescrObject *ct, else if (ct->ct_flags & (CT_POINTER|CT_ARRAY|CT_FUNCTIONPTR)) { return &ffi_type_pointer; } - else if (ct->ct_flags & CT_VOID) { + else if ((ct->ct_flags & CT_VOID) && is_result_type) { return &ffi_type_void; } @@ -4044,7 +4046,7 @@ static PyObject *b_buffer(PyObject *self, PyObject *args) static PyObject *b_get_errno(PyObject *self, PyObject *noarg) { int err; - restore_errno(); + restore_errno_only(); err = errno; errno = 0; return PyInt_FromLong(err); @@ -4056,7 +4058,7 @@ static PyObject *b_set_errno(PyObject *self, PyObject *args) if (!PyArg_ParseTuple(args, "i:set_errno", &i)) return NULL; errno = i; - save_errno(); + save_errno_only(); errno = 0; Py_INCREF(Py_None); return Py_None; diff --git a/c/misc_win32.h b/c/misc_win32.h index 718514d..115df7a 100644 --- a/c/misc_win32.h +++ b/c/misc_win32.h @@ -45,6 +45,18 @@ static void save_errno(void) /* else: cannot report the error */ } +static void save_errno_only(void) +{ + int current_err = errno; + struct cffi_errno_s *p; + + p = _geterrno_object(); + if (p != NULL) { + p->saved_errno = current_err; + } + /* else: cannot report the error */ +} + static void restore_errno(void) { struct cffi_errno_s *p; @@ -57,6 +69,16 @@ static void restore_errno(void) /* else: cannot report the error */ } +static void restore_errno_only(void) +{ + struct cffi_errno_s *p; + + p = _geterrno_object(); + if (p != NULL) { + errno = p->saved_errno; + } + /* else: cannot report the error */ +} /************************************************************/ /* Emulate dlopen()&co. from the Windows API */ diff --git a/c/test_c.py b/c/test_c.py index bd080ad..2faedd5 100644 --- a/c/test_c.py +++ b/c/test_c.py @@ -773,6 +773,11 @@ def test_function_void_result(): BFunc = new_function_type((BInt, BInt), BVoid, False) assert repr(BFunc) == "<ctype 'void(*)(int, int)'>" +def test_function_void_arg(): + BVoid = new_void_type() + BInt = new_primitive_type("int") + py.test.raises(TypeError, new_function_type, (BVoid,), BInt, False) + def test_call_function_0(): BSignedChar = new_primitive_type("signed char") BFunc0 = new_function_type((BSignedChar, BSignedChar), BSignedChar, False) diff --git a/cffi/cparser.py b/cffi/cparser.py index 24aed65..df0ef46 100644 --- a/cffi/cparser.py +++ b/cffi/cparser.py @@ -1,6 +1,6 @@ from . import api, model -import pycparser, weakref, re +import pycparser.c_parser, weakref, re _r_comment = re.compile(r"/\*.*?\*/|//.*?$", re.DOTALL | re.MULTILINE) _r_define = re.compile(r"^\s*#\s*define\s+([A-Za-z_][A-Za-z_0-9]*)\s+(.*?)$", @@ -61,9 +61,30 @@ class Parser(object): csource, macros = _preprocess(csource) csourcelines.append(csource) csource = '\n'.join(csourcelines) - ast = _get_parser().parse(csource) + try: + ast = _get_parser().parse(csource) + except pycparser.c_parser.ParseError, e: + self.convert_pycparser_error(e, csource) return ast, macros + def convert_pycparser_error(self, e, csource): + # xxx look for ":NUM:" at the start of str(e) and try to interpret + # it as a line number + line = None + msg = str(e) + if msg.startswith(':') and ':' in msg[1:]: + linenum = msg[1:msg.find(':',1)] + if linenum.isdigit(): + linenum = int(linenum, 10) + csourcelines = csource.splitlines() + if 1 <= linenum <= len(csourcelines): + line = csourcelines[linenum-1] + if line: + msg = 'cannot parse "%s"\n%s' % (line, msg) + else: + msg = 'parse error\n%s' % (msg,) + raise api.CDefError(msg) + def parse(self, csource, override=False): prev_override = self._override try: @@ -244,7 +265,11 @@ class Parser(object): params[-1].type.type.names == ['__dotdotdot__']) if ellipsis: params.pop() - if (len(params) == 1 and + if not params: + raise api.CDefError( + "%s: a function with only '(...)' as argument" + " is not correct C" % (funcname or 'in expression')) + elif (len(params) == 1 and isinstance(params[0].type, pycparser.c_ast.TypeDecl) and isinstance(params[0].type.type, pycparser.c_ast.IdentifierType) and list(params[0].type.type.names) == ['void']): diff --git a/testing/test_parsing.py b/testing/test_parsing.py index 0016239..da3b777 100644 --- a/testing/test_parsing.py +++ b/testing/test_parsing.py @@ -1,4 +1,4 @@ -import py, sys +import py, sys, re from cffi import FFI, FFIError, CDefError, VerificationError class FakeBackend(object): @@ -177,3 +177,15 @@ def test_override(): assert C.foo.BType == '<func (), <int>, False>' ffi.cdef("long foo(void);", override=True) assert C.foo.BType == '<func (), <long>, False>' + +def test_cannot_have_only_variadic_part(): + # this checks that we get a sensible error if we try "int foo(...);" + ffi = FFI() + e = py.test.raises(CDefError, ffi.cdef, "int foo(...);") + assert str(e.value) == \ + "foo: a function with only '(...)' as argument is not correct C" + +def test_parse_error(): + ffi = FFI() + e = py.test.raises(CDefError, ffi.cdef, " x y z ") + assert re.match(r'cannot parse " x y z "\n:\d+:', str(e.value)) |
