[Pharo-project] NB How can I pass a NULL argument?
Hello list, I want to call the following C function using NativeBoost: const char* uenum_next(UEnumeration * en, int32_t * resultLength, UErrorCode * status) According to the (icu4c) documentation you can pass NULL for the resultLenth argument [1]. But when I try: self nbCall: #( char* uenum_next_48( self, nil, ICUErrorCodeNB* anErrorCode ) ) module: 'libicuuc.dylib' My image craches. Does anyone know what I'm doing wrong? Jan. [1] http://icu-project.org/apiref/icu4c/uenum_8h.html#a99298eabaa3874cdfd9793b20...
Thanks for the question. Which version do you use? Stef
Hello list,
I want to call the following C function using NativeBoost:
const char* uenum_next(UEnumeration * en, int32_t * resultLength, UErrorCode * status)
According to the (icu4c) documentation you can pass NULL for the resultLenth argument [1]. But when I try:
self nbCall: #( char* uenum_next_48( self, nil, ICUErrorCodeNB* anErrorCode ) ) module: 'libicuuc.dylib'
My image craches. Does anyone know what I'm doing wrong?
Jan.
[1] http://icu-project.org/apiref/icu4c/uenum_8h.html#a99298eabaa3874cdfd9793b20...
Hello Stef, I'm using the latest packages from http://www.squeaksource.com/NativeBoostand Pharo version 1.3 Jan. On Mon, Feb 13, 2012 at 11:12 PM, Stéphane Ducasse < stephane.ducasse@inria.fr> wrote:
Thanks for the question. Which version do you use?
Stef
Hello list,
I want to call the following C function using NativeBoost:
const char* uenum_next(UEnumeration * en, int32_t * resultLength, UErrorCode * status)
According to the (icu4c) documentation you can pass NULL for the resultLenth argument [1]. But when I try:
self nbCall: #( char* uenum_next_48( self, nil, ICUErrorCodeNB* anErrorCode ) ) module: 'libicuuc.dylib'
My image craches. Does anyone know what I'm doing wrong?
Jan.
[1] http://icu-project.org/apiref/icu4c/uenum_8h.html#a99298eabaa3874cdfd9793b20...
On 13 February 2012 22:40, Jan van de Sandt <jvdsandt@gmail.com> wrote:
Hello list,
I want to call the following C function using NativeBoost:
const char* uenum_next(UEnumeration * en, int32_t * resultLength, UErrorCode * status)
According to the (icu4c) documentation you can pass NULL for the resultLenth argument [1]. But when I try:
self nbCall: #( char* uenum_next_48( self, nil, ICUErrorCodeNB* anErrorCode ) ) module: 'libicuuc.dylib'
should be no problem. you can try also to just pass zero, if it make any difference self nbCall: #( char* uenum_next_48( self, 0 , ICUErrorCodeNB* anErrorCode ) ) module: 'libicuuc.dylib' (in fact code generator should produce same code, since nil substituted by 0 at the end). Maybe the problem is not there, but in other arguments you passing. And, i recommend you to use ConfigurationOfNativeBoost from NBInstaller, but not latest packages directly, since Javier put a lot of changes lately and some parts might not work properly.
My image craches. Does anyone know what I'm doing wrong?
Jan.
[1]Â http://icu-project.org/apiref/icu4c/uenum_8h.html#a99298eabaa3874cdfd9793b20...
-- Best regards, Igor Stasenko.
I started with a new image and loaded ConfigurationOfNativeBoost. But it's still not working. First I do a call to get a handle: "UEnumeration* ucal_openTimeZones(UErrorCode * ec)" self nbCall: #( void* ucal_openTimeZones_48( ICUErrorCodeNB* anErrorCode ) ) module: 'libicui18n.dylib' This call succeeds. I store the result in a subclass of NBExternalHandle using the #value: class method. In the second call I want to use the handle to retrieve the next element: self nbCall: #( char* uenum_next_48(ICUEnumerationNB* aHandle, int* nil, ICUErrorCodeNB* anErrorCode ) ) module: 'libicuuc.dylib' But this call still causes the image to disappear. I think the nil and errorCode arguments are all right. Is there something wrong with the first argument? Jan. On Tue, Feb 14, 2012 at 11:34 AM, Igor Stasenko <siguctua@gmail.com> wrote:
On 13 February 2012 22:40, Jan van de Sandt <jvdsandt@gmail.com> wrote:
Hello list,
I want to call the following C function using NativeBoost:
const char* uenum_next(UEnumeration * en, int32_t * resultLength, UErrorCode * status)
According to the (icu4c) documentation you can pass NULL for the resultLenth argument [1]. But when I try:
self nbCall: #( char* uenum_next_48( self, nil, ICUErrorCodeNB* anErrorCode ) ) module: 'libicuuc.dylib'
should be no problem. you can try also to just pass zero, if it make any difference
self nbCall: #( char* uenum_next_48( self, 0 , ICUErrorCodeNB* anErrorCode ) ) module: 'libicuuc.dylib'
(in fact code generator should produce same code, since nil substituted by 0 at the end).
Maybe the problem is not there, but in other arguments you passing.
And, i recommend you to use ConfigurationOfNativeBoost from NBInstaller, but not latest packages directly, since Javier put a lot of changes lately and some parts might not work properly.
My image craches. Does anyone know what I'm doing wrong?
Jan.
[1]
http://icu-project.org/apiref/icu4c/uenum_8h.html#a99298eabaa3874cdfd9793b20...
-- Best regards, Igor Stasenko.
On 14 February 2012 22:59, Jan van de Sandt <jvdsandt@gmail.com> wrote:
I started with a new image and loaded ConfigurationOfNativeBoost. But it's still not working.
First I do a call to get a handle:
"UEnumeration* ucal_openTimeZones(UErrorCode * ec)"
self nbCall: #( void* ucal_openTimeZones_48( ICUErrorCodeNB* anErrorCode ) ) module:Â 'libicui18n.dylib'
This call succeeds. I store the result in a subclass of NBExternalHandle using the #value: class method.
In the second call I want to use the handle to retrieve the next element:
self nbCall: #( char* uenum_next_48(ICUEnumerationNB* aHandle, int* nil, ICUErrorCodeNB* anErrorCode ) ) module:Â 'libicuuc.dylib'
But this call still causes the image to disappear. I think the nil and errorCode arguments are all right. Is there something wrong with the first argument?
I cannot say precisely, because i don't see a code.. so lets see.. UEnumeration* U_EXPORT2 ucal_openTimeZones ( UErrorCode * ec ) returns a pointer. And you storing the pointer value to instance of ICUEnumerationNB Now i guess that next function should take that pointer value: char* uenum_next_48(ICUEnumerationNB aHandle, int* nil, ICUErrorCodeNB* anErrorCode ) but not a pointer to pointer value, like you wrote: char* uenum_next_48(ICUEnumerationNB* aHandle, int* nil, ICUErrorCodeNB* anErrorCode )
Jan.
On Tue, Feb 14, 2012 at 11:34 AM, Igor Stasenko <siguctua@gmail.com> wrote:
On 13 February 2012 22:40, Jan van de Sandt <jvdsandt@gmail.com> wrote:
Hello list,
I want to call the following C function using NativeBoost:
const char* uenum_next(UEnumeration * en, int32_t * resultLength, UErrorCode * status)
According to the (icu4c) documentation you can pass NULL for the resultLenth argument [1]. But when I try:
self nbCall: #( char* uenum_next_48( self, nil, ICUErrorCodeNB* anErrorCode ) ) module: 'libicuuc.dylib'
should be no problem. you can try also to just pass zero, if it make any difference
 self nbCall: #( char* uenum_next_48( self, 0 , ICUErrorCodeNB* anErrorCode ) ) module: 'libicuuc.dylib'
(in fact code generator should produce same code, since nil substituted by 0 at the end).
Maybe the problem is not there, but in other arguments you passing.
And, i recommend you to use ConfigurationOfNativeBoost from NBInstaller, but not latest packages directly, since Javier put a lot of changes lately and some parts might not work properly.
My image craches. Does anyone know what I'm doing wrong?
Jan.
[1]Â http://icu-project.org/apiref/icu4c/uenum_8h.html#a99298eabaa3874cdfd9793b20...
-- Best regards, Igor Stasenko.
-- Best regards, Igor Stasenko.
Hi, Well, it works if I don't use the ICUEnumeration class. The first call returns an NBExternalAddress instance. If I pass this instance to the second call than it works fine. The native call looks like this: self nbCall: #( char* uenum_next_48(void* aHandle, nil, ICUErrorCodeNB* anErrorCode ) ) My idea was to use a subclass of NBExternalHandle where I can put all the functions related to this handle. But it stops working when I copy the value from the ExternalAddress to my handle subclass ICUEnumerationNB and use one of these calls: self nbCall: #( char* uenum_next_48(ICUEnumerationNB* aHandle, nil, ICUErrorCodeNB* anErrorCode ) ) or self nbCall: #( char* uenum_next_48(ICUEnumerationNB aHandle, nil, ICUErrorCodeNB* anErrorCode ) ) Jan. On Tue, Feb 14, 2012 at 10:10 PM, Igor Stasenko <siguctua@gmail.com> wrote:
On 14 February 2012 22:59, Jan van de Sandt <jvdsandt@gmail.com> wrote:
I started with a new image and loaded ConfigurationOfNativeBoost. But it's still not working.
First I do a call to get a handle:
"UEnumeration* ucal_openTimeZones(UErrorCode * ec)"
self nbCall: #( void* ucal_openTimeZones_48( ICUErrorCodeNB* anErrorCode ) ) module: 'libicui18n.dylib'
This call succeeds. I store the result in a subclass of NBExternalHandle using the #value: class method.
In the second call I want to use the handle to retrieve the next element:
self nbCall: #( char* uenum_next_48(ICUEnumerationNB* aHandle, int* nil, ICUErrorCodeNB* anErrorCode ) ) module: 'libicuuc.dylib'
But this call still causes the image to disappear. I think the nil and errorCode arguments are all right. Is there something wrong with the first argument?
I cannot say precisely, because i don't see a code.. so lets see..
UEnumeration* U_EXPORT2 ucal_openTimeZones ( UErrorCode * ec )
returns a pointer. And you storing the pointer value to instance of ICUEnumerationNB
Now i guess that next function should take that pointer value:
char* uenum_next_48(ICUEnumerationNB aHandle, int* nil, ICUErrorCodeNB* anErrorCode )
but not a pointer to pointer value, like you wrote:
char* uenum_next_48(ICUEnumerationNB* aHandle, int* nil, ICUErrorCodeNB* anErrorCode )
Jan.
On Tue, Feb 14, 2012 at 11:34 AM, Igor Stasenko <siguctua@gmail.com>
wrote:
On 13 February 2012 22:40, Jan van de Sandt <jvdsandt@gmail.com> wrote:
Hello list,
I want to call the following C function using NativeBoost:
const char* uenum_next(UEnumeration * en, int32_t * resultLength, UErrorCode * status)
According to the (icu4c) documentation you can pass NULL for the resultLenth argument [1]. But when I try:
self nbCall: #( char* uenum_next_48( self, nil, ICUErrorCodeNB* anErrorCode ) ) module: 'libicuuc.dylib'
should be no problem. you can try also to just pass zero, if it make any difference
self nbCall: #( char* uenum_next_48( self, 0 , ICUErrorCodeNB* anErrorCode ) ) module: 'libicuuc.dylib'
(in fact code generator should produce same code, since nil substituted by 0 at the end).
Maybe the problem is not there, but in other arguments you passing.
And, i recommend you to use ConfigurationOfNativeBoost from NBInstaller, but not latest packages directly, since Javier put a lot of changes lately and some parts might not work properly.
My image craches. Does anyone know what I'm doing wrong?
Jan.
[1]
http://icu-project.org/apiref/icu4c/uenum_8h.html#a99298eabaa3874cdfd9793b20...
-- Best regards, Igor Stasenko.
-- Best regards, Igor Stasenko.
On 24 February 2012 12:10, Jan van de Sandt <jvdsandt@gmail.com> wrote:
Hi,
Well, it works if I don't use the ICUEnumeration class. The first call returns an NBExternalAddress instance. If I pass this instance to the second call than it works fine. The native call looks like this:
self nbCall: #( char* uenum_next_48(void* aHandle, nil, ICUErrorCodeNB* anErrorCode ) )
My idea was to use a subclass of NBExternalHandle where I can put all the functions related to this handle. But it stops working when I copy the value from the ExternalAddress to my handle subclass ICUEnumerationNB and use one of these calls:
self nbCall: #( char* uenum_next_48(ICUEnumerationNB* aHandle, nil, ICUErrorCodeNB* anErrorCode ) )
or
self nbCall: #( char* uenum_next_48(ICUEnumerationNB aHandle, nil, ICUErrorCodeNB* anErrorCode ) )
Since NBExternalHandle is variable byte class, if you pass a pointer to it, like ICUEnumerationNB* then FFI will push a pointer to the first indexable byte in ICUEnumerationNB instance, but not the value of handle stored in this instance. In your case, you stored UEnumeration*, but then you pushing UEnumeration**, while function expects UEnumeration*. It is hard to say, why "ICUEnumerationNB aHandle" doesn't works for you without looking at code, especially that NBExternalAddress is a subclass of NBExternalHandle. You can try the following: Since both functions working with same type (UEnumeration*) , you can actually treat it as if you would have typedef UEnumeration* ICUEnumerationNB; in C. So, then just remove '*' everywhere (in function which returns it, and in functions where you passing it as argument): self nbCall: #( ICUEnumerationNB ucal_openTimeZones_48( ICUErrorCodeNB* anErrorCode ) ) and: self nbCall: #( char* uenum_next_48(ICUEnumerationNB aHandle, nil, ICUErrorCodeNB* anErrorCode ) ) that should work fine, unless that library doing something strange (which also might be the case ;). P.S. originally, i intentionally raising an error when you passing a pointer to NBExternalAddress or Handle types (so is allows to pass a just a value, but not a pointer to the value) to prevent mistakes like that. But some functions actually wanting to get a pointer to the pointer (like int** etc), so then they can store a pointer at that pointer, and i was added that, because it is convenient. P.P.S Yo dawg, i put a pointer to that pointer so you can point to what it points ;) -- Best regards, Igor Stasenko.
Thanks for the explanation, it starts to make sense to me now. But when I change the return type of the first call from "void*" to ICUEnumerationNB I end up here: NBExternalStructureType>>coerceReturn: gen " ... should we support handling return of external structures? " self error: 'returning pointer to structure?' The problem is not so urgent for me anymore because I can work around it using just NBExternalAddress instances. But off course I'm still curious to know what's the best way to handle these kind of native calls. Jan. PS: The code is in http://www.squeaksource.com/ICU.html ICUCalendarNB>># nbTestAllTimeZones On Fri, Feb 24, 2012 at 2:35 PM, Igor Stasenko <siguctua@gmail.com> wrote:
On 24 February 2012 12:10, Jan van de Sandt <jvdsandt@gmail.com> wrote:
Hi,
Well, it works if I don't use the ICUEnumeration class. The first call returns an NBExternalAddress instance. If I pass this instance to the second call than it works fine. The native call looks like this:
self nbCall: #( char* uenum_next_48(void* aHandle, nil, ICUErrorCodeNB* anErrorCode ) )
My idea was to use a subclass of NBExternalHandle where I can put all the functions related to this handle. But it stops working when I copy the value from the ExternalAddress to my handle subclass ICUEnumerationNB and use one of these calls:
self nbCall: #( char* uenum_next_48(ICUEnumerationNB* aHandle, nil, ICUErrorCodeNB* anErrorCode ) )
or
self nbCall: #( char* uenum_next_48(ICUEnumerationNB aHandle, nil, ICUErrorCodeNB* anErrorCode ) )
Since NBExternalHandle is variable byte class, if you pass a pointer to it, like ICUEnumerationNB* then FFI will push a pointer to the first indexable byte in ICUEnumerationNB instance, but not the value of handle stored in this instance. In your case, you stored UEnumeration*, but then you pushing UEnumeration**, while function expects UEnumeration*.
It is hard to say, why "ICUEnumerationNB aHandle" doesn't works for you without looking at code, especially that NBExternalAddress is a subclass of NBExternalHandle.
You can try the following:
Since both functions working with same type (UEnumeration*) , you can actually treat it as if you would have
typedef UEnumeration* ICUEnumerationNB; in C.
So, then just remove '*' everywhere (in function which returns it, and in functions where you passing it as argument):
self nbCall: #( ICUEnumerationNB ucal_openTimeZones_48( ICUErrorCodeNB* anErrorCode ) )
and: self nbCall: #( char* uenum_next_48(ICUEnumerationNB aHandle, nil, ICUErrorCodeNB* anErrorCode ) )
that should work fine, unless that library doing something strange (which also might be the case ;).
P.S. originally, i intentionally raising an error when you passing a pointer to NBExternalAddress or Handle types (so is allows to pass a just a value, but not a pointer to the value) to prevent mistakes like that. But some functions actually wanting to get a pointer to the pointer (like int** etc), so then they can store a pointer at that pointer, and i was added that, because it is convenient.
P.P.S Yo dawg, i put a pointer to that pointer so you can point to what it points ;)
-- Best regards, Igor Stasenko.
On 24 February 2012 15:02, Jan van de Sandt <jvdsandt@gmail.com> wrote:
Thanks for the explanation, it starts to make sense to me now. But when I change the return type of the first call from "void*" to ICUEnumerationNB I end up here:
NBExternalStructureType>>coerceReturn: gen
" ... should we support handling return of external structures? " self error: 'returning pointer to structure?'
This happens when you putting a pointer to struct as return value in function signature, which means that you doing something wrong, or modified code in different place. What i see (in ICU-NativeBoost-Core-jvds.3) is following : nbTestprimOpenTimeZones: anErrorCode <primitive: #primitiveNativeCall module: #NativeBoostPlugin> ^ self nbCall: #( ICUEnumerationNB___>>>>_*__<<<< remove it___ ucal_openTimeZones_48( ICUErrorCodeNB* anErrorCode ) ) and once you will do that, the error you see will go away. but i cannot call the function since i don't have the corresponding library on my machine, have binaries somewhere for download?.
The problem is not so urgent for me anymore because I can work around it using just NBExternalAddress instances. But off course I'm still curious to know what's the best way to handle these kind of native calls.
I takes time to get used to it. I know by myself that interfacing with C is confusing, especially when dealing with pointers.
Jan.
PS: The code is in http://www.squeaksource.com/ICU.html  ICUCalendarNB>>#nbTestAllTimeZones
On Fri, Feb 24, 2012 at 2:35 PM, Igor Stasenko <siguctua@gmail.com> wrote:
On 24 February 2012 12:10, Jan van de Sandt <jvdsandt@gmail.com> wrote:
Hi,
Well, it works if I don't use the ICUEnumeration class. The first call returns an NBExternalAddress instance. If I pass this instance to the second call than it works fine. The native call looks like this:
self nbCall: #( char* uenum_next_48(void* aHandle, nil, ICUErrorCodeNB* anErrorCode ) )
My idea was to use a subclass of NBExternalHandle where I can put all the functions related to this handle. But it stops working when I copy the value from the ExternalAddress to my handle subclass ICUEnumerationNB and use one of these calls:
self nbCall: #( char* uenum_next_48(ICUEnumerationNB* aHandle, nil, ICUErrorCodeNB* anErrorCode ) )
or
self nbCall: #( char* uenum_next_48(ICUEnumerationNB aHandle, nil, ICUErrorCodeNB* anErrorCode ) )
Since NBExternalHandle is variable byte class, if you pass a pointer to it, like ICUEnumerationNB* then FFI will push a pointer to the first indexable byte in ICUEnumerationNB instance, but not the value of handle stored in this instance. In your case, you stored UEnumeration*, but then you pushing UEnumeration**, while function expects UEnumeration*.
It is hard to say, why "ICUEnumerationNB aHandle" doesn't works for you without looking at code, especially that NBExternalAddress is a subclass of NBExternalHandle.
You can try the following:
Since both functions working with same type (UEnumeration*) , Â you can actually treat it as if you would have
typedef UEnumeration* ICUEnumerationNB; in C.
So, then just remove '*' everywhere (in function which returns it, and in functions where you passing it as argument):
self nbCall: #( ICUEnumerationNB ucal_openTimeZones_48( ICUErrorCodeNB* anErrorCode ) )
and: self nbCall: #( char* uenum_next_48(ICUEnumerationNB aHandle, nil, ICUErrorCodeNB* anErrorCode ) )
that should work fine, unless that library doing something strange (which also might be the case ;).
P.S. originally, i intentionally raising an error when you passing a pointer to NBExternalAddress or Handle types (so is allows to pass a just a value, but not a pointer to the value) to prevent mistakes like that. But some functions actually wanting to get a pointer to the pointer (like int** etc), so then they can store a pointer at that pointer, and i was added that, because it is convenient.
P.P.S Yo dawg, i put a pointer to that pointer so you can point to what it points ;)
-- Best regards, Igor Stasenko.
-- Best regards, Igor Stasenko.
And one more thing which i missed initially: ICUEnumerationNB is a subclass of NBExternalHandle. This class was actually done for holding a handle but not interact directly with marchalling types, and subclassing from it makes little sense actually unless you override #asNBExternalType: on class side. For this purpose there is NBExternalObject. So, i recommend you to change ICUEnumerationNB to be a subclass of NBExternalObject. The instances of NBExternalObject holding a handle in 1st inst var, and you free to add more ivars if you like (opposite to NBExternalHandle where you can't because it is a varbyte class). -- Best regards, Igor Stasenko.
Ah Yes!! After changing the superclass it works perfectly. Thank you very much Igor! Jan. PS: ICU binaries can be downloaded from http://apps.icu-project.org/icu-jsp/downloadPage.jsp?ver=4.8.1&base=cUnfortu... no binary downloads for OSX and making a 32 bit version for Lion is a bit of a hassle. If you want I can mail the binaries. On Fri, Feb 24, 2012 at 4:23 PM, Igor Stasenko <siguctua@gmail.com> wrote:
And one more thing which i missed initially: ICUEnumerationNB is a subclass of NBExternalHandle.
This class was actually done for holding a handle but not interact directly with marchalling types, and subclassing from it makes little sense actually unless you override #asNBExternalType: on class side.
For this purpose there is NBExternalObject. So, i recommend you to change ICUEnumerationNB to be a subclass of NBExternalObject. The instances of NBExternalObject holding a handle in 1st inst var, and you free to add more ivars if you like (opposite to NBExternalHandle where you can't because it is a varbyte class).
-- Best regards, Igor Stasenko.
On 24 February 2012 16:44, Jan van de Sandt <jvdsandt@gmail.com> wrote:
Ah Yes!! After changing the superclass it works perfectly. Thank you very much Igor!
Thanks for feedback. Now i know what to do to prevent such mistakes. I will add class comment and override #asNBExternalType: to raise an error telling users that they should use NBExternalObject instead , or otherwise override #asNBExternalType: like NBExternalAddress does.
Jan.
PS: ICU binaries can be downloaded from http://apps.icu-project.org/icu-jsp/downloadPage.jsp?ver=4.8.1&base=c Unfortunately no binary downloads for OSX and making a 32 bit version for Lion is a bit of a hassle. If you want I can mail the binaries.
If you will have more issues. :) -- Best regards, Igor Stasenko.
participants (3)
-
Igor Stasenko -
Jan van de Sandt -
Stéphane Ducasse