comp.lang.ada
 help / color / mirror / Atom feed
From: "David C. Hoos, Sr." <david.c.hoos.sr@ada95.com>
Subject: Re: Recommended way of reading file as byte blocks
Date: 1996/09/21
Date: 1996-09-21T00:00:00+00:00	[thread overview]
Message-ID: <R.01bba7c6$c6776fe0$0a8371a5@dhoossr.iquest.com> (raw)
In-Reply-To: 01BBA702.69F8B220@idc213.rb.icl.co.uk


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






       reply	other threads:[~1996-09-21  0:00 UTC|newest]

Thread overview: 6+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
     [not found] <01BBA702.69F8B220@idc213.rb.icl.co.uk>
1996-09-21  0:00 ` David C. Hoos, Sr. [this message]
1996-09-28  0:00   ` Recommended way of reading file as byte blocks Robert Dewar
1996-09-29  0:00     ` Matthew Heaney
1996-09-21  0:00 ` David C. Hoos, Sr.
1996-09-21  0:00 ` Robert Dewar
1996-09-21  0:00 ` Robert Dewar
replies disabled

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