pharo-users@lists.pharo.org

Any question about pharo is welcome

View all threads

Re: uFFI provide buffer to C

TT
Tomaž Turk
Sun, Nov 28, 2021 5:39 PM

Hi,

try with this:

FFITutorial>>getHostNameInto: hostName ofLenght: length
^self ffiCall: #( int gethostname(char *hostName, int length) )
library: 'Ws2_32.dll'. "... on Windows"

From Playground, you can then do:

| name len |
len := 50.
name:= ByteArray new: len.
FFITutorial new getHostNameInto: name ofLenght: len.
name inspect.

I hope this helps.

Best wishes,
Tomaz

Hi, try with this: FFITutorial>>getHostNameInto: hostName ofLenght: length ^self ffiCall: #( int gethostname(char *hostName, int length) ) library: 'Ws2_32.dll'. "... on Windows" From Playground, you can then do: | name len | len := 50. name:= ByteArray new: len. FFITutorial new getHostNameInto: name ofLenght: len. name inspect. I hope this helps. Best wishes, Tomaz
GW
Gerry Weaver
Sun, Nov 28, 2021 11:56 PM

Hi,

Thanks for the example. Unfortunately, it doesn't work on Linux.

Thanks,
Gerry


From: Tomaž Turk tomaz.turk@ef.uni-lj.si
Sent: Sunday, November 28, 2021 11:39 AM
To: Any question about pharo is welcome pharo-users@lists.pharo.org
Subject: [Pharo-users] Re: uFFI provide buffer to C

Hi,

try with this:

FFITutorial>>getHostNameInto: hostName ofLenght: length
^self ffiCall: #( int gethostname(char *hostName, int length) ) library: 'Ws2_32.dll'. "... on Windows"

From Playground, you can then do:

| name len |
len := 50.
name:= ByteArray new: len.
FFITutorial new getHostNameInto: name ofLenght: len.
name inspect.

I hope this helps.

Best wishes,
Tomaz

Hi, Thanks for the example. Unfortunately, it doesn't work on Linux. Thanks, Gerry ________________________________ From: Tomaž Turk <tomaz.turk@ef.uni-lj.si> Sent: Sunday, November 28, 2021 11:39 AM To: Any question about pharo is welcome <pharo-users@lists.pharo.org> Subject: [Pharo-users] Re: uFFI provide buffer to C Hi, try with this: FFITutorial>>getHostNameInto: hostName ofLenght: length ^self ffiCall: #( int gethostname(char *hostName, int length) ) library: 'Ws2_32.dll'. "... on Windows" From Playground, you can then do: | name len | len := 50. name:= ByteArray new: len. FFITutorial new getHostNameInto: name ofLenght: len. name inspect. I hope this helps. Best wishes, Tomaz
GP
Guillermo Polito
Mon, Nov 29, 2021 9:10 AM

Hi Gerry,

I think the point of Tomaz is that an FFI method can only have a single #ffiCall: statement.
In your example, what you can do is to split your method in two methods:

First a method with the mapping (following the idea of Tomaz but using libc)

FFITutorial>>getHostNameInto: hostName ofLenght: length

 ^self ffiCall: #( int gethostname(char *hostName, int length) ) library: 'libc.so.6'. 

And then have a second method that calls this one:

FFITutorial>>getHostName

   | nameBuffer |      

nameBuffer := ByteArray new: 256.

self getHostNameInto: nameBuffer ofLenght: 256.

^nameBuffer asString

Notice that converting the byte array buffer to string will only work by chance if the called function returns characters encoded in ascii.
In Pharo strings are Unicode characters where each character is a unicode code-point.
The best thing is to read the documentation of the library and check the encoding of the string that is put in the buffer to decode it accordingly, for example from utf8.

G

El 29 nov 2021, a las 0:56, Gerry Weaver gerryw@compvia.com escribió:

Hi,

Thanks for the example. Unfortunately, it doesn't work on Linux.

Thanks,
Gerry

From: Tomaž Turk tomaz.turk@ef.uni-lj.si
Sent: Sunday, November 28, 2021 11:39 AM
To: Any question about pharo is welcome pharo-users@lists.pharo.org
Subject: [Pharo-users] Re: uFFI provide buffer to C

Hi,

try with this:

FFITutorial>>getHostNameInto: hostName ofLenght: length
^self ffiCall: #( int gethostname(char *hostName, int length) ) library: 'Ws2_32.dll'. "... on Windows"

From Playground, you can then do:

| name len |
len := 50.
name:= ByteArray new: len.
FFITutorial new getHostNameInto: name ofLenght: len.
name inspect.

I hope this helps.

Best wishes,
Tomaz

Hi Gerry, I think the point of Tomaz is that an FFI method can only have a single #ffiCall: statement. In your example, what you can do is to split your method in two methods: First a method with the mapping (following the idea of Tomaz but using libc) FFITutorial>>getHostNameInto: hostName ofLenght: length > ^self ffiCall: #( int gethostname(char *hostName, int length) ) library: 'libc.so.6'. And then have a second method that calls this one: FFITutorial>>getHostName | nameBuffer | nameBuffer := ByteArray new: 256. self getHostNameInto: nameBuffer ofLenght: 256. ^nameBuffer asString Notice that converting the byte array buffer to string will only work by chance if the called function returns characters encoded in ascii. In Pharo strings are Unicode characters where each character is a unicode code-point. The best thing is to read the documentation of the library and check the encoding of the string that is put in the buffer to decode it accordingly, for example from utf8. G > El 29 nov 2021, a las 0:56, Gerry Weaver <gerryw@compvia.com> escribió: > > Hi, > > Thanks for the example. Unfortunately, it doesn't work on Linux. > > Thanks, > Gerry > > > From: Tomaž Turk <tomaz.turk@ef.uni-lj.si> > Sent: Sunday, November 28, 2021 11:39 AM > To: Any question about pharo is welcome <pharo-users@lists.pharo.org> > Subject: [Pharo-users] Re: uFFI provide buffer to C > > Hi, > > try with this: > > FFITutorial>>getHostNameInto: hostName ofLenght: length > ^self ffiCall: #( int gethostname(char *hostName, int length) ) library: 'Ws2_32.dll'. "... on Windows" > > From Playground, you can then do: > > | name len | > len := 50. > name:= ByteArray new: len. > FFITutorial new getHostNameInto: name ofLenght: len. > name inspect. > > I hope this helps. > > Best wishes, > Tomaz
SV
Sven Van Caekenberghe
Mon, Nov 29, 2021 9:29 AM

On 29 Nov 2021, at 10:10, Guillermo Polito guillermopolito@gmail.com wrote:

Hi Gerry,

I think the point of Tomaz is that an FFI method can only have a single #ffiCall: statement.
In your example, what you can do is to split your method in two methods:

First a method with the mapping (following the idea of Tomaz but using libc)

FFITutorial>>getHostNameInto: hostName ofLenght: length

 ^self ffiCall: #( int gethostname(char *hostName, int length) ) library: 'libc.so.6'. 

And then have a second method that calls this one:

FFITutorial>>getHostName

    | nameBuffer |      

nameBuffer := ByteArray new: 256.

self getHostNameInto: nameBuffer ofLenght: 256.

^nameBuffer asString

Notice that converting the byte array buffer to string will only work by chance if the called function returns characters encoded in ascii.
In Pharo strings are Unicode characters where each character is a unicode code-point.

In general #utf8Decoded is better than #asString since UTF-8 includes 7-bit ASCII. It will fail when the native encoding is one of the simpler byte encodings, like Latin1 (or iso-8859-1), though.

The best thing is to read the documentation of the library and check the encoding of the string that is put in the buffer to decode it accordingly, for example from utf8.

G

El 29 nov 2021, a las 0:56, Gerry Weaver gerryw@compvia.com escribió:

Hi,

Thanks for the example. Unfortunately, it doesn't work on Linux.

Thanks,
Gerry

From: Tomaž Turk tomaz.turk@ef.uni-lj.si
Sent: Sunday, November 28, 2021 11:39 AM
To: Any question about pharo is welcome pharo-users@lists.pharo.org
Subject: [Pharo-users] Re: uFFI provide buffer to C

Hi,

try with this:

FFITutorial>>getHostNameInto: hostName ofLenght: length
^self ffiCall: #( int gethostname(char *hostName, int length) ) library: 'Ws2_32.dll'. "... on Windows"

From Playground, you can then do:

| name len |
len := 50.
name:= ByteArray new: len.
FFITutorial new getHostNameInto: name ofLenght: len.
name inspect.

I hope this helps.

Best wishes,
Tomaz

> On 29 Nov 2021, at 10:10, Guillermo Polito <guillermopolito@gmail.com> wrote: > > Hi Gerry, > > I think the point of Tomaz is that an FFI method can only have a single #ffiCall: statement. > In your example, what you can do is to split your method in two methods: > > First a method with the mapping (following the idea of Tomaz but using libc) > > FFITutorial>>getHostNameInto: hostName ofLenght: length >> ^self ffiCall: #( int gethostname(char *hostName, int length) ) library: 'libc.so.6'. > > And then have a second method that calls this one: > > FFITutorial>>getHostName > > | nameBuffer | > > nameBuffer := ByteArray new: 256. > > self getHostNameInto: nameBuffer ofLenght: 256. > > ^nameBuffer asString > > Notice that converting the byte array buffer to string will only work by chance if the called function returns characters encoded in ascii. > In Pharo strings are Unicode characters where each character is a unicode code-point. In general #utf8Decoded is better than #asString since UTF-8 includes 7-bit ASCII. It will fail when the native encoding is one of the simpler byte encodings, like Latin1 (or iso-8859-1), though. > The best thing is to read the documentation of the library and check the encoding of the string that is put in the buffer to decode it accordingly, for example from utf8. > > G > > >> El 29 nov 2021, a las 0:56, Gerry Weaver <gerryw@compvia.com> escribió: >> >> Hi, >> >> Thanks for the example. Unfortunately, it doesn't work on Linux. >> >> Thanks, >> Gerry >> >> >> From: Tomaž Turk <tomaz.turk@ef.uni-lj.si> >> Sent: Sunday, November 28, 2021 11:39 AM >> To: Any question about pharo is welcome <pharo-users@lists.pharo.org> >> Subject: [Pharo-users] Re: uFFI provide buffer to C >> >> Hi, >> >> try with this: >> >> FFITutorial>>getHostNameInto: hostName ofLenght: length >> ^self ffiCall: #( int gethostname(char *hostName, int length) ) library: 'Ws2_32.dll'. "... on Windows" >> >> From Playground, you can then do: >> >> | name len | >> len := 50. >> name:= ByteArray new: len. >> FFITutorial new getHostNameInto: name ofLenght: len. >> name inspect. >> >> I hope this helps. >> >> Best wishes, >> Tomaz >
GW
Gerry Weaver
Mon, Nov 29, 2021 4:13 PM

Hi Guillermo,

Ah ok. I didn’t realize that I could only have a single statement. I got it working now.

Thanks to you and everyone that helped me out.

Thanks,
Gerry

Gerry Weaver
(800) 318-6118

From: Guillermo Polito guillermopolito@gmail.com
Sent: Monday, November 29, 2021 3:11 AM
To: Any question about pharo is welcome pharo-users@lists.pharo.org
Subject: [Pharo-users] Re: uFFI provide buffer to C

Hi Gerry,

I think the point of Tomaz is that an FFI method can only have a single #ffiCall: statement.
In your example, what you can do is to split your method in two methods:

First a method with the mapping (following the idea of Tomaz but using libc)

FFITutorial>>getHostNameInto: hostName ofLenght: length
^self ffiCall: #( int gethostname(char *hostName, int length) ) library: 'libc.so.6'.

And then have a second method that calls this one:

FFITutorial>>getHostName

   | nameBuffer |

nameBuffer := ByteArray new: 256.

self getHostNameInto: nameBuffer ofLenght: 256.

^nameBuffer asString

Notice that converting the byte array buffer to string will only work by chance if the called function returns characters encoded in ascii.
In Pharo strings are Unicode characters where each character is a unicode code-point.
The best thing is to read the documentation of the library and check the encoding of the string that is put in the buffer to decode it accordingly, for example from utf8.

G

El 29 nov 2021, a las 0:56, Gerry Weaver <gerryw@compvia.commailto:gerryw@compvia.com> escribió:

Hi,

Thanks for the example. Unfortunately, it doesn't work on Linux.

Thanks,
Gerry


From: Tomaž Turk <tomaz.turk@ef.uni-lj.simailto:tomaz.turk@ef.uni-lj.si>
Sent: Sunday, November 28, 2021 11:39 AM
To: Any question about pharo is welcome <pharo-users@lists.pharo.orgmailto:pharo-users@lists.pharo.org>
Subject: [Pharo-users] Re: uFFI provide buffer to C

Hi,

try with this:

FFITutorial>>getHostNameInto: hostName ofLenght: length
^self ffiCall: #( int gethostname(char *hostName, int length) ) library: 'Ws2_32.dll'. "... on Windows"

From Playground, you can then do:

| name len |
len := 50.
name:= ByteArray new: len.
FFITutorial new getHostNameInto: name ofLenght: len.
name inspect.

I hope this helps.

Best wishes,
Tomaz

Hi Guillermo, Ah ok. I didn’t realize that I could only have a single statement. I got it working now. Thanks to you and everyone that helped me out. Thanks, Gerry Gerry Weaver (800) 318-6118 From: Guillermo Polito <guillermopolito@gmail.com> Sent: Monday, November 29, 2021 3:11 AM To: Any question about pharo is welcome <pharo-users@lists.pharo.org> Subject: [Pharo-users] Re: uFFI provide buffer to C Hi Gerry, I think the point of Tomaz is that an FFI method can only have a single #ffiCall: statement. In your example, what you can do is to split your method in two methods: First a method with the mapping (following the idea of Tomaz but using libc) FFITutorial>>getHostNameInto: hostName ofLenght: length ^self ffiCall: #( int gethostname(char *hostName, int length) ) library: 'libc.so.6'. And then have a second method that calls this one: FFITutorial>>getHostName | nameBuffer | nameBuffer := ByteArray new: 256. self getHostNameInto: nameBuffer ofLenght: 256. ^nameBuffer asString Notice that converting the byte array buffer to string will only work by chance if the called function returns characters encoded in ascii. In Pharo strings are Unicode characters where each character is a unicode code-point. The best thing is to read the documentation of the library and check the encoding of the string that is put in the buffer to decode it accordingly, for example from utf8. G El 29 nov 2021, a las 0:56, Gerry Weaver <gerryw@compvia.com<mailto:gerryw@compvia.com>> escribió: Hi, Thanks for the example. Unfortunately, it doesn't work on Linux. Thanks, Gerry ________________________________ From: Tomaž Turk <tomaz.turk@ef.uni-lj.si<mailto:tomaz.turk@ef.uni-lj.si>> Sent: Sunday, November 28, 2021 11:39 AM To: Any question about pharo is welcome <pharo-users@lists.pharo.org<mailto:pharo-users@lists.pharo.org>> Subject: [Pharo-users] Re: uFFI provide buffer to C Hi, try with this: FFITutorial>>getHostNameInto: hostName ofLenght: length ^self ffiCall: #( int gethostname(char *hostName, int length) ) library: 'Ws2_32.dll'. "... on Windows" From Playground, you can then do: | name len | len := 50. name:= ByteArray new: len. FFITutorial new getHostNameInto: name ofLenght: len. name inspect. I hope this helps. Best wishes, Tomaz