diff options
Diffstat (limited to 'gcc/ada/xr_tabls.adb')
-rw-r--r-- | gcc/ada/xr_tabls.adb | 1702 |
1 files changed, 973 insertions, 729 deletions
diff --git a/gcc/ada/xr_tabls.adb b/gcc/ada/xr_tabls.adb index 93be4f86900..8e332ec6276 100644 --- a/gcc/ada/xr_tabls.adb +++ b/gcc/ada/xr_tabls.adb @@ -6,7 +6,7 @@ -- -- -- B o d y -- -- -- --- Copyright (C) 1998-2002 Free Software Foundation, Inc. -- +-- Copyright (C) 1998-2003 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- -- @@ -19,105 +19,284 @@ -- to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, -- -- MA 02111-1307, USA. -- -- -- --- Extensive contributions were provided by Ada Core Technologies Inc. -- +-- GNAT was originally developed by the GNAT team at New York University. -- +-- Extensive contributions were provided by Ada Core Technologies Inc. -- -- -- ------------------------------------------------------------------------------ +with Types; use Types; with Osint; -with Unchecked_Deallocation; +with Hostparm; -with Ada.IO_Exceptions; +with Ada.Unchecked_Conversion; +with Ada.Unchecked_Deallocation; with Ada.Strings.Fixed; with Ada.Strings; with Ada.Text_IO; -with Ada.Strings.Unbounded; use Ada.Strings.Unbounded; +with Ada.Characters.Handling; use Ada.Characters.Handling; +with Ada.Strings.Unbounded; use Ada.Strings.Unbounded; -with GNAT.IO_Aux; with GNAT.OS_Lib; use GNAT.OS_Lib; with GNAT.Directory_Operations; use GNAT.Directory_Operations; +with GNAT.HTable; use GNAT.HTable; +with GNAT.Heap_Sort_G; package body Xr_Tabls is - function Base_File_Name (File : String) return String; - -- Return the base file name for File (ie not including the directory) + type HTable_Headers is range 1 .. 10000; + + procedure Set_Next (E : File_Reference; Next : File_Reference); + function Next (E : File_Reference) return File_Reference; + function Get_Key (E : File_Reference) return Cst_String_Access; + function Hash (F : Cst_String_Access) return HTable_Headers; + function Equal (F1, F2 : Cst_String_Access) return Boolean; + -- The five subprograms above are used to instanciate the static + -- htable to store the files that should be processed. + + package File_HTable is new GNAT.HTable.Static_HTable + (Header_Num => HTable_Headers, + Element => File_Record, + Elmt_Ptr => File_Reference, + Null_Ptr => null, + Set_Next => Set_Next, + Next => Next, + Key => Cst_String_Access, + Get_Key => Get_Key, + Hash => Hash, + Equal => Equal); + -- A hash table to store all the files referenced in the + -- application. The keys in this htable are the name of the files + -- themselves, therefore it is assumed that the source path + -- doesn't contain twice the same source or ALI file name + + type Unvisited_Files_Record; + type Unvisited_Files_Access is access Unvisited_Files_Record; + type Unvisited_Files_Record is record + File : File_Reference; + Next : Unvisited_Files_Access; + end record; + -- A special list, in addition to File_HTable, that only stores + -- the files that haven't been visited so far. Note that the File + -- list points to some data in File_HTable, and thus should never be freed. + + function Next (E : Declaration_Reference) return Declaration_Reference; + procedure Set_Next (E, Next : Declaration_Reference); + function Get_Key (E : Declaration_Reference) return Cst_String_Access; + -- The subprograms above are used to instanciate the static + -- htable to store the entities that have been found in the application + + package Entities_HTable is new GNAT.HTable.Static_HTable + (Header_Num => HTable_Headers, + Element => Declaration_Record, + Elmt_Ptr => Declaration_Reference, + Null_Ptr => null, + Set_Next => Set_Next, + Next => Next, + Key => Cst_String_Access, + Get_Key => Get_Key, + Hash => Hash, + Equal => Equal); + -- A hash table to store all the entities defined in the + -- application. For each entity, we store a list of its reference + -- locations as well. + -- The keys in this htable should be created with Key_From_Ref, + -- and are the file, line and column of the declaration, which are + -- unique for every entity. + + Entities_Count : Natural := 0; + -- Number of entities in Entities_HTable. This is used in the end + -- when sorting the table. + + Longest_File_Name_In_Table : Natural := 0; + Unvisited_Files : Unvisited_Files_Access := null; + Directories : Project_File_Ptr; + Default_Match : Boolean := False; + -- The above need commenting ??? + + function Parse_Gnatls_Src return String; + -- Return the standard source directories (taking into account the + -- ADA_INCLUDE_PATH environment variable, if Osint.Add_Default_Search_Dirs + -- was called first). + + function Parse_Gnatls_Obj return String; + -- Return the standard object directories (taking into account the + -- ADA_OBJECTS_PATH environment variable). + + function Key_From_Ref + (File_Ref : File_Reference; + Line : Natural; + Column : Natural) + return String; + -- Return a key for the symbol declared at File_Ref, Line, + -- Column. This key should be used for lookup in Entity_HTable + + function Is_Less_Than (Decl1, Decl2 : Declaration_Reference) return Boolean; + -- Compare two declarations. The comparison is case-insensitive. + + function Is_Less_Than (Ref1, Ref2 : Reference) return Boolean; + -- Compare two references + + procedure Store_References + (Decl : Declaration_Reference; + Get_Writes : Boolean := False; + Get_Reads : Boolean := False; + Get_Bodies : Boolean := False; + Get_Declaration : Boolean := False; + Arr : in out Reference_Array; + Index : in out Natural); + -- Store in Arr, starting at Index, all the references to Decl. + -- The Get_* parameters can be used to indicate which references should be + -- stored. + -- Constraint_Error will be raised if Arr is not big enough. + + procedure Sort (Arr : in out Reference_Array); + -- Sort an array of references. + -- Arr'First must be 1. + + -------------- + -- Set_Next -- + -------------- + + procedure Set_Next (E : File_Reference; Next : File_Reference) is + begin + E.Next := Next; + end Set_Next; + + procedure Set_Next + (E : Declaration_Reference; Next : Declaration_Reference) is + begin + E.Next := Next; + end Set_Next; + + ------------- + -- Get_Key -- + ------------- + + function Get_Key (E : File_Reference) return Cst_String_Access is + begin + return E.File; + end Get_Key; - function Dir_Name (File : String; Base : String := "") return String; - -- Return the directory name of File, or "" if there is no directory part - -- in File. - -- This includes the last separator at the end, and always return an - -- absolute path name (directories are relative to Base, or the current - -- directory if Base is "") + function Get_Key (E : Declaration_Reference) return Cst_String_Access is + begin + return E.Key; + end Get_Key; + + ---------- + -- Hash -- + ---------- + + function Hash (F : Cst_String_Access) return HTable_Headers is + function H is new GNAT.HTable.Hash (HTable_Headers); + + begin + return H (F.all); + end Hash; - Dir_Sep : Character renames GNAT.OS_Lib.Directory_Separator; + ----------- + -- Equal -- + ----------- - Files : File_Table; - Entities : Entity_Table; - Directories : Project_File_Ptr; - Default_Match : Boolean := False; + function Equal (F1, F2 : Cst_String_Access) return Boolean is + begin + return F1.all = F2.all; + end Equal; + + ------------------ + -- Key_From_Ref -- + ------------------ + + function Key_From_Ref + (File_Ref : File_Reference; + Line : Natural; + Column : Natural) + return String + is + begin + return File_Ref.File.all & Natural'Image (Line) & Natural'Image (Column); + end Key_From_Ref; --------------------- -- Add_Declaration -- --------------------- function Add_Declaration - (File_Ref : File_Reference; - Symbol : String; - Line : Natural; - Column : Natural; - Decl_Type : Character) - return Declaration_Reference + (File_Ref : File_Reference; + Symbol : String; + Line : Natural; + Column : Natural; + Decl_Type : Character; + Remove_Only : Boolean := False; + Symbol_Match : Boolean := True) + return Declaration_Reference is - The_Entities : Declaration_Reference := Entities.Table; - New_Decl : Declaration_Reference; - Result : Compare_Result; - Prev : Declaration_Reference := null; + procedure Unchecked_Free is new Ada.Unchecked_Deallocation + (Declaration_Record, Declaration_Reference); - begin - -- Check if the identifier already exists in the table + Key : aliased constant String := Key_From_Ref (File_Ref, Line, Column); - while The_Entities /= null loop - Result := Compare (The_Entities, File_Ref, Line, Column, Symbol); - exit when Result = GreaterThan; + New_Decl : Declaration_Reference := + Entities_HTable.Get (Key'Unchecked_Access); - if Result = Equal then - return The_Entities; - end if; + Is_Parameter : Boolean := False; - Prev := The_Entities; - The_Entities := The_Entities.Next; - end loop; - - -- Insert the Declaration in the table - - New_Decl := - new Declaration_Record' - (Symbol_Length => Symbol'Length, - Symbol => Symbol, - Decl => (File => File_Ref, - Line => Line, - Column => Column, - Source_Line => Null_Unbounded_String, - Next => null), - Decl_Type => Decl_Type, - Body_Ref => null, - Ref_Ref => null, - Modif_Ref => null, - Match => Default_Match - or else Match (File_Ref, Line, Column), - Par_Symbol => null, - Next => null); - - if Prev = null then - New_Decl.Next := Entities.Table; - Entities.Table := New_Decl; - else - New_Decl.Next := Prev.Next; - Prev.Next := New_Decl; + begin + -- Insert the Declaration in the table. There might already be a + -- declaration in the table if the entity is a parameter, so we + -- need to check that first. + + if New_Decl /= null and then New_Decl.Symbol_Length = 0 then + Is_Parameter := New_Decl.Is_Parameter; + Entities_HTable.Remove (Key'Unrestricted_Access); + Entities_Count := Entities_Count - 1; + Free (New_Decl.Key); + Unchecked_Free (New_Decl); + New_Decl := null; end if; - if New_Decl.Match then - Files.Longest_Name := Natural'Max (File_Ref.File'Length, - Files.Longest_Name); + -- The declaration might also already be there for parent types. In + -- this case, we should keep the entry, since some other entries are + -- pointing to it. + + if New_Decl = null + and then not Remove_Only + then + New_Decl := + new Declaration_Record' + (Symbol_Length => Symbol'Length, + Symbol => Symbol, + Key => new String'(Key), + Decl => new Reference_Record' + (File => File_Ref, + Line => Line, + Column => Column, + Source_Line => null, + Next => null), + Is_Parameter => Is_Parameter, + Decl_Type => Decl_Type, + Body_Ref => null, + Ref_Ref => null, + Modif_Ref => null, + Match => Symbol_Match + and then + (Default_Match + or else Match (File_Ref, Line, Column)), + Par_Symbol => null, + Next => null); + + Entities_HTable.Set (New_Decl); + Entities_Count := Entities_Count + 1; + + if New_Decl.Match then + Longest_File_Name_In_Table := + Natural'Max (File_Ref.File'Length, Longest_File_Name_In_Table); + end if; + + elsif New_Decl /= null + and then not New_Decl.Match + then + New_Decl.Match := Default_Match + or else Match (File_Ref, Line, Column); end if; return New_Decl; @@ -127,52 +306,46 @@ package body Xr_Tabls is -- Add_To_Xref_File -- ---------------------- - procedure Add_To_Xref_File + function Add_To_Xref_File (File_Name : String; - File_Existed : out Boolean; - Ref : out File_Reference; Visited : Boolean := True; Emit_Warning : Boolean := False; Gnatchop_File : String := ""; - Gnatchop_Offset : Integer := 0) + Gnatchop_Offset : Integer := 0) return File_Reference is - The_Files : File_Reference := Files.Table; - Base : constant String := Base_File_Name (File_Name); - Dir : constant String := Xr_Tabls.Dir_Name (File_Name); - Dir_Acc : String_Access := null; + Base : aliased constant String := Base_Name (File_Name); + Dir : constant String := Dir_Name (File_Name); + Dir_Acc : GNAT.OS_Lib.String_Access := null; + Ref : File_Reference; begin -- Do we have a directory name as well? - if Dir /= "" then - Dir_Acc := new String' (Dir); + if File_Name /= Base then + Dir_Acc := new String'(Dir); end if; - -- Check if the file already exists in the table + Ref := File_HTable.Get (Base'Unchecked_Access); + if Ref = null then + Ref := new File_Record' + (File => new String'(Base), + Dir => Dir_Acc, + Lines => null, + Visited => Visited, + Emit_Warning => Emit_Warning, + Gnatchop_File => new String'(Gnatchop_File), + Gnatchop_Offset => Gnatchop_Offset, + Next => null); + File_HTable.Set (Ref); - while The_Files /= null loop + if not Visited then - if The_Files.File = File_Name then - File_Existed := True; - Ref := The_Files; - return; - end if; + -- Keep a separate list for faster access - The_Files := The_Files.Next; - end loop; - - Ref := new File_Record' - (File_Length => Base'Length, - File => Base, - Dir => Dir_Acc, - Lines => null, - Visited => Visited, - Emit_Warning => Emit_Warning, - Gnatchop_File => new String' (Gnatchop_File), - Gnatchop_Offset => Gnatchop_Offset, - Next => Files.Table); - Files.Table := Ref; - File_Existed := False; + Set_Unvisited (Ref); + end if; + end if; + return Ref; end Add_To_Xref_File; -------------- @@ -202,21 +375,11 @@ package body Xr_Tabls is File_Ref : File_Reference) is begin - Declaration.Par_Symbol := new Declaration_Record' - (Symbol_Length => Symbol'Length, - Symbol => Symbol, - Decl => (File => File_Ref, - Line => Line, - Column => Column, - Source_Line => Null_Unbounded_String, - Next => null), - Decl_Type => ' ', - Body_Ref => null, - Ref_Ref => null, - Modif_Ref => null, - Match => False, - Par_Symbol => null, - Next => null); + Declaration.Par_Symbol := + Add_Declaration + (File_Ref, Symbol, Line, Column, + Decl_Type => ' ', + Symbol_Match => False); end Add_Parent; ------------------- @@ -224,37 +387,55 @@ package body Xr_Tabls is ------------------- procedure Add_Reference - (Declaration : Declaration_Reference; - File_Ref : File_Reference; - Line : Natural; - Column : Natural; - Ref_Type : Character) + (Declaration : Declaration_Reference; + File_Ref : File_Reference; + Line : Natural; + Column : Natural; + Ref_Type : Character; + Labels_As_Ref : Boolean) is - procedure Free is new Unchecked_Deallocation - (Reference_Record, Reference); - - Ref : Reference; - Prev : Reference := null; - Result : Compare_Result; - New_Ref : Reference := new Reference_Record' - (File => File_Ref, - Line => Line, - Column => Column, - Source_Line => Null_Unbounded_String, - Next => null); + New_Ref : Reference; begin case Ref_Type is - when 'b' | 'c' => - Ref := Declaration.Body_Ref; + when 'b' | 'c' | 'm' | 'r' | 'i' | ' ' | 'x' => + null; - when 'r' | 'i' | 'l' | ' ' | 'x' => - Ref := Declaration.Ref_Ref; + when 'l' | 'w' => + if not Labels_As_Ref then + return; + end if; - when 'm' => - Ref := Declaration.Modif_Ref; + when '=' | '<' | '>' | '^' => - when 'e' | 't' | 'p' => + -- Create a dummy declaration in the table to report it as a + -- parameter. Note that the current declaration for the subprogram + -- comes before the declaration of the parameter. + + declare + Key : constant String := + Key_From_Ref (File_Ref, Line, Column); + New_Decl : Declaration_Reference; + + begin + New_Decl := new Declaration_Record' + (Symbol_Length => 0, + Symbol => "", + Key => new String'(Key), + Decl => null, + Is_Parameter => True, + Decl_Type => ' ', + Body_Ref => null, + Ref_Ref => null, + Modif_Ref => null, + Match => False, + Par_Symbol => null, + Next => null); + Entities_HTable.Set (New_Decl); + Entities_Count := Entities_Count + 1; + end; + + when 'e' | 'z' | 't' | 'p' | 'P' | 'k' | 'd' => return; when others => @@ -262,53 +443,43 @@ package body Xr_Tabls is return; end case; - -- Check if the reference already exists - - while Ref /= null loop - Result := Compare (New_Ref, Ref); - exit when Result = LessThan; + New_Ref := new Reference_Record' + (File => File_Ref, + Line => Line, + Column => Column, + Source_Line => null, + Next => null); - if Result = Equal then - Free (New_Ref); - return; - end if; + -- We can insert the reference in the list directly, since all + -- the references will appear only once in the ALI file + -- corresponding to the file where they are referenced. + -- This saves a lot of time compared to checking the list to check + -- if it exists. - Prev := Ref; - Ref := Ref.Next; - end loop; + case Ref_Type is + when 'b' | 'c' => + New_Ref.Next := Declaration.Body_Ref; + Declaration.Body_Ref := New_Ref; - -- Insert it in the list + when 'r' | 'i' | 'l' | ' ' | 'x' | 'w' => + New_Ref.Next := Declaration.Ref_Ref; + Declaration.Ref_Ref := New_Ref; - if Prev /= null then - New_Ref.Next := Prev.Next; - Prev.Next := New_Ref; + when 'm' => + New_Ref.Next := Declaration.Modif_Ref; + Declaration.Modif_Ref := New_Ref; - else - case Ref_Type is - when 'b' | 'c' => - New_Ref.Next := Declaration.Body_Ref; - Declaration.Body_Ref := New_Ref; - - when 'r' | 'i' | 'l' | ' ' | 'x' => - New_Ref.Next := Declaration.Ref_Ref; - Declaration.Ref_Ref := New_Ref; - - when 'm' => - New_Ref.Next := Declaration.Modif_Ref; - Declaration.Modif_Ref := New_Ref; - - when others => - null; - end case; - end if; + when others => + null; + end case; if not Declaration.Match then Declaration.Match := Match (File_Ref, Line, Column); end if; if Declaration.Match then - Files.Longest_Name := Natural'Max (File_Ref.File'Length, - Files.Longest_Name); + Longest_File_Name_In_Table := + Natural'Max (File_Ref.File'Length, Longest_File_Name_In_Table); end if; end Add_Reference; @@ -317,150 +488,91 @@ package body Xr_Tabls is ------------------- function ALI_File_Name (Ada_File_Name : String) return String is - Index : Natural := Ada.Strings.Fixed.Index - (Ada_File_Name, ".", Going => Ada.Strings.Backward); + + -- ??? Should ideally be based on the naming scheme defined in + -- project files. + + Index : constant Natural := + Ada.Strings.Fixed.Index + (Ada_File_Name, ".", Going => Ada.Strings.Backward); begin if Index /= 0 then - return Ada_File_Name (Ada_File_Name'First .. Index) - & "ali"; + return Ada_File_Name (Ada_File_Name'First .. Index) & "ali"; else return Ada_File_Name & ".ali"; end if; end ALI_File_Name; - -------------------- - -- Base_File_Name -- - -------------------- - - function Base_File_Name (File : String) return String is - begin - for J in reverse File'Range loop - if File (J) = '/' or else File (J) = Dir_Sep then - return File (J + 1 .. File'Last); - end if; - end loop; - - return File; - end Base_File_Name; - - ------------- - -- Compare -- - ------------- + ------------------ + -- Is_Less_Than -- + ------------------ - function Compare - (Ref1 : Reference; - Ref2 : Reference) - return Compare_Result - is + function Is_Less_Than (Ref1, Ref2 : Reference) return Boolean is begin if Ref1 = null then - return GreaterThan; + return False; elsif Ref2 = null then - return LessThan; + return True; end if; - if Ref1.File.File < Ref2.File.File then - return LessThan; + if Ref1.File.File.all < Ref2.File.File.all then + return True; - elsif Ref1.File.File = Ref2.File.File then - if Ref1.Line < Ref2.Line then - return LessThan; + elsif Ref1.File.File.all = Ref2.File.File.all then + return (Ref1.Line < Ref2.Line + or else (Ref1.Line = Ref2.Line + and then Ref1.Column < Ref2.Column)); + end if; - elsif Ref1.Line = Ref2.Line then - if Ref1.Column < Ref2.Column then - return LessThan; - elsif Ref1.Column = Ref2.Column then - return Equal; - else - return GreaterThan; - end if; + return False; + end Is_Less_Than; - else - return GreaterThan; - end if; + ------------------ + -- Is_Less_Than -- + ------------------ - else - return GreaterThan; - end if; - end Compare; + function Is_Less_Than (Decl1, Decl2 : Declaration_Reference) return Boolean + is + -- We cannot store the data case-insensitive in the table, + -- since we wouldn't be able to find the right casing for the + -- display later on. - ------------- - -- Compare -- - ------------- + S1 : constant String := To_Lower (Decl1.Symbol); + S2 : constant String := To_Lower (Decl2.Symbol); - function Compare - (Decl1 : Declaration_Reference; - File2 : File_Reference; - Line2 : Integer; - Col2 : Integer; - Symb2 : String) - return Compare_Result - is begin - if Decl1 = null then - return GreaterThan; + if S1 < S2 then + return True; + elsif S1 > S2 then + return False; end if; - if Decl1.Symbol < Symb2 then - return LessThan; - elsif Decl1.Symbol > Symb2 then - return GreaterThan; - end if; - - if Decl1.Decl.File.File < Get_File (File2) then - return LessThan; - - elsif Decl1.Decl.File.File = Get_File (File2) then - if Decl1.Decl.Line < Line2 then - return LessThan; - - elsif Decl1.Decl.Line = Line2 then - if Decl1.Decl.Column < Col2 then - return LessThan; - - elsif Decl1.Decl.Column = Col2 then - return Equal; - - else - return GreaterThan; - end if; - - else - return GreaterThan; - end if; - - else - return GreaterThan; - end if; - end Compare; + return Decl1.Key.all < Decl2.Key.all; + end Is_Less_Than; ------------------------- -- Create_Project_File -- ------------------------- - procedure Create_Project_File - (Name : String) - is + procedure Create_Project_File (Name : String) is use Ada.Strings.Unbounded; Obj_Dir : Unbounded_String := Null_Unbounded_String; Src_Dir : Unbounded_String := Null_Unbounded_String; - Build_Dir : Unbounded_String; - - Gnatls_Src_Cache : Unbounded_String; - Gnatls_Obj_Cache : Unbounded_String; + Build_Dir : GNAT.OS_Lib.String_Access := new String'(""); F : File_Descriptor; Len : Positive; File_Name : aliased String := Name & ASCII.NUL; begin - -- Read the size of the file + F := Open_Read (File_Name'Address, Text); -- Project file not found + if F /= Invalid_FD then Len := Positive (File_Length (F)); @@ -468,6 +580,7 @@ package body Xr_Tabls is Buffer : String (1 .. Len); Index : Positive := Buffer'First; Last : Positive; + begin Len := Read (F, Buffer'Address, Len); Close (F); @@ -477,7 +590,7 @@ package body Xr_Tabls is while Index <= Buffer'Last loop - -- find the end of line + -- Find the end of line Last := Index; while Last <= Buffer'Last @@ -498,11 +611,8 @@ package body Xr_Tabls is Index := Index + 1; end loop; - Build_Dir := - To_Unbounded_String (Buffer (Index .. Last - 1)); - if Buffer (Last - 1) /= Dir_Sep then - Append (Build_Dir, Dir_Sep); - end if; + Free (Build_Dir); + Build_Dir := new String'(Buffer (Index .. Last - 1)); end if; Index := Last + 1; @@ -522,7 +632,7 @@ package body Xr_Tabls is Index := Buffer'First; while Index <= Buffer'Last loop - -- find the end of line + -- Find the end of line Last := Index; while Last <= Buffer'Last @@ -535,40 +645,18 @@ package body Xr_Tabls is if Index <= Buffer'Last - 7 and then Buffer (Index .. Index + 7) = "src_dir=" then - declare - S : String := Ada.Strings.Fixed.Trim - (Buffer (Index + 8 .. Last - 1), Ada.Strings.Both); - begin - -- A relative directory ? - if S (S'First) /= Dir_Sep then - Append (Src_Dir, Build_Dir); - end if; - - if S (S'Last) = Dir_Sep then - Append (Src_Dir, S & " "); - else - Append (Src_Dir, S & Dir_Sep & " "); - end if; - end; + Append (Src_Dir, Normalize_Pathname + (Name => Ada.Strings.Fixed.Trim + (Buffer (Index + 8 .. Last - 1), Ada.Strings.Both), + Directory => Build_Dir.all) & Path_Separator); elsif Index <= Buffer'Last - 7 and then Buffer (Index .. Index + 7) = "obj_dir=" then - declare - S : String := Ada.Strings.Fixed.Trim - (Buffer (Index + 8 .. Last - 1), Ada.Strings.Both); - begin - -- A relative directory ? - if S (S'First) /= Dir_Sep then - Append (Obj_Dir, Build_Dir); - end if; - - if S (S'Last) = Dir_Sep then - Append (Obj_Dir, S & " "); - else - Append (Obj_Dir, S & Dir_Sep & " "); - end if; - end; + Append (Obj_Dir, Normalize_Pathname + (Name => Ada.Strings.Fixed.Trim + (Buffer (Index + 8 .. Last - 1), Ada.Strings.Both), + Directory => Build_Dir.all) & Path_Separator); end if; -- In case we had a ASCII.CR/ASCII.LF end of line, skip the @@ -584,16 +672,24 @@ package body Xr_Tabls is end; end if; - Parse_Gnatls (Gnatls_Src_Cache, Gnatls_Obj_Cache); + Osint.Add_Default_Search_Dirs; - Directories := new Project_File' - (Src_Dir_Length => Length (Src_Dir) + Length (Gnatls_Src_Cache), - Obj_Dir_Length => Length (Obj_Dir) + Length (Gnatls_Obj_Cache), - Src_Dir => To_String (Src_Dir & Gnatls_Src_Cache), - Obj_Dir => To_String (Obj_Dir & Gnatls_Obj_Cache), - Src_Dir_Index => 1, - Obj_Dir_Index => 1, - Last_Obj_Dir_Start => 0); + declare + Src : constant String := Parse_Gnatls_Src; + Obj : constant String := Parse_Gnatls_Obj; + + begin + Directories := new Project_File' + (Src_Dir_Length => Length (Src_Dir) + Src'Length, + Obj_Dir_Length => Length (Obj_Dir) + Obj'Length, + Src_Dir => To_String (Src_Dir) & Src, + Obj_Dir => To_String (Obj_Dir) & Obj, + Src_Dir_Index => 1, + Obj_Dir_Index => 1, + Last_Obj_Dir_Start => 0); + end; + + Free (Build_Dir); end Create_Project_File; --------------------- @@ -602,137 +698,10 @@ package body Xr_Tabls is function Current_Obj_Dir return String is begin - return Directories.Obj_Dir (Directories.Last_Obj_Dir_Start - .. Directories.Obj_Dir_Index - 2); + return Directories.Obj_Dir + (Directories.Last_Obj_Dir_Start .. Directories.Obj_Dir_Index - 2); end Current_Obj_Dir; - -------------- - -- Dir_Name -- - -------------- - - function Dir_Name (File : String; Base : String := "") return String is - begin - for J in reverse File'Range loop - if File (J) = '/' or else File (J) = Dir_Sep then - - -- Is this an absolute directory ? - if File (File'First) = '/' - or else File (File'First) = Dir_Sep - then - return File (File'First .. J); - - -- Else do we know the base directory ? - elsif Base /= "" then - return Base & File (File'First .. J); - - else - declare - Max_Path : Integer; - pragma Import (C, Max_Path, "__gnat_max_path_len"); - - Base2 : Dir_Name_Str (1 .. Max_Path); - Last : Natural; - begin - Get_Current_Dir (Base2, Last); - return Base2 (Base2'First .. Last) & File (File'First .. J); - end; - end if; - end if; - end loop; - return ""; - end Dir_Name; - - ------------------- - -- Find_ALI_File -- - ------------------- - - function Find_ALI_File (Short_Name : String) return String is - use type Ada.Strings.Unbounded.String_Access; - Old_Obj_Dir : constant Integer := Directories.Obj_Dir_Index; - - begin - Reset_Obj_Dir; - - loop - declare - Obj_Dir : String := Next_Obj_Dir; - begin - exit when Obj_Dir'Length = 0; - if GNAT.IO_Aux.File_Exists (Obj_Dir & Short_Name) then - Directories.Obj_Dir_Index := Old_Obj_Dir; - return Obj_Dir; - end if; - end; - end loop; - - -- Finally look in the standard directories - - Directories.Obj_Dir_Index := Old_Obj_Dir; - return ""; - end Find_ALI_File; - - ---------------------- - -- Find_Source_File -- - ---------------------- - - function Find_Source_File (Short_Name : String) return String is - use type Ada.Strings.Unbounded.String_Access; - - begin - Reset_Src_Dir; - loop - declare - Src_Dir : String := Next_Src_Dir; - begin - exit when Src_Dir'Length = 0; - - if GNAT.IO_Aux.File_Exists (Src_Dir & Short_Name) then - return Src_Dir; - end if; - end; - end loop; - - -- Finally look in the standard directories - - return ""; - end Find_Source_File; - - ---------------- - -- First_Body -- - ---------------- - - function First_Body (Decl : Declaration_Reference) return Reference is - begin - return Decl.Body_Ref; - end First_Body; - - ----------------------- - -- First_Declaration -- - ----------------------- - - function First_Declaration return Declaration_Reference is - begin - return Entities.Table; - end First_Declaration; - - ----------------- - -- First_Modif -- - ----------------- - - function First_Modif (Decl : Declaration_Reference) return Reference is - begin - return Decl.Modif_Ref; - end First_Modif; - - --------------------- - -- First_Reference -- - --------------------- - - function First_Reference (Decl : Declaration_Reference) return Reference is - begin - return Decl.Ref_Ref; - end First_Reference; - ---------------- -- Get_Column -- ---------------- @@ -759,20 +728,10 @@ package body Xr_Tabls is Column : Natural) return Declaration_Reference is - The_Entities : Declaration_Reference := Entities.Table; - begin - while The_Entities /= null loop - if The_Entities.Decl.Line = Line - and then The_Entities.Decl.Column = Column - and then The_Entities.Decl.File = File_Ref - then - return The_Entities; - else - The_Entities := The_Entities.Next; - end if; - end loop; + Key : aliased constant String := Key_From_Ref (File_Ref, Line, Column); - return Empty_Declaration; + begin + return Entities_HTable.Get (Key'Unchecked_Access); end Get_Declaration; ---------------------- @@ -809,9 +768,11 @@ package body Xr_Tabls is function Get_File (File : File_Reference; With_Dir : in Boolean := False; - Strip : Natural := 0) + Strip : Natural := 0) return String is + Tmp : GNAT.OS_Lib.String_Access; + function Internal_Strip (Full_Name : String) return String; -- Internal function to process the Strip parameter @@ -820,8 +781,10 @@ package body Xr_Tabls is -------------------- function Internal_Strip (Full_Name : String) return String is - Unit_End, Extension_Start : Natural; - S : Natural := Strip; + Unit_End : Natural; + Extension_Start : Natural; + S : Natural; + begin if Strip = 0 then return Full_Name; @@ -838,6 +801,7 @@ package body Xr_Tabls is -- Strip the right number of subunit_names + S := Strip; Unit_End := Extension_Start - 1; while Unit_End >= Full_Name'First and then S > 0 @@ -845,6 +809,7 @@ package body Xr_Tabls is if Full_Name (Unit_End) = '-' then S := S - 1; end if; + Unit_End := Unit_End - 1; end loop; @@ -856,23 +821,33 @@ package body Xr_Tabls is end if; end Internal_Strip; + -- Start of processing for Get_File; + begin -- If we do not want the full path name if not With_Dir then - return Internal_Strip (File.File); + return Internal_Strip (File.File.all); end if; if File.Dir = null then + if Ada.Strings.Fixed.Tail (File.File.all, 3) = "ali" then + Tmp := Locate_Regular_File + (Internal_Strip (File.File.all), Directories.Obj_Dir); + else + Tmp := Locate_Regular_File + (File.File.all, Directories.Src_Dir); + end if; - if Ada.Strings.Fixed.Tail (File.File, 3) = "ali" then - File.Dir := new String'(Find_ALI_File (File.File)); + if Tmp = null then + File.Dir := new String'(""); else - File.Dir := new String'(Find_Source_File (File.File)); + File.Dir := new String'(Dir_Name (Tmp.all)); + Free (Tmp); end if; end if; - return Internal_Strip (File.Dir.all & File.File); + return Internal_Strip (File.Dir.all & File.File.all); end Get_File; ------------------ @@ -889,7 +864,10 @@ package body Xr_Tabls is ----------------------- function Get_Gnatchop_File - (File : File_Reference; With_Dir : Boolean := False) return String is + (File : File_Reference; + With_Dir : Boolean := False) + return String + is begin if File.Gnatchop_File.all = "" then return Get_File (File, With_Dir); @@ -898,22 +876,19 @@ package body Xr_Tabls is end if; end Get_Gnatchop_File; - ----------------------- - -- Get_Gnatchop_File -- - ----------------------- - function Get_Gnatchop_File - (Ref : Reference; With_Dir : Boolean := False) return String is + (Ref : Reference; + With_Dir : Boolean := False) + return String + is begin return Get_Gnatchop_File (Ref.File, With_Dir); end Get_Gnatchop_File; - ----------------------- - -- Get_Gnatchop_File -- - ----------------------- - function Get_Gnatchop_File - (Decl : Declaration_Reference; With_Dir : Boolean := False) return String + (Decl : Declaration_Reference; + With_Dir : Boolean := False) + return String is begin return Get_Gnatchop_File (Decl.Decl.File, With_Dir); @@ -941,7 +916,8 @@ package body Xr_Tabls is function Get_Parent (Decl : Declaration_Reference) - return Declaration_Reference is + return Declaration_Reference + is begin return Decl.Par_Symbol; end Get_Parent; @@ -952,12 +928,20 @@ package body Xr_Tabls is function Get_Source_Line (Ref : Reference) return String is begin - return To_String (Ref.Source_Line); + if Ref.Source_Line /= null then + return Ref.Source_Line.all; + else + return ""; + end if; end Get_Source_Line; function Get_Source_Line (Decl : Declaration_Reference) return String is begin - return To_String (Decl.Decl.Source_Line); + if Decl.Decl.Source_Line /= null then + return Decl.Decl.Source_Line.all; + else + return ""; + end if; end Get_Source_Line; ---------------- @@ -978,202 +962,201 @@ package body Xr_Tabls is return Decl.Decl_Type; end Get_Type; - ----------------------- - -- Grep_Source_Files -- - ----------------------- - - procedure Grep_Source_Files is - Decl : Declaration_Reference := First_Declaration; - - type Simple_Ref; - type Simple_Ref_Access is access Simple_Ref; - type Simple_Ref is record - Ref : Reference; - Next : Simple_Ref_Access; - end record; - List : Simple_Ref_Access := null; - -- This structure is used to speed up the parsing of Ada sources: - -- Every reference found by parsing the .ali files is inserted in this - -- list, sorted by filename and line numbers. This allows avoiding - -- parsing a same ada file multiple times - - procedure Free is new Unchecked_Deallocation - (Simple_Ref, Simple_Ref_Access); - -- Clear an element of the list - - procedure Grep_List; - -- For each reference in the list, parse the file and find the - -- source line - - procedure Insert_In_Order (Ref : Reference); - -- Insert a new reference in the list, ordered by line numbers - - procedure Insert_List_Ref (First_Ref : Reference); - -- Process a list of references - - --------------- - -- Grep_List -- - --------------- - - procedure Grep_List is - Line : String (1 .. 1024); - Last : Natural; - File : Ada.Text_IO.File_Type; - Line_Number : Natural; - Pos : Natural; - Save_List : Simple_Ref_Access := List; - Current_File : File_Reference; + ---------- + -- Sort -- + ---------- - begin - while List /= null loop + procedure Sort (Arr : in out Reference_Array) is + Tmp : Reference; - -- Makes sure we can find and read the file + function Lt (Op1, Op2 : Natural) return Boolean; + procedure Move (From, To : Natural); + -- See GNAT.Heap_Sort_G - Current_File := List.Ref.File; - Line_Number := 0; + -------- + -- Lt -- + -------- - begin - Ada.Text_IO.Open (File, - Ada.Text_IO.In_File, - Get_File (List.Ref, True)); + function Lt (Op1, Op2 : Natural) return Boolean is + begin + if Op1 = 0 then + return Is_Less_Than (Tmp, Arr (Op2)); + elsif Op2 = 0 then + return Is_Less_Than (Arr (Op1), Tmp); + else + return Is_Less_Than (Arr (Op1), Arr (Op2)); + end if; + end Lt; - -- Read the file and find every relevant lines + ---------- + -- Move -- + ---------- - while List /= null - and then List.Ref.File = Current_File - and then not Ada.Text_IO.End_Of_File (File) - loop - Ada.Text_IO.Get_Line (File, Line, Last); - Line_Number := Line_Number + 1; + procedure Move (From, To : Natural) is + begin + if To = 0 then + Tmp := Arr (From); + elsif From = 0 then + Arr (To) := Tmp; + else + Arr (To) := Arr (From); + end if; + end Move; - while List /= null - and then Line_Number = List.Ref.Line - loop + package Ref_Sort is new GNAT.Heap_Sort_G (Move, Lt); - -- Skip the leading blanks on the line + -- Start of processing for Sort - Pos := 1; - while Line (Pos) = ' ' - or else Line (Pos) = ASCII.HT - loop - Pos := Pos + 1; - end loop; + begin + Ref_Sort.Sort (Arr'Last); + end Sort; - List.Ref.Source_Line := - To_Unbounded_String (Line (Pos .. Last)); + ----------------------- + -- Grep_Source_Files -- + ----------------------- - -- Find the next element in the list + procedure Grep_Source_Files is + Length : Natural := 0; + Decl : Declaration_Reference := Entities_HTable.Get_First; + Arr : Reference_Array_Access; + Index : Natural; + End_Index : Natural; + Current_File : File_Reference; + Current_Line : Cst_String_Access; + Buffer : GNAT.OS_Lib.String_Access; + Ref : Reference; + Line : Natural; - List := List.Next; - end loop; + begin + -- Create a temporary array, where all references will be + -- sorted by files. This way, we only have to read the source + -- files once. - end loop; + while Decl /= null loop - Ada.Text_IO.Close (File); + -- Add 1 for the declaration itself - -- If the Current_File was not found, just skip it + Length := Length + References_Count (Decl, True, True, True) + 1; + Decl := Entities_HTable.Get_Next; + end loop; - exception - when Ada.IO_Exceptions.Name_Error => - null; - end; + Arr := new Reference_Array (1 .. Length); + Index := Arr'First; - -- If the line or the file were not found + Decl := Entities_HTable.Get_First; + while Decl /= null loop + Store_References (Decl, True, True, True, True, Arr.all, Index); + Decl := Entities_HTable.Get_Next; + end loop; - while List /= null - and then List.Ref.File = Current_File - loop - List := List.Next; - end loop; + Sort (Arr.all); - end loop; + -- Now traverse the whole array and find the appropriate source + -- lines. - -- Clear the list + for R in Arr'Range loop + Ref := Arr (R); - while Save_List /= null loop - List := Save_List; - Save_List := Save_List.Next; - Free (List); - end loop; - end Grep_List; + if Ref.File /= Current_File then + Free (Buffer); + begin + Read_File (Get_File (Ref.File, With_Dir => True), Buffer); + End_Index := Buffer'First - 1; + Line := 0; + exception + when Ada.Text_IO.Name_Error | Ada.Text_IO.End_Error => + Line := Natural'Last; + end; + Current_File := Ref.File; + end if; - --------------------- - -- Insert_In_Order -- - --------------------- + if Ref.Line > Line then - procedure Insert_In_Order (Ref : Reference) is - Iter : Simple_Ref_Access := List; - Prev : Simple_Ref_Access := null; + -- Do not free Current_Line, it is referenced by the last + -- Ref we processed. - begin - while Iter /= null loop + loop + Index := End_Index + 1; - -- If we have found the file, sort by lines + loop + End_Index := End_Index + 1; + exit when End_Index > Buffer'Last + or else Buffer (End_Index) = ASCII.LF; + end loop; - if Iter.Ref.File = Ref.File then + -- Skip spaces at beginning of line - while Iter /= null - and then Iter.Ref.File = Ref.File + while Index < End_Index and then + (Buffer (Index) = ' ' or else Buffer (Index) = ASCII.HT) loop - if Iter.Ref.Line > Ref.Line then - - if Iter = List then - List := new Simple_Ref'(Ref, List); - else - Prev.Next := new Simple_Ref'(Ref, Iter); - end if; - return; - end if; - - Prev := Iter; - Iter := Iter.Next; + Index := Index + 1; end loop; - if Iter = List then - List := new Simple_Ref'(Ref, List); - else - Prev.Next := new Simple_Ref'(Ref, Iter); - end if; + Line := Line + 1; + exit when Ref.Line = Line; + end loop; - return; - end if; + Current_Line := new String'(Buffer (Index .. End_Index - 1)); + end if; - Prev := Iter; - Iter := Iter.Next; - end loop; + Ref.Source_Line := Current_Line; + end loop; - -- The file was not already in the list, insert it + Free (Buffer); + Free (Arr); + end Grep_Source_Files; - List := new Simple_Ref'(Ref, List); - end Insert_In_Order; + --------------- + -- Read_File -- + --------------- - --------------------- - -- Insert_List_Ref -- - --------------------- + procedure Read_File + (File_Name : String; + Contents : out GNAT.OS_Lib.String_Access) + is + Name_0 : constant String := File_Name & ASCII.NUL; + FD : constant File_Descriptor := Open_Read (Name_0'Address, Binary); + Length : Natural; - procedure Insert_List_Ref (First_Ref : Reference) is - Ref : Reference := First_Ref; + begin + if FD = Invalid_FD then + raise Ada.Text_IO.Name_Error; + end if; + + -- Include room for EOF char + + Length := Natural (File_Length (FD)); + + declare + Buffer : String (1 .. Length + 1); + This_Read : Integer; + Read_Ptr : Natural := 1; begin - while Ref /= Empty_Reference loop - Insert_In_Order (Ref); - Ref := Next (Ref); + loop + This_Read := Read (FD, + A => Buffer (Read_Ptr)'Address, + N => Length + 1 - Read_Ptr); + Read_Ptr := Read_Ptr + Integer'Max (This_Read, 0); + exit when This_Read <= 0; end loop; - end Insert_List_Ref; - -- Start of processing for Grep_Source_Files + Buffer (Read_Ptr) := EOF; + Contents := new String'(Buffer (1 .. Read_Ptr)); - begin - while Decl /= Empty_Declaration loop - Insert_In_Order (Decl.Decl'Access); - Insert_List_Ref (First_Body (Decl)); - Insert_List_Ref (First_Reference (Decl)); - Insert_List_Ref (First_Modif (Decl)); - Decl := Next (Decl); - end loop; + -- Things are not simple on VMS due to the plethora of file types + -- and organizations. It seems clear that there shouldn't be more + -- bytes read than are contained in the file though. - Grep_List; - end Grep_Source_Files; + if (Hostparm.OpenVMS and then Read_Ptr > Length + 1) + or else (not Hostparm.OpenVMS and then Read_Ptr /= Length + 1) + then + raise Ada.Text_IO.End_Error; + end if; + + Close (FD); + end; + end Read_File; ----------------------- -- Longest_File_Name -- @@ -1181,7 +1164,7 @@ package body Xr_Tabls is function Longest_File_Name return Natural is begin - return Files.Longest_Name; + return Longest_File_Name_In_Table; end Longest_File_Name; ----------- @@ -1223,18 +1206,14 @@ package body Xr_Tabls is -- Next -- ---------- - function Next (Decl : Declaration_Reference) return Declaration_Reference is + function Next (E : File_Reference) return File_Reference is begin - return Decl.Next; + return E.Next; end Next; - ---------- - -- Next -- - ---------- - - function Next (Ref : Reference) return Reference is + function Next (E : Declaration_Reference) return Declaration_Reference is begin - return Ref.Next; + return E.Next; end Next; ------------------ @@ -1242,15 +1221,17 @@ package body Xr_Tabls is ------------------ function Next_Obj_Dir return String is - First : Integer := Directories.Obj_Dir_Index; - Last : Integer := Directories.Obj_Dir_Index; + First : constant Integer := Directories.Obj_Dir_Index; + Last : Integer; begin + Last := Directories.Obj_Dir_Index; + if Last > Directories.Obj_Dir_Length then return String'(1 .. 0 => ' '); end if; - while Directories.Obj_Dir (Last) /= ' ' loop + while Directories.Obj_Dir (Last) /= Path_Separator loop Last := Last + 1; end loop; @@ -1259,76 +1240,109 @@ package body Xr_Tabls is return Directories.Obj_Dir (First .. Last - 1); end Next_Obj_Dir; - ------------------ - -- Next_Src_Dir -- - ------------------ - - function Next_Src_Dir return String is - First : Integer := Directories.Src_Dir_Index; - Last : Integer := Directories.Src_Dir_Index; - - begin - if Last > Directories.Src_Dir_Length then - return String'(1 .. 0 => ' '); - end if; - - while Directories.Src_Dir (Last) /= ' ' loop - Last := Last + 1; - end loop; - - Directories.Src_Dir_Index := Last + 1; - return Directories.Src_Dir (First .. Last - 1); - end Next_Src_Dir; - ------------------------- -- Next_Unvisited_File -- ------------------------- function Next_Unvisited_File return File_Reference is - The_Files : File_Reference := Files.Table; - - begin - while The_Files /= null loop - if not The_Files.Visited then - The_Files.Visited := True; - return The_Files; - end if; + procedure Unchecked_Free is new Ada.Unchecked_Deallocation + (Unvisited_Files_Record, Unvisited_Files_Access); - The_Files := The_Files.Next; - end loop; + Ref : File_Reference; + Tmp : Unvisited_Files_Access; - return Empty_File; + begin + if Unvisited_Files = null then + return Empty_File; + else + Tmp := Unvisited_Files; + Ref := Unvisited_Files.File; + Unvisited_Files := Unvisited_Files.Next; + Unchecked_Free (Tmp); + return Ref; + end if; end Next_Unvisited_File; - ------------------ - -- Parse_Gnatls -- - ------------------ + ---------------------- + -- Parse_Gnatls_Src -- + ---------------------- - procedure Parse_Gnatls - (Gnatls_Src_Cache : out Ada.Strings.Unbounded.Unbounded_String; - Gnatls_Obj_Cache : out Ada.Strings.Unbounded.Unbounded_String) - is - begin - Osint.Add_Default_Search_Dirs; + function Parse_Gnatls_Src return String is + Length : Natural; + begin + Length := 0; for J in 1 .. Osint.Nb_Dir_In_Src_Search_Path loop if Osint.Dir_In_Src_Search_Path (J)'Length = 0 then - Ada.Strings.Unbounded.Append (Gnatls_Src_Cache, "./" & ' '); + Length := Length + 2; else - Ada.Strings.Unbounded.Append - (Gnatls_Src_Cache, Osint.Dir_In_Src_Search_Path (J).all & ' '); + Length := Length + Osint.Dir_In_Src_Search_Path (J)'Length + 1; end if; end loop; + declare + Result : String (1 .. Length); + L : Natural; + + begin + L := Result'First; + for J in 1 .. Osint.Nb_Dir_In_Src_Search_Path loop + if Osint.Dir_In_Src_Search_Path (J)'Length = 0 then + Result (L .. L + 1) := "." & Path_Separator; + L := L + 2; + + else + Result (L .. L + Osint.Dir_In_Src_Search_Path (J)'Length - 1) := + Osint.Dir_In_Src_Search_Path (J).all; + L := L + Osint.Dir_In_Src_Search_Path (J)'Length; + Result (L) := Path_Separator; + L := L + 1; + end if; + end loop; + + return Result; + end; + end Parse_Gnatls_Src; + + ---------------------- + -- Parse_Gnatls_Obj -- + ---------------------- + + function Parse_Gnatls_Obj return String is + Length : Natural; + + begin + Length := 0; for J in 1 .. Osint.Nb_Dir_In_Obj_Search_Path loop if Osint.Dir_In_Obj_Search_Path (J)'Length = 0 then - Ada.Strings.Unbounded.Append (Gnatls_Obj_Cache, "./" & ' '); + Length := Length + 2; else - Ada.Strings.Unbounded.Append - (Gnatls_Obj_Cache, Osint.Dir_In_Obj_Search_Path (J).all & ' '); + Length := Length + Osint.Dir_In_Obj_Search_Path (J)'Length + 1; end if; end loop; - end Parse_Gnatls; + + declare + Result : String (1 .. Length); + L : Natural; + + begin + L := Result'First; + for J in 1 .. Osint.Nb_Dir_In_Obj_Search_Path loop + if Osint.Dir_In_Obj_Search_Path (J)'Length = 0 then + Result (L .. L + 1) := "." & Path_Separator; + L := L + 2; + else + Result (L .. L + Osint.Dir_In_Obj_Search_Path (J)'Length - 1) := + Osint.Dir_In_Obj_Search_Path (J).all; + L := L + Osint.Dir_In_Obj_Search_Path (J)'Length; + Result (L) := Path_Separator; + L := L + 1; + end if; + end loop; + + return Result; + end; + end Parse_Gnatls_Obj; ------------------- -- Reset_Obj_Dir -- @@ -1339,15 +1353,6 @@ package body Xr_Tabls is Directories.Obj_Dir_Index := 1; end Reset_Obj_Dir; - ------------------- - -- Reset_Src_Dir -- - ------------------- - - procedure Reset_Src_Dir is - begin - Directories.Src_Dir_Index := 1; - end Reset_Src_Dir; - ----------------------- -- Set_Default_Match -- ----------------------- @@ -1357,34 +1362,273 @@ package body Xr_Tabls is Default_Match := Value; end Set_Default_Match; - ------------------- - -- Set_Directory -- - ------------------- + ---------- + -- Free -- + ---------- - procedure Set_Directory - (File : in File_Reference; - Dir : in String) - is + procedure Free (Str : in out Cst_String_Access) is + function Convert is new Ada.Unchecked_Conversion + (Cst_String_Access, GNAT.OS_Lib.String_Access); + + S : GNAT.OS_Lib.String_Access := Convert (Str); + + begin + Free (S); + Str := null; + end Free; + + --------------------- + -- Reset_Directory -- + --------------------- + + procedure Reset_Directory (File : File_Reference) is begin - File.Dir := new String'(Dir); - end Set_Directory; + Free (File.Dir); + end Reset_Directory; ------------------- -- Set_Unvisited -- ------------------- - procedure Set_Unvisited (File_Ref : in File_Reference) is - The_Files : File_Reference := Files.Table; + procedure Set_Unvisited (File_Ref : File_Reference) is + F : constant String := Get_File (File_Ref, With_Dir => False); begin - while The_Files /= null loop - if The_Files = File_Ref then - The_Files.Visited := False; - return; + File_Ref.Visited := False; + + -- ??? Do not add a source file to the list. This is true at + -- least for gnatxref, and probably for gnatfind as wel + + if F'Length > 4 + and then F (F'Last - 3 .. F'Last) = ".ali" + then + Unvisited_Files := new Unvisited_Files_Record' + (File => File_Ref, + Next => Unvisited_Files); + end if; + end Set_Unvisited; + + ---------------------- + -- Get_Declarations -- + ---------------------- + + function Get_Declarations + (Sorted : Boolean := True) + return Declaration_Array_Access + is + Arr : Declaration_Array_Access := + new Declaration_Array (1 .. Entities_Count); + Decl : Declaration_Reference := Entities_HTable.Get_First; + Index : Natural := Arr'First; + Tmp : Declaration_Reference; + + procedure Move (From : Natural; To : Natural); + function Lt (Op1, Op2 : Natural) return Boolean; + -- See GNAT.Heap_Sort_G + + -------- + -- Lt -- + -------- + + function Lt (Op1, Op2 : Natural) return Boolean is + begin + if Op1 = 0 then + return Is_Less_Than (Tmp, Arr (Op2)); + elsif Op2 = 0 then + return Is_Less_Than (Arr (Op1), Tmp); + else + return Is_Less_Than (Arr (Op1), Arr (Op2)); end if; + end Lt; + + ---------- + -- Move -- + ---------- + + procedure Move (From : Natural; To : Natural) is + begin + if To = 0 then + Tmp := Arr (From); + elsif From = 0 then + Arr (To) := Tmp; + else + Arr (To) := Arr (From); + end if; + end Move; + + package Decl_Sort is new GNAT.Heap_Sort_G (Move, Lt); - The_Files := The_Files.Next; + -- Start of processing for Get_Declarations + + begin + while Decl /= null loop + Arr (Index) := Decl; + Index := Index + 1; + Decl := Entities_HTable.Get_Next; end loop; - end Set_Unvisited; + + if Sorted and then Arr'Length /= 0 then + Decl_Sort.Sort (Entities_Count); + end if; + + return Arr; + end Get_Declarations; + + ---------------------- + -- References_Count -- + ---------------------- + + function References_Count + (Decl : Declaration_Reference; + Get_Reads : Boolean := False; + Get_Writes : Boolean := False; + Get_Bodies : Boolean := False) + return Natural + is + function List_Length (E : Reference) return Natural; + -- Return the number of references in E + + ----------------- + -- List_Length -- + ----------------- + + function List_Length (E : Reference) return Natural is + L : Natural := 0; + E1 : Reference := E; + + begin + while E1 /= null loop + L := L + 1; + E1 := E1.Next; + end loop; + + return L; + end List_Length; + + Length : Natural := 0; + + -- Start of processing for References_Count + + begin + if Get_Reads then + Length := List_Length (Decl.Ref_Ref); + end if; + + if Get_Writes then + Length := Length + List_Length (Decl.Modif_Ref); + end if; + + if Get_Bodies then + Length := Length + List_Length (Decl.Body_Ref); + end if; + + return Length; + end References_Count; + + ---------------------- + -- Store_References -- + ---------------------- + + procedure Store_References + (Decl : Declaration_Reference; + Get_Writes : Boolean := False; + Get_Reads : Boolean := False; + Get_Bodies : Boolean := False; + Get_Declaration : Boolean := False; + Arr : in out Reference_Array; + Index : in out Natural) + is + procedure Add (List : Reference); + -- Add all the references in List to Arr + + --------- + -- Add -- + --------- + + procedure Add (List : Reference) is + E : Reference := List; + begin + while E /= null loop + Arr (Index) := E; + Index := Index + 1; + E := E.Next; + end loop; + end Add; + + -- Start of processing for Store_References + + begin + if Get_Declaration then + Add (Decl.Decl); + end if; + + if Get_Reads then + Add (Decl.Ref_Ref); + end if; + + if Get_Writes then + Add (Decl.Modif_Ref); + end if; + + if Get_Bodies then + Add (Decl.Body_Ref); + end if; + end Store_References; + + -------------------- + -- Get_References -- + -------------------- + + function Get_References + (Decl : Declaration_Reference; + Get_Reads : Boolean := False; + Get_Writes : Boolean := False; + Get_Bodies : Boolean := False) + return Reference_Array_Access + is + Length : constant Natural := + References_Count (Decl, Get_Reads, Get_Writes, Get_Bodies); + + Arr : constant Reference_Array_Access := + new Reference_Array (1 .. Length); + + Index : Natural := Arr'First; + + begin + Store_References + (Decl => Decl, + Get_Writes => Get_Writes, + Get_Reads => Get_Reads, + Get_Bodies => Get_Bodies, + Get_Declaration => False, + Arr => Arr.all, + Index => Index); + + if Arr'Length /= 0 then + Sort (Arr.all); + end if; + + return Arr; + end Get_References; + + ---------- + -- Free -- + ---------- + + procedure Free (Arr : in out Reference_Array_Access) is + procedure Internal is new Ada.Unchecked_Deallocation + (Reference_Array, Reference_Array_Access); + begin + Internal (Arr); + end Free; + + ------------------ + -- Is_Parameter -- + ------------------ + + function Is_Parameter (Decl : Declaration_Reference) return Boolean is + begin + return Decl.Is_Parameter; + end Is_Parameter; end Xr_Tabls; |