-------------------------------------------------------------------------------
-- (C) Altran Praxis Limited
-------------------------------------------------------------------------------
--
-- The SPARK toolset is free software; you can redistribute it and/or modify it
-- under terms of the GNU General Public License as published by the Free
-- Software Foundation; either version 3, or (at your option) any later
-- version. The SPARK toolset is distributed in the hope that it will be
-- useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
-- Public License for more details. You should have received a copy of the GNU
-- General Public License distributed with the SPARK toolset; see file
-- COPYING3. If not, go to http://www.gnu.org/licenses for a complete copy of
-- the license.
--
--=============================================================================

-- Provides routines to support analysis of "files of files"                  --
--------------------------------------------------------------------------------

with Ada.Characters.Latin_1;
with CommandLineData;
with CommandLineHandler;
with ErrorHandler;
with FileSystem;
with ScreenEcho;
with SystemErrors;
with XMLReport;

package body MetaFile is

   Empty_Meta_File_Element : constant Meta_File_Element := Meta_File_Element'(SPARK_IO.Null_File, E_Strings.Empty_String);

   Null_Meta_File : constant Meta_Files := Meta_Files'(Vector => Vectors'(Indexes => Empty_Meta_File_Element),
                                                       Ptr    => 0);

   function Is_Empty (The_Meta_File : Meta_Files) return Boolean is
   begin
      return The_Meta_File.Ptr = 0;
   end Is_Empty;

   function Is_White_Space (Space_Char : Character) return Boolean is
   begin
      return (Space_Char = ' ') or (Space_Char = Ada.Characters.Latin_1.HT) or (Space_Char = Ada.Characters.Latin_1.CR);
   end Is_White_Space;

   procedure Push (The_File      : in     SPARK_IO.File_Type;
                   The_Path      : in     E_Strings.T;
                   The_Meta_File : in out Meta_Files)
   --# derives The_Meta_File from *,
   --#                            The_File,
   --#                            The_Path;
   is
   begin
      if The_Meta_File.Ptr = Ptrs'Last then
         SystemErrors.Fatal_Error (Sys_Err => SystemErrors.Meta_File_Stack_Overflow,
                                   Msg     => "");
      end if;
      The_Meta_File.Ptr                        := The_Meta_File.Ptr + 1;
      The_Meta_File.Vector (The_Meta_File.Ptr) := Meta_File_Element'(The_File, The_Path);
   end Push;

   procedure Pop (The_Meta_File : in out Meta_Files;
                  The_File      :    out SPARK_IO.File_Type;
                  The_Path      :    out E_Strings.T)
   --# derives The_File,
   --#         The_Meta_File,
   --#         The_Path      from The_Meta_File;
   --# pre not Is_Empty (The_Meta_File);
   is
   begin
      The_File          := The_Meta_File.Vector (The_Meta_File.Ptr).File_Handle;
      The_Path          := The_Meta_File.Vector (The_Meta_File.Ptr).Path_Name;
      The_Meta_File.Ptr := The_Meta_File.Ptr - 1;
   end Pop;

   function Strip_At (S : E_Strings.T) return E_Strings.T is
   begin
      return E_Strings.Section (E_Str     => S,
                                Start_Pos => 2,
                                Length    => E_Strings.Get_Length (E_Str => S) - 1);
   end Strip_At;

   function Strip_Leading_Spaces (S : E_Strings.T) return E_Strings.T is
      Ptr : E_Strings.Positions := 1;
   begin
      loop
         exit when Ptr > E_Strings.Get_Length (E_Str => S);
         exit when not Is_White_Space (Space_Char => E_Strings.Get_Element (E_Str => S,
                                                                            Pos   => Ptr));
         Ptr := Ptr + 1;
      end loop;
      return E_Strings.Section (E_Str     => S,
                                Start_Pos => Ptr,
                                Length    => (E_Strings.Get_Length (E_Str => S) - Ptr) + 1);
   end Strip_Leading_Spaces;

   function Strip_Comments (S : E_Strings.T) return E_Strings.T is
      Res : E_Strings.T;
   begin
      if E_Strings.Get_Element (E_Str => S,
                                Pos   => 1) = '-' and then E_Strings.Get_Element (E_Str => S,
                                                                                  Pos   => 2) = '-' then
         Res := E_Strings.Empty_String;
      else
         Res := S;
      end if;
      return Res;
   end Strip_Comments;

   function Line_Is_Empty (S : E_Strings.T) return Boolean is
   begin
      return E_Strings.Get_Length (E_Str => S) = 0;
   end Line_Is_Empty;

   function Get_Metafile_Name (S : E_Strings.T) return E_Strings.T is
      Res              : E_Strings.T := E_Strings.Empty_String;
      In_Quoted_String : Boolean;
   begin
      In_Quoted_String := False;

      for I in E_Strings.Positions range 1 .. E_Strings.Get_Length (E_Str => S) loop
         exit when Is_White_Space (Space_Char => E_Strings.Get_Element (E_Str => S,
                                                                        Pos   => I)) and then not In_Quoted_String;

         -- allow for quoted strings containing spaces
         if E_Strings.Get_Element (E_Str => S,
                                   Pos   => I) = Ada.Characters.Latin_1.Quotation then
            In_Quoted_String := not In_Quoted_String;
         else
            if E_Strings.Get_Element (E_Str => S,
                                      Pos   => I) /= '@' then
               E_Strings.Append_Char (E_Str => Res,
                                      Ch    => E_Strings.Get_Element (E_Str => S,
                                                                      Pos   => I));
            end if;
         end if;
      end loop;
      FileSystem.Check_Extension (Fn  => Res,
                                  Ext => E_Strings.Copy_String (Str => CommandLineData.Meta_File_Extension));
      return Res;
   end Get_Metafile_Name;

   -- Exported Meta File Operations

   procedure Create (File_Name     : in     E_Strings.T;
                     The_Meta_File :    out Meta_Files) is
      The_File        : SPARK_IO.File_Type := SPARK_IO.Null_File;
      Status          : SPARK_IO.File_Status;
      Meta_File_Local : Meta_Files         := Null_Meta_File;
      Filename_Local  : E_Strings.T;
      Filename_Full   : E_Strings.T;
      Find_Status     : FileSystem.Typ_File_Spec_Status;
   begin
      Filename_Local := Strip_At (S => File_Name);
      E_Strings.Open
        (File         => The_File,
         Mode_Of_File => SPARK_IO.In_File,
         Name_Of_File => Filename_Local,
         Form_Of_File => "",
         Status       => Status);
      if Status = SPARK_IO.Ok then
         --# accept F, 10, Find_Status, "Known to be ineffective, must be true at this point";
         FileSystem.Find_Full_File_Name (File_Spec      => Filename_Local,
                                         File_Status    => Find_Status,
                                         Full_File_Name => Filename_Full);
         --# end accept;
         Push (The_File      => The_File,
               The_Path      => Filename_Full,
               The_Meta_File => Meta_File_Local);
      else
         ScreenEcho.New_Line (1);
         ScreenEcho.Put_String ("Cannot open file ");
         if CommandLineData.Content.Plain_Output then
            ScreenEcho.Put_ExaminerLine (FileSystem.Just_File (Fn  => Filename_Local,
                                                               Ext => True));
         else
            ScreenEcho.Put_ExaminerLine (Filename_Local);
         end if;
         ScreenEcho.New_Line (1);
      end if;
      The_Meta_File := Meta_File_Local;
      --# accept F, 33, Find_Status, "Known to be ineffective, must be true at this point";
   end Create;

   procedure Next_Name
     (The_Meta_File    : in out Meta_Files;
      The_Filename     :    out E_Strings.T;
      Do_Listing       :    out Boolean;
      The_Listing_Name :    out E_Strings.T;
      Do_VCG           :    out Boolean;
      File_Found       :    out Boolean)
   is
      The_File        : SPARK_IO.File_Type;
      Tmp_Filename    : E_Strings.T;
      The_Path        : E_Strings.T;
      Current_Line    : E_Strings.T;
      Data_Line_Found : Boolean;
      Unused, Status  : SPARK_IO.File_Status;

      procedure Parse
        (Current_Line     : in     E_Strings.T;
         The_Filename     :    out E_Strings.T;
         Do_Listing       :    out Boolean;
         The_Listing_Name :    out E_Strings.T;
         Do_VCG           :    out Boolean)
      --# global in CommandLineData.Content;
      --# derives Do_Listing,
      --#         Do_VCG           from Current_Line &
      --#         The_Filename,
      --#         The_Listing_Name from CommandLineData.Content,
      --#                               Current_Line;
      is
         Switch           : E_Strings.T         := E_Strings.Empty_String;
         Ptr              : E_Strings.Positions := 1;
         In_Quoted_String : Boolean;
      begin
         The_Filename     := E_Strings.Empty_String;
         Do_Listing       := True;
         The_Listing_Name := E_Strings.Empty_String;
         Do_VCG           := False;
         In_Quoted_String := False;
         loop
            exit when Is_White_Space (Space_Char => E_Strings.Get_Element (E_Str => Current_Line,
                                                                           Pos   => Ptr))
              and then not In_Quoted_String;

            -- Allow for quoted strings containing spaces
            if E_Strings.Get_Element (E_Str => Current_Line,
                                      Pos   => Ptr) = Ada.Characters.Latin_1.Quotation then
               In_Quoted_String := not In_Quoted_String;
            else
               E_Strings.Append_Char (E_Str => The_Filename,
                                      Ch    => E_Strings.Get_Element (E_Str => Current_Line,
                                                                      Pos   => Ptr));
            end if;

            exit when Ptr = E_Strings.Get_Length (E_Str => Current_Line);
            Ptr := Ptr + 1;
         end loop;
         FileSystem.Check_Extension (Fn  => The_Filename,
                                     Ext => CommandLineData.Content.Source_Extension);

         -- at this point The_Filename has the whole of any file name
         -- and Ptr either points at a switch character or at the end
         -- of Current_Line or at a space

         -- skip leading spaces before possible switch character
         while Ptr < E_Strings.Get_Length (E_Str => Current_Line) loop

            -- Find the switch character or the end of Current_Line
            if Is_White_Space (Space_Char => E_Strings.Get_Element (E_Str => Current_Line,
                                                                    Pos   => Ptr)) then
               Ptr := Ptr + 1;
               loop
                  exit when E_Strings.Get_Element (E_Str => Current_Line,
                                                   Pos   => Ptr) = '-'
                    or else Ptr = E_Strings.Get_Length (E_Str => Current_Line);
                  Ptr := Ptr + 1;
               end loop;
            end if;

            -- At this point Ptr either points at a switch character or at the end of Current_Line
            if E_Strings.Get_Element (E_Str => Current_Line,
                                      Pos   => Ptr) = '-' then
               Ptr := Ptr + 1;
               loop
                  exit when Is_White_Space (Space_Char => E_Strings.Get_Element (E_Str => Current_Line,
                                                                                 Pos   => Ptr))
                    or else E_Strings.Get_Element (E_Str => Current_Line,
                                                   Pos   => Ptr) = '=';
                  E_Strings.Append_Char (E_Str => Switch,
                                         Ch    => E_Strings.Get_Element (E_Str => Current_Line,
                                                                         Pos   => Ptr));
                  exit when Ptr = E_Strings.Get_Length (E_Str => Current_Line);
                  Ptr := Ptr + 1;
               end loop;

               -- At this point we have any command line argument in variable 'switch'
               if CommandLineHandler.Check_Option_Name (Opt_Name => Switch,
                                                        Str      => CommandLineData.Option_No_Listing_File) then
                  Do_Listing := False;
               end if;

               if CommandLineHandler.Check_Option_Name (Opt_Name => Switch,
                                                        Str      => CommandLineData.Option_Listing_File) then
                  -- the user has given a specific name to the listing file
                  -- first skip the '=' and any leading spaces
                  loop
                     exit when (not Is_White_Space (Space_Char => E_Strings.Get_Element (E_Str => Current_Line,
                                                                                         Pos   => Ptr)))
                       and then E_Strings.Get_Element (E_Str => Current_Line,
                                                       Pos   => Ptr) /= '=';
                     exit when Ptr = E_Strings.Get_Length (E_Str => Current_Line);
                     Ptr := Ptr + 1;
                  end loop;
                  -- we are either at the end of the line (error no file name provided)
                  -- at the start of a comment (error no file name provided)
                  -- at the start of the listing file name
                  if Ptr < E_Strings.Get_Length (E_Str => Current_Line)
                    and then E_Strings.Get_Element (E_Str => Current_Line,
                                                    Pos   => Ptr) /= '-' then
                     In_Quoted_String := False;
                     loop
                        exit when Is_White_Space (Space_Char => E_Strings.Get_Element (E_Str => Current_Line,
                                                                                       Pos   => Ptr))
                          and then not In_Quoted_String;

                        -- allow for quoted strings containing spaces
                        if E_Strings.Get_Element (E_Str => Current_Line,
                                                  Pos   => Ptr) = Ada.Characters.Latin_1.Quotation then
                           In_Quoted_String := not In_Quoted_String;
                        else
                           E_Strings.Append_Char
                             (E_Str => The_Listing_Name,
                              Ch    => E_Strings.Get_Element (E_Str => Current_Line,
                                                              Pos   => Ptr));
                        end if;

                        exit when Ptr = E_Strings.Get_Length (E_Str => Current_Line);
                        Ptr := Ptr + 1;
                     end loop;

                     FileSystem.Check_Listing_Extension
                       (Source_Name => The_Filename,
                        Fn          => The_Listing_Name,
                        Ext         => CommandLineData.Content.Listing_Extension);
                  end if;
               end if;

               if CommandLineHandler.Check_Option_Name (Opt_Name => Switch,
                                                        Str      => CommandLineData.Option_Vcg) then
                  Do_VCG := True;
               end if;
            end if;
         end loop;

         if E_Strings.Is_Empty (E_Str => The_Listing_Name) then
            -- no switch found so listing is on and listing name is default listing name
            The_Listing_Name := FileSystem.Just_File (Fn  => The_Filename,
                                                      Ext => False);
            FileSystem.Check_Listing_Extension
              (Source_Name => The_Filename,
               Fn          => The_Listing_Name,
               Ext         => CommandLineData.Content.Listing_Extension);
         end if;
      end Parse;

   begin -- Next_Name
      The_Filename     := E_Strings.Empty_String;
      Do_Listing       := False;
      The_Listing_Name := E_Strings.Empty_String;
      Do_VCG           := False;
      File_Found       := False;
      loop
         exit when Is_Empty (The_Meta_File => The_Meta_File); -- fail exit

         Pop (The_Meta_File => The_Meta_File,
              The_File      => The_File,
              The_Path      => The_Path);

         loop -- look for non-empty line in current file
            Data_Line_Found := False;

            if SPARK_IO.End_Of_File (The_File) then
               --# accept Flow, 10, Unused, "Expected ineffective assignment to unused" &
               --#        Flow, 10, The_File, "Expected ineffective assignment to The_File";
               SPARK_IO.Close (The_File, Unused);
               --# end accept;
               exit;
            end if;

            E_Strings.Get_Line (File  => The_File,
                                E_Str => Current_Line); -- to get
            Current_Line := Strip_Comments (S => Strip_Leading_Spaces (S => Current_Line));

            if not Line_Is_Empty (S => Current_Line) then
               Data_Line_Found := True;
               Push (The_File      => The_File,
                     The_Path      => The_Path,
                     The_Meta_File => The_Meta_File);  -- put file back ready for next
                                                                                                   --call

               if E_Strings.Get_Element (E_Str => Current_Line,
                                         Pos   => 1) = '@' then
                  Current_Line := Get_Metafile_Name (S => Current_Line);
                  -- Interpret this FileSpec relative to the current
                  -- metafile's location
                  Current_Line := FileSystem.Interpret_Relative (File_Name             => Current_Line,
                                                                 Relative_To_Directory => The_Path);
                  E_Strings.Open
                    (File         => The_File,
                     Mode_Of_File => SPARK_IO.In_File,
                     Name_Of_File => Current_Line,
                     Form_Of_File => "",
                     Status       => Status);
                  if Status = SPARK_IO.Ok then
                     Push (The_File      => The_File,
                           The_Path      => Current_Line,
                           The_Meta_File => The_Meta_File);
                  elsif Status = SPARK_IO.Use_Error then
                     -- for GNAT we get Use_Error if the file is already open; this means recursive
                     -- meta files have been detected.
                     ScreenEcho.New_Line (1);
                     ScreenEcho.Put_String ("Circular reference found to file ");
                     --# accept Flow, 41, "Expect stable expression";
                     if CommandLineData.Content.Plain_Output then
                        --# end accept;
                        ScreenEcho.Put_ExaminerLine (FileSystem.Just_File (Fn  => Current_Line,
                                                                           Ext => True));
                     else
                        ScreenEcho.Put_ExaminerLine (Current_Line);
                     end if;
                     ScreenEcho.New_Line (1);
                  else
                     ScreenEcho.New_Line (1);
                     ScreenEcho.Put_String ("Cannot open file ");
                     ErrorHandler.Set_File_Open_Error;
                     --# accept Flow, 41, "Expect stable expression";
                     if CommandLineData.Content.Plain_Output then
                        --# end accept;
                        ScreenEcho.Put_ExaminerLine (FileSystem.Just_File (Fn  => Current_Line,
                                                                           Ext => True));
                     else
                        ScreenEcho.Put_ExaminerLine (Current_Line);
                     end if;
                     ScreenEcho.New_Line (1);
                  end if;

               else -- ordinary file found
                  File_Found := True;
                  Parse
                    (Current_Line     => Current_Line,
                     The_Filename     => Tmp_Filename,
                     Do_Listing       => Do_Listing,
                     The_Listing_Name => The_Listing_Name,
                     Do_VCG           => Do_VCG);
                  -- Interpret this FileSpec relative to the current
                  -- metafile's location
                  The_Filename := FileSystem.Interpret_Relative (File_Name             => Tmp_Filename,
                                                                 Relative_To_Directory => The_Path);
               end if;
            end if;
            exit when Data_Line_Found;
         end loop; -- looping through file lines for a non-blank and valid one
         exit when File_Found;  -- success exit
      end loop;  -- processing stacked metafile entries

      --# accept Flow, 33, Unused, "Expected unused to be neither referenced or exported";
   end Next_Name;

   procedure Report_File_Content (To_File        : in     SPARK_IO.File_Type;
                                  Filename       : in     E_Strings.T;
                                  Meta_File_Used : in out Boolean) is
      The_File                               : SPARK_IO.File_Type := SPARK_IO.Null_File;
      Status, Unused                         : SPARK_IO.File_Status;
      Data_Line_Found                        : Boolean;
      The_Meta_File                          : Meta_Files         := Null_Meta_File;
      Current_Line, Filename_Local, The_Path : E_Strings.T;
      Filename_Full                          : E_Strings.T;
      Ptr                                    : E_Strings.Positions;
      In_Quoted_String                       : Boolean;
      Find_Status                            : FileSystem.Typ_File_Spec_Status;

      Margin : Natural          := 3;
      Offset : constant Natural := 3;

      procedure Print_Filename (To_File  : in SPARK_IO.File_Type;
                                Filename : in E_Strings.T;
                                Margin   : in Natural)
      --# global in     CommandLineData.Content;
      --#        in out SPARK_IO.File_Sys;
      --# derives SPARK_IO.File_Sys from *,
      --#                                CommandLineData.Content,
      --#                                Filename,
      --#                                Margin,
      --#                                To_File;
      is
      begin
         for I in Natural range 1 .. Margin loop
            SPARK_IO.Put_Char (To_File, ' ');
         end loop;
         if CommandLineData.Content.Plain_Output then
            E_Strings.Put_Line (File  => To_File,
                                E_Str => FileSystem.Just_File (Fn  => Filename,
                                                               Ext => True));
         else
            E_Strings.Put_Line (File  => To_File,
                                E_Str => Filename);
         end if;
      end Print_Filename;

      procedure Inc_Margin
      --# global in out Margin;
      --# derives Margin from *;
      is
      begin
         Margin := Margin + Offset;
      end Inc_Margin;

      procedure Dec_Margin
      --# global in out Margin;
      --# derives Margin from *;
      is
      begin
         Margin := Margin - Offset;
      end Dec_Margin;

   begin -- Report_File_Content

      Filename_Local := Strip_At (S => Filename);

      E_Strings.Open
        (File         => The_File,
         Mode_Of_File => SPARK_IO.In_File,
         Name_Of_File => Filename_Local,
         Form_Of_File => "",
         Status       => Status);
      if Status = SPARK_IO.Ok then
         if not Meta_File_Used then
            Meta_File_Used := True;
            if not CommandLineData.Content.XML then -- Expect stable expression
               SPARK_IO.New_Line (To_File, 1);
               SPARK_IO.Put_Line (To_File, "Meta File(s) used were:", 0);
            end if;
         end if;
         if CommandLineData.Content.XML then -- Expect stable expression
            XMLReport.Start_Meta_File (Name   => Filename_Local,
                                       Report => To_File);
         else
            Print_Filename (To_File  => To_File,
                            Filename => Filename_Local,
                            Margin   => Margin);
            Inc_Margin;
         end if;

         --# accept F, 10, Find_Status, "Known to be ineffective, must be true at this point";
         FileSystem.Find_Full_File_Name (File_Spec      => Filename_Local,
                                         File_Status    => Find_Status,
                                         Full_File_Name => Filename_Full);
         --# end accept;
         Push (The_File      => The_File,
               The_Path      => Filename_Full,
               The_Meta_File => The_Meta_File);

      end if;

      loop
         exit when Is_Empty (The_Meta_File => The_Meta_File);
         Pop (The_Meta_File => The_Meta_File,
              The_File      => The_File,
              The_Path      => The_Path);
         loop -- look for non-empty line in current file
            Data_Line_Found := False;

            if SPARK_IO.End_Of_File (The_File) then
               --# accept Flow, 10, The_File, "Expected ineffective assignment to The_File" &
               --#        Flow, 10, Unused, "Expected ineffective assignment to unused";
               SPARK_IO.Close (The_File, Unused);
               --# end accept;
               --# accept Flow, 41, "Expect stable expression";
               if CommandLineData.Content.XML then
                  --# end accept;
                  XMLReport.End_Meta_File (Report => To_File);
               else
                  Dec_Margin;
               end if;
               exit;
            end if;

            E_Strings.Get_Line (File  => The_File,
                                E_Str => Current_Line); -- to get
            Current_Line := Strip_Comments (S => Strip_Leading_Spaces (S => Current_Line));

            if not Line_Is_Empty (S => Current_Line) then
               Data_Line_Found := True;
               Push (The_File      => The_File,
                     The_Path      => The_Path,
                     The_Meta_File => The_Meta_File);  -- put file back ready for next
                                                                                                   --call

               if E_Strings.Get_Element (E_Str => Current_Line,
                                         Pos   => 1) = '@' then
                  Current_Line := Get_Metafile_Name (S => Current_Line);
                  Current_Line := FileSystem.Interpret_Relative (File_Name             => Current_Line,
                                                                 Relative_To_Directory => The_Path);
                  E_Strings.Open
                    (File         => The_File,
                     Mode_Of_File => SPARK_IO.In_File,
                     Name_Of_File => Current_Line,
                     Form_Of_File => "",
                     Status       => Status);
                  if Status = SPARK_IO.Ok then
                     Push (The_File      => The_File,
                           The_Path      => Current_Line,
                           The_Meta_File => The_Meta_File);

                     --# accept Flow, 41, "Expect stable expression";
                     if CommandLineData.Content.Plain_Output then
                        --# end accept;
                        Current_Line := FileSystem.Just_File (Fn  => Current_Line,
                                                              Ext => True);
                     end if;

                     --# accept Flow, 41, "Expect stable expression";
                     if CommandLineData.Content.XML then
                        --# end accept;
                        XMLReport.Start_Meta_File (Name   => Current_Line,
                                                   Report => To_File);
                     else
                        Print_Filename (To_File  => To_File,
                                        Filename => Current_Line,
                                        Margin   => Margin);
                        Inc_Margin;
                     end if;
                  end if;

               else -- ordinary file found
                  Filename_Local   := E_Strings.Empty_String;
                  Ptr              := 1;
                  In_Quoted_String := False;
                  loop
                     exit when Is_White_Space (Space_Char => E_Strings.Get_Element (E_Str => Current_Line,
                                                                                    Pos   => Ptr))
                       and then not In_Quoted_String;

                     -- allow for quoted strings containing spaces
                     if E_Strings.Get_Element (E_Str => Current_Line,
                                               Pos   => Ptr) = Ada.Characters.Latin_1.Quotation then
                        In_Quoted_String := not In_Quoted_String;
                     else
                        E_Strings.Append_Char
                          (E_Str => Filename_Local,
                           Ch    => E_Strings.Get_Element (E_Str => Current_Line,
                                                           Pos   => Ptr));
                     end if;
                     exit when Ptr = E_Strings.Get_Length (E_Str => Current_Line);
                     Ptr := Ptr + 1;
                  end loop;

                  --# accept Flow, 41, "Expect stable expression";
                  if CommandLineData.Content.Plain_Output then
                     --# end accept;
                     Filename_Local := FileSystem.Just_File (Fn  => Filename_Local,
                                                             Ext => True);
                  else
                     Filename_Local :=
                       FileSystem.Interpret_Relative (File_Name             => Filename_Local,
                                                      Relative_To_Directory => The_Path);
                  end if;

                  --# accept Flow, 41, "Expect stable expression";
                  if CommandLineData.Content.XML then
                     --# end accept;
                     XMLReport.Filename (Plain_Output => CommandLineData.Content.Plain_Output,
                                         File         => Filename_Local);
                     E_Strings.Put_String (File  => To_File,
                                           E_Str => Filename_Local);
                  else
                     Print_Filename (To_File  => To_File,
                                     Filename => Filename_Local,
                                     Margin   => Margin);
                  end if;
               end if;
            end if;
            exit when Data_Line_Found;
         end loop; -- looping through file lines for a non-blank and valid one
      end loop;
      --# accept Flow, 33, Unused, "Expected unused to be neither referenced or exported" &
      --#        Flow, 33, Find_Status, "Expected Find_Status to be neither referenced or exported";
   end Report_File_Content;

end MetaFile;
