ctypes: Setting callback functions in C libraries

S

sjdevnull

Hey,

I'm trying to wrap GNU readline with ctypes (the Python readline
library doesn't support the callback interface), but I can't figure out
how to set values to a variable inside the library. This is Python 2.5
on Linux. Here's what I have so far--if you comment out the memmove
call (3 lines) it works as expected:

# START
#!/usr/local/bin/python2.5
import ctypes

ctypes.cdll.LoadLibrary("libcurses.so")#, mode=ctypes.RTLD_GLOBAL)
ctypes.CDLL("libcurses.so", mode=ctypes.RTLD_GLOBAL)
ctypes.cdll.LoadLibrary("libreadline.so")
readline = ctypes.CDLL("libreadline.so")

RL_COMPLETION_FUNC_T =
ctypes.CFUNCTYPE(ctypes.POINTER(ctypes.c_char_p),
ctypes.c_char_p, ctypes.c_int, ctypes.c_int)
RL_LINE_BUFFER = ctypes.c_char_p.in_dll(readline, "rl_line_buffer")
RL_ATTEMPTED_COMPLETION_FUNCTION =
RL_COMPLETION_FUNC_T.in_dll(readline,

"rl_attempted_completion_function")

def our_complete(text, start, end):
print "Test", text, start, end
rv = None
arrtype = ctypes.c_char_p*4
globals()["rv"] = arrtype("hello", "hatpin", "hammer", None)
globals()["crv"]=ctypes.cast(rv, ctypes.POINTER(ctypes.c_char_p))
return rv
ourfunc = RL_COMPLETION_FUNC_T(our_complete)

_readline = readline.readline
_readline.argtypes = [ctypes.c_char_p]
_readline.restype = ctypes.c_char_p

ctypes.memmove(ctypes.addressof(RL_ATTEMPTED_COMPLETION_FUNCTION),
ctypes.addressof(ourfunc),
4)
line = _readline("Input: ")
print "INPUT was: ", line
#END

I need to assign ourfunc to RL_ATTEMPTED_COMPLETION_FUNCTION, but
obviously simple assignment rebinds the name rather than assigning it
to the C variable.

Using ctypes.memmove to overwrite it(as I have here) will run the
function but segfault when ourfunc goes to return (poking around with
the debugger shows it's dying in ctypes' callbacks.c at line 216, "keep
= setfunc(mem, result, 0);" because setfunc is NULL). I'm not entirely
sure that's not because of some error in the prototyping or restype
setting rather than as a result of memmove, but the memmove seems
sketchy enough (only sets the function pointer itself presumably, not
anything that ctypes wrappers need) that I'm looking for a better way
to do it.

As it is, returning rv directly or simply returning None causes the
same segfault.


Any ideas?

Thanks very much for your time!
 
S

sjdevnull

I realized my wrapping was broken, fixing that below...

I'm trying to wrap GNU readline withctypes(the Python readline
library doesn't support the callback interface), but I can't figure out
how to set values to a variable inside the library. This is Python 2.5
on Linux. Here's what I have so far--if you comment out the memmove
call (3 lines) it works as expected: [SNIP]
I need to assign ourfunc to RL_ATTEMPTED_COMPLETION_FUNCTION, but
obviously simple assignment rebinds the name rather than assigning it
to the C variable.

Usingctypes.memmove to overwrite it(as I have here) will run the
function but segfault when ourfunc goes to return (poking around with
the debugger shows it's dying inctypes' callbacks.c at line 216, "keep
= setfunc(mem, result, 0);" because setfunc is NULL). I'm not entirely
sure that's not because of some error in the prototyping or restype
setting rather than as a result of memmove, but the memmove seems
sketchy enough (only sets the function pointer itself presumably, not
anything thatctypeswrappers need) that I'm looking for a better way
to do it.

As it is, returning rv directly or simply returning None causes the
same segfault.

Any idea?

Thanks very much for your time!

# START
#!/usr/local/bin/python2.5
import ctypes

ctypes.cdll.LoadLibrary("libcurses.so")#, mode=ctypes.RTLD_GLOBAL)
ctypes.CDLL("libcurses.so", mode=ctypes.RTLD_GLOBAL)
ctypes.cdll.LoadLibrary("libreadline.so")
readline = ctypes.CDLL("libreadline.so")

RL_COMPLETION_FUNC_T = \
ctypes.CFUNCTYPE(ctypes.POINTER(ctypes.c_char_p),
ctypes.c_char_p, ctypes.c_int, ctypes.c_int)
RL_LINE_BUFFER = ctypes.c_char_p.in_dll(readline, "rl_line_buffer")
RL_ATTEMPTED_COMPLETION_FUNCTION = \
RL_COMPLETION_FUNC_T.in_dll(readline,
"rl_attempted_completion_function")

def our_complete(text, start, end):
print "Test", text, start, end
rv = None
arrtype = ctypes.c_char_p*4
globals()["rv"] = arrtype("hello", "hatpin", "hammer", None)
globals()["crv"]=ctypes.cast(rv, ctypes.POINTER(ctypes.c_char_p))
return rv
ourfunc = RL_COMPLETION_FUNC_T(our_complete)

_readline = readline.readline
_readline.argtypes = [ctypes.c_char_p]
_readline.restype = ctypes.c_char_p

ctypes.memmove(ctypes.addressof(RL_ATTEMPTED_COMPLETION_FUNCTION),
ctypes.addressof(ourfunc),
4)
line = _readline("Input: ")
print "INPUT was: ", line
#END
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,757
Messages
2,569,543
Members
45,026
Latest member
camilin05

Latest Threads

Top