-- tail1.adb - show the last ten lines from a named text file

with Ada.Characters.Latin_1;
with Ada.Command_Line;
with Ada.Text_IO;
with POSIX;
with POSIX.IO;
with POSIX.Memory_Mapping;
with System;
with System.Storage_Elements;

procedure Tail is
   use POSIX;
   use POSIX.IO;
   use POSIX.Memory_Mapping;
   use System.Storage_Elements;

   Text_File    : File_Descriptor;
   Text_Size    : System.Storage_Elements.Storage_Offset;
   Text_Address : System.Address;
begin
   Text_File := Open (Name => To_POSIX_String (Ada.Command_Line.Argument (1)),
                      Mode => Read_Only);
   Text_Size := Storage_Offset (File_Size (Text_File));
   Text_Address := Map_Memory (Length     => Text_Size,
                               Protection => Allow_Read,
                               Mapping    => Map_Shared,
                               File       => Text_File,
                               Offset     => 0);

   declare
      package Latin_1 renames Ada.Characters.Latin_1;
      Bit_Count       : constant Natural :=
                          Natural (Text_Size) * Storage_Element'Size;
      Character_Count : constant Natural :=
                          Bit_Count / Character'Size;

      Text : String (1 .. Character_Count);
      for Text'Address use Text_Address;
      Position         : Natural := Text'Last;
      Found_Line_Feeds : Natural := 0;
   begin
      while Position >= Text'First loop
         if Text (Position) = Latin_1.LF then
            Found_Line_Feeds := Found_Line_Feeds + 1;
         end if;
         exit when Found_Line_Feeds >= 10;
         Position := Position - 1;
      end loop;

      declare
         POSIX_Text : POSIX_String (Text'Range);
         for POSIX_Text'Address use Text'Address;
      begin
         while Position < Text'Last loop
            NONSTANDARD_Write
              (File   => Standard_Output,
               Buffer => POSIX_Text (Position + 1 .. Text'Last),
               Last   => Position);
         end loop;
      end;
   end;

   Unmap_Memory (First  => Text_Address,
                 Length => Text_Size);
   Close (File => Text_File);
end Tail;

