comp.lang.ada
 help / color / mirror / Atom feed
* Byte streams
@ 2007-08-02 19:21 shaunpatterson
  2007-08-02 20:18 ` Gautier
                   ` (2 more replies)
  0 siblings, 3 replies; 9+ messages in thread
From: shaunpatterson @ 2007-08-02 19:21 UTC (permalink / raw)


You guys have been a great help lately.  Perhaps a few more of my
questions could be answered...

I've written a socket functions to send and receive data in C and then
created a spec in Ada so I could use those same functions:

-- C functions --

unsigned char *readBytes (const unsigned int numBytes);
void sendBytes (unsigned char *data, const unsigned int numBytes);


--- Ada side
type Byte is mod 256;
for Byte'Size use 8;

type ByteStream is array (Integer range <>) of Byte;


function readBytes (numBytes : Integer) return System.Address;
pragma import (C, readBytes, "readBytes");

procedure sendBytes (data : ByteStream; numBytes : Integer);
pragma import (C, sendBytes, "sendBytes");


-------------

Now I'm not sure if I'm doing the function prototypes correctly
in Ada.  I've actually gotten receiving to work correctly.

I'm having some trouble converting the byte stream to a structure
(I actually have this working... although I'm SURE there is a
better way) and then converting a structure to a byte stream


BYTESTREAM to STRUCTURE:

        type TestStructure is record
                value : Integer;
        end record;

-- data is read off the socket successfully
        function create (data : System.Address) is
                return TestStructure

                type IntegerPtr is access all Integer;
                function to_IntegerPtr is new Unchecked_Conversion
                      (source => System.Address, target =>
IntegerPtr);

                testData : IntegerPtr := to_IntegerPtr (data)

                intValue : Integer := msgData.all;
        begin
                return TestStructure'(value => intValue);
        end;


--- this works...and I can do all the conversions I need using an
unchecked_conversion

However, I cannot seem to figure out how to send data correctly.

consider:

type AnotherStructure is record
    a : Integer;
    b : Integer;
    c : Integer;
end Record;

How would I go about converting to a byte stream to send it
along to the socket sendBytes function?

Again, I'm not sure if I rewrote the spec correctly in Ada.


I have tried something like:

toByteStream is new Unchecked_Conversion
    (source => AnotherStructure, Target => ByteStream);

however ByteStream is unconstrained...

Any suggestions?

Thanks so much
--
Shaun




^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: Byte streams
  2007-08-02 19:21 Byte streams shaunpatterson
@ 2007-08-02 20:18 ` Gautier
  2007-08-02 20:27 ` tmoran
  2007-08-03  5:34 ` Jeffrey R. Carter
  2 siblings, 0 replies; 9+ messages in thread
From: Gautier @ 2007-08-02 20:18 UTC (permalink / raw)


You seem to bump against the "strong-typing vs. mixed data stream" issue that 
Ada 95 (and later) solves with Ada.Streams. No need to define i/o for every 
type, no need of unchecked_conversion; and unconstrained types are also 
supported iirc.
Look at the 'Read, 'Write, 'Input, 'Output ( a bit of search gives... 
http://www.adaic.com/standards/95lrm/html/RM-13-13-2.html )

Here is an example of a custom input stream, from a zip file:

http://homepage.sunrise.ch/mysunrise/gdm/uza_html/test_unz_streams__adb.htm

Maybe you are looking at something else, but I have the impression that you'll 
like these streams...
HTH
______________________________________________________________
Gautier         -- http://www.mysunrise.ch/users/gdm/index.htm
Ada programming -- http://www.mysunrise.ch/users/gdm/gsoft.htm

NB: For a direct answer, e-mail address on the Web site!



^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: Byte streams
  2007-08-02 19:21 Byte streams shaunpatterson
  2007-08-02 20:18 ` Gautier
@ 2007-08-02 20:27 ` tmoran
  2007-08-02 21:44   ` Robert A Duff
  2007-08-03  5:34 ` Jeffrey R. Carter
  2 siblings, 1 reply; 9+ messages in thread
From: tmoran @ 2007-08-02 20:27 UTC (permalink / raw)


> type AnotherStructure is record
>     a : Integer;
>     b : Integer;
>     c : Integer;
> end Record;
>
> toByteStream is new Unchecked_Conversion
>     (source => AnotherStructure, Target => ByteStream);
>
> however ByteStream is unconstrained...
>
> Any suggestions?

   1) Either use, or look at the source code of, one or more of the
      multiple Ada socket implementations available on the internet.

   2) Assuming Integer is 4 bytes,
      subtype External_AnotherStructure is Bytestream(1 .. 12);
      toByteStream is new Unchecked_Conversion
          (source => AnotherStructure, Target => External_AnotherStructure);

   3) If you send AnotherStructure a lot, and assuming Integer is 4 bytes,
      procedure send_AnotherStructure (data : AnotherStructure;
                                       numBytes : Integer => 12);
      pragma import (C, send_AnotherStructure, "sendBytes");



^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: Byte streams
  2007-08-02 20:27 ` tmoran
@ 2007-08-02 21:44   ` Robert A Duff
  2007-08-02 22:45     ` tmoran
  0 siblings, 1 reply; 9+ messages in thread
From: Robert A Duff @ 2007-08-02 21:44 UTC (permalink / raw)


tmoran@acm.org writes:

>    1) Either use, or look at the source code of, one or more of the
>       multiple Ada socket implementations available on the internet.

Why not use GNAT.Sockets, which comes with GNAT?

- Bob



^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: Byte streams
  2007-08-02 21:44   ` Robert A Duff
@ 2007-08-02 22:45     ` tmoran
  2007-08-02 22:54       ` shaunpatterson
  0 siblings, 1 reply; 9+ messages in thread
From: tmoran @ 2007-08-02 22:45 UTC (permalink / raw)


> >    1) Either use, or look at the source code of, one or more of the
> >       multiple Ada socket implementations available on the internet.
>
> Why not use GNAT.Sockets, which comes with GNAT?
>
> - Bob

   Or Claw.Sockets, which comes with Claw and is compiler independent. ;)
But I presume the OP is interested in learning about interfacing Ada to
C, more than he is interested in building an app using sockets, so he
really ought to look at several ways different people have approached
the job.



^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: Byte streams
  2007-08-02 22:45     ` tmoran
@ 2007-08-02 22:54       ` shaunpatterson
  0 siblings, 0 replies; 9+ messages in thread
From: shaunpatterson @ 2007-08-02 22:54 UTC (permalink / raw)


Well... I already had the socket stuff written in C.  I was hoping
it would be easy to just link it with Ada and convert the types
into byte streams.  I think I'll keep my C interface and just
use streams (hopefully...)

Thanks
--
Shaun




^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: Byte streams
  2007-08-02 19:21 Byte streams shaunpatterson
  2007-08-02 20:18 ` Gautier
  2007-08-02 20:27 ` tmoran
@ 2007-08-03  5:34 ` Jeffrey R. Carter
  2007-08-03 13:15   ` shaunpatterson
  2 siblings, 1 reply; 9+ messages in thread
From: Jeffrey R. Carter @ 2007-08-03  5:34 UTC (permalink / raw)


shaunpatterson@gmail.com wrote:
> 
> I've written a socket functions to send and receive data in C and then
> created a spec in Ada so I could use those same functions:
> 
> -- C functions --
> 
> unsigned char *readBytes (const unsigned int numBytes);
> void sendBytes (unsigned char *data, const unsigned int numBytes);
> 
> 
> --- Ada side
> type Byte is mod 256;
> for Byte'Size use 8;
> 
> type ByteStream is array (Integer range <>) of Byte;
> 
> 
> function readBytes (numBytes : Integer) return System.Address;
> pragma import (C, readBytes, "readBytes");

Integer? What would Readbytes (-7) mean?

> procedure sendBytes (data : ByteStream; numBytes : Integer);
> pragma import (C, sendBytes, "sendBytes");

For a direct translation, you should use the types in Interfaces.C and 
Interfaces.C.Strings (ARM B.3[.1]):

function Read_Bytes (Num_Bytes : in Interfaces.C.Unsigned)
return Interfaces.C.Strings.Chars_Ptr;

procedure Send_Bytes (Data      : in Interfaces.C.Char_Array;
                       Num_Bytes : in Interfaces.C.Unsigned);

More in the spirit rather than the letter of what the C is trying to 
say, you probably want to use System.Storage_Elements.Storage_Array:

procedure Send_Bytes
    (Data      : in System.Storage_Elements.Storage_Array;
     Num_Bytes : in Interfaces.C.Unsigned);

You send data by creating a subtype of 
System.Storage_Elements.Storage_Array with a length equal to the value 
you'll pass to Num_Bytes, and instantiating Ada.Unchecked_Conversion 
with this subtype as the target.

>                 type IntegerPtr is access all Integer;
>                 function to_IntegerPtr is new Unchecked_Conversion
>                       (source => System.Address, target =>
> IntegerPtr);
> 
> --- this works...and I can do all the conversions I need using an
> unchecked_conversion

This is highly compiler dependent. There is no guarantee that a 
System.Address and a C pointer are the same size, much less the same 
representation. There is no guarantee that a System.Address and an 
access value are the same size, much less the same representation. There 
are compilers where these things aren't and this won't work.

For situations where you must convert between System.Address and access 
values, there's System.Address_To_Access_Conversions, but this isn't one 
of those cases.

Reading is a little more complicated:

with System;

type Value is ...

type Value_Ptr is access all Value;
pragma Convention (C, Value_Ptr);

The pragma Convention is important; it tells the compiler to use the 
same representation as C. That may be different from Ada's default 
representation.

function Get (Num_Bytes : in Interfaces.C.Unsigned :=
                  Value'Size / System.Storage_Unit)
return Value_Ptr;

This is a way to do it at the low level (streams are another, and 
perhaps better, way). But Ada is usually about hiding the low level. You 
shouldn't want your application declaring access types and imported 
functions and doing unchecked conversions all over the place.

generic -- Socket_IF
    type Value (<>) is private;
package Socket_IF is
    procedure Send (Data : in Value);

    function Read return Value;
end Socket_IF;

with Ada.Unchecked_Conversion;
with Interfaces.C;
with System.Storage_Elements;

package Body Socket_IF is
    subtype Unsigned is Interfaces.C.Unsigned;
    use type Unsigned;

    Num_Bytes : constant Unsigned := Value'Size / System.Storage_Unit;

    procedure Send (Data : in Value) is
       subtype List is
          System.Storage_Elements.Storage_Array (1 .. Num_Bytes);

       function To_List is new Ada.Unchecked_Conversion
          (Source => Value, Target => List);

       procedure C_Send (Data : in List; Size : in Unsigned);
       pragma Import (C, C_Send, ...);
    begin -- Send
       C_Send (Data => To_List (Data), Size => Num_Bytes);
    end Send;

    function Read return Value is
       type Value_Ptr is access all Value;
       pragma Convention (C, Value_Ptr);

       function C_Read (Size : in Unsigned) return Value_Ptr;
       pragma Import (C, C_Read, ...);
    begin -- Read
       return C_Read (Num_Bytes).all;
    end Read;
end Socket_IF;

I haven't tested this, but it might even work.

Now your application only has to instantiate Socket_IF for each type of 
interest, and call the resulting Send and Read operations. Much 
replication of code is eliminated, and you only have to get this right once.

Something similar for the streams approach is left as an exercise for 
the reader.

-- 
Jeff Carter
"We call your door-opening request a silly thing."
Monty Python & the Holy Grail
17



^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: Byte streams
  2007-08-03  5:34 ` Jeffrey R. Carter
@ 2007-08-03 13:15   ` shaunpatterson
  2007-08-10 20:22     ` Simon Wright
  0 siblings, 1 reply; 9+ messages in thread
From: shaunpatterson @ 2007-08-03 13:15 UTC (permalink / raw)


Yeah, I definitely don't feel "comfortable" doing
Unchecked_Conversions all over the place.

I think I'm going to change everything over to Streams
and use GNAT.Sockets.  It seems this way works much
the same way as Java's ByteBuffer in reading/writing
integers, characters, etc safely.

Safety and correctness is what I want.

Thanks

--
Shaun




^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: Byte streams
  2007-08-03 13:15   ` shaunpatterson
@ 2007-08-10 20:22     ` Simon Wright
  0 siblings, 0 replies; 9+ messages in thread
From: Simon Wright @ 2007-08-10 20:22 UTC (permalink / raw)


shaunpatterson@gmail.com writes:

> Yeah, I definitely don't feel "comfortable" doing
> Unchecked_Conversions all over the place.

Of course, when you go out on the wire and then back you are doing a
conversion which is actually unchecked .. if the sender does
Float'Write and the receiver does Integer'Read through being confused
about where in the byte stream it is, the results are going to be
confused too. You may find 'Valid useful. Discipline is all!



^ permalink raw reply	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2007-08-10 20:22 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2007-08-02 19:21 Byte streams shaunpatterson
2007-08-02 20:18 ` Gautier
2007-08-02 20:27 ` tmoran
2007-08-02 21:44   ` Robert A Duff
2007-08-02 22:45     ` tmoran
2007-08-02 22:54       ` shaunpatterson
2007-08-03  5:34 ` Jeffrey R. Carter
2007-08-03 13:15   ` shaunpatterson
2007-08-10 20:22     ` Simon Wright

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox