Not sure the best forum to use to ask Ada programming questions. I’ve used reasonable effort so far to solve with Google search and various trials.
How do I find the number of bytes actually read into variable “buffer” (array (1…128) of char) through ada.sequential_io read if EOF occurs while reading that 128 byte block of data? I had expected some tick attribute might apply.
I gave the Ada Reference Manual a quick check to provide this answer.
If Ada.Sequential_IO is instantiated with such a type, it provides no mechanism to handle a partial read. Either instantiate it with a different type, use a different package, or handle this case differently.
I haven’t looked at the rm to see (on the road). Is there an option to override the Read attribute for the byte and array types? If so you could put a counter var in to keep track.
I don’t have experience using Sequential IO, but perhaps this example can give some ideas:
File:
with Ada.Text_IO; use Ada.Text_IO;
with Ada.Text_IO.Text_Streams; use Ada.Text_IO.Text_Streams;
with Ada.Streams;
procedure jdoodle is
type Array_Type is array (Positive range 1 .. 128) of Character with Pack, Size => 128*8;
type Streamable_With_Count is record
Value : Array_Type;
Count : Natural := 0;
end record;
procedure Read(
Stream : not null access Ada.Streams.Root_Stream_Type'Class;
Item : out Streamable_With_Count);
for Streamable_With_Count'Read use Read;
procedure Read(
Stream : not null access Ada.Streams.Root_Stream_Type'Class;
Item : out Streamable_With_Count)
is begin
Item.Count := 0;
for Index in Item.Value'Range loop
Character'Read(Stream, Item.Value(Index));
Item.Count := Item.Count + 1;
Put_Line("Read: " & Item.Value(Index)'Image);
end loop;
end Read;
v : Streamable_With_Count := (Value => (others => ' '), Count => 0);
begin
Streamable_With_Count'Read(Stream(Standard_Input), v);
exception
when others =>
Put_Line("Read" & v.Count'Image & " Characters");
end jdoodle;
Thank you, Jere, for the helpful response. I use a disk file as input and my open routine conflicts with the modified read. Your example uses the default stdin. I’ve so far not been able to resolve how to integrate a working open. I feel a bit like a ballet audience member watching a workshop on ballet technique, looks good put if I get on stage to dance I fall over in spectacular fashion
I tried to structure my example so you could change input types. If you notice I take a stream of standard in, not standard in directly, so that could be replaced with a file stream for example (or a serial port stream, or any type of stream).
I just took standard in’s stream due to lack of actual input to test, but streams are a general base type and can be anything. You can change 'Stream(Standard_Input)' to any stream you like if that helps.
I would recommend using the Ada.Streams.Stream_IO package so you can use the `Read attribute to get your count. See the modified example that uses a file as input and tries to read 128 characters but stops at 10 due to input limitations:
jdoodle.adb
with Ada.Text_IO; use Ada.Text_IO;
with Ada.Streams.Stream_IO; Use Ada.Streams.Stream_IO;
with Ada.Streams;
procedure jdoodle is
type Array_Type is array (Positive range 1 .. 128) of Character with Pack, Size => 128*8;
type Streamable_With_Count is record
Value : Array_Type;
Count : Natural := 0; -- This variable isn't read from the file, only used in processing
end record;
procedure Read(
Stream : not null access Ada.Streams.Root_Stream_Type'Class;
Item : out Streamable_With_Count);
for Streamable_With_Count'Read use Read;
-- The magic happens in this operation
procedure Read(
Stream : not null access Ada.Streams.Root_Stream_Type'Class;
Item : out Streamable_With_Count)
is begin
Item.Count := 0;
for Index in Item.Value'Range loop
Character'Read(Stream, Item.Value(Index)); -- Read individual values of the array
Item.Count := Item.Count + 1; -- an exception won't update the count
Put_Line("Read: " & Item.Value(Index)'Image);
end loop;
end Read;
package My_IO renames Ada.Streams.Stream_IO;
File : My_IO.File_Type;
v : Streamable_With_Count := (Value => (others => ' '), Count => 0);
begin
My_IO.Open(File, My_IO.In_File, "/uploads/jdoodle.txt");
Put_Line("Opened File");
Streamable_With_Count'Read(Stream(File), v); -- This calls the magic function
My_IO.Close(File);
exception
when others =>
My_IO.Close(File);
Put_Line("Read" & v.Count'Image & " Characters");
end jdoodle;
Notice how my example didn’t change much other than adding a file variable, opening the file variable, getting the stream from it (instead of Standard_Input) and using that stream in the same code.