comp.lang.ada
 help / color / mirror / Atom feed
* Re: Recommended way of reading file as byte blocks
       [not found] <01BBA702.69F8B220@idc213.rb.icl.co.uk>
@ 1996-09-21  0:00 ` David C. Hoos, Sr.
  1996-09-21  0:00 ` David C. Hoos, Sr.
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 6+ messages in thread
From: David C. Hoos, Sr. @ 1996-09-21  0:00 UTC (permalink / raw)



Simon Johnston <skj@ACM.ORG> wrote in article
<01BBA702.69F8B220@idc213.rb.icl.co.uk>...
Hi, I have tried a number of ways of doing this, reading a file as blocks
of bytes. In most cases when the application is examined a better way is
found, however I am now at a point where I am converting some C code which
does:

    fp = fopen(...)
    i = fread(fp, buffer, 512)
    while (!feof(fp)) {
       for ( ; i > 0; i--) {
          ..
       }
       handle buffer
       i = fread(...)
    }

and it really matters that this logic is preserved. I can open the file as
a Direct_IO(Element => BYTE) file which is nasty, I have tried using
Streams but never quite get it right.
Any ideas?
Thanks.

Well, for what they're worth, here are my ideas.
First, I want to point out that the correct call to fread is "i = fread
(buffer, 1, 512, fp)", rather than "i = fread (fp, buffer, 512)", so the
code which follows is based on that difference.
I would make a generic package instantiated for the element type, and the
"buffer" of elements.  I have included a partial implementation here, just
enough to show that it works.
What I have tried to do here, is to preserve the syntax as close to that of
C, as much as possible, to simplify translation.  This involves some
compromises.  For example, you will get a compiler warning that
The_Byte_Array is never assigned a value.  This is because the Ada compiler
doesn't know that the C library function to which we've interfaced is going
to use the address we've passed it to tell where write the data.  On the
other hand, if we make the parameter of Fread an "out" parameter, we would
have to make Fread a procedure, instead of a function, and, then the number
of bytes read would also have to be an "out" parameter.  This was my
compromise in favor of preserving the C syntax.
This code also illustrates the use of the Ada.Command_Line package, as well
as some other Ada Features.
The style is somewhat verbose, but I prefer to make the code sufficiently
descriptive that the need for comments is reduced.
------------ source code begins ---------------------
with Interfaces.C;
with System;
generic
  type ELEMENT_TYPE is private;
  type ELEMENT_ARRAY_TYPE is private;
package stdio is
  -- This is only sufficiently completed so as to illustrate the principles
  package C renames Interfaces.C;
  use type C.INT;
  use type C.CHAR_ARRAY;
  use type C.SIZE_T;
  type FILE_TYPE is limited private;
  type FILE_ACCESS_TYPE is access FILE_TYPE;
  -- NOTE: From a strictly-Ada point-of-view, this type should be limited
  -- private, but to make it more closely mimic C, we make it assignable
  -- and copyable, etc., so Fopen can be a function instead of a procedure.
  function Fopen (
      Name : in C.CHAR_ARRAY;
      Mode : in C.CHAR_ARRAY
      ) return FILE_ACCESS_TYPE;
  function Feof (
      File : in FILE_ACCESS_TYPE
      ) return C.INT;
  function Fread (
      Buffer             : in ELEMENT_ARRAY_TYPE;
      Element_Size       : in NATURAL := ELEMENT_TYPE'SIZE /
System.STORAGE_UNIT;
      Number_Of_Elements : in NATURAL;
      File               : in FILE_ACCESS_TYPE
      ) return C.SIZE_T;
  function Fclose (
      File : in FILE_ACCESS_TYPE
      ) return C.INT;
private
  type FILE_TYPE is null record;
  -- NOTE:  Since we don't manipulate any of the components of C's * FILE
  -- directly, and since Fopen and Fclose handle allocation and
deallocation,
  -- we don't really care what the Ada type is.
  pragma IMPORT (C, Fopen,  "fopen");
  pragma IMPORT (C, Feof,   "feof");
  pragma IMPORT (C, Fread,  "fread");
  pragma IMPORT (C, Fclose, "fclose");
end Stdio;

with Ada.Command_Line;    
with Interfaces.C;
with Stdio;
with Ada.Text_IO;
procedure SKJ is
  package C renames Interfaces.C;
  package CL renames Ada.Command_line;
  package Text_IO renames Ada.Text_IO;
  type BYTE is mod 256;
  type BYTE_ARRAY_TYPE is array (0 .. 511) of aliased BYTE;
  package Byte_Stdio is new Stdio (
      Element_Type       => BYTE,
      Element_Array_Type => BYTE_ARRAY_TYPE
      );
  package Byte_IO is new Text_IO.Modular_IO (BYTE);
  use type C.INT;
  use type C.CHAR_ARRAY;
  The_Number_Of_Bytes_Read : C.SIZE_T;
  The_File                 : Byte_Stdio.FILE_ACCESS_TYPE;
  The_Byte_Array           : aliased BYTE_ARRAY_TYPE;
  The_Status               : C.INT;
begin
  if CL.Argument_Count /= 1 then
    Text_IO.Put_Line (
        File => Text_IO.Standard_Error,
        Item => "USAGE: " & CL.Command_Name & 
            " <input-file-name>"
        );
    CL.Set_Exit_Status (1);
    return;
  end if;
  The_File := Byte_Stdio.Fopen (
      Name => C.To_C (CL.Argument (1)),          
      Mode => "r" & C.NUL
      );
  if Byte_Stdio."=" (The_File, null) then
    Text_IO.Put_Line (
        File => Text_IO.Standard_Error,
        Item => "Attempt to open file '" & CL.Argument (1) & "' for read
failed"
        );
    CL.Set_Exit_Status (2);
    return;
  end if;
  loop
    The_Number_Of_Bytes_Read := Byte_Stdio.Fread (
        Buffer             => The_Byte_Array,
        Number_Of_Elements => The_Byte_Array'LENGTH,
        File               => The_File
        );
    
    Text_IO.Put_Line ("Bytes Read =>" & C.SIZE_T'IMAGE
(The_Number_Of_Bytes_Read));
    for i in 0 .. INTEGER(The_Number_Of_Bytes_Read) -1 loop
      Byte_IO.Put (The_Byte_Array (i));
    end loop; 
    for i in 0 .. INTEGER(The_Number_Of_Bytes_Read) -1 loop
      Text_IO.Put (CHARACTER'VAL(The_Byte_Array (i)));
    end loop;
    exit when Byte_Stdio.Feof (The_File) /= 0;
  end loop; 
  The_Status := Byte_Stdio.Fclose (The_File);
  if The_Status = 0 then
    The_File := null;
  else
    Text_IO.Put_Line (
        File => Text_IO.Standard_Error,
        Item => "Attempt to close file '" & CL.Argument (1) & "' failed"
        );
    CL.Set_Exit_Status (3);
    return;
  end if;
end SKJ;
------------ source code ends ---------------------
Hope this helps.
-- 
David C. Hoos, Sr.,
http://www.dbhwww.com
http://www.ada95.com






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

* Re: Recommended way of reading file as byte blocks
       [not found] <01BBA702.69F8B220@idc213.rb.icl.co.uk>
  1996-09-21  0:00 ` Recommended way of reading file as byte blocks David C. Hoos, Sr.
  1996-09-21  0:00 ` David C. Hoos, Sr.
@ 1996-09-21  0:00 ` Robert Dewar
  1996-09-21  0:00 ` Robert Dewar
  3 siblings, 0 replies; 6+ messages in thread
From: Robert Dewar @ 1996-09-21  0:00 UTC (permalink / raw)



Simon said

"and it really matters that this logic is preserved. I can open the file =
as a Direct_IO(Element =3D> BYTE) file which is nasty, I have tried =
using Streams but never quite get it right.
Any ideas?
Thanks."


Definitely the solution is to use Stream_IO and get it right :-)

You can certainly duplicate the desired effect with Stream_IO, can you
be clearer as to why you had trouble doing this?





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

* Re: Recommended way of reading file as byte blocks
       [not found] <01BBA702.69F8B220@idc213.rb.icl.co.uk>
  1996-09-21  0:00 ` Recommended way of reading file as byte blocks David C. Hoos, Sr.
@ 1996-09-21  0:00 ` David C. Hoos, Sr.
  1996-09-28  0:00   ` Robert Dewar
  1996-09-21  0:00 ` Robert Dewar
  1996-09-21  0:00 ` Robert Dewar
  3 siblings, 1 reply; 6+ messages in thread
From: David C. Hoos, Sr. @ 1996-09-21  0:00 UTC (permalink / raw)



Reposting article removed by rogue canceller.

Simon Johnston <skj@ACM.ORG> wrote in article
<01BBA702.69F8B220@idc213.rb.icl.co.uk>...
Hi, I have tried a number of ways of doing this, reading a file as blocks
of bytes. In most cases when the application is examined a better way is
found, however I am now at a point where I am converting some C code which
does:

    fp = fopen(...)
    i = fread(fp, buffer, 512)
    while (!feof(fp)) {
       for ( ; i > 0; i--) {
          ..
       }
       handle buffer
       i = fread(...)
    }

and it really matters that this logic is preserved. I can open the file as
a Direct_IO(Element => BYTE) file which is nasty, I have tried using
Streams but never quite get it right.
Any ideas?
Thanks.

Well, for what they're worth, here are my ideas.
First, I want to point out that the correct call to fread is "i = fread
(buffer, 1, 512, fp)", rather than "i = fread (fp, buffer, 512)", so the
code which follows is based on that difference.
I would make a generic package instantiated for the element type, and the
"buffer" of elements.  I have included a partial implementation here, just
enough to show that it works.
What I have tried to do here, is to preserve the syntax as close to that of
C, as much as possible, to simplify translation.  This involves some
compromises.  For example, you will get a compiler warning that
The_Byte_Array is never assigned a value.  This is because the Ada compiler
doesn't know that the C library function to which we've interfaced is going
to use the address we've passed it to tell where write the data.  On the
other hand, if we make the parameter of Fread an "out" parameter, we would
have to make Fread a procedure, instead of a function, and, then the number
of bytes read would also have to be an "out" parameter.  This was my
compromise in favor of preserving the C syntax.
This code also illustrates the use of the Ada.Command_Line package, as well
as some other Ada Features.
The style is somewhat verbose, but I prefer to make the code sufficiently
descriptive that the need for comments is reduced.
------------ source code begins ---------------------
with Interfaces.C;
with System;
generic
  type ELEMENT_TYPE is private;
  type ELEMENT_ARRAY_TYPE is private;
package stdio is
  -- This is only sufficiently completed so as to illustrate the principles
  package C renames Interfaces.C;
  use type C.INT;
  use type C.CHAR_ARRAY;
  use type C.SIZE_T;
  type FILE_TYPE is limited private;
  type FILE_ACCESS_TYPE is access FILE_TYPE;
  -- NOTE: From a strictly-Ada point-of-view, this type should be limited
  -- private, but to make it more closely mimic C, we make it assignable
  -- and copyable, etc., so Fopen can be a function instead of a procedure.
  function Fopen (
      Name : in C.CHAR_ARRAY;
      Mode : in C.CHAR_ARRAY
      ) return FILE_ACCESS_TYPE;
  function Feof (
      File : in FILE_ACCESS_TYPE
      ) return C.INT;
  function Fread (
      Buffer             : in ELEMENT_ARRAY_TYPE;
      Element_Size       : in NATURAL := ELEMENT_TYPE'SIZE /
System.STORAGE_UNIT;
      Number_Of_Elements : in NATURAL;
      File               : in FILE_ACCESS_TYPE
      ) return C.SIZE_T;
  function Fclose (
      File : in FILE_ACCESS_TYPE
      ) return C.INT;
private
  type FILE_TYPE is null record;
  -- NOTE:  Since we don't manipulate any of the components of C's * FILE
  -- directly, and since Fopen and Fclose handle allocation and
deallocation,
  -- we don't really care what the Ada type is.
  pragma IMPORT (C, Fopen,  "fopen");
  pragma IMPORT (C, Feof,   "feof");
  pragma IMPORT (C, Fread,  "fread");
  pragma IMPORT (C, Fclose, "fclose");
end Stdio;

with Ada.Command_Line;    
with Interfaces.C;
with Stdio;
with Ada.Text_IO;
procedure SKJ is
  package C renames Interfaces.C;
  package CL renames Ada.Command_line;
  package Text_IO renames Ada.Text_IO;
  type BYTE is mod 256;
  type BYTE_ARRAY_TYPE is array (0 .. 511) of aliased BYTE;
  package Byte_Stdio is new Stdio (
      Element_Type       => BYTE,
      Element_Array_Type => BYTE_ARRAY_TYPE
      );
  package Byte_IO is new Text_IO.Modular_IO (BYTE);
  use type C.INT;
  use type C.CHAR_ARRAY;
  The_Number_Of_Bytes_Read : C.SIZE_T;
  The_File                 : Byte_Stdio.FILE_ACCESS_TYPE;
  The_Byte_Array           : aliased BYTE_ARRAY_TYPE;
  The_Status               : C.INT;
begin
  if CL.Argument_Count /= 1 then
    Text_IO.Put_Line (
        File => Text_IO.Standard_Error,
        Item => "USAGE: " & CL.Command_Name & 
            " <input-file-name>"
        );
    CL.Set_Exit_Status (1);
    return;
  end if;
  The_File := Byte_Stdio.Fopen (
      Name => C.To_C (CL.Argument (1)),          
      Mode => "r" & C.NUL
      );
  if Byte_Stdio."=" (The_File, null) then
    Text_IO.Put_Line (
        File => Text_IO.Standard_Error,
        Item => "Attempt to open file '" & CL.Argument (1) & "' for read
failed"
        );
    CL.Set_Exit_Status (2);
    return;
  end if;
  loop
    The_Number_Of_Bytes_Read := Byte_Stdio.Fread (
        Buffer             => The_Byte_Array,
        Number_Of_Elements => The_Byte_Array'LENGTH,
        File               => The_File
        );
    
    Text_IO.Put_Line ("Bytes Read =>" & C.SIZE_T'IMAGE
(The_Number_Of_Bytes_Read));
    for i in 0 .. INTEGER(The_Number_Of_Bytes_Read) -1 loop
      Byte_IO.Put (The_Byte_Array (i));
    end loop; 
    for i in 0 .. INTEGER(The_Number_Of_Bytes_Read) -1 loop
      Text_IO.Put (CHARACTER'VAL(The_Byte_Array (i)));
    end loop;
    exit when Byte_Stdio.Feof (The_File) /= 0;
  end loop; 
  The_Status := Byte_Stdio.Fclose (The_File);
  if The_Status = 0 then
    The_File := null;
  else
    Text_IO.Put_Line (
        File => Text_IO.Standard_Error,
        Item => "Attempt to close file '" & CL.Argument (1) & "' failed"
        );
    CL.Set_Exit_Status (3);
    return;
  end if;
end SKJ;
------------ source code ends ---------------------
Hope this helps.
-- 
David C. Hoos, Sr.,
http://www.dbhwww.com
http://www.ada95.com






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

* Re: Recommended way of reading file as byte blocks
       [not found] <01BBA702.69F8B220@idc213.rb.icl.co.uk>
                   ` (2 preceding siblings ...)
  1996-09-21  0:00 ` Robert Dewar
@ 1996-09-21  0:00 ` Robert Dewar
  3 siblings, 0 replies; 6+ messages in thread
From: Robert Dewar @ 1996-09-21  0:00 UTC (permalink / raw)



Reposting article removed by rogue canceller.

Simon said

"and it really matters that this logic is preserved. I can open the file =
as a Direct_IO(Element =3D> BYTE) file which is nasty, I have tried =
using Streams but never quite get it right.
Any ideas?
Thanks."


Definitely the solution is to use Stream_IO and get it right :-)

You can certainly duplicate the desired effect with Stream_IO, can you
be clearer as to why you had trouble doing this?





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

* Re: Recommended way of reading file as byte blocks
  1996-09-21  0:00 ` David C. Hoos, Sr.
@ 1996-09-28  0:00   ` Robert Dewar
  1996-09-29  0:00     ` Matthew Heaney
  0 siblings, 1 reply; 6+ messages in thread
From: Robert Dewar @ 1996-09-28  0:00 UTC (permalink / raw)



"
Simon Johnston <skj@ACM.ORG> wrote in article
<01BBA702.69F8B220@idc213.rb.icl.co.uk>...
Hi, I have tried a number of ways of doing this, reading a file as blocks
of bytes. In most cases when the application is examined a better way is
found, however I am now at a point where I am converting some C code which
does:

    fp = fopen(...)
    i = fread(fp, buffer, 512)
    while (!feof(fp)) {
       for ( ; i > 0; i--) {
          ..
       }
       handle buffer
       i = fread(...)
    }

and it really matters that this logic is preserved. I can open the file as
a Direct_IO(Element => BYTE) file which is nasty, I have tried using
Streams but never quite get it right.
Any ideas?
Thanks.
"


Two obvious answers. First, use stream_io, second, call fread directly.
Both allow you to duplicate the logic exactly.





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

* Re: Recommended way of reading file as byte blocks
  1996-09-28  0:00   ` Robert Dewar
@ 1996-09-29  0:00     ` Matthew Heaney
  0 siblings, 0 replies; 6+ messages in thread
From: Matthew Heaney @ 1996-09-29  0:00 UTC (permalink / raw)



In article <dewar.843914492@schonberg>, dewar@schonberg.cs.nyu.edu (Robert
Dewar) wrote:

>Simon Johnston <skj@ACM.ORG> wrote in article
<01BBA702.69F8B220@idc213.rb.icl.co.uk>...
>Hi, I have tried a number of ways of doing this, reading a file as blocks
>of bytes. In most cases when the application is examined a better way is
>found, however I am now at a point where I am converting some C code which
>does:
>
>    fp = fopen(...)
>    i = fread(fp, buffer, 512)
>    while (!feof(fp)) {
>       for ( ; i > 0; i--) {
>          ..
>       }
>       handle buffer
>       i = fread(...)
>    }
>
>and it really matters that this logic is preserved. I can open the file as
>a Direct_IO(Element => BYTE) file which is nasty, I have tried using
>Streams but never quite get it right.

>Two obvious answers. First, use stream_io, second, call fread directly.
>Both allow you to duplicate the logic exactly.

Here's a 3rd option: write a small C subprogram (or just keep the one
you're converting) that does the algorithm you want, and write an Ada
binding to _that_.  That way, you don't have to write bindings to all the
OS calls required to implement the algorithm.

I prefer this approach, because you can't write a binding to everything,
for example to #define constants or macros.  You could find the value of
the C constant in the header file, and declare a constant in your Ada code
with the same value, but what happens if the OS changes, and the constant
has a different value?  By keeping all the OS calls in C, you avoid these
headaches.

My Ada package then really has 2 bodies: one written in a Ada, and the
other in C.  The Ada subprograms are implemented by calling the routines in
the C body (that in turn call the OS) and checking the return value, and
raising an appropriate exception when required.

This way I get the best of both worlds: I don't have to write OS bindings,
and I can handle problems using exceptions instead of status values.

Matt

--------------------------------------------------------------------
Matthew Heaney
Software Development Consultant
mheaney@ni.net
(818) 985-1271




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

end of thread, other threads:[~1996-09-29  0:00 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
     [not found] <01BBA702.69F8B220@idc213.rb.icl.co.uk>
1996-09-21  0:00 ` Recommended way of reading file as byte blocks David C. Hoos, Sr.
1996-09-21  0:00 ` David C. Hoos, Sr.
1996-09-28  0:00   ` Robert Dewar
1996-09-29  0:00     ` Matthew Heaney
1996-09-21  0:00 ` Robert Dewar
1996-09-21  0:00 ` Robert Dewar

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