| ------------------------------------------------------------------------------ |
| -- -- |
| -- GNAT COMPILER COMPONENTS -- |
| -- -- |
| -- X R _ T A B L S -- |
| -- -- |
| -- B o d y -- |
| -- -- |
| -- $Revision: 1.36 $ |
| -- -- |
| -- Copyright (C) 1998-2001 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 2, 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 COPYING. If not, write -- |
| -- to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, -- |
| -- MA 02111-1307, USA. -- |
| -- -- |
| -- GNAT is maintained by Ada Core Technologies Inc (http://www.gnat.com). -- |
| -- -- |
| ------------------------------------------------------------------------------ |
| |
| with Ada.IO_Exceptions; |
| with Ada.Strings.Fixed; |
| with Ada.Strings; |
| with Ada.Text_IO; |
| with Hostparm; |
| with GNAT.IO_Aux; |
| with Unchecked_Deallocation; |
| with GNAT.OS_Lib; use GNAT.OS_Lib; |
| with GNAT.Directory_Operations; use GNAT.Directory_Operations; |
| with Osint; |
| |
| with Ada.Strings.Unbounded; use Ada.Strings.Unbounded; |
| |
| package body Xr_Tabls is |
| |
| subtype Line_String is String (1 .. Hostparm.Max_Line_Length); |
| subtype File_Name_String is String (1 .. Hostparm.Max_Name_Length); |
| |
| function Base_File_Name (File : String) return String; |
| -- Return the base file name for File (ie not including the directory) |
| |
| 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 "") |
| |
| Dir_Sep : Character renames GNAT.OS_Lib.Directory_Separator; |
| |
| Files : File_Table; |
| Entities : Entity_Table; |
| Directories : Project_File_Ptr; |
| Default_Match : Boolean := False; |
| |
| --------------------- |
| -- Add_Declaration -- |
| --------------------- |
| |
| function Add_Declaration |
| (File_Ref : File_Reference; |
| Symbol : String; |
| Line : Natural; |
| Column : Natural; |
| Decl_Type : Character) |
| return Declaration_Reference |
| is |
| The_Entities : Declaration_Reference := Entities.Table; |
| New_Decl : Declaration_Reference; |
| Result : Compare_Result; |
| Prev : Declaration_Reference := null; |
| |
| begin |
| -- Check if the identifier already exists in the table |
| |
| while The_Entities /= null loop |
| Result := Compare (The_Entities, File_Ref, Line, Column, Symbol); |
| exit when Result = GreaterThan; |
| |
| if Result = Equal then |
| return The_Entities; |
| end if; |
| |
| 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; |
| end if; |
| |
| if New_Decl.Match then |
| Files.Longest_Name := Natural'Max (File_Ref.File'Length, |
| Files.Longest_Name); |
| end if; |
| |
| return New_Decl; |
| end Add_Declaration; |
| |
| -------------- |
| -- Add_File -- |
| -------------- |
| |
| procedure Add_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) |
| 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; |
| |
| begin |
| -- Do we have a directory name as well ? |
| if Dir /= "" then |
| Dir_Acc := new String' (Dir); |
| end if; |
| |
| -- Check if the file already exists in the table |
| |
| while The_Files /= null loop |
| |
| if The_Files.File = File_Name then |
| File_Existed := True; |
| Ref := The_Files; |
| return; |
| end if; |
| |
| 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; |
| end Add_File; |
| |
| -------------- |
| -- Add_Line -- |
| -------------- |
| |
| procedure Add_Line |
| (File : File_Reference; |
| Line : Natural; |
| Column : Natural) |
| is |
| begin |
| File.Lines := new Ref_In_File'(Line => Line, |
| Column => Column, |
| Next => File.Lines); |
| end Add_Line; |
| |
| ---------------- |
| -- Add_Parent -- |
| ---------------- |
| |
| procedure Add_Parent |
| (Declaration : in out Declaration_Reference; |
| Symbol : String; |
| Line : Natural; |
| Column : Natural; |
| 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); |
| end Add_Parent; |
| |
| ------------------- |
| -- Add_Reference -- |
| ------------------- |
| |
| procedure Add_Reference |
| (Declaration : Declaration_Reference; |
| File_Ref : File_Reference; |
| Line : Natural; |
| Column : Natural; |
| Ref_Type : Character) |
| 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); |
| |
| begin |
| case Ref_Type is |
| when 'b' | 'c' => Ref := Declaration.Body_Ref; |
| when 'r' | 'i' => Ref := Declaration.Ref_Ref; |
| when 'm' => Ref := Declaration.Modif_Ref; |
| when others => return; |
| end case; |
| |
| -- Check if the reference already exists |
| |
| while Ref /= null loop |
| Result := Compare (New_Ref, Ref); |
| exit when Result = LessThan; |
| |
| if Result = Equal then |
| Free (New_Ref); |
| return; |
| end if; |
| |
| Prev := Ref; |
| Ref := Ref.Next; |
| end loop; |
| |
| -- Insert it in the list |
| |
| if Prev /= null then |
| New_Ref.Next := Prev.Next; |
| Prev.Next := New_Ref; |
| |
| else |
| case Ref_Type is |
| when 'b' | 'c' => |
| New_Ref.Next := Declaration.Body_Ref; |
| Declaration.Body_Ref := New_Ref; |
| when 'r' | 'i' => |
| 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; |
| |
| 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); |
| end if; |
| end Add_Reference; |
| |
| ------------------- |
| -- ALI_File_Name -- |
| ------------------- |
| |
| function ALI_File_Name (Ada_File_Name : String) return String is |
| Index : 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"; |
| 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 -- |
| ------------- |
| |
| function Compare |
| (Ref1 : Reference; |
| Ref2 : Reference) |
| return Compare_Result |
| is |
| begin |
| if Ref1 = null then |
| return GreaterThan; |
| elsif Ref2 = null then |
| return LessThan; |
| end if; |
| |
| if Ref1.File.File < Ref2.File.File then |
| return LessThan; |
| |
| elsif Ref1.File.File = Ref2.File.File then |
| if Ref1.Line < Ref2.Line then |
| return LessThan; |
| |
| 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; |
| |
| else |
| return GreaterThan; |
| end if; |
| |
| else |
| return GreaterThan; |
| end if; |
| end Compare; |
| |
| ------------- |
| -- Compare -- |
| ------------- |
| |
| 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; |
| 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; |
| |
| ------------------------- |
| -- Create_Project_File -- |
| ------------------------- |
| |
| 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; |
| |
| 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)); |
| |
| declare |
| Buffer : String (1 .. Len); |
| Index : Positive := Buffer'First; |
| Last : Positive; |
| begin |
| Len := Read (F, Buffer'Address, Len); |
| Close (F); |
| |
| -- First, look for Build_Dir, since all the source and object |
| -- path are relative to it. |
| |
| while Index <= Buffer'Last loop |
| |
| -- find the end of line |
| |
| Last := Index; |
| while Last <= Buffer'Last |
| and then Buffer (Last) /= ASCII.LF |
| and then Buffer (Last) /= ASCII.CR |
| loop |
| Last := Last + 1; |
| end loop; |
| |
| if Index <= Buffer'Last - 9 |
| and then Buffer (Index .. Index + 9) = "build_dir=" |
| then |
| Index := Index + 10; |
| while Index <= Last |
| and then (Buffer (Index) = ' ' |
| or else Buffer (Index) = ASCII.HT) |
| loop |
| 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; |
| end if; |
| |
| Index := Last + 1; |
| |
| -- In case we had a ASCII.CR/ASCII.LF end of line, skip the |
| -- remaining symbol |
| |
| if Index <= Buffer'Last |
| and then Buffer (Index) = ASCII.LF |
| then |
| Index := Index + 1; |
| end if; |
| end loop; |
| |
| -- Now parse the source and object paths |
| |
| Index := Buffer'First; |
| while Index <= Buffer'Last loop |
| |
| -- find the end of line |
| |
| Last := Index; |
| while Last <= Buffer'Last |
| and then Buffer (Last) /= ASCII.LF |
| and then Buffer (Last) /= ASCII.CR |
| loop |
| Last := Last + 1; |
| end loop; |
| |
| 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; |
| |
| 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; |
| end if; |
| |
| -- In case we had a ASCII.CR/ASCII.LF end of line, skip the |
| -- remaining symbol |
| Index := Last + 1; |
| |
| if Index <= Buffer'Last |
| and then Buffer (Index) = ASCII.LF |
| then |
| Index := Index + 1; |
| end if; |
| end loop; |
| end; |
| end if; |
| |
| Parse_Gnatls (Gnatls_Src_Cache, Gnatls_Obj_Cache); |
| |
| 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); |
| end Create_Project_File; |
| |
| --------------------- |
| -- Current_Obj_Dir -- |
| --------------------- |
| |
| function Current_Obj_Dir return String is |
| begin |
| 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, "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 -- |
| ---------------- |
| |
| function Get_Column (Decl : Declaration_Reference) return String is |
| begin |
| return Ada.Strings.Fixed.Trim (Natural'Image (Decl.Decl.Column), |
| Ada.Strings.Left); |
| end Get_Column; |
| |
| function Get_Column (Ref : Reference) return String is |
| begin |
| return Ada.Strings.Fixed.Trim (Natural'Image (Ref.Column), |
| Ada.Strings.Left); |
| end Get_Column; |
| |
| --------------------- |
| -- Get_Declaration -- |
| --------------------- |
| |
| function Get_Declaration |
| (File_Ref : File_Reference; |
| Line : Natural; |
| 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; |
| |
| return Empty_Declaration; |
| end Get_Declaration; |
| |
| ---------------------- |
| -- Get_Emit_Warning -- |
| ---------------------- |
| |
| function Get_Emit_Warning (File : File_Reference) return Boolean is |
| begin |
| return File.Emit_Warning; |
| end Get_Emit_Warning; |
| |
| -------------- |
| -- Get_File -- |
| -------------- |
| |
| function Get_File |
| (Decl : Declaration_Reference; |
| With_Dir : Boolean := False) |
| return String |
| is |
| begin |
| return Get_File (Decl.Decl.File, With_Dir); |
| end Get_File; |
| |
| function Get_File |
| (Ref : Reference; |
| With_Dir : Boolean := False) |
| return String |
| is |
| begin |
| return Get_File (Ref.File, With_Dir); |
| end Get_File; |
| |
| function Get_File |
| (File : File_Reference; |
| With_Dir : in Boolean := False; |
| Strip : Natural := 0) |
| return String |
| is |
| function Internal_Strip (Full_Name : String) return String; |
| -- Internal function to process the Strip parameter |
| |
| -------------------- |
| -- Internal_Strip -- |
| -------------------- |
| |
| function Internal_Strip (Full_Name : String) return String is |
| Unit_End, Extension_Start : Natural; |
| S : Natural := Strip; |
| begin |
| if Strip = 0 then |
| return Full_Name; |
| end if; |
| |
| -- Isolate the file extension |
| |
| Extension_Start := Full_Name'Last; |
| while Extension_Start >= Full_Name'First |
| and then Full_Name (Extension_Start) /= '.' |
| loop |
| Extension_Start := Extension_Start - 1; |
| end loop; |
| |
| -- Strip the right number of subunit_names |
| |
| Unit_End := Extension_Start - 1; |
| while Unit_End >= Full_Name'First |
| and then S > 0 |
| loop |
| if Full_Name (Unit_End) = '-' then |
| S := S - 1; |
| end if; |
| Unit_End := Unit_End - 1; |
| end loop; |
| |
| if Unit_End < Full_Name'First then |
| return ""; |
| else |
| return Full_Name (Full_Name'First .. Unit_End) |
| & Full_Name (Extension_Start .. Full_Name'Last); |
| end if; |
| end Internal_Strip; |
| |
| begin |
| -- If we do not want the full path name |
| |
| if not With_Dir then |
| return Internal_Strip (File.File); |
| end if; |
| |
| if File.Dir = null then |
| |
| if Ada.Strings.Fixed.Tail (File.File, 3) = "ali" then |
| File.Dir := new String'(Find_ALI_File (File.File)); |
| else |
| File.Dir := new String'(Find_Source_File (File.File)); |
| end if; |
| end if; |
| |
| return Internal_Strip (File.Dir.all & File.File); |
| end Get_File; |
| |
| ------------------ |
| -- Get_File_Ref -- |
| ------------------ |
| |
| function Get_File_Ref (Ref : Reference) return File_Reference is |
| begin |
| return Ref.File; |
| end Get_File_Ref; |
| |
| ----------------------- |
| -- Get_Gnatchop_File -- |
| ----------------------- |
| |
| function Get_Gnatchop_File |
| (File : File_Reference; With_Dir : Boolean := False) return String is |
| begin |
| if File.Gnatchop_File.all = "" then |
| return Get_File (File, With_Dir); |
| else |
| return File.Gnatchop_File.all; |
| end if; |
| end Get_Gnatchop_File; |
| |
| ----------------------- |
| -- Get_Gnatchop_File -- |
| ----------------------- |
| |
| function Get_Gnatchop_File |
| (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 |
| is |
| begin |
| return Get_Gnatchop_File (Decl.Decl.File, With_Dir); |
| end Get_Gnatchop_File; |
| |
| -------------- |
| -- Get_Line -- |
| -------------- |
| |
| function Get_Line (Decl : Declaration_Reference) return String is |
| begin |
| return Ada.Strings.Fixed.Trim (Natural'Image (Decl.Decl.Line), |
| Ada.Strings.Left); |
| end Get_Line; |
| |
| function Get_Line (Ref : Reference) return String is |
| begin |
| return Ada.Strings.Fixed.Trim (Natural'Image (Ref.Line), |
| Ada.Strings.Left); |
| end Get_Line; |
| |
| ---------------- |
| -- Get_Parent -- |
| ---------------- |
| |
| function Get_Parent |
| (Decl : Declaration_Reference) |
| return Declaration_Reference is |
| begin |
| return Decl.Par_Symbol; |
| end Get_Parent; |
| |
| --------------------- |
| -- Get_Source_Line -- |
| --------------------- |
| |
| function Get_Source_Line (Ref : Reference) return String is |
| begin |
| return To_String (Ref.Source_Line); |
| end Get_Source_Line; |
| |
| function Get_Source_Line (Decl : Declaration_Reference) return String is |
| begin |
| return To_String (Decl.Decl.Source_Line); |
| end Get_Source_Line; |
| |
| ---------------- |
| -- Get_Symbol -- |
| ---------------- |
| |
| function Get_Symbol (Decl : Declaration_Reference) return String is |
| begin |
| return Decl.Symbol; |
| end Get_Symbol; |
| |
| -------------- |
| -- Get_Type -- |
| -------------- |
| |
| function Get_Type (Decl : Declaration_Reference) return Character is |
| begin |
| 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 use not to parse 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; |
| |
| begin |
| while List /= null loop |
| |
| -- Makes sure we can find and read the file |
| |
| Current_File := List.Ref.File; |
| Line_Number := 0; |
| |
| begin |
| Ada.Text_IO.Open (File, |
| Ada.Text_IO.In_File, |
| Get_File (List.Ref, True)); |
| |
| -- Read the file and find every relevant lines |
| |
| 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; |
| |
| while List /= null |
| and then Line_Number = List.Ref.Line |
| loop |
| |
| -- Skip the leading blanks on the line |
| |
| Pos := 1; |
| while Line (Pos) = ' ' |
| or else Line (Pos) = ASCII.HT |
| loop |
| Pos := Pos + 1; |
| end loop; |
| |
| List.Ref.Source_Line := |
| To_Unbounded_String (Line (Pos .. Last)); |
| |
| -- Find the next element in the list |
| |
| List := List.Next; |
| end loop; |
| |
| end loop; |
| |
| Ada.Text_IO.Close (File); |
| |
| -- If the Current_File was not found, just skip it |
| |
| exception |
| when Ada.IO_Exceptions.Name_Error => |
| null; |
| end; |
| |
| -- If the line or the file were not found |
| |
| while List /= null |
| and then List.Ref.File = Current_File |
| loop |
| List := List.Next; |
| end loop; |
| |
| end loop; |
| |
| -- Clear the list |
| |
| while Save_List /= null loop |
| List := Save_List; |
| Save_List := Save_List.Next; |
| Free (List); |
| end loop; |
| end Grep_List; |
| |
| --------------------- |
| -- Insert_In_Order -- |
| --------------------- |
| |
| procedure Insert_In_Order (Ref : Reference) is |
| Iter : Simple_Ref_Access := List; |
| Prev : Simple_Ref_Access := null; |
| |
| begin |
| while Iter /= null loop |
| |
| -- If we have found the file, sort by lines |
| |
| if Iter.Ref.File = Ref.File then |
| |
| while Iter /= null |
| and then Iter.Ref.File = Ref.File |
| 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; |
| end loop; |
| |
| 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; |
| end loop; |
| |
| -- The file was not already in the list, insert it |
| |
| List := new Simple_Ref'(Ref, List); |
| end Insert_In_Order; |
| |
| --------------------- |
| -- Insert_List_Ref -- |
| --------------------- |
| |
| procedure Insert_List_Ref (First_Ref : Reference) is |
| Ref : Reference := First_Ref; |
| |
| begin |
| while Ref /= Empty_Reference loop |
| Insert_In_Order (Ref); |
| Ref := Next (Ref); |
| end loop; |
| end Insert_List_Ref; |
| |
| -- Start of processing for Grep_Source_Files |
| |
| 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; |
| |
| Grep_List; |
| end Grep_Source_Files; |
| |
| ----------------------- |
| -- Longest_File_Name -- |
| ----------------------- |
| |
| function Longest_File_Name return Natural is |
| begin |
| return Files.Longest_Name; |
| end Longest_File_Name; |
| |
| ----------- |
| -- Match -- |
| ----------- |
| |
| function Match |
| (File : File_Reference; |
| Line : Natural; |
| Column : Natural) |
| return Boolean |
| is |
| Ref : Ref_In_File_Ptr := File.Lines; |
| |
| begin |
| while Ref /= null loop |
| if (Ref.Line = 0 or else Ref.Line = Line) |
| and then (Ref.Column = 0 or else Ref.Column = Column) |
| then |
| return True; |
| end if; |
| |
| Ref := Ref.Next; |
| end loop; |
| |
| return False; |
| end Match; |
| |
| ----------- |
| -- Match -- |
| ----------- |
| |
| function Match (Decl : Declaration_Reference) return Boolean is |
| begin |
| return Decl.Match; |
| end Match; |
| |
| ---------- |
| -- Next -- |
| ---------- |
| |
| function Next (Decl : Declaration_Reference) return Declaration_Reference is |
| begin |
| return Decl.Next; |
| end Next; |
| |
| ---------- |
| -- Next -- |
| ---------- |
| |
| function Next (Ref : Reference) return Reference is |
| begin |
| return Ref.Next; |
| end Next; |
| |
| ------------------ |
| -- Next_Obj_Dir -- |
| ------------------ |
| |
| function Next_Obj_Dir return String is |
| First : Integer := Directories.Obj_Dir_Index; |
| Last : Integer := Directories.Obj_Dir_Index; |
| |
| begin |
| if Last > Directories.Obj_Dir_Length then |
| return String'(1 .. 0 => ' '); |
| end if; |
| |
| while Directories.Obj_Dir (Last) /= ' ' loop |
| Last := Last + 1; |
| end loop; |
| |
| Directories.Obj_Dir_Index := Last + 1; |
| Directories.Last_Obj_Dir_Start := First; |
| 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; |
| |
| The_Files := The_Files.Next; |
| end loop; |
| |
| return Empty_File; |
| end Next_Unvisited_File; |
| |
| ------------------ |
| -- Parse_Gnatls -- |
| ------------------ |
| |
| 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; |
| |
| 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, "./" & ' '); |
| else |
| Ada.Strings.Unbounded.Append |
| (Gnatls_Src_Cache, Osint.Dir_In_Src_Search_Path (J).all & ' '); |
| end if; |
| end loop; |
| |
| 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, "./" & ' '); |
| else |
| Ada.Strings.Unbounded.Append |
| (Gnatls_Obj_Cache, Osint.Dir_In_Obj_Search_Path (J).all & ' '); |
| end if; |
| end loop; |
| end Parse_Gnatls; |
| |
| ------------------- |
| -- Reset_Obj_Dir -- |
| ------------------- |
| |
| procedure Reset_Obj_Dir is |
| begin |
| 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 -- |
| ----------------------- |
| |
| procedure Set_Default_Match (Value : Boolean) is |
| begin |
| Default_Match := Value; |
| end Set_Default_Match; |
| |
| ------------------- |
| -- Set_Directory -- |
| ------------------- |
| |
| procedure Set_Directory |
| (File : in File_Reference; |
| Dir : in String) |
| is |
| begin |
| File.Dir := new String'(Dir); |
| end Set_Directory; |
| |
| ------------------- |
| -- Set_Unvisited -- |
| ------------------- |
| |
| procedure Set_Unvisited (File_Ref : in File_Reference) is |
| The_Files : File_Reference := Files.Table; |
| |
| begin |
| while The_Files /= null loop |
| if The_Files = File_Ref then |
| The_Files.Visited := False; |
| return; |
| end if; |
| |
| The_Files := The_Files.Next; |
| end loop; |
| end Set_Unvisited; |
| |
| end Xr_Tabls; |