OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-dev/] [or1k-gcc/] [gcc/] [ada/] [xref_lib.adb] - Rev 848

Go to most recent revision | Compare with Previous | Blame | View Log

------------------------------------------------------------------------------
--                                                                          --
--                         GNAT COMPILER COMPONENTS                         --
--                                                                          --
--                             X R E F _ L I B                              --
--                                                                          --
--                                 B o d y                                  --
--                                                                          --
--          Copyright (C) 1998-2011, Free Software Foundation, Inc.         --
--                                                                          --
-- GNAT is free software;  you can  redistribute it  and/or modify it under --
-- terms of the  GNU General Public License as published  by the Free Soft- --
-- ware  Foundation;  either version 3,  or (at your option) any later ver- --
-- sion.  GNAT is distributed in the hope that it will be useful, but WITH- --
-- OUT 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 GNAT; see file COPYING3.  If not, go to --
-- http://www.gnu.org/licenses for a complete copy of the license.          --
--                                                                          --
-- GNAT was originally developed  by the GNAT team at  New York University. --
-- Extensive contributions were provided by Ada Core Technologies Inc.      --
--                                                                          --
------------------------------------------------------------------------------
 
with Osint;
with Output; use Output;
with Types;  use Types;
 
with Unchecked_Deallocation;
 
with Ada.Strings.Fixed; use Ada.Strings.Fixed;
with Ada.Text_IO;       use Ada.Text_IO;
 
with GNAT.Command_Line; use GNAT.Command_Line;
with GNAT.IO_Aux;       use GNAT.IO_Aux;
 
package body Xref_Lib is
 
   Type_Position : constant := 50;
   --  Column for label identifying type of entity
 
   ---------------------
   -- Local Variables --
   ---------------------
 
   Pipe : constant Character := '|';
   --  First character on xref lines in the .ali file
 
   No_Xref_Information : exception;
   --  Exception raised when there is no cross-referencing information in
   --  the .ali files.
 
   procedure Parse_EOL
     (Source                 : not null access String;
      Ptr                    : in out Positive;
      Skip_Continuation_Line : Boolean := False);
   --  On return Source (Ptr) is the first character of the next line
   --  or EOF. Source.all must be terminated by EOF.
   --
   --  If Skip_Continuation_Line is True, this subprogram skips as many
   --  lines as required when the second or more lines starts with '.'
   --  (continuation lines in ALI files).
 
   function Current_Xref_File (File : ALI_File) return File_Reference;
   --  Return the file matching the last 'X' line we found while parsing
   --  the ALI file.
 
   function File_Name (File : ALI_File; Num : Positive) return File_Reference;
   --  Returns the dependency file name number Num
 
   function Get_Full_Type (Decl : Declaration_Reference) return String;
   --  Returns the full type corresponding to a type letter as found in
   --  the .ali files.
 
   procedure Open
     (Name         : String;
      File         : out ALI_File;
      Dependencies : Boolean := False);
   --  Open a new ALI file. If Dependencies is True, the insert every library
   --  file 'with'ed in the files database (used for gnatxref)
 
   procedure Parse_Identifier_Info
     (Pattern       : Search_Pattern;
      File          : in out ALI_File;
      Local_Symbols : Boolean;
      Der_Info      : Boolean := False;
      Type_Tree     : Boolean := False;
      Wide_Search   : Boolean := True;
      Labels_As_Ref : Boolean := True);
   --  Output the file and the line where the identifier was referenced,
   --  If Local_Symbols is False then only the publicly visible symbols
   --  will be processed.
   --
   --  If Labels_As_Ref is true, then the references to the entities after
   --  the end statements ("end Foo") will be counted as actual references.
   --  The entity will never be reported as unreferenced by gnatxref -u
 
   procedure Parse_Token
     (Source    : not null access String;
      Ptr       : in out Positive;
      Token_Ptr : out Positive);
   --  Skips any separators and stores the start of the token in Token_Ptr.
   --  Then stores the position of the next separator in Ptr. On return
   --  Source (Token_Ptr .. Ptr - 1) is the token. Separators are space
   --  and ASCII.HT. Parse_Token will never skip to the next line.
 
   procedure Parse_Number
     (Source : not null access String;
      Ptr    : in out Positive;
      Number : out Natural);
   --  Skips any separators and parses Source up to the first character that
   --  is not a decimal digit. Returns value of parsed digits or 0 if none.
 
   procedure Parse_X_Filename (File : in out ALI_File);
   --  Reads and processes "X..." lines in the ALI file
   --  and updates the File.X_File information.
 
   procedure Skip_To_First_X_Line
     (File    : in out ALI_File;
      D_Lines : Boolean;
      W_Lines : Boolean);
   --  Skip the lines in the ALI file until the first cross-reference line
   --  (^X...) is found. Search is started from the beginning of the file.
   --  If not such line is found, No_Xref_Information is raised.
   --  If W_Lines is false, then the lines "^W" are not parsed.
   --  If D_Lines is false, then the lines "^D" are not parsed.
 
   ----------------
   -- Add_Entity --
   ----------------
 
   procedure Add_Entity
     (Pattern : in out Search_Pattern;
      Entity  : String;
      Glob    : Boolean := False)
   is
      File_Start : Natural;
      Line_Start : Natural;
      Col_Start  : Natural;
      Line_Num   : Natural := 0;
      Col_Num    : Natural := 0;
 
      File_Ref : File_Reference := Empty_File;
      pragma Warnings (Off, File_Ref);
 
   begin
      --  Find the end of the first item in Entity (pattern or file?)
      --  If there is no ':', we only have a pattern
 
      File_Start := Index (Entity, ":");
 
      --  If the regular expression is invalid, just consider it as a string
 
      if File_Start = 0 then
         begin
            Pattern.Entity := Compile (Entity, Glob, False);
            Pattern.Initialized := True;
 
         exception
            when Error_In_Regexp =>
 
               --  The basic idea is to insert a \ before every character
 
               declare
                  Tmp_Regexp : String (1 .. 2 * Entity'Length);
                  Index      : Positive := 1;
 
               begin
                  for J in Entity'Range loop
                     Tmp_Regexp (Index) := '\';
                     Tmp_Regexp (Index + 1) := Entity (J);
                     Index := Index + 2;
                  end loop;
 
                  Pattern.Entity := Compile (Tmp_Regexp, True, False);
                  Pattern.Initialized := True;
               end;
         end;
 
         Set_Default_Match (True);
         return;
      end if;
 
      --  If there is a dot in the pattern, then it is a file name
 
      if (Glob and then
           Index (Entity (Entity'First .. File_Start - 1), ".") /= 0)
             or else
              (not Glob
                 and then Index (Entity (Entity'First .. File_Start - 1),
                                   "\.") /= 0)
      then
         Pattern.Entity      := Compile (".*", False);
         Pattern.Initialized := True;
         File_Start          := Entity'First;
 
      else
         --  If the regular expression is invalid, just consider it as a string
 
         begin
            Pattern.Entity :=
              Compile (Entity (Entity'First .. File_Start - 1), Glob, False);
            Pattern.Initialized := True;
 
         exception
            when Error_In_Regexp =>
 
               --  The basic idea is to insert a \ before every character
 
               declare
                  Tmp_Regexp : String (1 .. 2 * (File_Start - Entity'First));
                  Index      : Positive := 1;
 
               begin
                  for J in Entity'First .. File_Start - 1 loop
                     Tmp_Regexp (Index) := '\';
                     Tmp_Regexp (Index + 1) := Entity (J);
                     Index := Index + 2;
                  end loop;
 
                  Pattern.Entity := Compile (Tmp_Regexp, True, False);
                  Pattern.Initialized := True;
               end;
         end;
 
         File_Start := File_Start + 1;
      end if;
 
      --  Parse the file name
 
      Line_Start := Index (Entity (File_Start .. Entity'Last), ":");
 
      --  Check if it was a disk:\directory item (for Windows)
 
      if File_Start = Line_Start - 1
        and then Line_Start < Entity'Last
        and then Entity (Line_Start + 1) = '\'
      then
         Line_Start := Index (Entity (Line_Start + 1 .. Entity'Last), ":");
      end if;
 
      if Line_Start = 0 then
         Line_Start := Entity'Length + 1;
 
      elsif Line_Start /= Entity'Last then
         Col_Start := Index (Entity (Line_Start + 1 .. Entity'Last), ":");
 
         if Col_Start = 0 then
            Col_Start := Entity'Last + 1;
         end if;
 
         if Col_Start > Line_Start + 1 then
            begin
               Line_Num := Natural'Value
                 (Entity (Line_Start + 1 .. Col_Start - 1));
 
            exception
               when Constraint_Error =>
                  raise Invalid_Argument;
            end;
         end if;
 
         if Col_Start < Entity'Last then
            begin
               Col_Num := Natural'Value (Entity
                                         (Col_Start + 1 .. Entity'Last));
 
            exception
               when Constraint_Error => raise Invalid_Argument;
            end;
         end if;
      end if;
 
      File_Ref :=
        Add_To_Xref_File
          (Entity (File_Start .. Line_Start - 1), Visited => True);
      Pattern.File_Ref := File_Ref;
 
      Add_Line (Pattern.File_Ref, Line_Num, Col_Num);
 
      File_Ref :=
        Add_To_Xref_File
          (ALI_File_Name (Entity (File_Start .. Line_Start - 1)),
           Visited      => False,
           Emit_Warning => True);
   end Add_Entity;
 
   -------------------
   -- Add_Xref_File --
   -------------------
 
   procedure Add_Xref_File (File : String) is
      File_Ref : File_Reference := Empty_File;
      pragma Unreferenced (File_Ref);
 
      Iterator : Expansion_Iterator;
 
      procedure Add_Xref_File_Internal (File : String);
      --  Do the actual addition of the file
 
      ----------------------------
      -- Add_Xref_File_Internal --
      ----------------------------
 
      procedure Add_Xref_File_Internal (File : String) is
      begin
         --  Case where we have an ALI file, accept it even though this is
         --  not official usage, since the intention is obvious
 
         if Tail (File, 4) = "." & Osint.ALI_Suffix.all then
            File_Ref := Add_To_Xref_File
                          (File, Visited => False, Emit_Warning => True);
 
         --  Normal non-ali file case
 
         else
            File_Ref := Add_To_Xref_File (File, Visited => True);
 
            File_Ref := Add_To_Xref_File
                         (ALI_File_Name (File),
                          Visited => False, Emit_Warning => True);
         end if;
      end Add_Xref_File_Internal;
 
   --  Start of processing for Add_Xref_File
 
   begin
      --  Check if we need to do the expansion
 
      if Ada.Strings.Fixed.Index (File, "*") /= 0
        or else Ada.Strings.Fixed.Index (File, "?") /= 0
      then
         Start_Expansion (Iterator, File);
 
         loop
            declare
               S : constant String := Expansion (Iterator);
 
            begin
               exit when S'Length = 0;
               Add_Xref_File_Internal (S);
            end;
         end loop;
 
      else
         Add_Xref_File_Internal (File);
      end if;
   end Add_Xref_File;
 
   -----------------------
   -- Current_Xref_File --
   -----------------------
 
   function Current_Xref_File (File : ALI_File) return File_Reference is
   begin
      return File.X_File;
   end Current_Xref_File;
 
   --------------------------
   -- Default_Project_File --
   --------------------------
 
   function Default_Project_File (Dir_Name : String) return String is
      My_Dir  : Dir_Type;
      Dir_Ent : File_Name_String;
      Last    : Natural;
 
   begin
      Open (My_Dir, Dir_Name);
 
      loop
         Read (My_Dir, Dir_Ent, Last);
         exit when Last = 0;
 
         if Tail (Dir_Ent (1 .. Last), 4) = ".adp" then
 
            --  The first project file found is the good one
 
            Close (My_Dir);
            return Dir_Ent (1 .. Last);
         end if;
      end loop;
 
      Close (My_Dir);
      return String'(1 .. 0 => ' ');
 
   exception
      when Directory_Error => return String'(1 .. 0 => ' ');
   end Default_Project_File;
 
   ---------------
   -- File_Name --
   ---------------
 
   function File_Name
     (File : ALI_File;
      Num  : Positive) return File_Reference
   is
   begin
      return File.Dep.Table (Num);
   end File_Name;
 
   --------------------
   -- Find_ALI_Files --
   --------------------
 
   procedure Find_ALI_Files is
      My_Dir  : Rec_DIR;
      Dir_Ent : File_Name_String;
      Last    : Natural;
 
      File_Ref : File_Reference;
      pragma Unreferenced (File_Ref);
 
      function Open_Next_Dir return Boolean;
      --  Tries to open the next object directory, and return False if
      --  the directory cannot be opened.
 
      -------------------
      -- Open_Next_Dir --
      -------------------
 
      function Open_Next_Dir return Boolean is
      begin
         --  Until we are able to open a new directory
 
         loop
            declare
               Obj_Dir : constant String := Next_Obj_Dir;
 
            begin
               --  Case of no more Obj_Dir lines
 
               if Obj_Dir'Length = 0 then
                  return False;
               end if;
 
               Open (My_Dir.Dir, Obj_Dir);
               exit;
 
            exception
 
               --  Could not open the directory
 
               when Directory_Error => null;
            end;
         end loop;
 
         return True;
      end Open_Next_Dir;
 
   --  Start of processing for Find_ALI_Files
 
   begin
      Reset_Obj_Dir;
 
      if Open_Next_Dir then
         loop
            Read (My_Dir.Dir, Dir_Ent, Last);
 
            if Last = 0 then
               Close (My_Dir.Dir);
 
               if not Open_Next_Dir then
                  return;
               end if;
 
            elsif Last > 4
              and then Dir_Ent (Last - 3 .. Last) = "." & Osint.ALI_Suffix.all
            then
               File_Ref :=
                 Add_To_Xref_File (Dir_Ent (1 .. Last), Visited => False);
            end if;
         end loop;
      end if;
   end Find_ALI_Files;
 
   -------------------
   -- Get_Full_Type --
   -------------------
 
   function Get_Full_Type (Decl : Declaration_Reference) return String is
 
      function Param_String return String;
      --  Return the string to display depending on whether Decl is a parameter
 
      ------------------
      -- Param_String --
      ------------------
 
      function Param_String return String is
      begin
         if Is_Parameter (Decl) then
            return "parameter ";
         else
            return "";
         end if;
      end Param_String;
 
   --  Start of processing for Get_Full_Type
 
   begin
      case Get_Type (Decl) is
         when 'A' => return "array type";
         when 'B' => return "boolean type";
         when 'C' => return "class-wide type";
         when 'D' => return "decimal type";
         when 'E' => return "enumeration type";
         when 'F' => return "float type";
         when 'H' => return "abstract type";
         when 'I' => return "integer type";
         when 'M' => return "modular type";
         when 'O' => return "fixed type";
         when 'P' => return "access type";
         when 'R' => return "record type";
         when 'S' => return "string type";
         when 'T' => return "task type";
         when 'W' => return "protected type";
 
         when 'a' => return Param_String & "array object";
         when 'b' => return Param_String & "boolean object";
         when 'c' => return Param_String & "class-wide object";
         when 'd' => return Param_String & "decimal object";
         when 'e' => return Param_String & "enumeration object";
         when 'f' => return Param_String & "float object";
         when 'i' => return Param_String & "integer object";
         when 'j' => return Param_String & "class object";
         when 'm' => return Param_String & "modular object";
         when 'o' => return Param_String & "fixed object";
         when 'p' => return Param_String & "access object";
         when 'r' => return Param_String & "record object";
         when 's' => return Param_String & "string object";
         when 't' => return Param_String & "task object";
         when 'w' => return Param_String & "protected object";
         when 'x' => return Param_String & "abstract procedure";
         when 'y' => return Param_String & "abstract function";
 
         when 'h' => return "interface";
         when 'g' => return "macro";
         when 'J' => return "class";
         when 'K' => return "package";
         when 'k' => return "generic package";
         when 'L' => return "statement label";
         when 'l' => return "loop label";
         when 'N' => return "named number";
         when 'n' => return "enumeration literal";
         when 'q' => return "block label";
         when 'Q' => return "include file";
         when 'U' => return "procedure";
         when 'u' => return "generic procedure";
         when 'V' => return "function";
         when 'v' => return "generic function";
         when 'X' => return "exception";
         when 'Y' => return "entry";
 
         when '+' => return "private type";
         when '*' => return "private variable";
 
         --  The above should be the only possibilities, but for this kind
         --  of informational output, we don't want to bomb if we find
         --  something else, so just return three question marks when we
         --  have an unknown Abbrev value
 
         when others =>
            if Is_Parameter (Decl) then
               return "parameter";
            else
               return "??? (" & Get_Type (Decl) & ")";
            end if;
      end case;
   end Get_Full_Type;
 
   --------------------------
   -- Skip_To_First_X_Line --
   --------------------------
 
   procedure Skip_To_First_X_Line
     (File    : in out ALI_File;
      D_Lines : Boolean;
      W_Lines : Boolean)
   is
      Ali              : String_Access renames File.Buffer;
      Token            : Positive;
      Ptr              : Positive := Ali'First;
      Num_Dependencies : Natural  := 0;
      File_Start       : Positive;
      File_End         : Positive;
      Gnatchop_Offset  : Integer;
      Gnatchop_Name    : Positive;
 
      File_Ref : File_Reference;
      pragma Unreferenced (File_Ref);
 
   begin
      --  Read all the lines possibly processing with-clauses and dependency
      --  information and exit on finding the first Xref line.
      --  A fall-through of the loop means that there is no xref information
      --  which is an error condition.
 
      while Ali (Ptr) /= EOF loop
         if D_Lines and then Ali (Ptr) = 'D' then
 
            --  Found dependency information. Format looks like:
            --  D src-nam time-stmp checksum [subunit-name] [line:file-name]
 
            --  Skip the D and parse the filenam
 
            Ptr := Ptr + 1;
            Parse_Token (Ali, Ptr, Token);
            File_Start := Token;
            File_End := Ptr - 1;
 
            Num_Dependencies := Num_Dependencies + 1;
            Set_Last (File.Dep, Num_Dependencies);
 
            Parse_Token (Ali, Ptr, Token); --  Skip time-stamp
            Parse_Token (Ali, Ptr, Token); --  Skip checksum
            Parse_Token (Ali, Ptr, Token); --  Read next entity on the line
 
            if not (Ali (Token) in '0' .. '9') then
               Parse_Token (Ali, Ptr, Token); --  Was a subunit name
            end if;
 
            --  Did we have a gnatchop-ed file with a pragma Source_Reference ?
 
            Gnatchop_Offset := 0;
 
            if Ali (Token) in '0' .. '9' then
               Gnatchop_Name := Token;
               while Ali (Gnatchop_Name) /= ':' loop
                  Gnatchop_Name := Gnatchop_Name + 1;
               end loop;
 
               Gnatchop_Offset :=
                 2 - Natural'Value (Ali (Token .. Gnatchop_Name - 1));
               Token := Gnatchop_Name + 1;
            end if;
 
            File.Dep.Table (Num_Dependencies) := Add_To_Xref_File
              (Ali (File_Start .. File_End),
               Gnatchop_File => Ali (Token .. Ptr - 1),
               Gnatchop_Offset => Gnatchop_Offset);
 
         elsif W_Lines and then Ali (Ptr) = 'W' then
 
            --  Found with-clause information. Format looks like:
            --     "W debug%s               debug.adb               debug.ali"
 
            --  Skip the W and parse the .ali filename (3rd token)
 
            Parse_Token (Ali, Ptr, Token);
            Parse_Token (Ali, Ptr, Token);
            Parse_Token (Ali, Ptr, Token);
 
            File_Ref :=
              Add_To_Xref_File (Ali (Token .. Ptr - 1), Visited => False);
 
         elsif Ali (Ptr) = 'X' then
 
            --  Found a cross-referencing line - stop processing
 
            File.Current_Line := Ptr;
            File.Xref_Line    := Ptr;
            return;
         end if;
 
         Parse_EOL (Ali, Ptr);
      end loop;
 
      raise No_Xref_Information;
   end Skip_To_First_X_Line;
 
   ----------
   -- Open --
   ----------
 
   procedure Open
     (Name         : String;
      File         : out ALI_File;
      Dependencies : Boolean := False)
   is
      Ali : String_Access renames File.Buffer;
      pragma Warnings (Off, Ali);
 
   begin
      if File.Buffer /= null then
         Free (File.Buffer);
      end if;
 
      Init (File.Dep);
 
      begin
         Read_File (Name, Ali);
 
      exception
         when Ada.Text_IO.Name_Error | Ada.Text_IO.End_Error =>
            raise No_Xref_Information;
      end;
 
      Skip_To_First_X_Line (File, D_Lines => True, W_Lines => Dependencies);
   end Open;
 
   ---------------
   -- Parse_EOL --
   ---------------
 
   procedure Parse_EOL
     (Source                 : not null access String;
      Ptr                    : in out Positive;
      Skip_Continuation_Line : Boolean := False)
   is
   begin
      loop
         --  Skip to end of line
 
         while Source (Ptr) /= ASCII.CR and then Source (Ptr) /= ASCII.LF
           and then Source (Ptr) /= EOF
         loop
            Ptr := Ptr + 1;
         end loop;
 
         --  Skip CR or LF if not at end of file
 
         if Source (Ptr) /= EOF then
            Ptr := Ptr + 1;
         end if;
 
         --  Skip past CR/LF or LF/CR combination
 
         if (Source (Ptr) = ASCII.CR or else Source (Ptr) = ASCII.LF)
           and then Source (Ptr) /= Source (Ptr - 1)
         then
            Ptr := Ptr + 1;
         end if;
 
         exit when not Skip_Continuation_Line or else Source (Ptr) /= '.';
      end loop;
   end Parse_EOL;
 
   ---------------------------
   -- Parse_Identifier_Info --
   ---------------------------
 
   procedure Parse_Identifier_Info
     (Pattern       : Search_Pattern;
      File          : in out ALI_File;
      Local_Symbols : Boolean;
      Der_Info      : Boolean := False;
      Type_Tree     : Boolean := False;
      Wide_Search   : Boolean := True;
      Labels_As_Ref : Boolean := True)
   is
      Ptr      : Positive renames File.Current_Line;
      Ali      : String_Access renames File.Buffer;
 
      E_Line   : Natural;   --  Line number of current entity
      E_Col    : Natural;   --  Column number of current entity
      E_Type   : Character; --  Type of current entity
      E_Name   : Positive;  --  Pointer to begin of entity name
      E_Global : Boolean;   --  True iff entity is global
 
      R_Line   : Natural;   --  Line number of current reference
      R_Col    : Natural;   --  Column number of current reference
      R_Type   : Character; --  Type of current reference
 
      Decl_Ref : Declaration_Reference;
      File_Ref : File_Reference := Current_Xref_File (File);
 
      function Get_Symbol_Name (Eun, Line, Col : Natural) return String;
      --  Returns the symbol name for the entity defined at the specified
      --  line and column in the dependent unit number Eun. For this we need
      --  to parse the ali file again because the parent entity is not in
      --  the declaration table if it did not match the search pattern.
 
      procedure Skip_To_Matching_Closing_Bracket;
      --  When Ptr points to an opening square bracket, moves it to the
      --  character following the matching closing bracket
 
      ---------------------
      -- Get_Symbol_Name --
      ---------------------
 
      function Get_Symbol_Name (Eun, Line, Col : Natural) return String is
         Ptr    : Positive := 1;
         E_Eun  : Positive;   --  Unit number of current entity
         E_Line : Natural;    --  Line number of current entity
         E_Col  : Natural;    --  Column number of current entity
         E_Name : Positive;   --  Pointer to begin of entity name
 
      begin
         --  Look for the X lines corresponding to unit Eun
 
         loop
            if Ali (Ptr) = 'X' then
               Ptr := Ptr + 1;
               Parse_Number (Ali, Ptr, E_Eun);
               exit when E_Eun = Eun;
            end if;
 
            Parse_EOL (Ali, Ptr, Skip_Continuation_Line => True);
         end loop;
 
         --  Here we are in the right Ali section, we now look for the entity
         --  declared at position (Line, Col).
 
         loop
            Parse_Number (Ali, Ptr, E_Line);
            exit when Ali (Ptr) = EOF;
            Ptr := Ptr + 1;
            Parse_Number (Ali, Ptr, E_Col);
            exit when Ali (Ptr) = EOF;
            Ptr := Ptr + 1;
 
            if Line = E_Line and then Col = E_Col then
               Parse_Token (Ali, Ptr, E_Name);
               return Ali (E_Name .. Ptr - 1);
            end if;
 
            Parse_EOL (Ali, Ptr, Skip_Continuation_Line => True);
            exit when Ali (Ptr) = EOF;
         end loop;
 
         --  We were not able to find the symbol, this should not happen but
         --  since we don't want to stop here we return a string of three
         --  question marks as the symbol name.
 
         return "???";
      end Get_Symbol_Name;
 
      --------------------------------------
      -- Skip_To_Matching_Closing_Bracket --
      --------------------------------------
 
      procedure Skip_To_Matching_Closing_Bracket is
         Num_Brackets : Natural;
 
      begin
         Num_Brackets := 1;
         while Num_Brackets /= 0 loop
            Ptr := Ptr + 1;
            if Ali (Ptr) = '[' then
               Num_Brackets := Num_Brackets + 1;
            elsif Ali (Ptr) = ']' then
               Num_Brackets := Num_Brackets - 1;
            end if;
         end loop;
 
         Ptr := Ptr + 1;
      end Skip_To_Matching_Closing_Bracket;
 
   --  Start of processing for Parse_Identifier_Info
 
   begin
      --  The identifier info looks like:
      --     "38U9*Debug 12|36r6 36r19"
 
      --  Extract the line, column and entity name information
 
      Parse_Number (Ali, Ptr, E_Line);
 
      if Ali (Ptr) > ' ' then
         E_Type := Ali (Ptr);
         Ptr := Ptr + 1;
      end if;
 
      --  Ignore some of the entities (labels,...)
 
      case E_Type is
         when 'l' | 'L' | 'q' =>
            Parse_EOL (Ali, Ptr, Skip_Continuation_Line => True);
            return;
 
         when others =>
            null;
      end case;
 
      Parse_Number (Ali, Ptr, E_Col);
 
      E_Global := False;
      if Ali (Ptr) >= ' ' then
         E_Global := (Ali (Ptr) = '*');
         Ptr := Ptr + 1;
      end if;
 
      Parse_Token (Ali, Ptr, E_Name);
 
      --  Exit if the symbol does not match
      --  or if we have a local symbol and we do not want it
 
      if (not Local_Symbols and not E_Global)
        or else (Pattern.Initialized
                  and then not Match (Ali (E_Name .. Ptr - 1), Pattern.Entity))
        or else (E_Name >= Ptr)
      then
         Decl_Ref := Add_Declaration
           (File.X_File, Ali (E_Name .. Ptr - 1), E_Line, E_Col, E_Type,
            Remove_Only => True);
         Parse_EOL (Ali, Ptr, Skip_Continuation_Line => True);
         return;
      end if;
 
      --  Insert the declaration in the table
 
      Decl_Ref := Add_Declaration
        (File.X_File, Ali (E_Name .. Ptr - 1), E_Line, E_Col, E_Type);
 
      if Ali (Ptr) = '[' then
         Skip_To_Matching_Closing_Bracket;
      end if;
 
      --  Skip any renaming indication
 
      if Ali (Ptr) = '=' then
         declare
            P_Line, P_Column : Natural;
            pragma Warnings (Off, P_Line);
            pragma Warnings (Off, P_Column);
         begin
            Ptr := Ptr + 1;
            Parse_Number (Ali, Ptr, P_Line);
            Ptr := Ptr + 1;
            Parse_Number (Ali, Ptr, P_Column);
         end;
      end if;
 
      if Ali (Ptr) = '<'
        or else Ali (Ptr) = '('
        or else Ali (Ptr) = '{'
      then
         --  Here we have a type derivation information. The format is
         --  <3|12I45> which means that the current entity is derived from the
         --  type defined in unit number 3, line 12 column 45. The pipe and
         --  unit number is optional. It is specified only if the parent type
         --  is not defined in the current unit.
 
         --  We also have the format for generic instantiations, as in
         --  7a5*Uid(3|5I8[4|2]) 2|4r74
 
         --  We could also have something like
         --  16I9*I<integer>
         --  that indicates that I derives from the predefined type integer.
 
         Ptr := Ptr + 1;
 
         if Ali (Ptr) in '0' .. '9' then
            Parse_Derived_Info : declare
               P_Line   : Natural;          --  parent entity line
               P_Column : Natural;          --  parent entity column
               P_Eun    : Positive;         --  parent entity file number
 
            begin
               Parse_Number (Ali, Ptr, P_Line);
 
               --  If we have a pipe then the first number was the unit number
 
               if Ali (Ptr) = '|' then
                  P_Eun := P_Line;
                  Ptr := Ptr + 1;
 
                  --  Now we have the line number
 
                  Parse_Number (Ali, Ptr, P_Line);
 
               else
                  --  We don't have a unit number specified, so we set P_Eun to
                  --  the current unit.
 
                  for K in Dependencies_Tables.First .. Last (File.Dep) loop
                     P_Eun := K;
                     exit when File.Dep.Table (K) = File_Ref;
                  end loop;
               end if;
 
               --  Then parse the type and column number
 
               Ptr := Ptr + 1;
               Parse_Number (Ali, Ptr, P_Column);
 
               --  Skip the information for generics instantiations
 
               if Ali (Ptr) = '[' then
                  Skip_To_Matching_Closing_Bracket;
               end if;
 
               --  Skip '>', or ')' or '>'
 
               Ptr := Ptr + 1;
 
               --  The derived info is needed only is the derived info mode is
               --  on or if we want to output the type hierarchy
 
               if Der_Info or else Type_Tree then
                  declare
                     Symbol : constant String :=
                                Get_Symbol_Name (P_Eun, P_Line, P_Column);
                  begin
                     if Symbol /= "???" then
                        Add_Parent
                          (Decl_Ref,
                           Symbol,
                           P_Line,
                           P_Column,
                           File.Dep.Table (P_Eun));
                     end if;
                  end;
               end if;
 
               if Type_Tree
                 and then (Pattern.File_Ref = Empty_File
                             or else
                           Pattern.File_Ref = Current_Xref_File (File))
               then
                  Search_Parent_Tree : declare
                     Pattern         : Search_Pattern;  --  Parent type pattern
                     File_Pos_Backup : Positive;
 
                  begin
                     Add_Entity
                       (Pattern,
                        Get_Symbol_Name (P_Eun, P_Line, P_Column)
                        & ':' & Get_Gnatchop_File (File.Dep.Table (P_Eun))
                        & ':' & Get_Line (Get_Parent (Decl_Ref))
                        & ':' & Get_Column (Get_Parent (Decl_Ref)),
                        False);
 
                     --  No default match is needed to look for the parent type
                     --  since we are using the fully qualified symbol name:
                     --  symbol:file:line:column
 
                     Set_Default_Match (False);
 
                     --  The parent hierarchy is defined in the same unit as
                     --  the derived type. So we want to revisit the unit.
 
                     File_Pos_Backup   := File.Current_Line;
 
                     Skip_To_First_X_Line
                       (File, D_Lines => False, W_Lines => False);
 
                     while File.Buffer (File.Current_Line) /= EOF loop
                        Parse_X_Filename (File);
                        Parse_Identifier_Info
                          (Pattern       => Pattern,
                           File          => File,
                           Local_Symbols => False,
                           Der_Info      => Der_Info,
                           Type_Tree     => True,
                           Wide_Search   => False,
                           Labels_As_Ref => Labels_As_Ref);
                     end loop;
 
                     File.Current_Line := File_Pos_Backup;
                  end Search_Parent_Tree;
               end if;
            end Parse_Derived_Info;
 
         else
            while Ali (Ptr) /= '>'
              and then Ali (Ptr) /= ')'
              and then Ali (Ptr) /= '}'
            loop
               Ptr := Ptr + 1;
            end loop;
            Ptr := Ptr + 1;
         end if;
      end if;
 
      --  To find the body, we will have to parse the file too
 
      if Wide_Search then
         declare
            File_Ref : File_Reference;
            pragma Unreferenced (File_Ref);
            File_Name : constant String := Get_Gnatchop_File (File.X_File);
         begin
            File_Ref := Add_To_Xref_File (ALI_File_Name (File_Name), False);
         end;
      end if;
 
      --  Parse references to this entity.
      --  Ptr points to next reference with leading blanks
 
      loop
         --  Process references on current line
 
         while Ali (Ptr) = ' ' or else Ali (Ptr) = ASCII.HT loop
 
            --  For every reference read the line, type and column,
            --  optionally preceded by a file number and a pipe symbol.
 
            Parse_Number (Ali, Ptr, R_Line);
 
            if Ali (Ptr) = Pipe then
               Ptr := Ptr + 1;
               File_Ref := File_Name (File, R_Line);
 
               Parse_Number (Ali, Ptr, R_Line);
            end if;
 
            if Ali (Ptr) > ' ' then
               R_Type := Ali (Ptr);
               Ptr := Ptr + 1;
            end if;
 
            --  Imported entities might special indication as to their external
            --  name:
            --    5U14*Foo2 5>20 6b<c,myfoo2>22
 
            if R_Type = 'b'
              and then Ali (Ptr) = '<'
            then
               while Ptr <= Ali'Last
                 and then Ali (Ptr) /= '>'
               loop
                  Ptr := Ptr + 1;
               end loop;
               Ptr := Ptr + 1;
            end if;
 
            Parse_Number (Ali, Ptr, R_Col);
 
            --  Insert the reference or body in the table
 
            Add_Reference
              (Decl_Ref, File_Ref, R_Line, R_Col, R_Type, Labels_As_Ref);
 
            --  Skip generic information, if any
 
            if Ali (Ptr) = '[' then
               declare
                  Num_Nested : Integer := 1;
 
               begin
                  Ptr := Ptr + 1;
                  while Num_Nested /= 0 loop
                     if Ali (Ptr) = ']' then
                        Num_Nested := Num_Nested - 1;
                     elsif Ali (Ptr) = '[' then
                        Num_Nested := Num_Nested + 1;
                     end if;
 
                     Ptr := Ptr + 1;
                  end loop;
               end;
            end if;
 
         end loop;
 
         Parse_EOL (Ali, Ptr);
 
         --   Loop until new line is no continuation line
 
         exit when Ali (Ptr) /= '.';
         Ptr := Ptr + 1;
      end loop;
   end Parse_Identifier_Info;
 
   ------------------
   -- Parse_Number --
   ------------------
 
   procedure Parse_Number
     (Source : not null access String;
      Ptr    : in out Positive;
      Number : out Natural)
   is
   begin
      --  Skip separators
 
      while Source (Ptr) = ' ' or else Source (Ptr) = ASCII.HT loop
         Ptr := Ptr + 1;
      end loop;
 
      Number := 0;
      while Source (Ptr) in '0' .. '9' loop
         Number :=
           10 * Number + (Character'Pos (Source (Ptr)) - Character'Pos ('0'));
         Ptr := Ptr + 1;
      end loop;
   end Parse_Number;
 
   -----------------
   -- Parse_Token --
   -----------------
 
   procedure Parse_Token
     (Source    : not null access String;
      Ptr       : in out Positive;
      Token_Ptr : out Positive)
   is
      In_Quotes : Character := ASCII.NUL;
 
   begin
      --  Skip separators
 
      while Source (Ptr) = ' ' or else Source (Ptr) = ASCII.HT loop
         Ptr := Ptr + 1;
      end loop;
 
      Token_Ptr := Ptr;
 
      --  Find end-of-token
 
      while (In_Quotes /= ASCII.NUL or else
               not (Source (Ptr) = ' '
                     or else Source (Ptr) = ASCII.HT
                     or else Source (Ptr) = '<'
                     or else Source (Ptr) = '{'
                     or else Source (Ptr) = '['
                     or else Source (Ptr) = '='
                     or else Source (Ptr) = '('))
        and then Source (Ptr) >= ' '
      loop
         --  Double-quotes are used for operators
         --  Simple-quotes are used for character constants, for instance when
         --  they are found in an enumeration type "type A is ('+', '-');"
 
         case Source (Ptr) is
            when '"' | ''' =>
               if In_Quotes = Source (Ptr) then
                  In_Quotes := ASCII.NUL;
               elsif In_Quotes = ASCII.NUL then
                  In_Quotes := Source (Ptr);
               end if;
 
            when others =>
               null;
         end case;
 
         Ptr := Ptr + 1;
      end loop;
   end Parse_Token;
 
   ----------------------
   -- Parse_X_Filename --
   ----------------------
 
   procedure Parse_X_Filename (File : in out ALI_File) is
      Ali     : String_Access renames File.Buffer;
      Ptr     : Positive renames File.Current_Line;
      File_Nr : Natural;
 
   begin
      while Ali (Ptr) = 'X' loop
 
         --  The current line is the start of a new Xref file section,
         --  whose format looks like:
 
         --     " X 1 debug.ads"
 
         --  Skip the X and read the file number for the new X_File
 
         Ptr := Ptr + 1;
         Parse_Number (Ali, Ptr, File_Nr);
 
         if File_Nr > 0 then
            File.X_File := File.Dep.Table (File_Nr);
         end if;
 
         Parse_EOL (Ali, Ptr);
      end loop;
   end Parse_X_Filename;
 
   --------------------
   -- Print_Gnatfind --
   --------------------
 
   procedure Print_Gnatfind
     (References     : Boolean;
      Full_Path_Name : Boolean)
   is
      Decls : constant Declaration_Array_Access := Get_Declarations;
      Decl  : Declaration_Reference;
      Arr   : Reference_Array_Access;
 
      procedure Print_Ref
        (Ref : Reference;
         Msg : String := "      ");
      --  Print a reference, according to the extended tag of the output
 
      ---------------
      -- Print_Ref --
      ---------------
 
      procedure Print_Ref
        (Ref : Reference;
         Msg : String := "      ")
      is
         F : String_Access :=
               Osint.To_Host_File_Spec
                (Get_Gnatchop_File (Ref, Full_Path_Name));
 
         Buffer : constant String :=
                    F.all &
                    ":" & Get_Line (Ref)   &
                    ":" & Get_Column (Ref) &
                    ": ";
 
         Num_Blanks : Integer := Longest_File_Name + 10 - Buffer'Length;
 
      begin
         Free (F);
         Num_Blanks := Integer'Max (0, Num_Blanks);
         Write_Line
           (Buffer
            & String'(1 .. Num_Blanks => ' ')
            & Msg & " " & Get_Symbol (Decl));
 
         if Get_Source_Line (Ref)'Length /= 0 then
            Write_Line ("   " & Get_Source_Line (Ref));
         end if;
      end Print_Ref;
 
   --  Start of processing for Print_Gnatfind
 
   begin
      for D in Decls'Range loop
         Decl := Decls (D);
 
         if Match (Decl) then
 
            --  Output the declaration
 
            declare
               Parent : constant Declaration_Reference := Get_Parent (Decl);
 
               F : String_Access :=
                     Osint.To_Host_File_Spec
                      (Get_Gnatchop_File (Decl, Full_Path_Name));
 
               Buffer : constant String :=
                          F.all &
                          ":" & Get_Line (Decl)   &
                          ":" & Get_Column (Decl) &
                          ": ";
 
               Num_Blanks : Integer := Longest_File_Name + 10 - Buffer'Length;
 
            begin
               Free (F);
               Num_Blanks := Integer'Max (0, Num_Blanks);
               Write_Line
                 (Buffer & String'(1 .. Num_Blanks => ' ')
                  & "(spec) " & Get_Symbol (Decl));
 
               if Parent /= Empty_Declaration then
                  F := Osint.To_Host_File_Spec (Get_Gnatchop_File (Parent));
                  Write_Line
                    (Buffer & String'(1 .. Num_Blanks => ' ')
                     & "   derived from " & Get_Symbol (Parent)
                     & " ("
                     & F.all
                     & ':' & Get_Line (Parent)
                     & ':' & Get_Column (Parent) & ')');
                  Free (F);
               end if;
            end;
 
            if Get_Source_Line (Decl)'Length /= 0 then
               Write_Line ("   " & Get_Source_Line (Decl));
            end if;
 
            --  Output the body (sorted)
 
            Arr := Get_References (Decl, Get_Bodies => True);
 
            for R in Arr'Range loop
               Print_Ref (Arr (R), "(body)");
            end loop;
 
            Free (Arr);
 
            if References then
               Arr := Get_References
                 (Decl, Get_Writes => True, Get_Reads => True);
 
               for R in Arr'Range loop
                  Print_Ref (Arr (R));
               end loop;
 
               Free (Arr);
            end if;
         end if;
      end loop;
   end Print_Gnatfind;
 
   ------------------
   -- Print_Unused --
   ------------------
 
   procedure Print_Unused (Full_Path_Name : Boolean) is
      Decls : constant Declaration_Array_Access := Get_Declarations;
      Decl  : Declaration_Reference;
      Arr   : Reference_Array_Access;
      F     : String_Access;
 
   begin
      for D in Decls'Range loop
         Decl := Decls (D);
 
         if References_Count
             (Decl, Get_Reads => True, Get_Writes => True) = 0
         then
            F := Osint.To_Host_File_Spec
              (Get_Gnatchop_File (Decl, Full_Path_Name));
            Write_Str (Get_Symbol (Decl)
                        & " ("
                        & Get_Full_Type (Decl)
                        & ") "
                        & F.all
                        & ':'
                        & Get_Line (Decl)
                        & ':'
                        & Get_Column (Decl));
            Free (F);
 
            --  Print the body if any
 
            Arr := Get_References (Decl, Get_Bodies => True);
 
            for R in Arr'Range loop
               F := Osint.To_Host_File_Spec
                      (Get_Gnatchop_File (Arr (R), Full_Path_Name));
               Write_Str (' '
                           & F.all
                           & ':' & Get_Line (Arr (R))
                           & ':' & Get_Column (Arr (R)));
               Free (F);
            end loop;
 
            Write_Eol;
            Free (Arr);
         end if;
      end loop;
   end Print_Unused;
 
   --------------
   -- Print_Vi --
   --------------
 
   procedure Print_Vi (Full_Path_Name : Boolean) is
      Tab   : constant Character := ASCII.HT;
      Decls : constant Declaration_Array_Access :=
                Get_Declarations (Sorted => False);
      Decl  : Declaration_Reference;
      Arr   : Reference_Array_Access;
      F     : String_Access;
 
   begin
      for D in Decls'Range loop
         Decl := Decls (D);
 
         F := Osint.To_Host_File_Spec (Get_File (Decl, Full_Path_Name));
         Write_Line (Get_Symbol (Decl) & Tab & F.all & Tab & Get_Line (Decl));
         Free (F);
 
         --  Print the body if any
 
         Arr := Get_References (Decl, Get_Bodies => True);
 
         for R in Arr'Range loop
            F := Osint.To_Host_File_Spec (Get_File (Arr (R), Full_Path_Name));
            Write_Line
              (Get_Symbol (Decl) & Tab & F.all & Tab  & Get_Line (Arr (R)));
            Free (F);
         end loop;
 
         Free (Arr);
 
         --  Print the modifications
 
         Arr := Get_References (Decl, Get_Writes => True, Get_Reads => True);
 
         for R in Arr'Range loop
            F := Osint.To_Host_File_Spec (Get_File (Arr (R), Full_Path_Name));
            Write_Line
              (Get_Symbol (Decl) & Tab & F.all & Tab & Get_Line (Arr (R)));
            Free (F);
         end loop;
 
         Free (Arr);
      end loop;
   end Print_Vi;
 
   ----------------
   -- Print_Xref --
   ----------------
 
   procedure Print_Xref (Full_Path_Name : Boolean) is
      Decls : constant Declaration_Array_Access := Get_Declarations;
      Decl : Declaration_Reference;
 
      Margin : constant := 10;
      --  Column where file names start
 
      procedure New_Line80;
      --  Go to start of new line
 
      procedure Print80 (S : String);
      --  Print the text, respecting the 80 columns rule
 
      procedure Print_Ref (Line, Column : String);
      --  The beginning of the output is aligned on a column multiple of 9
 
      procedure Print_List
        (Decl       : Declaration_Reference;
         Msg        : String;
         Get_Reads  : Boolean := False;
         Get_Writes : Boolean := False;
         Get_Bodies : Boolean := False);
      --  Print a list of references. If the list is not empty, Msg will
      --  be printed prior to the list.
 
      ----------------
      -- New_Line80 --
      ----------------
 
      procedure New_Line80 is
      begin
         Write_Eol;
         Write_Str (String'(1 .. Margin - 1 => ' '));
      end New_Line80;
 
      -------------
      -- Print80 --
      -------------
 
      procedure Print80 (S : String) is
         Align : Natural := Margin - (Integer (Column) mod Margin);
 
      begin
         if Align = Margin then
            Align := 0;
         end if;
 
         Write_Str (String'(1 .. Align => ' ') & S);
      end Print80;
 
      ---------------
      -- Print_Ref --
      ---------------
 
      procedure Print_Ref (Line, Column : String) is
         Line_Align : constant Integer := 4 - Line'Length;
 
         S : constant String := String'(1 .. Line_Align => ' ')
                                  & Line & ':' & Column;
 
         Align : Natural := Margin - (Integer (Output.Column) mod Margin);
 
      begin
         if Align = Margin then
            Align := 0;
         end if;
 
         if Integer (Output.Column) + Align + S'Length > 79 then
            New_Line80;
            Align := 0;
         end if;
 
         Write_Str (String'(1 .. Align => ' ') & S);
      end Print_Ref;
 
      ----------------
      -- Print_List --
      ----------------
 
      procedure Print_List
        (Decl       : Declaration_Reference;
         Msg        : String;
         Get_Reads  : Boolean := False;
         Get_Writes : Boolean := False;
         Get_Bodies : Boolean := False)
      is
         Arr : Reference_Array_Access :=
                 Get_References
                   (Decl,
                    Get_Writes => Get_Writes,
                    Get_Reads  => Get_Reads,
                    Get_Bodies => Get_Bodies);
         File : File_Reference := Empty_File;
         F    : String_Access;
 
      begin
         if Arr'Length /= 0 then
            Write_Eol;
            Write_Str (Msg);
         end if;
 
         for R in Arr'Range loop
            if Get_File_Ref (Arr (R)) /= File then
               if File /= Empty_File then
                  New_Line80;
               end if;
 
               File := Get_File_Ref (Arr (R));
               F := Osint.To_Host_File_Spec
                 (Get_Gnatchop_File (Arr (R), Full_Path_Name));
 
               if F = null then
                  Write_Str ("<unknown> ");
               else
                  Write_Str (F.all & ' ');
                  Free (F);
               end if;
            end if;
 
            Print_Ref (Get_Line (Arr (R)), Get_Column (Arr (R)));
         end loop;
 
         Free (Arr);
      end Print_List;
 
      F : String_Access;
 
   --  Start of processing for Print_Xref
 
   begin
      for D in Decls'Range loop
         Decl := Decls (D);
 
         Write_Str (Get_Symbol (Decl));
 
         --  Put the declaration type in column Type_Position, but if the
         --  declaration name is too long, put at least one space between its
         --  name and its type.
 
         while Column < Type_Position - 1 loop
            Write_Char (' ');
         end loop;
 
         Write_Char (' ');
 
         Write_Line (Get_Full_Type (Decl));
 
         Write_Parent_Info : declare
            Parent : constant Declaration_Reference := Get_Parent (Decl);
 
         begin
            if Parent /= Empty_Declaration then
               Write_Str ("  Ptype: ");
               F := Osint.To_Host_File_Spec (Get_Gnatchop_File (Parent));
               Print80 (F.all);
               Free (F);
               Print_Ref (Get_Line (Parent), Get_Column (Parent));
               Print80 ("  " & Get_Symbol (Parent));
               Write_Eol;
            end if;
         end Write_Parent_Info;
 
         Write_Str ("  Decl:  ");
         F := Osint.To_Host_File_Spec
               (Get_Gnatchop_File (Decl, Full_Path_Name));
 
         if F = null then
            Print80 ("<unknown> ");
         else
            Print80 (F.all & ' ');
            Free (F);
         end if;
 
         Print_Ref (Get_Line (Decl), Get_Column (Decl));
 
         Print_List
           (Decl, "  Body:  ", Get_Bodies => True);
         Print_List
           (Decl, "  Modi:  ", Get_Writes => True);
         Print_List
           (Decl, "  Ref:   ", Get_Reads => True);
         Write_Eol;
      end loop;
   end Print_Xref;
 
   ------------
   -- Search --
   ------------
 
   procedure Search
     (Pattern       : Search_Pattern;
      Local_Symbols : Boolean;
      Wide_Search   : Boolean;
      Read_Only     : Boolean;
      Der_Info      : Boolean;
      Type_Tree     : Boolean)
   is
      type String_Access is access String;
      procedure Free is new Unchecked_Deallocation (String, String_Access);
 
      ALIfile   : ALI_File;
      File_Ref  : File_Reference;
      Strip_Num : Natural := 0;
      Ali_Name  : String_Access;
 
   begin
      --  If we want all the .ali files, then find them
 
      if Wide_Search then
         Find_ALI_Files;
      end if;
 
      loop
         --  Get the next unread ali file
 
         File_Ref := Next_Unvisited_File;
 
         exit when File_Ref = Empty_File;
 
         --  Find the ALI file to use. Most of the time, it will be the unit
         --  name, with a different extension. However, when dealing with
         --  separates the ALI file is in fact the parent's ALI file (and this
         --  is recursive, in case the parent itself is a separate).
 
         Strip_Num := 0;
         loop
            Free (Ali_Name);
            Ali_Name := new String'
              (Get_File (File_Ref, With_Dir => True, Strip => Strip_Num));
 
            --  Stripped too many things...
 
            if Ali_Name.all = "" then
               if Get_Emit_Warning (File_Ref) then
                  Set_Standard_Error;
                  Write_Line
                    ("warning : file " & Get_File (File_Ref, With_Dir => True)
                     & " not found");
                  Set_Standard_Output;
               end if;
               Free (Ali_Name);
               exit;
 
            --  If not found, try the parent's ALI file (this is needed for
            --  separate units and subprograms).
 
            --  Reset the cached directory first, in case the separate's
            --  ALI file is not in the same directory.
 
            elsif not File_Exists (Ali_Name.all) then
               Strip_Num := Strip_Num + 1;
               Reset_Directory (File_Ref);
 
            --  Else we finally found it
 
            else
               exit;
            end if;
         end loop;
 
         --  If we had to get the parent's ALI, insert it in the list as usual.
         --  This is to avoid parsing it twice in case it has already been
         --  parsed.
 
         if Ali_Name /= null and then Strip_Num /= 0 then
            File_Ref := Add_To_Xref_File
              (File_Name => Ali_Name.all,
               Visited   => False);
 
         --  Now that we have a file name, parse it to find any reference to
         --  the entity.
 
         elsif Ali_Name /= null
           and then (Read_Only or else Is_Writable_File (Ali_Name.all))
         then
            begin
               Open (Ali_Name.all, ALIfile);
 
               --  The cross-reference section in the ALI file may be followed
               --  by other sections, which can be identified by the starting
               --  character of every line, which should neither be 'X' nor a
               --  figure in '1' .. '9'.
 
               --  The loop tests below also take into account the end-of-file
               --  possibility.
 
               while ALIfile.Buffer (ALIfile.Current_Line) = 'X' loop
                  Parse_X_Filename (ALIfile);
 
                  while ALIfile.Buffer (ALIfile.Current_Line) in '1' .. '9'
                  loop
                     Parse_Identifier_Info
                       (Pattern, ALIfile, Local_Symbols, Der_Info, Type_Tree,
                        Wide_Search, Labels_As_Ref => True);
                  end loop;
               end loop;
 
            exception
               when No_Xref_Information   =>
                  if Get_Emit_Warning (File_Ref) then
                     Set_Standard_Error;
                     Write_Line
                       ("warning : No cross-referencing information in  "
                        & Ali_Name.all);
                     Set_Standard_Output;
                  end if;
            end;
         end if;
      end loop;
 
      Free (Ali_Name);
   end Search;
 
   -----------------
   -- Search_Xref --
   -----------------
 
   procedure Search_Xref
     (Local_Symbols : Boolean;
      Read_Only     : Boolean;
      Der_Info      : Boolean)
   is
      ALIfile      : ALI_File;
      File_Ref     : File_Reference;
      Null_Pattern : Search_Pattern;
 
   begin
      Null_Pattern.Initialized := False;
 
      loop
         --  Find the next unvisited file
 
         File_Ref := Next_Unvisited_File;
         exit when File_Ref = Empty_File;
 
         --  Search the object directories for the .ali file
 
         declare
            F : constant String := Get_File (File_Ref, With_Dir => True);
 
         begin
            if Read_Only or else Is_Writable_File (F) then
               Open (F, ALIfile, True);
 
               --  The cross-reference section in the ALI file may be followed
               --  by other sections, which can be identified by the starting
               --  character of every line, which should neither be 'X' nor a
               --  figure in '1' .. '9'.
 
               --  The loop tests below also take into account the end-of-file
               --  possibility.
 
               while ALIfile.Buffer (ALIfile.Current_Line) = 'X' loop
                  Parse_X_Filename (ALIfile);
 
                  while ALIfile.Buffer (ALIfile.Current_Line) in '1' .. '9'
                  loop
                     Parse_Identifier_Info
                       (Null_Pattern, ALIfile, Local_Symbols, Der_Info,
                        Labels_As_Ref => False);
                  end loop;
               end loop;
            end if;
 
         exception
            when No_Xref_Information =>  null;
         end;
      end loop;
   end Search_Xref;
 
end Xref_Lib;

Go to most recent revision | Compare with Previous | Blame | View Log

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.