1 ------------------------------------------------------------------------------
3 -- GNAT COMPILER COMPONENTS --
9 -- Copyright (C) 1998-2004 Free Software Foundation, Inc. --
11 -- GNAT is free software; you can redistribute it and/or modify it under --
12 -- terms of the GNU General Public License as published by the Free Soft- --
13 -- ware Foundation; either version 2, or (at your option) any later ver- --
14 -- sion. GNAT is distributed in the hope that it will be useful, but WITH- --
15 -- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY --
16 -- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License --
17 -- for more details. You should have received a copy of the GNU General --
18 -- Public License distributed with GNAT; see file COPYING. If not, write --
19 -- to the Free Software Foundation, 51 Franklin Street, Fifth Floor, --
20 -- Boston, MA 02110-1301, USA. --
22 -- GNAT was originally developed by the GNAT team at New York University. --
23 -- Extensive contributions were provided by Ada Core Technologies Inc. --
25 ------------------------------------------------------------------------------
27 with Types
; use Types
;
31 with Ada
.Unchecked_Conversion
;
32 with Ada
.Unchecked_Deallocation
;
33 with Ada
.Strings
.Fixed
;
36 with Ada
.Characters
.Handling
; use Ada
.Characters
.Handling
;
37 with Ada
.Strings
.Unbounded
; use Ada
.Strings
.Unbounded
;
39 with GNAT
.OS_Lib
; use GNAT
.OS_Lib
;
40 with GNAT
.Directory_Operations
; use GNAT
.Directory_Operations
;
41 with GNAT
.HTable
; use GNAT
.HTable
;
42 with GNAT
.Heap_Sort_G
;
44 package body Xr_Tabls
is
46 type HTable_Headers
is range 1 .. 10000;
48 procedure Set_Next
(E
: File_Reference
; Next
: File_Reference
);
49 function Next
(E
: File_Reference
) return File_Reference
;
50 function Get_Key
(E
: File_Reference
) return Cst_String_Access
;
51 function Hash
(F
: Cst_String_Access
) return HTable_Headers
;
52 function Equal
(F1
, F2
: Cst_String_Access
) return Boolean;
53 -- The five subprograms above are used to instanciate the static
54 -- htable to store the files that should be processed.
56 package File_HTable
is new GNAT
.HTable
.Static_HTable
57 (Header_Num
=> HTable_Headers
,
58 Element
=> File_Record
,
59 Elmt_Ptr
=> File_Reference
,
63 Key
=> Cst_String_Access
,
67 -- A hash table to store all the files referenced in the
68 -- application. The keys in this htable are the name of the files
69 -- themselves, therefore it is assumed that the source path
70 -- doesn't contain twice the same source or ALI file name
72 type Unvisited_Files_Record
;
73 type Unvisited_Files_Access
is access Unvisited_Files_Record
;
74 type Unvisited_Files_Record
is record
75 File
: File_Reference
;
76 Next
: Unvisited_Files_Access
;
78 -- A special list, in addition to File_HTable, that only stores
79 -- the files that haven't been visited so far. Note that the File
80 -- list points to some data in File_HTable, and thus should never be freed.
82 function Next
(E
: Declaration_Reference
) return Declaration_Reference
;
83 procedure Set_Next
(E
, Next
: Declaration_Reference
);
84 function Get_Key
(E
: Declaration_Reference
) return Cst_String_Access
;
85 -- The subprograms above are used to instanciate the static
86 -- htable to store the entities that have been found in the application
88 package Entities_HTable
is new GNAT
.HTable
.Static_HTable
89 (Header_Num
=> HTable_Headers
,
90 Element
=> Declaration_Record
,
91 Elmt_Ptr
=> Declaration_Reference
,
95 Key
=> Cst_String_Access
,
99 -- A hash table to store all the entities defined in the
100 -- application. For each entity, we store a list of its reference
101 -- locations as well.
102 -- The keys in this htable should be created with Key_From_Ref,
103 -- and are the file, line and column of the declaration, which are
104 -- unique for every entity.
106 Entities_Count
: Natural := 0;
107 -- Number of entities in Entities_HTable. This is used in the end
108 -- when sorting the table.
110 Longest_File_Name_In_Table
: Natural := 0;
111 Unvisited_Files
: Unvisited_Files_Access
:= null;
112 Directories
: Project_File_Ptr
;
113 Default_Match
: Boolean := False;
114 -- The above need commenting ???
116 function Parse_Gnatls_Src
return String;
117 -- Return the standard source directories (taking into account the
118 -- ADA_INCLUDE_PATH environment variable, if Osint.Add_Default_Search_Dirs
119 -- was called first).
121 function Parse_Gnatls_Obj
return String;
122 -- Return the standard object directories (taking into account the
123 -- ADA_OBJECTS_PATH environment variable).
125 function Key_From_Ref
126 (File_Ref
: File_Reference
;
130 -- Return a key for the symbol declared at File_Ref, Line,
131 -- Column. This key should be used for lookup in Entity_HTable
133 function Is_Less_Than
(Decl1
, Decl2
: Declaration_Reference
) return Boolean;
134 -- Compare two declarations. The comparison is case-insensitive.
136 function Is_Less_Than
(Ref1
, Ref2
: Reference
) return Boolean;
137 -- Compare two references
139 procedure Store_References
140 (Decl
: Declaration_Reference
;
141 Get_Writes
: Boolean := False;
142 Get_Reads
: Boolean := False;
143 Get_Bodies
: Boolean := False;
144 Get_Declaration
: Boolean := False;
145 Arr
: in out Reference_Array
;
146 Index
: in out Natural);
147 -- Store in Arr, starting at Index, all the references to Decl.
148 -- The Get_* parameters can be used to indicate which references should be
150 -- Constraint_Error will be raised if Arr is not big enough.
152 procedure Sort
(Arr
: in out Reference_Array
);
153 -- Sort an array of references.
154 -- Arr'First must be 1.
160 procedure Set_Next
(E
: File_Reference
; Next
: File_Reference
) is
166 (E
: Declaration_Reference
; Next
: Declaration_Reference
) is
175 function Get_Key
(E
: File_Reference
) return Cst_String_Access
is
180 function Get_Key
(E
: Declaration_Reference
) return Cst_String_Access
is
189 function Hash
(F
: Cst_String_Access
) return HTable_Headers
is
190 function H
is new GNAT
.HTable
.Hash
(HTable_Headers
);
200 function Equal
(F1
, F2
: Cst_String_Access
) return Boolean is
202 return F1
.all = F2
.all;
209 function Key_From_Ref
210 (File_Ref
: File_Reference
;
216 return File_Ref
.File
.all & Natural'Image (Line
) & Natural'Image (Column
);
219 ---------------------
220 -- Add_Declaration --
221 ---------------------
223 function Add_Declaration
224 (File_Ref
: File_Reference
;
228 Decl_Type
: Character;
229 Remove_Only
: Boolean := False;
230 Symbol_Match
: Boolean := True)
231 return Declaration_Reference
233 procedure Unchecked_Free
is new Ada
.Unchecked_Deallocation
234 (Declaration_Record
, Declaration_Reference
);
236 Key
: aliased constant String := Key_From_Ref
(File_Ref
, Line
, Column
);
238 New_Decl
: Declaration_Reference
:=
239 Entities_HTable
.Get
(Key
'Unchecked_Access);
241 Is_Parameter
: Boolean := False;
244 -- Insert the Declaration in the table. There might already be a
245 -- declaration in the table if the entity is a parameter, so we
246 -- need to check that first.
248 if New_Decl
/= null and then New_Decl
.Symbol_Length
= 0 then
249 Is_Parameter
:= New_Decl
.Is_Parameter
;
250 Entities_HTable
.Remove
(Key
'Unrestricted_Access);
251 Entities_Count
:= Entities_Count
- 1;
253 Unchecked_Free
(New_Decl
);
257 -- The declaration might also already be there for parent types. In
258 -- this case, we should keep the entry, since some other entries are
262 and then not Remove_Only
265 new Declaration_Record
'
266 (Symbol_Length => Symbol'Length,
268 Key => new String'(Key
),
269 Decl
=> new Reference_Record
'
275 Is_Parameter => Is_Parameter,
276 Decl_Type => Decl_Type,
280 Match => Symbol_Match
283 or else Match (File_Ref, Line, Column)),
287 Entities_HTable.Set (New_Decl);
288 Entities_Count := Entities_Count + 1;
290 if New_Decl.Match then
291 Longest_File_Name_In_Table :=
292 Natural'Max (File_Ref.File'Length, Longest_File_Name_In_Table);
295 elsif New_Decl /= null
296 and then not New_Decl.Match
298 New_Decl.Match := Default_Match
299 or else Match (File_Ref, Line, Column);
305 ----------------------
306 -- Add_To_Xref_File --
307 ----------------------
309 function Add_To_Xref_File
311 Visited : Boolean := True;
312 Emit_Warning : Boolean := False;
313 Gnatchop_File : String := "";
314 Gnatchop_Offset : Integer := 0) return File_Reference
316 Base : aliased constant String := Base_Name (File_Name);
317 Dir : constant String := Dir_Name (File_Name);
318 Dir_Acc : GNAT.OS_Lib.String_Access := null;
319 Ref : File_Reference;
322 -- Do we have a directory name as well?
324 if File_Name /= Base then
325 Dir_Acc := new String'(Dir
);
328 Ref
:= File_HTable
.Get
(Base
'Unchecked_Access);
330 Ref
:= new File_Record
'
331 (File => new String'(Base
),
335 Emit_Warning
=> Emit_Warning
,
336 Gnatchop_File
=> new String'(Gnatchop_File),
337 Gnatchop_Offset => Gnatchop_Offset,
339 File_HTable.Set (Ref);
343 -- Keep a separate list for faster access
349 end Add_To_Xref_File;
356 (File : File_Reference;
361 File.Lines := new Ref_In_File'(Line
=> Line
,
371 (Declaration
: in out Declaration_Reference
;
375 File_Ref
: File_Reference
)
378 Declaration
.Par_Symbol
:=
380 (File_Ref
, Symbol
, Line
, Column
,
382 Symbol_Match
=> False);
389 procedure Add_Reference
390 (Declaration
: Declaration_Reference
;
391 File_Ref
: File_Reference
;
394 Ref_Type
: Character;
395 Labels_As_Ref
: Boolean)
401 when 'b' |
'c' |
'm' |
'r' |
'i' |
' ' |
'x' =>
405 if not Labels_As_Ref
then
409 when '=' |
'<' |
'>' |
'^' =>
411 -- Create a dummy declaration in the table to report it as a
412 -- parameter. Note that the current declaration for the subprogram
413 -- comes before the declaration of the parameter.
416 Key
: constant String :=
417 Key_From_Ref
(File_Ref
, Line
, Column
);
418 New_Decl
: Declaration_Reference
;
421 New_Decl
:= new Declaration_Record
'
424 Key => new String'(Key
),
426 Is_Parameter
=> True,
434 Entities_HTable
.Set
(New_Decl
);
435 Entities_Count
:= Entities_Count
+ 1;
438 when 'e' |
'z' |
't' |
'p' |
'P' |
'k' |
'd' =>
442 Ada
.Text_IO
.Put_Line
("Unknown reference type: " & Ref_Type
);
446 New_Ref
:= new Reference_Record
'
453 -- We can insert the reference in the list directly, since all
454 -- the references will appear only once in the ALI file
455 -- corresponding to the file where they are referenced.
456 -- This saves a lot of time compared to checking the list to check
461 New_Ref.Next := Declaration.Body_Ref;
462 Declaration.Body_Ref := New_Ref;
464 when 'r
' | 'i
' | 'l
' | ' ' | 'x
' | 'w
' =>
465 New_Ref.Next := Declaration.Ref_Ref;
466 Declaration.Ref_Ref := New_Ref;
469 New_Ref.Next := Declaration.Modif_Ref;
470 Declaration.Modif_Ref := New_Ref;
476 if not Declaration.Match then
477 Declaration.Match := Match (File_Ref, Line, Column);
480 if Declaration.Match then
481 Longest_File_Name_In_Table :=
482 Natural'Max (File_Ref.File'Length, Longest_File_Name_In_Table);
490 function ALI_File_Name (Ada_File_Name : String) return String is
492 -- ??? Should ideally be based on the naming scheme defined in
495 Index : constant Natural :=
496 Ada.Strings.Fixed.Index
497 (Ada_File_Name, ".", Going => Ada.Strings.Backward);
501 return Ada_File_Name (Ada_File_Name'First .. Index) & "ali";
503 return Ada_File_Name & ".ali";
511 function Is_Less_Than (Ref1, Ref2 : Reference) return Boolean is
515 elsif Ref2 = null then
519 if Ref1.File.File.all < Ref2.File.File.all then
522 elsif Ref1.File.File.all = Ref2.File.File.all then
523 return (Ref1.Line < Ref2.Line
524 or else (Ref1.Line = Ref2.Line
525 and then Ref1.Column < Ref2.Column));
535 function Is_Less_Than (Decl1, Decl2 : Declaration_Reference) return Boolean
537 -- We cannot store the data case-insensitive in the table,
538 -- since we wouldn't be able to find the right casing for the
541 S1 : constant String := To_Lower (Decl1.Symbol);
542 S2 : constant String := To_Lower (Decl2.Symbol);
551 return Decl1.Key.all < Decl2.Key.all;
554 -------------------------
555 -- Create_Project_File --
556 -------------------------
558 procedure Create_Project_File (Name : String) is
559 use Ada.Strings.Unbounded;
561 Obj_Dir : Unbounded_String := Null_Unbounded_String;
562 Src_Dir : Unbounded_String := Null_Unbounded_String;
563 Build_Dir : GNAT.OS_Lib.String_Access := new String'("");
567 File_Name
: aliased String := Name
& ASCII
.NUL
;
570 -- Read the size of the file
572 F
:= Open_Read
(File_Name
'Address, Text
);
574 -- Project file not found
576 if F
/= Invalid_FD
then
577 Len
:= Positive (File_Length
(F
));
580 Buffer
: String (1 .. Len
);
581 Index
: Positive := Buffer
'First;
585 Len
:= Read
(F
, Buffer
'Address, Len
);
588 -- First, look for Build_Dir, since all the source and object
589 -- path are relative to it.
591 while Index
<= Buffer
'Last loop
593 -- Find the end of line
596 while Last
<= Buffer
'Last
597 and then Buffer
(Last
) /= ASCII
.LF
598 and then Buffer
(Last
) /= ASCII
.CR
603 if Index
<= Buffer
'Last - 9
604 and then Buffer
(Index
.. Index
+ 9) = "build_dir="
608 and then (Buffer
(Index
) = ' '
609 or else Buffer
(Index
) = ASCII
.HT
)
615 Build_Dir
:= new String'(Buffer (Index .. Last - 1));
620 -- In case we had a ASCII.CR/ASCII.LF end of line, skip the
623 if Index <= Buffer'Last
624 and then Buffer (Index) = ASCII.LF
630 -- Now parse the source and object paths
632 Index := Buffer'First;
633 while Index <= Buffer'Last loop
635 -- Find the end of line
638 while Last <= Buffer'Last
639 and then Buffer (Last) /= ASCII.LF
640 and then Buffer (Last) /= ASCII.CR
645 if Index <= Buffer'Last - 7
646 and then Buffer (Index .. Index + 7) = "src_dir="
648 Append (Src_Dir, Normalize_Pathname
649 (Name => Ada.Strings.Fixed.Trim
650 (Buffer (Index + 8 .. Last - 1), Ada.Strings.Both),
651 Directory => Build_Dir.all) & Path_Separator);
653 elsif Index <= Buffer'Last - 7
654 and then Buffer (Index .. Index + 7) = "obj_dir="
656 Append (Obj_Dir, Normalize_Pathname
657 (Name => Ada.Strings.Fixed.Trim
658 (Buffer (Index + 8 .. Last - 1), Ada.Strings.Both),
659 Directory => Build_Dir.all) & Path_Separator);
662 -- In case we had a ASCII.CR/ASCII.LF end of line, skip the
666 if Index <= Buffer'Last
667 and then Buffer (Index) = ASCII.LF
675 Osint.Add_Default_Search_Dirs;
678 Src : constant String := Parse_Gnatls_Src;
679 Obj : constant String := Parse_Gnatls_Obj;
682 Directories := new Project_File'
683 (Src_Dir_Length
=> Length
(Src_Dir
) + Src
'Length,
684 Obj_Dir_Length
=> Length
(Obj_Dir
) + Obj
'Length,
685 Src_Dir
=> To_String
(Src_Dir
) & Src
,
686 Obj_Dir
=> To_String
(Obj_Dir
) & Obj
,
689 Last_Obj_Dir_Start
=> 0);
693 end Create_Project_File
;
695 ---------------------
696 -- Current_Obj_Dir --
697 ---------------------
699 function Current_Obj_Dir
return String is
701 return Directories
.Obj_Dir
702 (Directories
.Last_Obj_Dir_Start
.. Directories
.Obj_Dir_Index
- 2);
709 function Get_Column
(Decl
: Declaration_Reference
) return String is
711 return Ada
.Strings
.Fixed
.Trim
(Natural'Image (Decl
.Decl
.Column
),
715 function Get_Column
(Ref
: Reference
) return String is
717 return Ada
.Strings
.Fixed
.Trim
(Natural'Image (Ref
.Column
),
721 ---------------------
722 -- Get_Declaration --
723 ---------------------
725 function Get_Declaration
726 (File_Ref
: File_Reference
;
729 return Declaration_Reference
731 Key
: aliased constant String := Key_From_Ref
(File_Ref
, Line
, Column
);
734 return Entities_HTable
.Get
(Key
'Unchecked_Access);
737 ----------------------
738 -- Get_Emit_Warning --
739 ----------------------
741 function Get_Emit_Warning
(File
: File_Reference
) return Boolean is
743 return File
.Emit_Warning
;
744 end Get_Emit_Warning
;
751 (Decl
: Declaration_Reference
;
752 With_Dir
: Boolean := False) return String
755 return Get_File
(Decl
.Decl
.File
, With_Dir
);
760 With_Dir
: Boolean := False) return String
763 return Get_File
(Ref
.File
, With_Dir
);
767 (File
: File_Reference
;
768 With_Dir
: in Boolean := False;
769 Strip
: Natural := 0) return String
771 Tmp
: GNAT
.OS_Lib
.String_Access
;
773 function Internal_Strip
(Full_Name
: String) return String;
774 -- Internal function to process the Strip parameter
780 function Internal_Strip
(Full_Name
: String) return String is
782 Extension_Start
: Natural;
790 -- Isolate the file extension
792 Extension_Start
:= Full_Name
'Last;
793 while Extension_Start
>= Full_Name
'First
794 and then Full_Name
(Extension_Start
) /= '.'
796 Extension_Start
:= Extension_Start
- 1;
799 -- Strip the right number of subunit_names
802 Unit_End
:= Extension_Start
- 1;
803 while Unit_End
>= Full_Name
'First
806 if Full_Name
(Unit_End
) = '-' then
810 Unit_End
:= Unit_End
- 1;
813 if Unit_End
< Full_Name
'First then
816 return Full_Name
(Full_Name
'First .. Unit_End
)
817 & Full_Name
(Extension_Start
.. Full_Name
'Last);
821 -- Start of processing for Get_File;
824 -- If we do not want the full path name
827 return Internal_Strip
(File
.File
.all);
830 if File
.Dir
= null then
831 if Ada
.Strings
.Fixed
.Tail
(File
.File
.all, 3) = "ali" then
832 Tmp
:= Locate_Regular_File
833 (Internal_Strip
(File
.File
.all), Directories
.Obj_Dir
);
835 Tmp
:= Locate_Regular_File
836 (File
.File
.all, Directories
.Src_Dir
);
840 File
.Dir
:= new String'("");
842 File.Dir := new String'(Dir_Name
(Tmp
.all));
847 return Internal_Strip
(File
.Dir
.all & File
.File
.all);
854 function Get_File_Ref
(Ref
: Reference
) return File_Reference
is
859 -----------------------
860 -- Get_Gnatchop_File --
861 -----------------------
863 function Get_Gnatchop_File
864 (File
: File_Reference
;
865 With_Dir
: Boolean := False)
869 if File
.Gnatchop_File
.all = "" then
870 return Get_File
(File
, With_Dir
);
872 return File
.Gnatchop_File
.all;
874 end Get_Gnatchop_File
;
876 function Get_Gnatchop_File
878 With_Dir
: Boolean := False)
882 return Get_Gnatchop_File
(Ref
.File
, With_Dir
);
883 end Get_Gnatchop_File
;
885 function Get_Gnatchop_File
886 (Decl
: Declaration_Reference
;
887 With_Dir
: Boolean := False)
891 return Get_Gnatchop_File
(Decl
.Decl
.File
, With_Dir
);
892 end Get_Gnatchop_File
;
898 function Get_Line
(Decl
: Declaration_Reference
) return String is
900 return Ada
.Strings
.Fixed
.Trim
(Natural'Image (Decl
.Decl
.Line
),
904 function Get_Line
(Ref
: Reference
) return String is
906 return Ada
.Strings
.Fixed
.Trim
(Natural'Image (Ref
.Line
),
915 (Decl
: Declaration_Reference
)
916 return Declaration_Reference
919 return Decl
.Par_Symbol
;
922 ---------------------
923 -- Get_Source_Line --
924 ---------------------
926 function Get_Source_Line
(Ref
: Reference
) return String is
928 if Ref
.Source_Line
/= null then
929 return Ref
.Source_Line
.all;
935 function Get_Source_Line
(Decl
: Declaration_Reference
) return String is
937 if Decl
.Decl
.Source_Line
/= null then
938 return Decl
.Decl
.Source_Line
.all;
948 function Get_Symbol
(Decl
: Declaration_Reference
) return String is
957 function Get_Type
(Decl
: Declaration_Reference
) return Character is
959 return Decl
.Decl_Type
;
966 procedure Sort
(Arr
: in out Reference_Array
) is
969 function Lt
(Op1
, Op2
: Natural) return Boolean;
970 procedure Move
(From
, To
: Natural);
971 -- See GNAT.Heap_Sort_G
977 function Lt
(Op1
, Op2
: Natural) return Boolean is
980 return Is_Less_Than
(Tmp
, Arr
(Op2
));
982 return Is_Less_Than
(Arr
(Op1
), Tmp
);
984 return Is_Less_Than
(Arr
(Op1
), Arr
(Op2
));
992 procedure Move
(From
, To
: Natural) is
999 Arr
(To
) := Arr
(From
);
1003 package Ref_Sort
is new GNAT
.Heap_Sort_G
(Move
, Lt
);
1005 -- Start of processing for Sort
1008 Ref_Sort
.Sort
(Arr
'Last);
1011 -----------------------
1012 -- Grep_Source_Files --
1013 -----------------------
1015 procedure Grep_Source_Files
is
1016 Length
: Natural := 0;
1017 Decl
: Declaration_Reference
:= Entities_HTable
.Get_First
;
1018 Arr
: Reference_Array_Access
;
1020 End_Index
: Natural;
1021 Current_File
: File_Reference
;
1022 Current_Line
: Cst_String_Access
;
1023 Buffer
: GNAT
.OS_Lib
.String_Access
;
1028 -- Create a temporary array, where all references will be
1029 -- sorted by files. This way, we only have to read the source
1032 while Decl
/= null loop
1034 -- Add 1 for the declaration itself
1036 Length
:= Length
+ References_Count
(Decl
, True, True, True) + 1;
1037 Decl
:= Entities_HTable
.Get_Next
;
1040 Arr
:= new Reference_Array
(1 .. Length
);
1043 Decl
:= Entities_HTable
.Get_First
;
1044 while Decl
/= null loop
1045 Store_References
(Decl
, True, True, True, True, Arr
.all, Index
);
1046 Decl
:= Entities_HTable
.Get_Next
;
1051 -- Now traverse the whole array and find the appropriate source
1054 for R
in Arr
'Range loop
1057 if Ref
.File
/= Current_File
then
1060 Read_File
(Get_File
(Ref
.File
, With_Dir
=> True), Buffer
);
1061 End_Index
:= Buffer
'First - 1;
1064 when Ada
.Text_IO
.Name_Error | Ada
.Text_IO
.End_Error
=>
1065 Line
:= Natural'Last;
1067 Current_File
:= Ref
.File
;
1070 if Ref
.Line
> Line
then
1072 -- Do not free Current_Line, it is referenced by the last
1073 -- Ref we processed.
1076 Index
:= End_Index
+ 1;
1079 End_Index
:= End_Index
+ 1;
1080 exit when End_Index
> Buffer
'Last
1081 or else Buffer
(End_Index
) = ASCII
.LF
;
1084 -- Skip spaces at beginning of line
1086 while Index
< End_Index
and then
1087 (Buffer
(Index
) = ' ' or else Buffer
(Index
) = ASCII
.HT
)
1093 exit when Ref
.Line
= Line
;
1096 Current_Line
:= new String'(Buffer (Index .. End_Index - 1));
1099 Ref.Source_Line := Current_Line;
1104 end Grep_Source_Files;
1111 (File_Name : String;
1112 Contents : out GNAT.OS_Lib.String_Access)
1114 Name_0 : constant String := File_Name & ASCII.NUL;
1115 FD : constant File_Descriptor := Open_Read (Name_0'Address, Binary);
1119 if FD = Invalid_FD then
1120 raise Ada.Text_IO.Name_Error;
1123 -- Include room for EOF char
1125 Length := Natural (File_Length (FD));
1128 Buffer : String (1 .. Length + 1);
1129 This_Read : Integer;
1130 Read_Ptr : Natural := 1;
1134 This_Read := Read (FD,
1135 A => Buffer (Read_Ptr)'Address,
1136 N => Length + 1 - Read_Ptr);
1137 Read_Ptr := Read_Ptr + Integer'Max (This_Read, 0);
1138 exit when This_Read <= 0;
1141 Buffer (Read_Ptr) := EOF;
1142 Contents := new String'(Buffer
(1 .. Read_Ptr
));
1144 -- Things are not simple on VMS due to the plethora of file types
1145 -- and organizations. It seems clear that there shouldn't be more
1146 -- bytes read than are contained in the file though.
1148 if (Hostparm
.OpenVMS
and then Read_Ptr
> Length
+ 1)
1149 or else (not Hostparm
.OpenVMS
and then Read_Ptr
/= Length
+ 1)
1151 raise Ada
.Text_IO
.End_Error
;
1158 -----------------------
1159 -- Longest_File_Name --
1160 -----------------------
1162 function Longest_File_Name
return Natural is
1164 return Longest_File_Name_In_Table
;
1165 end Longest_File_Name
;
1172 (File
: File_Reference
;
1177 Ref
: Ref_In_File_Ptr
:= File
.Lines
;
1180 while Ref
/= null loop
1181 if (Ref
.Line
= 0 or else Ref
.Line
= Line
)
1182 and then (Ref
.Column
= 0 or else Ref
.Column
= Column
)
1197 function Match
(Decl
: Declaration_Reference
) return Boolean is
1206 function Next
(E
: File_Reference
) return File_Reference
is
1211 function Next
(E
: Declaration_Reference
) return Declaration_Reference
is
1220 function Next_Obj_Dir
return String is
1221 First
: constant Integer := Directories
.Obj_Dir_Index
;
1225 Last
:= Directories
.Obj_Dir_Index
;
1227 if Last
> Directories
.Obj_Dir_Length
then
1228 return String'(1 .. 0 => ' ');
1231 while Directories.Obj_Dir (Last) /= Path_Separator loop
1235 Directories.Obj_Dir_Index := Last + 1;
1236 Directories.Last_Obj_Dir_Start := First;
1237 return Directories.Obj_Dir (First .. Last - 1);
1240 -------------------------
1241 -- Next_Unvisited_File --
1242 -------------------------
1244 function Next_Unvisited_File return File_Reference is
1245 procedure Unchecked_Free is new Ada.Unchecked_Deallocation
1246 (Unvisited_Files_Record, Unvisited_Files_Access);
1248 Ref : File_Reference;
1249 Tmp : Unvisited_Files_Access;
1252 if Unvisited_Files = null then
1255 Tmp := Unvisited_Files;
1256 Ref := Unvisited_Files.File;
1257 Unvisited_Files := Unvisited_Files.Next;
1258 Unchecked_Free (Tmp);
1261 end Next_Unvisited_File;
1263 ----------------------
1264 -- Parse_Gnatls_Src --
1265 ----------------------
1267 function Parse_Gnatls_Src return String is
1272 for J in 1 .. Osint.Nb_Dir_In_Src_Search_Path loop
1273 if Osint.Dir_In_Src_Search_Path (J)'Length = 0 then
1274 Length := Length + 2;
1276 Length := Length + Osint.Dir_In_Src_Search_Path (J)'Length + 1;
1281 Result : String (1 .. Length);
1286 for J in 1 .. Osint.Nb_Dir_In_Src_Search_Path loop
1287 if Osint.Dir_In_Src_Search_Path (J)'Length = 0 then
1288 Result (L .. L + 1) := "." & Path_Separator;
1292 Result (L .. L + Osint.Dir_In_Src_Search_Path (J)'Length - 1) :=
1293 Osint.Dir_In_Src_Search_Path (J).all;
1294 L := L + Osint.Dir_In_Src_Search_Path (J)'Length;
1295 Result (L) := Path_Separator;
1302 end Parse_Gnatls_Src;
1304 ----------------------
1305 -- Parse_Gnatls_Obj --
1306 ----------------------
1308 function Parse_Gnatls_Obj return String is
1313 for J in 1 .. Osint.Nb_Dir_In_Obj_Search_Path loop
1314 if Osint.Dir_In_Obj_Search_Path (J)'Length = 0 then
1315 Length := Length + 2;
1317 Length := Length + Osint.Dir_In_Obj_Search_Path (J)'Length + 1;
1322 Result : String (1 .. Length);
1327 for J in 1 .. Osint.Nb_Dir_In_Obj_Search_Path loop
1328 if Osint.Dir_In_Obj_Search_Path (J)'Length = 0 then
1329 Result (L .. L + 1) := "." & Path_Separator;
1332 Result (L .. L + Osint.Dir_In_Obj_Search_Path (J)'Length - 1) :=
1333 Osint.Dir_In_Obj_Search_Path (J).all;
1334 L := L + Osint.Dir_In_Obj_Search_Path (J)'Length;
1335 Result (L) := Path_Separator;
1342 end Parse_Gnatls_Obj;
1348 procedure Reset_Obj_Dir is
1350 Directories.Obj_Dir_Index := 1;
1353 -----------------------
1354 -- Set_Default_Match --
1355 -----------------------
1357 procedure Set_Default_Match (Value : Boolean) is
1359 Default_Match := Value;
1360 end Set_Default_Match;
1366 procedure Free (Str : in out Cst_String_Access) is
1367 function Convert is new Ada.Unchecked_Conversion
1368 (Cst_String_Access, GNAT.OS_Lib.String_Access);
1370 S : GNAT.OS_Lib.String_Access := Convert (Str);
1377 ---------------------
1378 -- Reset_Directory --
1379 ---------------------
1381 procedure Reset_Directory (File : File_Reference) is
1384 end Reset_Directory;
1390 procedure Set_Unvisited (File_Ref : File_Reference) is
1391 F : constant String := Get_File (File_Ref, With_Dir => False);
1394 File_Ref.Visited := False;
1396 -- ??? Do not add a source file to the list. This is true at
1397 -- least for gnatxref, and probably for gnatfind as wel
1400 and then F (F'Last - 3 .. F'Last) = ".ali"
1402 Unvisited_Files := new Unvisited_Files_Record'
1404 Next
=> Unvisited_Files
);
1408 ----------------------
1409 -- Get_Declarations --
1410 ----------------------
1412 function Get_Declarations
1413 (Sorted
: Boolean := True)
1414 return Declaration_Array_Access
1416 Arr
: constant Declaration_Array_Access
:=
1417 new Declaration_Array
(1 .. Entities_Count
);
1418 Decl
: Declaration_Reference
:= Entities_HTable
.Get_First
;
1419 Index
: Natural := Arr
'First;
1420 Tmp
: Declaration_Reference
;
1422 procedure Move
(From
: Natural; To
: Natural);
1423 function Lt
(Op1
, Op2
: Natural) return Boolean;
1424 -- See GNAT.Heap_Sort_G
1430 function Lt
(Op1
, Op2
: Natural) return Boolean is
1433 return Is_Less_Than
(Tmp
, Arr
(Op2
));
1435 return Is_Less_Than
(Arr
(Op1
), Tmp
);
1437 return Is_Less_Than
(Arr
(Op1
), Arr
(Op2
));
1445 procedure Move
(From
: Natural; To
: Natural) is
1452 Arr
(To
) := Arr
(From
);
1456 package Decl_Sort
is new GNAT
.Heap_Sort_G
(Move
, Lt
);
1458 -- Start of processing for Get_Declarations
1461 while Decl
/= null loop
1462 Arr
(Index
) := Decl
;
1464 Decl
:= Entities_HTable
.Get_Next
;
1467 if Sorted
and then Arr
'Length /= 0 then
1468 Decl_Sort
.Sort
(Entities_Count
);
1472 end Get_Declarations
;
1474 ----------------------
1475 -- References_Count --
1476 ----------------------
1478 function References_Count
1479 (Decl
: Declaration_Reference
;
1480 Get_Reads
: Boolean := False;
1481 Get_Writes
: Boolean := False;
1482 Get_Bodies
: Boolean := False)
1485 function List_Length
(E
: Reference
) return Natural;
1486 -- Return the number of references in E
1492 function List_Length
(E
: Reference
) return Natural is
1494 E1
: Reference
:= E
;
1497 while E1
/= null loop
1505 Length
: Natural := 0;
1507 -- Start of processing for References_Count
1511 Length
:= List_Length
(Decl
.Ref_Ref
);
1515 Length
:= Length
+ List_Length
(Decl
.Modif_Ref
);
1519 Length
:= Length
+ List_Length
(Decl
.Body_Ref
);
1523 end References_Count
;
1525 ----------------------
1526 -- Store_References --
1527 ----------------------
1529 procedure Store_References
1530 (Decl
: Declaration_Reference
;
1531 Get_Writes
: Boolean := False;
1532 Get_Reads
: Boolean := False;
1533 Get_Bodies
: Boolean := False;
1534 Get_Declaration
: Boolean := False;
1535 Arr
: in out Reference_Array
;
1536 Index
: in out Natural)
1538 procedure Add
(List
: Reference
);
1539 -- Add all the references in List to Arr
1545 procedure Add
(List
: Reference
) is
1546 E
: Reference
:= List
;
1548 while E
/= null loop
1555 -- Start of processing for Store_References
1558 if Get_Declaration
then
1567 Add
(Decl
.Modif_Ref
);
1571 Add
(Decl
.Body_Ref
);
1573 end Store_References
;
1575 --------------------
1576 -- Get_References --
1577 --------------------
1579 function Get_References
1580 (Decl
: Declaration_Reference
;
1581 Get_Reads
: Boolean := False;
1582 Get_Writes
: Boolean := False;
1583 Get_Bodies
: Boolean := False)
1584 return Reference_Array_Access
1586 Length
: constant Natural :=
1587 References_Count
(Decl
, Get_Reads
, Get_Writes
, Get_Bodies
);
1589 Arr
: constant Reference_Array_Access
:=
1590 new Reference_Array
(1 .. Length
);
1592 Index
: Natural := Arr
'First;
1597 Get_Writes
=> Get_Writes
,
1598 Get_Reads
=> Get_Reads
,
1599 Get_Bodies
=> Get_Bodies
,
1600 Get_Declaration
=> False,
1604 if Arr
'Length /= 0 then
1615 procedure Free
(Arr
: in out Reference_Array_Access
) is
1616 procedure Internal
is new Ada
.Unchecked_Deallocation
1617 (Reference_Array
, Reference_Array_Access
);
1626 function Is_Parameter
(Decl
: Declaration_Reference
) return Boolean is
1628 return Decl
.Is_Parameter
;