PageRenderTime 47ms CodeModel.GetById 13ms RepoModel.GetById 0ms app.codeStats 0ms

/pypy/module/_rawffi/interp_rawffi.py

https://bitbucket.org/pypy/pypy/
Python | 649 lines | 612 code | 27 blank | 10 comment | 42 complexity | f7aa1a69169855f7a1a944d1320db41f MD5 | raw file
Possible License(s): AGPL-3.0, BSD-3-Clause, Apache-2.0
  1. import sys
  2. from pypy.interpreter.baseobjspace import W_Root
  3. from pypy.interpreter.error import OperationError, oefmt, wrap_oserror
  4. from pypy.interpreter.gateway import interp2app, unwrap_spec
  5. from pypy.interpreter.typedef import interp_attrproperty
  6. from pypy.interpreter.typedef import TypeDef, GetSetProperty
  7. from rpython.rlib.clibffi import *
  8. from rpython.rtyper.lltypesystem import lltype, rffi
  9. from rpython.rtyper.tool import rffi_platform
  10. from rpython.rlib.unroll import unrolling_iterable
  11. import rpython.rlib.rposix as rposix
  12. _MS_WINDOWS = os.name == "nt"
  13. if _MS_WINDOWS:
  14. from rpython.rlib import rwin32
  15. from rpython.tool.sourcetools import func_with_new_name
  16. from rpython.rlib.rarithmetic import intmask, r_uint
  17. from pypy.module._rawffi.buffer import RawFFIBuffer
  18. from pypy.module._rawffi.tracker import tracker
  19. BIGENDIAN = sys.byteorder == 'big'
  20. TYPEMAP = {
  21. # XXX A mess with unsigned/signed/normal chars :-/
  22. 'c' : ffi_type_uchar,
  23. 'b' : ffi_type_schar,
  24. 'B' : ffi_type_uchar,
  25. 'h' : ffi_type_sshort,
  26. 'u' : cast_type_to_ffitype(lltype.UniChar),
  27. 'H' : ffi_type_ushort,
  28. 'i' : cast_type_to_ffitype(rffi.INT),
  29. 'I' : cast_type_to_ffitype(rffi.UINT),
  30. 'l' : cast_type_to_ffitype(rffi.LONG),
  31. 'L' : cast_type_to_ffitype(rffi.ULONG),
  32. 'q' : cast_type_to_ffitype(rffi.LONGLONG),
  33. 'Q' : cast_type_to_ffitype(rffi.ULONGLONG),
  34. 'f' : ffi_type_float,
  35. 'd' : ffi_type_double,
  36. 'g' : ffi_type_longdouble,
  37. 's' : ffi_type_pointer,
  38. 'P' : ffi_type_pointer,
  39. 'z' : ffi_type_pointer,
  40. 'O' : ffi_type_pointer,
  41. 'Z' : ffi_type_pointer,
  42. '?' : cast_type_to_ffitype(lltype.Bool),
  43. }
  44. TYPEMAP_PTR_LETTERS = "POszZ"
  45. TYPEMAP_NUMBER_LETTERS = "bBhHiIlLqQ?"
  46. TYPEMAP_FLOAT_LETTERS = "fd" # XXX long doubles are not propperly supported in
  47. # rpython, so we ignore then here
  48. if _MS_WINDOWS:
  49. TYPEMAP['X'] = ffi_type_pointer
  50. TYPEMAP['v'] = ffi_type_sshort
  51. TYPEMAP_PTR_LETTERS += 'X'
  52. TYPEMAP_NUMBER_LETTERS += 'v'
  53. def size_alignment(ffi_type):
  54. return intmask(ffi_type.c_size), intmask(ffi_type.c_alignment)
  55. LL_TYPEMAP = {
  56. 'c' : rffi.CHAR,
  57. 'u' : lltype.UniChar,
  58. 'b' : rffi.SIGNEDCHAR,
  59. 'B' : rffi.UCHAR,
  60. 'h' : rffi.SHORT,
  61. 'H' : rffi.USHORT,
  62. 'i' : rffi.INT,
  63. 'I' : rffi.UINT,
  64. 'l' : rffi.LONG,
  65. 'L' : rffi.ULONG,
  66. 'q' : rffi.LONGLONG,
  67. 'Q' : rffi.ULONGLONG,
  68. 'f' : rffi.FLOAT,
  69. 'd' : rffi.DOUBLE,
  70. 'g' : rffi.LONGDOUBLE,
  71. 's' : rffi.CCHARP,
  72. 'z' : rffi.CCHARP,
  73. 'Z' : rffi.CArrayPtr(lltype.UniChar),
  74. 'O' : rffi.VOIDP,
  75. 'P' : rffi.VOIDP,
  76. '?' : lltype.Bool,
  77. }
  78. if _MS_WINDOWS:
  79. LL_TYPEMAP['X'] = rffi.CCHARP
  80. LL_TYPEMAP['v'] = rffi.SHORT
  81. def letter2tp(space, key):
  82. from pypy.module._rawffi.array import PRIMITIVE_ARRAY_TYPES
  83. try:
  84. return PRIMITIVE_ARRAY_TYPES[key]
  85. except KeyError:
  86. raise oefmt(space.w_ValueError, "Unknown type letter %s", key)
  87. def unpack_simple_shape(space, w_shape):
  88. # 'w_shape' must be either a letter or a tuple (struct, 1).
  89. if space.isinstance_w(w_shape, space.w_str):
  90. letter = space.str_w(w_shape)
  91. return letter2tp(space, letter)
  92. else:
  93. w_shapetype, w_length = space.fixedview(w_shape, expected_length=2)
  94. from pypy.module._rawffi.structure import W_Structure
  95. return space.interp_w(W_Structure, w_shapetype)
  96. def unpack_shape_with_length(space, w_shape):
  97. # Allow 'w_shape' to be a letter or any (shape, number).
  98. # The result is always a W_Array.
  99. if space.isinstance_w(w_shape, space.w_str):
  100. letter = space.str_w(w_shape)
  101. return letter2tp(space, letter)
  102. else:
  103. w_shapetype, w_length = space.fixedview(w_shape, expected_length=2)
  104. length = space.int_w(w_length)
  105. shape = space.interp_w(W_DataShape, w_shapetype)
  106. if shape._array_shapes is None:
  107. shape._array_shapes = {}
  108. try:
  109. result = shape._array_shapes[length]
  110. except KeyError:
  111. from pypy.module._rawffi.array import W_Array
  112. if isinstance(shape, W_Array) and length == 1:
  113. result = shape
  114. else:
  115. ffitype = shape.get_basic_ffi_type()
  116. size = shape.size * length
  117. result = W_Array(ffitype, size)
  118. shape._array_shapes[length] = result
  119. return result
  120. def unpack_resshape(space, w_restype):
  121. if space.is_w(w_restype, space.w_None):
  122. return None
  123. return unpack_simple_shape(space, w_restype)
  124. def unpack_argshapes(space, w_argtypes):
  125. return [unpack_simple_shape(space, w_arg)
  126. for w_arg in space.unpackiterable(w_argtypes)]
  127. def got_libffi_error(space):
  128. raise oefmt(space.w_SystemError, "not supported by libffi")
  129. def wrap_dlopenerror(space, e, filename):
  130. return oefmt(space.w_OSError,
  131. "Cannot load library %s: %s",
  132. filename, e.msg if e.msg else "unspecified error")
  133. class W_CDLL(W_Root):
  134. def __init__(self, space, name, cdll):
  135. self.cdll = cdll
  136. self.name = name
  137. self.w_cache = space.newdict()
  138. self.space = space
  139. @unwrap_spec(flags=int)
  140. def ptr(self, space, w_name, w_argtypes, w_restype, flags=FUNCFLAG_CDECL):
  141. """ Get a pointer for function name with provided argtypes
  142. and restype
  143. """
  144. resshape = unpack_resshape(space, w_restype)
  145. w = space.wrap
  146. argtypes_w = space.fixedview(w_argtypes)
  147. w_argtypes = space.newtuple(argtypes_w)
  148. w_key = space.newtuple([w_name, w_argtypes, w(resshape)])
  149. try:
  150. return space.getitem(self.w_cache, w_key)
  151. except OperationError as e:
  152. if e.match(space, space.w_KeyError):
  153. pass
  154. else:
  155. raise
  156. # Array arguments not supported directly (in C, an array argument
  157. # will be just a pointer). And the result cannot be an array (at all).
  158. argshapes = unpack_argshapes(space, w_argtypes)
  159. ffi_argtypes = [shape.get_basic_ffi_type() for shape in argshapes]
  160. if resshape is not None:
  161. ffi_restype = resshape.get_basic_ffi_type()
  162. else:
  163. ffi_restype = ffi_type_void
  164. if space.isinstance_w(w_name, space.w_str):
  165. name = space.str_w(w_name)
  166. try:
  167. ptr = self.cdll.getrawpointer(name, ffi_argtypes, ffi_restype,
  168. flags)
  169. except KeyError:
  170. raise oefmt(space.w_AttributeError,
  171. "No symbol %s found in library %s",
  172. name, self.name)
  173. except LibFFIError:
  174. raise got_libffi_error(space)
  175. elif (_MS_WINDOWS and space.isinstance_w(w_name, space.w_int)):
  176. ordinal = space.int_w(w_name)
  177. try:
  178. ptr = self.cdll.getrawpointer_byordinal(ordinal, ffi_argtypes,
  179. ffi_restype, flags)
  180. except KeyError:
  181. raise oefmt(space.w_AttributeError,
  182. "No symbol %d found in library %s",
  183. ordinal, self.name)
  184. except LibFFIError:
  185. raise got_libffi_error(space)
  186. else:
  187. raise oefmt(space.w_TypeError,
  188. "function name must be string or integer")
  189. w_funcptr = W_FuncPtr(space, ptr, argshapes, resshape)
  190. space.setitem(self.w_cache, w_key, w_funcptr)
  191. return w_funcptr
  192. @unwrap_spec(name=str)
  193. def getaddressindll(self, space, name):
  194. try:
  195. address_as_uint = rffi.cast(lltype.Unsigned,
  196. self.cdll.getaddressindll(name))
  197. except KeyError:
  198. raise oefmt(space.w_ValueError, "Cannot find symbol %s", name)
  199. return space.wrap(address_as_uint)
  200. @unwrap_spec(name='str_or_None')
  201. def descr_new_cdll(space, w_type, name):
  202. try:
  203. cdll = CDLL(name)
  204. except DLOpenError as e:
  205. raise wrap_dlopenerror(space, e, name)
  206. except OSError as e:
  207. raise wrap_oserror(space, e)
  208. return space.wrap(W_CDLL(space, name, cdll))
  209. W_CDLL.typedef = TypeDef(
  210. 'CDLL',
  211. __new__ = interp2app(descr_new_cdll),
  212. ptr = interp2app(W_CDLL.ptr),
  213. getaddressindll = interp2app(W_CDLL.getaddressindll),
  214. name = interp_attrproperty('name', W_CDLL),
  215. __doc__ = """ C Dynamically loaded library
  216. use CDLL(libname) to create a handle to a C library (the argument is processed
  217. the same way as dlopen processes it). On such a library you can call:
  218. lib.ptr(func_name, argtype_list, restype)
  219. where argtype_list is a list of single characters and restype is a single
  220. character. The character meanings are more or less the same as in the struct
  221. module, except that s has trailing \x00 added, while p is considered a raw
  222. buffer.""" # xxx fix doc
  223. )
  224. unroll_letters_for_numbers = unrolling_iterable(TYPEMAP_NUMBER_LETTERS)
  225. unroll_letters_for_floats = unrolling_iterable(TYPEMAP_FLOAT_LETTERS)
  226. _ARM = rffi_platform.getdefined('__arm__', '')
  227. def read_ptr(ptr, ofs, TP):
  228. T = lltype.Ptr(rffi.CArray(TP))
  229. for c in unroll_letters_for_floats:
  230. # Note: if we are on ARM and have a float-ish value that is not word
  231. # aligned accessing it directly causes a SIGBUS. Instead we use memcpy
  232. # to avoid the problem
  233. if (_ARM and LL_TYPEMAP[c] is TP
  234. and rffi.cast(lltype.Signed, ptr) & 3 != 0):
  235. if ofs != 0:
  236. ptr = rffi.ptradd(ptr, ofs*rffi.sizeof(TP))
  237. with lltype.scoped_alloc(T.TO, 1) as t_array:
  238. rffi.c_memcpy(
  239. rffi.cast(rffi.VOIDP, t_array),
  240. rffi.cast(rffi.VOIDP, ptr),
  241. rffi.sizeof(TP))
  242. ptr_val = t_array[0]
  243. return ptr_val
  244. else:
  245. return rffi.cast(T, ptr)[ofs]
  246. read_ptr._annspecialcase_ = 'specialize:arg(2)'
  247. def write_ptr(ptr, ofs, value):
  248. TP = lltype.typeOf(value)
  249. T = lltype.Ptr(rffi.CArray(TP))
  250. for c in unroll_letters_for_floats:
  251. # Note: if we are on ARM and have a float-ish value that is not word
  252. # aligned accessing it directly causes a SIGBUS. Instead we use memcpy
  253. # to avoid the problem
  254. if (_ARM and LL_TYPEMAP[c] is TP
  255. and rffi.cast(lltype.Signed, ptr) & 3 != 0):
  256. if ofs != 0:
  257. ptr = rffi.ptradd(ptr, ofs*rffi.sizeof(TP))
  258. with lltype.scoped_alloc(T.TO, 1) as s_array:
  259. s_array[0] = value
  260. rffi.c_memcpy(
  261. rffi.cast(rffi.VOIDP, ptr),
  262. rffi.cast(rffi.VOIDP, s_array),
  263. rffi.sizeof(TP))
  264. return
  265. else:
  266. rffi.cast(T, ptr)[ofs] = value
  267. write_ptr._annspecialcase_ = 'specialize:argtype(2)'
  268. def segfault_exception(space, reason):
  269. w_mod = space.getbuiltinmodule("_rawffi")
  270. w_exception = space.getattr(w_mod, space.wrap("SegfaultException"))
  271. return OperationError(w_exception, space.wrap(reason))
  272. class W_DataShape(W_Root):
  273. _array_shapes = None
  274. size = 0
  275. alignment = 0
  276. itemcode = '\0'
  277. def allocate(self, space, length, autofree=False):
  278. raise NotImplementedError
  279. def get_basic_ffi_type(self):
  280. raise NotImplementedError
  281. def descr_get_ffi_type(self, space):
  282. from pypy.module._rawffi.alt.interp_ffitype import W_FFIType
  283. return W_FFIType('<unknown>', self.get_basic_ffi_type(), self)
  284. @unwrap_spec(n=int)
  285. def descr_size_alignment(self, space, n=1):
  286. return space.newtuple([space.wrap(self.size * n),
  287. space.wrap(self.alignment)])
  288. class W_DataInstance(W_Root):
  289. def __init__(self, space, size, address=r_uint(0)):
  290. if address:
  291. self.ll_buffer = rffi.cast(rffi.VOIDP, address)
  292. else:
  293. self.ll_buffer = lltype.malloc(rffi.VOIDP.TO, size, flavor='raw',
  294. zero=True, add_memory_pressure=True)
  295. if tracker.DO_TRACING:
  296. ll_buf = rffi.cast(lltype.Signed, self.ll_buffer)
  297. tracker.trace_allocation(ll_buf, self)
  298. self._ll_buffer = self.ll_buffer
  299. def getbuffer(self, space):
  300. return space.wrap(rffi.cast(lltype.Unsigned, self.ll_buffer))
  301. def buffer_advance(self, n):
  302. self.ll_buffer = rffi.ptradd(self.ll_buffer, n)
  303. def byptr(self, space):
  304. from pypy.module._rawffi.array import ARRAY_OF_PTRS
  305. array = ARRAY_OF_PTRS.allocate(space, 1)
  306. array.setitem(space, 0, space.wrap(self))
  307. return space.wrap(array)
  308. def free(self, space):
  309. if not self._ll_buffer:
  310. raise segfault_exception(space, "freeing NULL pointer")
  311. self._free()
  312. def _free(self):
  313. if tracker.DO_TRACING:
  314. ll_buf = rffi.cast(lltype.Signed, self._ll_buffer)
  315. tracker.trace_free(ll_buf)
  316. lltype.free(self._ll_buffer, flavor='raw')
  317. self.ll_buffer = lltype.nullptr(rffi.VOIDP.TO)
  318. self._ll_buffer = self.ll_buffer
  319. def buffer_w(self, space, flags):
  320. return RawFFIBuffer(self)
  321. def readbuf_w(self, space):
  322. return RawFFIBuffer(self)
  323. def writebuf_w(self, space):
  324. return RawFFIBuffer(self)
  325. def getrawsize(self):
  326. raise NotImplementedError("abstract base class")
  327. def unwrap_truncate_int(TP, space, w_arg):
  328. if space.isinstance_w(w_arg, space.w_int):
  329. return rffi.cast(TP, space.int_w(w_arg))
  330. else:
  331. return rffi.cast(TP, space.bigint_w(w_arg).ulonglongmask())
  332. unwrap_truncate_int._annspecialcase_ = 'specialize:arg(0)'
  333. def unwrap_value(space, push_func, add_arg, argdesc, letter, w_arg):
  334. if letter in TYPEMAP_PTR_LETTERS:
  335. # check for NULL ptr
  336. if isinstance(w_arg, W_DataInstance):
  337. ptr = w_arg.ll_buffer
  338. else:
  339. ptr = unwrap_truncate_int(rffi.VOIDP, space, w_arg)
  340. push_func(add_arg, argdesc, ptr)
  341. elif letter == "d":
  342. push_func(add_arg, argdesc, space.float_w(w_arg))
  343. elif letter == "f":
  344. push_func(add_arg, argdesc, rffi.cast(rffi.FLOAT,
  345. space.float_w(w_arg)))
  346. elif letter == "g":
  347. push_func(add_arg, argdesc, rffi.cast(rffi.LONGDOUBLE,
  348. space.float_w(w_arg)))
  349. elif letter == "c":
  350. s = space.str_w(w_arg)
  351. if len(s) != 1:
  352. raise oefmt(space.w_TypeError,
  353. "Expected string of length one as character")
  354. val = s[0]
  355. push_func(add_arg, argdesc, val)
  356. elif letter == 'u':
  357. s = space.unicode_w(w_arg)
  358. if len(s) != 1:
  359. raise oefmt(space.w_TypeError,
  360. "Expected unicode string of length one as wide "
  361. "character")
  362. val = s[0]
  363. push_func(add_arg, argdesc, val)
  364. else:
  365. for c in unroll_letters_for_numbers:
  366. if letter == c:
  367. TP = LL_TYPEMAP[c]
  368. val = unwrap_truncate_int(TP, space, w_arg)
  369. push_func(add_arg, argdesc, val)
  370. return
  371. else:
  372. raise oefmt(space.w_TypeError, "cannot directly write value")
  373. unwrap_value._annspecialcase_ = 'specialize:arg(1)'
  374. ll_typemap_iter = unrolling_iterable(LL_TYPEMAP.items())
  375. def wrap_value(space, func, add_arg, argdesc, letter):
  376. for c, ll_type in ll_typemap_iter:
  377. if letter == c:
  378. if c in TYPEMAP_PTR_LETTERS:
  379. res = func(add_arg, argdesc, rffi.VOIDP)
  380. return space.wrap(rffi.cast(lltype.Unsigned, res))
  381. elif c == 'f' or c == 'd' or c == 'g':
  382. return space.wrap(float(func(add_arg, argdesc, ll_type)))
  383. else:
  384. return space.wrap(func(add_arg, argdesc, ll_type))
  385. raise oefmt(space.w_TypeError, "cannot directly read value")
  386. wrap_value._annspecialcase_ = 'specialize:arg(1)'
  387. NARROW_INTEGER_TYPES = 'cbhiBIH?'
  388. def is_narrow_integer_type(letter):
  389. return letter in NARROW_INTEGER_TYPES
  390. class W_FuncPtr(W_Root):
  391. def __init__(self, space, ptr, argshapes, resshape):
  392. self.ptr = ptr
  393. self.argshapes = argshapes
  394. self.resshape = resshape
  395. self.narrow_integer = False
  396. if resshape is not None:
  397. self.narrow_integer = is_narrow_integer_type(resshape.itemcode.lower())
  398. def getbuffer(self, space):
  399. return space.wrap(rffi.cast(lltype.Unsigned, self.ptr.funcsym))
  400. def byptr(self, space):
  401. from pypy.module._rawffi.array import ARRAY_OF_PTRS
  402. array = ARRAY_OF_PTRS.allocate(space, 1)
  403. array.setitem(space, 0, self.getbuffer(space))
  404. if tracker.DO_TRACING:
  405. # XXX this is needed, because functions tend to live forever
  406. # hence our testing is not performing that well
  407. del tracker.alloced[rffi.cast(lltype.Signed, array.ll_buffer)]
  408. return space.wrap(array)
  409. def call(self, space, args_w):
  410. from pypy.module._rawffi.array import W_ArrayInstance
  411. from pypy.module._rawffi.structure import W_StructureInstance
  412. from pypy.module._rawffi.structure import W_Structure
  413. argnum = len(args_w)
  414. if argnum != len(self.argshapes):
  415. raise oefmt(space.w_TypeError,
  416. "Wrong number of arguments: expected %d, got %d",
  417. len(self.argshapes), argnum)
  418. args_ll = []
  419. for i in range(argnum):
  420. argshape = self.argshapes[i]
  421. w_arg = args_w[i]
  422. if isinstance(argshape, W_Structure): # argument by value
  423. arg = space.interp_w(W_StructureInstance, w_arg)
  424. xsize, xalignment = size_alignment(self.ptr.argtypes[i])
  425. if (arg.shape.size != xsize or
  426. arg.shape.alignment != xalignment):
  427. raise oefmt(space.w_TypeError,
  428. "Argument %d should be a structure of size %d "
  429. "and alignment %d, got instead size %d and "
  430. "alignment %d", i + 1, xsize, xalignment,
  431. arg.shape.size, arg.shape.alignment)
  432. else:
  433. arg = space.interp_w(W_ArrayInstance, w_arg)
  434. if arg.length != 1:
  435. raise oefmt(space.w_TypeError,
  436. "Argument %d should be an array of length 1, "
  437. "got length %d", i+1, arg.length)
  438. argletter = argshape.itemcode
  439. letter = arg.shape.itemcode
  440. if letter != argletter:
  441. if not (argletter in TYPEMAP_PTR_LETTERS and
  442. letter in TYPEMAP_PTR_LETTERS):
  443. raise oefmt(space.w_TypeError,
  444. "Argument %d should be typecode %s, got "
  445. "%s", i + 1, argletter, letter)
  446. args_ll.append(arg.ll_buffer)
  447. # XXX we could avoid the intermediate list args_ll
  448. try:
  449. if self.resshape is not None:
  450. result = self.resshape.allocate(space, 1, autofree=True)
  451. # adjust_return_size() was used here on result.ll_buffer
  452. self.ptr.call(args_ll, result.ll_buffer)
  453. if BIGENDIAN and self.narrow_integer:
  454. # we get a 8 byte value in big endian
  455. n = rffi.sizeof(lltype.Signed) - result.shape.size
  456. result.buffer_advance(n)
  457. return space.wrap(result)
  458. else:
  459. self.ptr.call(args_ll, lltype.nullptr(rffi.VOIDP.TO))
  460. return space.w_None
  461. except StackCheckError as e:
  462. raise OperationError(space.w_ValueError, space.wrap(e.message))
  463. @unwrap_spec(addr=r_uint, flags=int)
  464. def descr_new_funcptr(space, w_tp, addr, w_args, w_res, flags=FUNCFLAG_CDECL):
  465. argshapes = unpack_argshapes(space, w_args)
  466. resshape = unpack_resshape(space, w_res)
  467. ffi_args = [shape.get_basic_ffi_type() for shape in argshapes]
  468. if resshape is not None:
  469. ffi_res = resshape.get_basic_ffi_type()
  470. else:
  471. ffi_res = ffi_type_void
  472. try:
  473. ptr = RawFuncPtr('???', ffi_args, ffi_res, rffi.cast(rffi.VOIDP, addr),
  474. flags)
  475. except LibFFIError:
  476. raise got_libffi_error(space)
  477. return space.wrap(W_FuncPtr(space, ptr, argshapes, resshape))
  478. W_FuncPtr.typedef = TypeDef(
  479. 'FuncPtr',
  480. __new__ = interp2app(descr_new_funcptr),
  481. __call__ = interp2app(W_FuncPtr.call),
  482. buffer = GetSetProperty(W_FuncPtr.getbuffer),
  483. byptr = interp2app(W_FuncPtr.byptr),
  484. )
  485. W_FuncPtr.typedef.acceptable_as_base_class = False
  486. def _create_new_accessor(func_name, name):
  487. @unwrap_spec(tp_letter=str)
  488. def accessor(space, tp_letter):
  489. if len(tp_letter) != 1:
  490. raise oefmt(space.w_ValueError, "Expecting string of length one")
  491. tp_letter = tp_letter[0] # fool annotator
  492. try:
  493. return space.wrap(intmask(getattr(TYPEMAP[tp_letter], name)))
  494. except KeyError:
  495. raise oefmt(space.w_ValueError, "Unknown type specification %s",
  496. tp_letter)
  497. return func_with_new_name(accessor, func_name)
  498. sizeof = _create_new_accessor('sizeof', 'c_size')
  499. alignment = _create_new_accessor('alignment', 'c_alignment')
  500. @unwrap_spec(address=r_uint, maxlength=int)
  501. def charp2string(space, address, maxlength=-1):
  502. if address == 0:
  503. return space.w_None
  504. charp_addr = rffi.cast(rffi.CCHARP, address)
  505. if maxlength == -1:
  506. s = rffi.charp2str(charp_addr)
  507. else:
  508. s = rffi.charp2strn(charp_addr, maxlength)
  509. return space.newbytes(s)
  510. @unwrap_spec(address=r_uint, maxlength=int)
  511. def wcharp2unicode(space, address, maxlength=-1):
  512. if address == 0:
  513. return space.w_None
  514. wcharp_addr = rffi.cast(rffi.CWCHARP, address)
  515. if maxlength == -1:
  516. s = rffi.wcharp2unicode(wcharp_addr)
  517. else:
  518. s = rffi.wcharp2unicoden(wcharp_addr, maxlength)
  519. return space.wrap(s)
  520. @unwrap_spec(address=r_uint, maxlength=int)
  521. def charp2rawstring(space, address, maxlength=-1):
  522. if maxlength == -1:
  523. return charp2string(space, address)
  524. s = rffi.charpsize2str(rffi.cast(rffi.CCHARP, address), maxlength)
  525. return space.newbytes(s)
  526. @unwrap_spec(address=r_uint, maxlength=int)
  527. def wcharp2rawunicode(space, address, maxlength=-1):
  528. if maxlength == -1:
  529. return wcharp2unicode(space, address)
  530. s = rffi.wcharpsize2unicode(rffi.cast(rffi.CWCHARP, address), maxlength)
  531. return space.wrap(s)
  532. @unwrap_spec(address=r_uint, newcontent='bufferstr')
  533. def rawstring2charp(space, address, newcontent):
  534. from rpython.rtyper.annlowlevel import llstr
  535. from rpython.rtyper.lltypesystem.rstr import copy_string_to_raw
  536. array = rffi.cast(rffi.CCHARP, address)
  537. copy_string_to_raw(llstr(newcontent), array, 0, len(newcontent))
  538. if _MS_WINDOWS:
  539. @unwrap_spec(code=int)
  540. def FormatError(space, code):
  541. return space.wrap(rwin32.FormatError(code))
  542. @unwrap_spec(hresult=int)
  543. def check_HRESULT(space, hresult):
  544. if rwin32.FAILED(hresult):
  545. raise OperationError(space.w_WindowsError, space.wrap(hresult))
  546. return space.wrap(hresult)
  547. def get_libc(space):
  548. name = get_libc_name()
  549. try:
  550. cdll = CDLL(name)
  551. except OSError as e:
  552. raise wrap_oserror(space, e)
  553. return space.wrap(W_CDLL(space, name, cdll))
  554. def get_errno(space):
  555. return space.wrap(rposix.get_saved_alterrno())
  556. def set_errno(space, w_errno):
  557. rposix.set_saved_alterrno(space.int_w(w_errno))
  558. if sys.platform == 'win32':
  559. # see also
  560. # https://bitbucket.org/pypy/pypy/issue/1944/ctypes-on-windows-getlasterror
  561. def get_last_error(space):
  562. return space.wrap(rwin32.GetLastError_alt_saved())
  563. @unwrap_spec(error=int)
  564. def set_last_error(space, error):
  565. rwin32.SetLastError_alt_saved(error)
  566. else:
  567. # always have at least a dummy version of these functions
  568. # (https://bugs.pypy.org/issue1242)
  569. def get_last_error(space):
  570. return space.wrap(0)
  571. @unwrap_spec(error=int)
  572. def set_last_error(space, error):
  573. pass