Task

Truncate a file to a specific length.   This should be implemented as a routine that takes two parameters: the filename and the required file length (in bytes).



Truncation can be achieved using system or library calls intended for such a task, if such methods exist, or by creating a temporary file of a reduced size and renaming it, after first deleting the original file, if no other method is available.   The file may contain non human readable binary data in an unspecified format, so the routine should be "binary safe", leaving the contents of the untruncated part of the file unchanged.

If the specified filename does not exist, or the provided length is not less than the current file length, then the routine should raise an appropriate error condition.

On some systems, the provided file truncation facilities might not change the file or may extend the file, if the specified length is greater than the current length of the file.

This task permits the use of such facilities.   However, such behaviour should be noted, or optionally a warning message relating to an non change or increase in file size may be implemented.




with Ada.Command_Line, Ada.Sequential_IO, Ada.Directories;
 
procedure Truncate_File is
 
   type Byte is mod 256;
   for Byte'Size use 8;
 
   package Byte_IO is new Ada.Sequential_IO(Byte);
 
   function Arg(N: Positive) return String renames Ada.Command_Line.Argument;
   function Args return Natural renames Ada.Command_Line.Argument_Count;
 
begin
   -- give help output if neccessary
   if Args < 2 or else Args > 3 then
      raise Program_Error
        with "usage: truncate_file <filename> <length> [<temp_file>]";
   end if;
 
   -- now do the real work
   declare
      File_Name: String := Arg(1);
      Temp_Name: String := (if Args = 2 then Arg(1) & ".tmp" else Arg(3));
                             -- an Ada 2012 conditional expression
      File, Temp: Byte_IO.File_Type;
      Count: Natural := Natural'Value(Arg(2));
      Value: Byte;
   begin
      -- open files
      Byte_IO.Open  (File => File, Mode => Byte_IO.In_File,  Name => File_Name);
      Byte_IO.Create(File => Temp, Mode => Byte_IO.Out_File, Name => Temp_Name);
 
      -- copy the required bytes (but at most as much as File has) from File to Temp
      while (not Byte_IO.End_Of_File(File)) and Count > 0 loop
         Byte_IO.Read (File, Value);
         Byte_IO.Write(Temp, Value);
         Count := Count - 1;
      end loop;
 
      -- close files
      Byte_IO.Close(Temp);
      Byte_IO.Close(File);
 
      if Count = 0 then -- File was at least Count bytes long
         -- remove File and rename Temp to File
         Ada.Directories.Delete_File(Name => File_Name);
         Ada.Directories.Rename(Old_Name => Temp_Name, New_Name => File_Name);
      else -- File was too short
         -- remove Temp and leave File as it is, output error
         Ada.Directories.Delete_File(Name => Temp_Name);
         raise Program_Error
           with "Size of """ & File_Name & """ less than " & Arg(2);
      end if;
   end;
end Truncate_File;