-------------------------------------------------------------------------------
-- (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.
--
--=============================================================================

with CommandLineData;
with ErrorHandler;
with ExaminerConstants;
with Fatal;
with FileSystem;
with SystemErrors;
with XMLReport;

package body IndexManager.Index_Table_P is

   subtype Index_Sizes is Integer range 0 .. ExaminerConstants.MaxIndexNumber;

   subtype Index_Positions is Integer range 1 .. ExaminerConstants.MaxIndexNumber;

   --  Filename : contains the filename of the index, super index or
   --  the auxiliary index.
   --
   --  Position : position of the index filename in the source index
   --  file.
   --
   --  Done : if the index file has been parsed.
   --
   --  File_Type : kind of index (index, super index, auxiliary index).
   --
   --  Unit : the prefix of the unit name (only relevant for auxiliary
   --  index).
   --
   --  Parent_Index : a refence to the source index file in the list.
   type Index_Info is record
      Filename  : LexTokenManager.Lex_String;
      Position  : IndexManager.File_Position;
      Done      : Boolean;
      File_Type : IndexManager.Entry_Types;
      --  case File_Type is
      --     when IndexManager.AuxIndex =>
      Unit : LexTokenLists.Lists;
      --     when others =>
      --        null
      --  end case;
      Parent_Index : Index_Sizes;
   end record;

   type Index_Contents is array (Index_Positions) of Index_Info;

   type Index_Tables is record
      Size    : Index_Sizes;
      Content : Index_Contents;
   end record;

   --  This table represents a list which has a partial ordering which must be maintained.
   --
   --  * A full ordering between index file and super index files
   --
   --  * All auxiliary index files belonging to the same index file or
   --    super index file must be kept together as a set.
   --
   --  The relationship between an index file and its parent must be
   --  maintained.
   Index_Table : Index_Tables;

   Fatal_Error : Boolean;

   procedure Stop_SPARK is
      procedure Raise_Fatal_Index_Manager
      --# derives ;
      is
         --# hide Raise_Fatal_Index_Manager;
      begin
         raise Fatal.Index_Manager;
      end Raise_Fatal_Index_Manager;

   begin
      --# accept F, 10, "Ineffective statement here OK";
      if Fatal_Error then
         Raise_Fatal_Index_Manager;
      end if;
      --# end accept;
      --# accept F, 35, Fatal_Error, "Ineffective initial value of variable Fatal_Error here OK";
   end Stop_SPARK;

   procedure Debug_Put_E_Str (E_Str    : in E_Strings.T;
                              New_Line : in Boolean) is
      String_To_Print : E_Strings.T;
   begin

      if FileSystem.Use_Windows_Command_Line and then CommandLineData.Content.Plain_Output then
         String_To_Print := E_Strings.Lower_Case (E_Str => E_Str);
      else
         String_To_Print := E_Str;
      end if;

      if New_Line then
         E_Strings.Put_Line (File  => SPARK_IO.Standard_Output,
                             E_Str => String_To_Print);
      else
         E_Strings.Put_String (File  => SPARK_IO.Standard_Output,
                               E_Str => String_To_Print);
      end if;

   end Debug_Put_E_Str;

   procedure Output_Error
     (E              : in IndexManager.Library_Manager_Errors;
      Source_File    : in LexTokenManager.Lex_String;
      Token_Position : in IndexManager.File_Position;
      Token_String   : in E_Strings.T)
   is
   begin
      case E is
         when IndexManager.ES_FileLocation =>
            ErrorHandler.Index_Manager_Error
              (S                 => "Incorrect syntax in File location",
               Source_File       => Source_File,
               Line_No           => Token_Position.Line,
               Col_No            => Token_Position.Col,
               Token_String      => Token_String,
               Is_Token_Filename => False,
               Is_Fatal          => True);
            Fatal_Error := True;
         when IndexManager.ES_IsIn =>
            ErrorHandler.Index_Manager_Error
              (S                 => "Incorrect syntax, ""is in"" expected",
               Source_File       => Source_File,
               Line_No           => Token_Position.Line,
               Col_No            => Token_Position.Col,
               Token_String      => Token_String,
               Is_Token_Filename => False,
               Is_Fatal          => True);
            Fatal_Error := True;
         when IndexManager.ES_UnitEntry =>
            ErrorHandler.Index_Manager_Error
              (S                 => "Incorrect syntax in Entry type",
               Source_File       => Source_File,
               Line_No           => Token_Position.Line,
               Col_No            => Token_Position.Col,
               Token_String      => Token_String,
               Is_Token_Filename => False,
               Is_Fatal          => True);
            Fatal_Error := True;
         when IndexManager.ES_Comment =>
            ErrorHandler.Index_Manager_Error
              (S                 => "Illegal comment, ignored",
               Source_File       => Source_File,
               Line_No           => Token_Position.Line,
               Col_No            => Token_Position.Col,
               Token_String      => Token_String,
               Is_Token_Filename => False,
               Is_Fatal          => True);
            Fatal_Error := True;
         when IndexManager.EW_UnexpectedSuper =>
            ErrorHandler.Index_Manager_Error
              (S                 => "Unexpected superindex",
               Source_File       => Source_File,
               Line_No           => Token_Position.Line,
               Col_No            => Token_Position.Col,
               Token_String      => Token_String,
               Is_Token_Filename => False,
               Is_Fatal          => True);
            Fatal_Error := True;
         when IndexManager.EW_IllegalUnitName =>
            ErrorHandler.Index_Manager_Error
              (S                 => "Illegal Unit name",
               Source_File       => Source_File,
               Line_No           => Token_Position.Line,
               Col_No            => Token_Position.Col,
               Token_String      => Token_String,
               Is_Token_Filename => False,
               Is_Fatal          => True);
            Fatal_Error := True;
         when IndexManager.ES_Are =>
            ErrorHandler.Index_Manager_Error
              (S                 => "Incorrect syntax ""are"" expected",
               Source_File       => Source_File,
               Line_No           => Token_Position.Line,
               Col_No            => Token_Position.Col,
               Token_String      => Token_String,
               Is_Token_Filename => False,
               Is_Fatal          => True);
            Fatal_Error := True;
         when IndexManager.ES_Components =>
            ErrorHandler.Index_Manager_Error
              (S                 => "Illegal syntax in Component entry",
               Source_File       => Source_File,
               Line_No           => Token_Position.Line,
               Col_No            => Token_Position.Col,
               Token_String      => Token_String,
               Is_Token_Filename => False,
               Is_Fatal          => True);
            Fatal_Error := True;
         when IndexManager.EW_Aux =>
            ErrorHandler.Index_Manager_Error
              (S                 => "Unit name in auxindex file is not a suffix of",
               Source_File       => Source_File,
               Line_No           => Token_Position.Line,
               Col_No            => Token_Position.Col,
               Token_String      => Token_String,
               Is_Token_Filename => False,
               Is_Fatal          => True);
            Fatal_Error := True;
         when IndexManager.EW_Index =>
            ErrorHandler.Index_Manager_Error
              (S                 => "Cannot open index file",
               Source_File       => Source_File,
               Line_No           => Token_Position.Line,
               Col_No            => Token_Position.Col,
               Token_String      => Token_String,
               Is_Token_Filename => True,
               Is_Fatal          => True);
            Fatal_Error := True;
         when IndexManager.ES_Recursion =>
            ErrorHandler.Index_Manager_Error
              (S                 => "Recursive use of index file",
               Source_File       => Source_File,
               Line_No           => Token_Position.Line,
               Col_No            => Token_Position.Col,
               Token_String      => Token_String,
               Is_Token_Filename => True,
               Is_Fatal          => True);
            Fatal_Error := True;
         when IndexManager.EW_Super =>
            ErrorHandler.Index_Manager_Error
              (S                 => "Cannot open superindex file",
               Source_File       => Source_File,
               Line_No           => Token_Position.Line,
               Col_No            => Token_Position.Col,
               Token_String      => Token_String,
               Is_Token_Filename => True,
               Is_Fatal          => True);
            Fatal_Error := True;
         when IndexManager.EF_Contradiction =>
            ErrorHandler.Index_Manager_Error
              (S                 => "Contradiction in index files",
               Source_File       => Source_File,
               Line_No           => Token_Position.Line,
               Col_No            => Token_Position.Col,
               Token_String      => Token_String,
               Is_Token_Filename => False,
               Is_Fatal          => True);
            Fatal_Error := True;
         when IndexManager.EW_Duplicate =>
            ErrorHandler.Index_Manager_Error
              (S                 => "Duplication in index files",
               Source_File       => Source_File,
               Line_No           => Token_Position.Line,
               Col_No            => Token_Position.Col,
               Token_String      => Token_String,
               Is_Token_Filename => False,
               Is_Fatal          => False);
         when IndexManager.EW_DuplicateAux =>
            ErrorHandler.Index_Manager_Error
              (S                 => "Duplicated index files",
               Source_File       => Source_File,
               Line_No           => Token_Position.Line,
               Col_No            => Token_Position.Col,
               Token_String      => Token_String,
               Is_Token_Filename => True,
               Is_Fatal          => False);
      end case;
   end Output_Error;

   procedure Add_Index_File (Filename : in E_Strings.T) is
      Found        : Boolean;
      Lex_Filename : LexTokenManager.Lex_String;
   begin
      LexTokenManager.Insert_Examiner_String (Str     => Filename,
                                              Lex_Str => Lex_Filename);
      --  Try to find if the index file is already in the list of
      --  index files.
      Found :=
        LexTokenManager.Lex_String_Case_Sensitive_Compare
        (Lex_Str1 => Index_Table.Content (Index_Positions'First).Filename,
         Lex_Str2 => Lex_Filename) =
        LexTokenManager.Str_Eq;
      if not Found then
         --  The index file is not yet in the list of index files =>
         --  add it.
         Index_Table.Size                       := Index_Table.Size + 1;
         Index_Table.Content (Index_Table.Size) :=
           Index_Info'
           (Filename     => Lex_Filename,
            Position     => IndexManager.File_Position'(Line => 1,
                                                        Col  => 1),
            Done         => False,
            File_Type    => IndexManager.Invalid_Entry_Type,
            Unit         => LexTokenLists.Null_List,
            Parent_Index => Index_Sizes'First);
      end if;
   end Add_Index_File;

   procedure Add_Super_Index_File
     (Filename    : in E_Strings.T;
      Position    : in IndexManager.File_Position;
      Source_File : in LexTokenManager.Lex_String)
   is
      Found_Filename    : Boolean;
      Found_Source_File : Boolean;
      Index             : Index_Positions;
      Lex_Filename      : LexTokenManager.Lex_String;
   begin
      Found_Filename    := False;
      Found_Source_File := False;
      Index             := Index_Positions'First;

      LexTokenManager.Insert_Examiner_String (Str     => Filename,
                                              Lex_Str => Lex_Filename);
      --  Try to find if the super index file is already in the list
      --  of index files and the index file from where the super index
      --  file is called.
      for I in Index_Sizes range Index_Positions'First .. Index_Table.Size loop
         if not Found_Filename
           and then LexTokenManager.Lex_String_Case_Sensitive_Compare
           (Lex_Str1 => Index_Table.Content (I).Filename,
            Lex_Str2 => Lex_Filename) =
           LexTokenManager.Str_Eq then
            Found_Filename := True;
         end if;
         if not Found_Source_File
           and then LexTokenManager.Lex_String_Case_Sensitive_Compare
           (Lex_Str1 => Index_Table.Content (I).Filename,
            Lex_Str2 => Source_File) =
           LexTokenManager.Str_Eq then
            Found_Source_File := True;
            Index             := I;
         end if;
         exit when Found_Filename and Found_Source_File;
      end loop;

      if Found_Source_File then
         if not Found_Filename then
            if Index_Table.Size < ExaminerConstants.MaxIndexNumber then
               --  The super index file is not yet in the list of
               --  index files => add it.
               Index_Table.Size                       := Index_Table.Size + 1;
               Index_Table.Content (Index_Table.Size) :=
                 Index_Info'
                 (Filename     => Lex_Filename,
                  Position     => Position,
                  Done         => False,
                  File_Type    => IndexManager.Super_Index,
                  Unit         => LexTokenLists.Null_List,
                  Parent_Index => Index);
            else
               --  The list of index files is full.
               SystemErrors.Fatal_Error
                 (Sys_Err => SystemErrors.Index_Stack_Full,
                  Msg     => "INDEXMANAGER.INDEX_TABLE.ADD_SUPER_INDEX_FILE");
            end if;
         else
            --  The super index file is already in the list of index
            --  files => recursion.
            Output_Error
              (E              => IndexManager.ES_Recursion,
               Source_File    => Source_File,
               Token_Position => Position,
               Token_String   => Filename);
         end if;
      else
         --  The index file has not been found => not normal, stop
         --  SPARK.
         SystemErrors.Fatal_Error
           (Sys_Err => SystemErrors.Index_Stack_Full,
            Msg     => "INDEXMANAGER.INDEX_TABLE.ADD_SUPER_INDEX_FILE");
      end if;
   end Add_Super_Index_File;

   procedure Add_Aux_Index_File
     (Filename    : in E_Strings.T;
      Unit        : in LexTokenLists.Lists;
      Position    : in IndexManager.File_Position;
      Source_File : in LexTokenManager.Lex_String)
   is
      Found_Filename    : Boolean;
      Found_Source_File : Boolean;
      Filename_Index    : Index_Positions;
      Source_File_Index : Index_Positions;
      Lex_Filename      : LexTokenManager.Lex_String;
   begin
      Found_Filename    := False;
      Found_Source_File := False;
      Filename_Index    := Index_Positions'First;
      Source_File_Index := Index_Positions'First;

      LexTokenManager.Insert_Examiner_String (Str     => Filename,
                                              Lex_Str => Lex_Filename);
      --  Try to find if the auxiliary index file is already in the
      --  list of index files and the index file from where the
      --  auxiliary index file is called.
      for I in Index_Sizes range Index_Positions'First .. Index_Table.Size loop
         if not Found_Filename
           and then LexTokenManager.Lex_String_Case_Sensitive_Compare
           (Lex_Str1 => Index_Table.Content (I).Filename,
            Lex_Str2 => Lex_Filename) =
           LexTokenManager.Str_Eq then
            Found_Filename := True;
            Filename_Index := I;
         end if;
         if not Found_Source_File
           and then LexTokenManager.Lex_String_Case_Sensitive_Compare
           (Lex_Str1 => Index_Table.Content (I).Filename,
            Lex_Str2 => Source_File) =
           LexTokenManager.Str_Eq then
            Found_Source_File := True;
            Source_File_Index := I;
         end if;
         exit when Found_Filename and then Found_Source_File;
      end loop;

      if Found_Source_File then
         if not Found_Filename then
            if Index_Table.Size < ExaminerConstants.MaxIndexNumber then
               --  The auxiliary index file is not yet in the list of
               --  index files => add it to the set for this source
               --  file and update the parent index references.
               for I in reverse Index_Sizes range Source_File_Index + 1 .. Index_Table.Size loop
                  if Index_Table.Content (I).Parent_Index > Source_File_Index then
                     Index_Table.Content (I).Parent_Index := Index_Table.Content (I).Parent_Index + 1;
                  end if;
                  Index_Table.Content (I + 1) := Index_Table.Content (I);
               end loop;
               Index_Table.Size                            := Index_Table.Size + 1;
               Index_Table.Content (Source_File_Index + 1) :=
                 Index_Info'
                 (Filename     => Lex_Filename,
                  Position     => Position,
                  Done         => False,
                  File_Type    => IndexManager.Aux_Index,
                  Unit         => Unit,
                  Parent_Index => Source_File_Index);
            else
               --  The list of index files is full.
               SystemErrors.Fatal_Error
                 (Sys_Err => SystemErrors.Index_Stack_Full,
                  Msg     => "INDEXMANAGER.INDEX_TABLE.ADD_AUX_INDEX_FILE");
            end if;
         elsif not (Index_Table.Content (Filename_Index).Position = Position
                      and then Index_Table.Content (Filename_Index).File_Type = IndexManager.Aux_Index
                      and then Index_Table.Content (Filename_Index).Unit = Unit
                      and then Index_Table.Content (Filename_Index).Parent_Index = Source_File_Index) then
            --  The auxiliary index file is already in the list of
            --  index files => recursion.
            Output_Error
              (E              => IndexManager.EW_DuplicateAux,
               Source_File    => Source_File,
               Token_Position => Position,
               Token_String   => Filename);
         end if;
      else
         --  The index file has not been found => not normal, stop
         --  SPARK.
         SystemErrors.Fatal_Error (Sys_Err => SystemErrors.Index_Stack_Full,
                                   Msg     => "INDEXMANAGER.INDEX_TABLE.ADD_AUX_INDEX_FILE");
      end if;
   end Add_Aux_Index_File;

   procedure Index_File_Done (Filename : in LexTokenManager.Lex_String) is
      Found : Boolean;
      Index : Index_Positions;
   begin
      Found := False;
      Index := 1;

      --  Try to find the index file in the list of index files
      for I in Index_Sizes range Index_Positions'First .. Index_Table.Size loop
         Found :=
           LexTokenManager.Lex_String_Case_Sensitive_Compare (Lex_Str1 => Index_Table.Content (I).Filename,
                                                              Lex_Str2 => Filename) =
           LexTokenManager.Str_Eq;
         if Found then
            Index := I;
         end if;
         exit when Found;
      end loop;

      if Found and then not Index_Table.Content (Index).Done then
         --  The index file has been found and is not already marked
         --  as done => mark it as done.
         Index_Table.Content (Index).Done := True;
         if CommandLineData.Content.Debug.File_Names then
            --  Debug
            SPARK_IO.Put_String
              (File => SPARK_IO.Standard_Output,
               Item => "INDEXMANAGER.INDEX_TABLE.INDEX_FILE_DONE : ",
               Stop => 0);
            Debug_Put_E_Str (E_Str    => LexTokenManager.Lex_String_To_String (Lex_Str => Filename),
                             New_Line => True);
         end if;
      else
         --  The index file has not been found or is already marked as
         --  done => not normal, stop SPARK.
         SystemErrors.Fatal_Error (Sys_Err => SystemErrors.Index_Stack_Full,
                                   Msg     => "INDEXMANAGER.INDEX_TABLE.INDEX_FILE_DONE");
      end if;
   end Index_File_Done;

   function Is_File_Ancestor
     (Parent_Filename : in LexTokenManager.Lex_String;
      Filename        : in LexTokenManager.Lex_String)
     return            Boolean
   is
      Found_Parent_Filename : Boolean;
      Found_Filename        : Boolean;
      Found                 : Boolean;
      Index_Parent_Filename : Index_Sizes;
      Index_Filename        : Index_Sizes;
      Return_Val            : Boolean;

      procedure Trace
      --# derives ;
      is
         --# hide Trace;
      begin
         if CommandLineData.Content.Debug.File_Names then
            --  Debug
            SPARK_IO.Put_String
              (File => SPARK_IO.Standard_Output,
               Item => "INDEXMANAGER.INDEX_TABLE_P.IS_FILE_ANCESTOR ",
               Stop => 0);
            Debug_Put_E_Str (E_Str    => LexTokenManager.Lex_String_To_String (Lex_Str => Parent_Filename),
                             New_Line => False);
            SPARK_IO.Put_Char (File => SPARK_IO.Standard_Output,
                               Item => ' ');
            Debug_Put_E_Str (E_Str    => LexTokenManager.Lex_String_To_String (Lex_Str => Filename),
                             New_Line => True);
         end if;
      end Trace;

   begin

      Trace;

      if LexTokenManager.Lex_String_Case_Insensitive_Compare
        (Lex_Str1 => Parent_Filename,
         Lex_Str2 => LexTokenManager.Null_String) /=
        LexTokenManager.Str_Eq
        and then LexTokenManager.Lex_String_Case_Insensitive_Compare
        (Lex_Str1 => Filename,
         Lex_Str2 => LexTokenManager.Null_String) /=
        LexTokenManager.Str_Eq then
         --  Try to find the parent index file and the index file in
         --  the list of index files.
         Index_Parent_Filename := Index_Sizes'First;
         Index_Filename        := Index_Sizes'First;
         Found_Parent_Filename := False;
         Found_Filename        := False;
         for I in Index_Sizes range Index_Positions'First .. Index_Table.Size loop
            if not Found_Parent_Filename
              and then LexTokenManager.Lex_String_Case_Sensitive_Compare
              (Lex_Str1 => Index_Table.Content (I).Filename,
               Lex_Str2 => Parent_Filename) =
              LexTokenManager.Str_Eq then
               Found_Parent_Filename := True;
               Index_Parent_Filename := I;
            end if;
            if not Found_Filename
              and then LexTokenManager.Lex_String_Case_Sensitive_Compare
              (Lex_Str1 => Index_Table.Content (I).Filename,
               Lex_Str2 => Filename) =
              LexTokenManager.Str_Eq then
               Found_Filename := True;
               Index_Filename := I;
            end if;
            exit when Found_Parent_Filename and Found_Filename;
         end loop;

         if Found_Parent_Filename then
            --  If the parent index file is an auxiliary index file,
            --  find the associated index file or super index
            --  file. Index_Sizes'First represents no parent.
            while Index_Parent_Filename /= Index_Sizes'First
              and then Index_Table.Content (Index_Parent_Filename).File_Type = IndexManager.Aux_Index loop
               Index_Parent_Filename := Index_Table.Content (Index_Parent_Filename).Parent_Index;
            end loop;
         else
            --  The parent index file has not been found => not
            --  normal, stop SPARK.
            SystemErrors.Fatal_Error
              (Sys_Err => SystemErrors.Index_Stack_Full,
               Msg     => "INDEXMANAGER.INDEX_TABLE.IS_FILE_ANCESTOR");
         end if;

         if Found_Filename then
            --  If the index file is an auxiliary index file, find the
            --  associated index file or super index
            --  file. Index_Sizes'First represents no parent.
            while Index_Filename /= Index_Sizes'First
              and then Index_Table.Content (Index_Filename).File_Type = IndexManager.Aux_Index loop
               Index_Filename := Index_Table.Content (Index_Filename).Parent_Index;
            end loop;
         else
            --  The index file has not been found => not normal, stop
            --  SPARK.
            SystemErrors.Fatal_Error
              (Sys_Err => SystemErrors.Index_Stack_Full,
               Msg     => "INDEXMANAGER.INDEX_TABLE.IS_FILE_ANCESTOR");
         end if;

         --  Check if the parent index file is actually an ancestor of
         --  the index file. The index file is the parent of
         --  itself. Index_Sizes'First represents no parent.
         Found := Index_Parent_Filename = Index_Filename;
         while not Found and Index_Filename /= Index_Sizes'First loop
            Index_Filename := Index_Table.Content (Index_Filename).Parent_Index;
            Found          := Index_Parent_Filename = Index_Filename;
         end loop;
         Return_Val := Found;
      else
         --  The empty index filename is the parent of all the index
         --  files.
         Return_Val :=
           LexTokenManager.Lex_String_Case_Insensitive_Compare
           (Lex_Str1 => Parent_Filename,
            Lex_Str2 => LexTokenManager.Null_String) =
           LexTokenManager.Str_Eq;
      end if;

      return Return_Val;
   end Is_File_Ancestor;

   procedure Get_Next_Index_File
     (Unit           : in     LexTokenLists.Lists;
      Top_Filename   : in     LexTokenManager.Lex_String;
      Filename       :    out LexTokenManager.Lex_String;
      File_Type      :    out IndexManager.Entry_Types;
      Aux_Index_Unit :    out LexTokenLists.Lists;
      Position       :    out IndexManager.File_Position)
   is
      L_Filename       : LexTokenManager.Lex_String := LexTokenManager.Null_String;
      L_File_Type      : IndexManager.Entry_Types   := IndexManager.Invalid_Entry_Type;
      L_Aux_Index_Unit : LexTokenLists.Lists        := LexTokenLists.Null_List;
      L_Position       : IndexManager.File_Position := IndexManager.File_Position'(Line => 1,
                                                                                   Col  => 1);
      Found            : Boolean                    := False;
   begin
      if CommandLineData.Content.Debug.File_Names then
         --  Debug
         SPARK_IO.Put_String
           (File => SPARK_IO.Standard_Output,
            Item => "INDEXMANAGER.INDEX_TABLE_P.GET_NEXT_INDEX_FILE ",
            Stop => 0);
         LexTokenLists.Print_List (File => SPARK_IO.Standard_Output,
                                   List => Unit);
         SPARK_IO.Put_Char (File => SPARK_IO.Standard_Output,
                            Item => ' ');
      end if;

      --  First, try to find the more relevant auxiliary index
      --  file. This relies on the ordering of the list. More local
      --  index files will be earlier in the list.
      for I in Index_Sizes range Index_Positions'First .. Index_Table.Size loop
         --# accept F, 41, "Expect stable expression";
         if CommandLineData.Content.Debug.File_Names then
            --  Debug
            Debug_Put_E_Str
              (E_Str    => LexTokenManager.Lex_String_To_String (Lex_Str => Index_Table.Content (I).Filename),
               New_Line => False);
            SPARK_IO.Put_Char (File => SPARK_IO.Standard_Output,
                               Item => ' ');
            if not Index_Table.Content (I).Done then
               SPARK_IO.Put_String (File => SPARK_IO.Standard_Output,
                                    Item => "NOT DONE ",
                                    Stop => 0);
            end if;
            if Index_Table.Content (I).File_Type = IndexManager.Aux_Index then
               SPARK_IO.Put_String (File => SPARK_IO.Standard_Output,
                                    Item => "AUXFILE ",
                                    Stop => 0);
            end if;
            LexTokenLists.Print_List (File => SPARK_IO.Standard_Output,
                                      List => Index_Table.Content (I).Unit);
         end if;
         --# end accept;
         if not Index_Table.Content (I).Done
           and then Index_Table.Content (I).File_Type = IndexManager.Aux_Index
           and then LexTokenLists.Prefix_Unit (Poss_Prefix => Index_Table.Content (I).Unit,
                                               Prefixed    => Unit)
           and then (LexTokenManager.Lex_String_Case_Insensitive_Compare
                       (Lex_Str1 => Top_Filename,
                        Lex_Str2 => LexTokenManager.Null_String) =
                       LexTokenManager.Str_Eq
                       or else Is_File_Ancestor (Parent_Filename => Index_Table.Content (I).Filename,
                                                 Filename        => Top_Filename)) then
            L_Filename       := Index_Table.Content (I).Filename;
            L_File_Type      := Index_Table.Content (I).File_Type;
            L_Aux_Index_Unit := Index_Table.Content (I).Unit;
            L_Position       := Index_Table.Content (I).Position;
            Found            := True;
         end if;
         exit when Found;
      end loop;

      if CommandLineData.Content.Debug.File_Names then
         --  Debug
         SPARK_IO.New_Line (File    => SPARK_IO.Standard_Output,
                            Spacing => 1);
      end if;

      if not Found then
         --  No relevant auxiliary index file found, try to find an
         --  index file or a super index file.
         for I in Index_Sizes range Index_Positions'First .. Index_Table.Size loop
            if not Index_Table.Content (I).Done
              and then Index_Table.Content (I).File_Type /= IndexManager.Aux_Index
              and then (LexTokenManager.Lex_String_Case_Insensitive_Compare
                          (Lex_Str1 => Top_Filename,
                           Lex_Str2 => LexTokenManager.Null_String) =
                          LexTokenManager.Str_Eq
                          or else Is_File_Ancestor (Parent_Filename => Index_Table.Content (I).Filename,
                                                    Filename        => Top_Filename))
            then
               L_Filename       := Index_Table.Content (I).Filename;
               L_File_Type      := Index_Table.Content (I).File_Type;
               L_Aux_Index_Unit := LexTokenLists.Null_List;
               L_Position       := Index_Table.Content (I).Position;
               Found            := True;
            end if;
            exit when Found;
         end loop;
      end if;

      if Found then
         Filename       := L_Filename;
         File_Type      := L_File_Type;
         Aux_Index_Unit := L_Aux_Index_Unit;
         Position       := L_Position;
      else
         Filename       := LexTokenManager.Null_String;
         File_Type      := IndexManager.Invalid_Entry_Type;
         Aux_Index_Unit := LexTokenLists.Null_List;
         Position       := IndexManager.File_Position'(Line => 1,
                                                       Col  => 1);
      end if;

   end Get_Next_Index_File;

   function Is_Aux_File_Ancestor
     (Parent_Index_Filename : in LexTokenManager.Lex_String;
      Index_Filename        : in LexTokenManager.Lex_String)
     return                  Boolean
   is
      Found      : Boolean;
      Index      : Index_Sizes;
      Return_Val : Boolean;
   begin
      if LexTokenManager.Lex_String_Case_Insensitive_Compare
        (Lex_Str1 => Parent_Index_Filename,
         Lex_Str2 => LexTokenManager.Null_String) /=
        LexTokenManager.Str_Eq
        and then LexTokenManager.Lex_String_Case_Insensitive_Compare
        (Lex_Str1 => Index_Filename,
         Lex_Str2 => LexTokenManager.Null_String) /=
        LexTokenManager.Str_Eq then
         --  Try to find the index file in the list of index files.
         Found := False;
         Index := Index_Sizes'First;
         for I in Index_Sizes range Index_Positions'First .. Index_Table.Size loop
            Found :=
              LexTokenManager.Lex_String_Case_Sensitive_Compare
              (Lex_Str1 => Index_Table.Content (I).Filename,
               Lex_Str2 => Index_Filename) =
              LexTokenManager.Str_Eq;
            if Found then
               Index := I;
            end if;
            exit when Found;
         end loop;

         if Found then
            --  The index file has been found => if the index file is
            --  an auxiliary index file, check if the parent index
            --  file is between the auxiliary index file and the
            --  associated index file or super index file.
            Found :=
              LexTokenManager.Lex_String_Case_Sensitive_Compare
              (Lex_Str1 => Index_Table.Content (Index).Filename,
               Lex_Str2 => Parent_Index_Filename) =
              LexTokenManager.Str_Eq;
            while not Found and
              (Index /= Index_Sizes'First and then Index_Table.Content (Index).File_Type = IndexManager.Aux_Index) loop
               Index := Index_Table.Content (Index).Parent_Index;
               Found :=
                 LexTokenManager.Lex_String_Case_Sensitive_Compare
                 (Lex_Str1 => Index_Table.Content (Index).Filename,
                  Lex_Str2 => Parent_Index_Filename) =
                 LexTokenManager.Str_Eq;
            end loop;
            Return_Val := Found;
         else
            --  The index file has not been found => not normal, stop
            --  SPARK.
            SystemErrors.Fatal_Error
              (Sys_Err => SystemErrors.Index_Stack_Full,
               Msg     => "INDEXMANAGER.INDEX_TABLE.IS_AUX_FILE_ANCESTOR");
            Return_Val := False;
         end if;
      else
         --  The empty index filename can only be the auxiliary
         --  ancestor of itself.
         Return_Val :=
           LexTokenManager.Lex_String_Case_Sensitive_Compare (Lex_Str1 => Parent_Index_Filename,
                                                              Lex_Str2 => Index_Filename) =
           LexTokenManager.Str_Eq;
      end if;

      return Return_Val;
   end Is_Aux_File_Ancestor;

   procedure List_Index_File (Report_File : in SPARK_IO.File_Type) is
      Filename_Tmp : E_Strings.T;
   begin
      if Index_Table.Size = 0 then
         if not CommandLineData.Content.XML then
            SPARK_IO.Put_Line (Report_File, "No Index files were used", 0);
         end if;
      else
         if CommandLineData.Content.XML then
            XMLReport.Start_Section (Section => XMLReport.S_Indexes,
                                     Report  => Report_File);
         else
            SPARK_IO.Put_Line (Report_File, "Index Filename(s) used were: ", 0);
         end if;

         for I in Index_Sizes range Index_Positions'First .. Index_Table.Size loop
            if Index_Table.Content (I).Done then
               --# accept F, 41, "Expect stable expression";
               if CommandLineData.Content.XML then
                  Filename_Tmp := LexTokenManager.Lex_String_To_String (Lex_Str => Index_Table.Content (I).Filename);
                  XMLReport.Index (Plain_Output => CommandLineData.Content.Plain_Output,
                                   Idx          => Filename_Tmp);
                  E_Strings.Put_String (File  => Report_File,
                                        E_Str => Filename_Tmp);
               elsif CommandLineData.Content.Plain_Output then
                  SPARK_IO.Put_String (File => Report_File,
                                       Item => "   ",
                                       Stop => 0);
                  if FileSystem.Use_Windows_Command_Line then
                     --# end accept;
                     E_Strings.Put_String
                       (File  => Report_File,
                        E_Str => E_Strings.Lower_Case
                          (E_Str => FileSystem.Just_File
                             (Fn  => LexTokenManager.Lex_String_To_String (Lex_Str => Index_Table.Content (I).Filename),
                              Ext => True)));
                  else
                     E_Strings.Put_String
                       (File  => Report_File,
                        E_Str => FileSystem.Just_File
                          (Fn  => LexTokenManager.Lex_String_To_String (Lex_Str => Index_Table.Content (I).Filename),
                           Ext => True));
                  end if;
                  SPARK_IO.New_Line (File    => Report_File,
                                     Spacing => 1);
               else
                  SPARK_IO.Put_String (File => Report_File,
                                       Item => "   ",
                                       Stop => 0);
                  E_Strings.Put_String
                    (File  => Report_File,
                     E_Str => LexTokenManager.Lex_String_To_String (Lex_Str => Index_Table.Content (I).Filename));
                  SPARK_IO.New_Line (File    => Report_File,
                                     Spacing => 1);
               end if;
            end if;
         end loop;
         if CommandLineData.Content.XML then
            XMLReport.End_Section (Section => XMLReport.S_Indexes,
                                   Report  => Report_File);
         end if;
      end if;
   end List_Index_File;

begin
   Index_Table.Size := 0;
   Fatal_Error      := False;
   --# accept F, 32, Index_Table.Content, "Initialization is partial but effective" &
   --#        F, 31, Index_Table.Content, "Initialization is partial but effective" &
   --#        F, 602, Index_Table, Index_Table.Content, "Initialization is partial but effective";
end IndexManager.Index_Table_P;
