Add an UNSPEC_PROLOGUE_USE to prevent the link register from being considered dead.
[official-gcc.git] / gcc / ada / xr_tabls.adb
blob2f43edb5f07f38dbbb02d10f26cb95061a3a06c4
1 ------------------------------------------------------------------------------
2 -- --
3 -- GNAT COMPILER COMPONENTS --
4 -- --
5 -- X R _ T A B L S --
6 -- --
7 -- B o d y --
8 -- --
9 -- --
10 -- Copyright (C) 1998-2002 Free Software Foundation, Inc. --
11 -- --
12 -- GNAT is free software; you can redistribute it and/or modify it under --
13 -- terms of the GNU General Public License as published by the Free Soft- --
14 -- ware Foundation; either version 2, or (at your option) any later ver- --
15 -- sion. GNAT is distributed in the hope that it will be useful, but WITH- --
16 -- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY --
17 -- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License --
18 -- for more details. You should have received a copy of the GNU General --
19 -- Public License distributed with GNAT; see file COPYING. If not, write --
20 -- to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, --
21 -- MA 02111-1307, USA. --
22 -- --
23 -- Extensive contributions were provided by Ada Core Technologies Inc. --
24 -- --
25 ------------------------------------------------------------------------------
27 with Osint;
28 with Unchecked_Deallocation;
30 with Ada.IO_Exceptions;
31 with Ada.Strings.Fixed;
32 with Ada.Strings;
33 with Ada.Text_IO;
34 with Ada.Strings.Unbounded; use Ada.Strings.Unbounded;
36 with GNAT.IO_Aux;
37 with GNAT.OS_Lib; use GNAT.OS_Lib;
38 with GNAT.Directory_Operations; use GNAT.Directory_Operations;
40 package body Xr_Tabls is
42 function Base_File_Name (File : String) return String;
43 -- Return the base file name for File (ie not including the directory)
45 function Dir_Name (File : String; Base : String := "") return String;
46 -- Return the directory name of File, or "" if there is no directory part
47 -- in File.
48 -- This includes the last separator at the end, and always return an
49 -- absolute path name (directories are relative to Base, or the current
50 -- directory if Base is "")
52 Dir_Sep : Character renames GNAT.OS_Lib.Directory_Separator;
54 Files : File_Table;
55 Entities : Entity_Table;
56 Directories : Project_File_Ptr;
57 Default_Match : Boolean := False;
59 ---------------------
60 -- Add_Declaration --
61 ---------------------
63 function Add_Declaration
64 (File_Ref : File_Reference;
65 Symbol : String;
66 Line : Natural;
67 Column : Natural;
68 Decl_Type : Character)
69 return Declaration_Reference
71 The_Entities : Declaration_Reference := Entities.Table;
72 New_Decl : Declaration_Reference;
73 Result : Compare_Result;
74 Prev : Declaration_Reference := null;
76 begin
77 -- Check if the identifier already exists in the table
79 while The_Entities /= null loop
80 Result := Compare (The_Entities, File_Ref, Line, Column, Symbol);
81 exit when Result = GreaterThan;
83 if Result = Equal then
84 return The_Entities;
85 end if;
87 Prev := The_Entities;
88 The_Entities := The_Entities.Next;
89 end loop;
91 -- Insert the Declaration in the table
93 New_Decl :=
94 new Declaration_Record'
95 (Symbol_Length => Symbol'Length,
96 Symbol => Symbol,
97 Decl => (File => File_Ref,
98 Line => Line,
99 Column => Column,
100 Source_Line => Null_Unbounded_String,
101 Next => null),
102 Decl_Type => Decl_Type,
103 Body_Ref => null,
104 Ref_Ref => null,
105 Modif_Ref => null,
106 Match => Default_Match
107 or else Match (File_Ref, Line, Column),
108 Par_Symbol => null,
109 Next => null);
111 if Prev = null then
112 New_Decl.Next := Entities.Table;
113 Entities.Table := New_Decl;
114 else
115 New_Decl.Next := Prev.Next;
116 Prev.Next := New_Decl;
117 end if;
119 if New_Decl.Match then
120 Files.Longest_Name := Natural'Max (File_Ref.File'Length,
121 Files.Longest_Name);
122 end if;
124 return New_Decl;
125 end Add_Declaration;
127 ----------------------
128 -- Add_To_Xref_File --
129 ----------------------
131 procedure Add_To_Xref_File
132 (File_Name : String;
133 File_Existed : out Boolean;
134 Ref : out File_Reference;
135 Visited : Boolean := True;
136 Emit_Warning : Boolean := False;
137 Gnatchop_File : String := "";
138 Gnatchop_Offset : Integer := 0)
140 The_Files : File_Reference := Files.Table;
141 Base : constant String := Base_File_Name (File_Name);
142 Dir : constant String := Xr_Tabls.Dir_Name (File_Name);
143 Dir_Acc : String_Access := null;
145 begin
146 -- Do we have a directory name as well?
148 if Dir /= "" then
149 Dir_Acc := new String' (Dir);
150 end if;
152 -- Check if the file already exists in the table
154 while The_Files /= null loop
156 if The_Files.File = File_Name then
157 File_Existed := True;
158 Ref := The_Files;
159 return;
160 end if;
162 The_Files := The_Files.Next;
163 end loop;
165 Ref := new File_Record'
166 (File_Length => Base'Length,
167 File => Base,
168 Dir => Dir_Acc,
169 Lines => null,
170 Visited => Visited,
171 Emit_Warning => Emit_Warning,
172 Gnatchop_File => new String' (Gnatchop_File),
173 Gnatchop_Offset => Gnatchop_Offset,
174 Next => Files.Table);
175 Files.Table := Ref;
176 File_Existed := False;
177 end Add_To_Xref_File;
179 --------------
180 -- Add_Line --
181 --------------
183 procedure Add_Line
184 (File : File_Reference;
185 Line : Natural;
186 Column : Natural)
188 begin
189 File.Lines := new Ref_In_File'(Line => Line,
190 Column => Column,
191 Next => File.Lines);
192 end Add_Line;
194 ----------------
195 -- Add_Parent --
196 ----------------
198 procedure Add_Parent
199 (Declaration : in out Declaration_Reference;
200 Symbol : String;
201 Line : Natural;
202 Column : Natural;
203 File_Ref : File_Reference)
205 begin
206 Declaration.Par_Symbol := new Declaration_Record'
207 (Symbol_Length => Symbol'Length,
208 Symbol => Symbol,
209 Decl => (File => File_Ref,
210 Line => Line,
211 Column => Column,
212 Source_Line => Null_Unbounded_String,
213 Next => null),
214 Decl_Type => ' ',
215 Body_Ref => null,
216 Ref_Ref => null,
217 Modif_Ref => null,
218 Match => False,
219 Par_Symbol => null,
220 Next => null);
221 end Add_Parent;
223 -------------------
224 -- Add_Reference --
225 -------------------
227 procedure Add_Reference
228 (Declaration : Declaration_Reference;
229 File_Ref : File_Reference;
230 Line : Natural;
231 Column : Natural;
232 Ref_Type : Character)
234 procedure Free is new Unchecked_Deallocation
235 (Reference_Record, Reference);
237 Ref : Reference;
238 Prev : Reference := null;
239 Result : Compare_Result;
240 New_Ref : Reference := new Reference_Record'
241 (File => File_Ref,
242 Line => Line,
243 Column => Column,
244 Source_Line => Null_Unbounded_String,
245 Next => null);
247 begin
248 case Ref_Type is
249 when 'b' | 'c' =>
250 Ref := Declaration.Body_Ref;
252 when 'r' | 'i' | 'l' | ' ' | 'x' =>
253 Ref := Declaration.Ref_Ref;
255 when 'm' =>
256 Ref := Declaration.Modif_Ref;
258 when 'e' | 't' | 'p' =>
259 return;
261 when others =>
262 Ada.Text_IO.Put_Line ("Unknown reference type: " & Ref_Type);
263 return;
264 end case;
266 -- Check if the reference already exists
268 while Ref /= null loop
269 Result := Compare (New_Ref, Ref);
270 exit when Result = LessThan;
272 if Result = Equal then
273 Free (New_Ref);
274 return;
275 end if;
277 Prev := Ref;
278 Ref := Ref.Next;
279 end loop;
281 -- Insert it in the list
283 if Prev /= null then
284 New_Ref.Next := Prev.Next;
285 Prev.Next := New_Ref;
287 else
288 case Ref_Type is
289 when 'b' | 'c' =>
290 New_Ref.Next := Declaration.Body_Ref;
291 Declaration.Body_Ref := New_Ref;
293 when 'r' | 'i' | 'l' | ' ' | 'x' =>
294 New_Ref.Next := Declaration.Ref_Ref;
295 Declaration.Ref_Ref := New_Ref;
297 when 'm' =>
298 New_Ref.Next := Declaration.Modif_Ref;
299 Declaration.Modif_Ref := New_Ref;
301 when others =>
302 null;
303 end case;
304 end if;
306 if not Declaration.Match then
307 Declaration.Match := Match (File_Ref, Line, Column);
308 end if;
310 if Declaration.Match then
311 Files.Longest_Name := Natural'Max (File_Ref.File'Length,
312 Files.Longest_Name);
313 end if;
314 end Add_Reference;
316 -------------------
317 -- ALI_File_Name --
318 -------------------
320 function ALI_File_Name (Ada_File_Name : String) return String is
321 Index : Natural := Ada.Strings.Fixed.Index
322 (Ada_File_Name, ".", Going => Ada.Strings.Backward);
324 begin
325 if Index /= 0 then
326 return Ada_File_Name (Ada_File_Name'First .. Index)
327 & "ali";
328 else
329 return Ada_File_Name & ".ali";
330 end if;
331 end ALI_File_Name;
333 --------------------
334 -- Base_File_Name --
335 --------------------
337 function Base_File_Name (File : String) return String is
338 begin
339 for J in reverse File'Range loop
340 if File (J) = '/' or else File (J) = Dir_Sep then
341 return File (J + 1 .. File'Last);
342 end if;
343 end loop;
345 return File;
346 end Base_File_Name;
348 -------------
349 -- Compare --
350 -------------
352 function Compare
353 (Ref1 : Reference;
354 Ref2 : Reference)
355 return Compare_Result
357 begin
358 if Ref1 = null then
359 return GreaterThan;
360 elsif Ref2 = null then
361 return LessThan;
362 end if;
364 if Ref1.File.File < Ref2.File.File then
365 return LessThan;
367 elsif Ref1.File.File = Ref2.File.File then
368 if Ref1.Line < Ref2.Line then
369 return LessThan;
371 elsif Ref1.Line = Ref2.Line then
372 if Ref1.Column < Ref2.Column then
373 return LessThan;
374 elsif Ref1.Column = Ref2.Column then
375 return Equal;
376 else
377 return GreaterThan;
378 end if;
380 else
381 return GreaterThan;
382 end if;
384 else
385 return GreaterThan;
386 end if;
387 end Compare;
389 -------------
390 -- Compare --
391 -------------
393 function Compare
394 (Decl1 : Declaration_Reference;
395 File2 : File_Reference;
396 Line2 : Integer;
397 Col2 : Integer;
398 Symb2 : String)
399 return Compare_Result
401 begin
402 if Decl1 = null then
403 return GreaterThan;
404 end if;
406 if Decl1.Symbol < Symb2 then
407 return LessThan;
408 elsif Decl1.Symbol > Symb2 then
409 return GreaterThan;
410 end if;
412 if Decl1.Decl.File.File < Get_File (File2) then
413 return LessThan;
415 elsif Decl1.Decl.File.File = Get_File (File2) then
416 if Decl1.Decl.Line < Line2 then
417 return LessThan;
419 elsif Decl1.Decl.Line = Line2 then
420 if Decl1.Decl.Column < Col2 then
421 return LessThan;
423 elsif Decl1.Decl.Column = Col2 then
424 return Equal;
426 else
427 return GreaterThan;
428 end if;
430 else
431 return GreaterThan;
432 end if;
434 else
435 return GreaterThan;
436 end if;
437 end Compare;
439 -------------------------
440 -- Create_Project_File --
441 -------------------------
443 procedure Create_Project_File
444 (Name : String)
446 use Ada.Strings.Unbounded;
448 Obj_Dir : Unbounded_String := Null_Unbounded_String;
449 Src_Dir : Unbounded_String := Null_Unbounded_String;
450 Build_Dir : Unbounded_String;
452 Gnatls_Src_Cache : Unbounded_String;
453 Gnatls_Obj_Cache : Unbounded_String;
455 F : File_Descriptor;
456 Len : Positive;
457 File_Name : aliased String := Name & ASCII.NUL;
459 begin
461 -- Read the size of the file
462 F := Open_Read (File_Name'Address, Text);
464 -- Project file not found
465 if F /= Invalid_FD then
466 Len := Positive (File_Length (F));
468 declare
469 Buffer : String (1 .. Len);
470 Index : Positive := Buffer'First;
471 Last : Positive;
472 begin
473 Len := Read (F, Buffer'Address, Len);
474 Close (F);
476 -- First, look for Build_Dir, since all the source and object
477 -- path are relative to it.
479 while Index <= Buffer'Last loop
481 -- find the end of line
483 Last := Index;
484 while Last <= Buffer'Last
485 and then Buffer (Last) /= ASCII.LF
486 and then Buffer (Last) /= ASCII.CR
487 loop
488 Last := Last + 1;
489 end loop;
491 if Index <= Buffer'Last - 9
492 and then Buffer (Index .. Index + 9) = "build_dir="
493 then
494 Index := Index + 10;
495 while Index <= Last
496 and then (Buffer (Index) = ' '
497 or else Buffer (Index) = ASCII.HT)
498 loop
499 Index := Index + 1;
500 end loop;
502 Build_Dir :=
503 To_Unbounded_String (Buffer (Index .. Last - 1));
504 if Buffer (Last - 1) /= Dir_Sep then
505 Append (Build_Dir, Dir_Sep);
506 end if;
507 end if;
509 Index := Last + 1;
511 -- In case we had a ASCII.CR/ASCII.LF end of line, skip the
512 -- remaining symbol
514 if Index <= Buffer'Last
515 and then Buffer (Index) = ASCII.LF
516 then
517 Index := Index + 1;
518 end if;
519 end loop;
521 -- Now parse the source and object paths
523 Index := Buffer'First;
524 while Index <= Buffer'Last loop
526 -- find the end of line
528 Last := Index;
529 while Last <= Buffer'Last
530 and then Buffer (Last) /= ASCII.LF
531 and then Buffer (Last) /= ASCII.CR
532 loop
533 Last := Last + 1;
534 end loop;
536 if Index <= Buffer'Last - 7
537 and then Buffer (Index .. Index + 7) = "src_dir="
538 then
539 declare
540 S : String := Ada.Strings.Fixed.Trim
541 (Buffer (Index + 8 .. Last - 1), Ada.Strings.Both);
542 begin
543 -- A relative directory ?
544 if S (S'First) /= Dir_Sep then
545 Append (Src_Dir, Build_Dir);
546 end if;
548 if S (S'Last) = Dir_Sep then
549 Append (Src_Dir, S & " ");
550 else
551 Append (Src_Dir, S & Dir_Sep & " ");
552 end if;
553 end;
555 elsif Index <= Buffer'Last - 7
556 and then Buffer (Index .. Index + 7) = "obj_dir="
557 then
558 declare
559 S : String := Ada.Strings.Fixed.Trim
560 (Buffer (Index + 8 .. Last - 1), Ada.Strings.Both);
561 begin
562 -- A relative directory ?
563 if S (S'First) /= Dir_Sep then
564 Append (Obj_Dir, Build_Dir);
565 end if;
567 if S (S'Last) = Dir_Sep then
568 Append (Obj_Dir, S & " ");
569 else
570 Append (Obj_Dir, S & Dir_Sep & " ");
571 end if;
572 end;
573 end if;
575 -- In case we had a ASCII.CR/ASCII.LF end of line, skip the
576 -- remaining symbol
577 Index := Last + 1;
579 if Index <= Buffer'Last
580 and then Buffer (Index) = ASCII.LF
581 then
582 Index := Index + 1;
583 end if;
584 end loop;
585 end;
586 end if;
588 Parse_Gnatls (Gnatls_Src_Cache, Gnatls_Obj_Cache);
590 Directories := new Project_File'
591 (Src_Dir_Length => Length (Src_Dir) + Length (Gnatls_Src_Cache),
592 Obj_Dir_Length => Length (Obj_Dir) + Length (Gnatls_Obj_Cache),
593 Src_Dir => To_String (Src_Dir & Gnatls_Src_Cache),
594 Obj_Dir => To_String (Obj_Dir & Gnatls_Obj_Cache),
595 Src_Dir_Index => 1,
596 Obj_Dir_Index => 1,
597 Last_Obj_Dir_Start => 0);
598 end Create_Project_File;
600 ---------------------
601 -- Current_Obj_Dir --
602 ---------------------
604 function Current_Obj_Dir return String is
605 begin
606 return Directories.Obj_Dir (Directories.Last_Obj_Dir_Start
607 .. Directories.Obj_Dir_Index - 2);
608 end Current_Obj_Dir;
610 --------------
611 -- Dir_Name --
612 --------------
614 function Dir_Name (File : String; Base : String := "") return String is
615 begin
616 for J in reverse File'Range loop
617 if File (J) = '/' or else File (J) = Dir_Sep then
619 -- Is this an absolute directory ?
620 if File (File'First) = '/'
621 or else File (File'First) = Dir_Sep
622 then
623 return File (File'First .. J);
625 -- Else do we know the base directory ?
626 elsif Base /= "" then
627 return Base & File (File'First .. J);
629 else
630 declare
631 Max_Path : Integer;
632 pragma Import (C, Max_Path, "__gnat_max_path_len");
634 Base2 : Dir_Name_Str (1 .. Max_Path);
635 Last : Natural;
636 begin
637 Get_Current_Dir (Base2, Last);
638 return Base2 (Base2'First .. Last) & File (File'First .. J);
639 end;
640 end if;
641 end if;
642 end loop;
643 return "";
644 end Dir_Name;
646 -------------------
647 -- Find_ALI_File --
648 -------------------
650 function Find_ALI_File (Short_Name : String) return String is
651 use type Ada.Strings.Unbounded.String_Access;
652 Old_Obj_Dir : constant Integer := Directories.Obj_Dir_Index;
654 begin
655 Reset_Obj_Dir;
657 loop
658 declare
659 Obj_Dir : String := Next_Obj_Dir;
660 begin
661 exit when Obj_Dir'Length = 0;
662 if GNAT.IO_Aux.File_Exists (Obj_Dir & Short_Name) then
663 Directories.Obj_Dir_Index := Old_Obj_Dir;
664 return Obj_Dir;
665 end if;
666 end;
667 end loop;
669 -- Finally look in the standard directories
671 Directories.Obj_Dir_Index := Old_Obj_Dir;
672 return "";
673 end Find_ALI_File;
675 ----------------------
676 -- Find_Source_File --
677 ----------------------
679 function Find_Source_File (Short_Name : String) return String is
680 use type Ada.Strings.Unbounded.String_Access;
682 begin
683 Reset_Src_Dir;
684 loop
685 declare
686 Src_Dir : String := Next_Src_Dir;
687 begin
688 exit when Src_Dir'Length = 0;
690 if GNAT.IO_Aux.File_Exists (Src_Dir & Short_Name) then
691 return Src_Dir;
692 end if;
693 end;
694 end loop;
696 -- Finally look in the standard directories
698 return "";
699 end Find_Source_File;
701 ----------------
702 -- First_Body --
703 ----------------
705 function First_Body (Decl : Declaration_Reference) return Reference is
706 begin
707 return Decl.Body_Ref;
708 end First_Body;
710 -----------------------
711 -- First_Declaration --
712 -----------------------
714 function First_Declaration return Declaration_Reference is
715 begin
716 return Entities.Table;
717 end First_Declaration;
719 -----------------
720 -- First_Modif --
721 -----------------
723 function First_Modif (Decl : Declaration_Reference) return Reference is
724 begin
725 return Decl.Modif_Ref;
726 end First_Modif;
728 ---------------------
729 -- First_Reference --
730 ---------------------
732 function First_Reference (Decl : Declaration_Reference) return Reference is
733 begin
734 return Decl.Ref_Ref;
735 end First_Reference;
737 ----------------
738 -- Get_Column --
739 ----------------
741 function Get_Column (Decl : Declaration_Reference) return String is
742 begin
743 return Ada.Strings.Fixed.Trim (Natural'Image (Decl.Decl.Column),
744 Ada.Strings.Left);
745 end Get_Column;
747 function Get_Column (Ref : Reference) return String is
748 begin
749 return Ada.Strings.Fixed.Trim (Natural'Image (Ref.Column),
750 Ada.Strings.Left);
751 end Get_Column;
753 ---------------------
754 -- Get_Declaration --
755 ---------------------
757 function Get_Declaration
758 (File_Ref : File_Reference;
759 Line : Natural;
760 Column : Natural)
761 return Declaration_Reference
763 The_Entities : Declaration_Reference := Entities.Table;
764 begin
765 while The_Entities /= null loop
766 if The_Entities.Decl.Line = Line
767 and then The_Entities.Decl.Column = Column
768 and then The_Entities.Decl.File = File_Ref
769 then
770 return The_Entities;
771 else
772 The_Entities := The_Entities.Next;
773 end if;
774 end loop;
776 return Empty_Declaration;
777 end Get_Declaration;
779 ----------------------
780 -- Get_Emit_Warning --
781 ----------------------
783 function Get_Emit_Warning (File : File_Reference) return Boolean is
784 begin
785 return File.Emit_Warning;
786 end Get_Emit_Warning;
788 --------------
789 -- Get_File --
790 --------------
792 function Get_File
793 (Decl : Declaration_Reference;
794 With_Dir : Boolean := False)
795 return String
797 begin
798 return Get_File (Decl.Decl.File, With_Dir);
799 end Get_File;
801 function Get_File
802 (Ref : Reference;
803 With_Dir : Boolean := False)
804 return String
806 begin
807 return Get_File (Ref.File, With_Dir);
808 end Get_File;
810 function Get_File
811 (File : File_Reference;
812 With_Dir : in Boolean := False;
813 Strip : Natural := 0)
814 return String
816 function Internal_Strip (Full_Name : String) return String;
817 -- Internal function to process the Strip parameter
819 --------------------
820 -- Internal_Strip --
821 --------------------
823 function Internal_Strip (Full_Name : String) return String is
824 Unit_End, Extension_Start : Natural;
825 S : Natural := Strip;
826 begin
827 if Strip = 0 then
828 return Full_Name;
829 end if;
831 -- Isolate the file extension
833 Extension_Start := Full_Name'Last;
834 while Extension_Start >= Full_Name'First
835 and then Full_Name (Extension_Start) /= '.'
836 loop
837 Extension_Start := Extension_Start - 1;
838 end loop;
840 -- Strip the right number of subunit_names
842 Unit_End := Extension_Start - 1;
843 while Unit_End >= Full_Name'First
844 and then S > 0
845 loop
846 if Full_Name (Unit_End) = '-' then
847 S := S - 1;
848 end if;
849 Unit_End := Unit_End - 1;
850 end loop;
852 if Unit_End < Full_Name'First then
853 return "";
854 else
855 return Full_Name (Full_Name'First .. Unit_End)
856 & Full_Name (Extension_Start .. Full_Name'Last);
857 end if;
858 end Internal_Strip;
860 begin
861 -- If we do not want the full path name
863 if not With_Dir then
864 return Internal_Strip (File.File);
865 end if;
867 if File.Dir = null then
869 if Ada.Strings.Fixed.Tail (File.File, 3) = "ali" then
870 File.Dir := new String'(Find_ALI_File (File.File));
871 else
872 File.Dir := new String'(Find_Source_File (File.File));
873 end if;
874 end if;
876 return Internal_Strip (File.Dir.all & File.File);
877 end Get_File;
879 ------------------
880 -- Get_File_Ref --
881 ------------------
883 function Get_File_Ref (Ref : Reference) return File_Reference is
884 begin
885 return Ref.File;
886 end Get_File_Ref;
888 -----------------------
889 -- Get_Gnatchop_File --
890 -----------------------
892 function Get_Gnatchop_File
893 (File : File_Reference; With_Dir : Boolean := False) return String is
894 begin
895 if File.Gnatchop_File.all = "" then
896 return Get_File (File, With_Dir);
897 else
898 return File.Gnatchop_File.all;
899 end if;
900 end Get_Gnatchop_File;
902 -----------------------
903 -- Get_Gnatchop_File --
904 -----------------------
906 function Get_Gnatchop_File
907 (Ref : Reference; With_Dir : Boolean := False) return String is
908 begin
909 return Get_Gnatchop_File (Ref.File, With_Dir);
910 end Get_Gnatchop_File;
912 -----------------------
913 -- Get_Gnatchop_File --
914 -----------------------
916 function Get_Gnatchop_File
917 (Decl : Declaration_Reference; With_Dir : Boolean := False) return String
919 begin
920 return Get_Gnatchop_File (Decl.Decl.File, With_Dir);
921 end Get_Gnatchop_File;
923 --------------
924 -- Get_Line --
925 --------------
927 function Get_Line (Decl : Declaration_Reference) return String is
928 begin
929 return Ada.Strings.Fixed.Trim (Natural'Image (Decl.Decl.Line),
930 Ada.Strings.Left);
931 end Get_Line;
933 function Get_Line (Ref : Reference) return String is
934 begin
935 return Ada.Strings.Fixed.Trim (Natural'Image (Ref.Line),
936 Ada.Strings.Left);
937 end Get_Line;
939 ----------------
940 -- Get_Parent --
941 ----------------
943 function Get_Parent
944 (Decl : Declaration_Reference)
945 return Declaration_Reference is
946 begin
947 return Decl.Par_Symbol;
948 end Get_Parent;
950 ---------------------
951 -- Get_Source_Line --
952 ---------------------
954 function Get_Source_Line (Ref : Reference) return String is
955 begin
956 return To_String (Ref.Source_Line);
957 end Get_Source_Line;
959 function Get_Source_Line (Decl : Declaration_Reference) return String is
960 begin
961 return To_String (Decl.Decl.Source_Line);
962 end Get_Source_Line;
964 ----------------
965 -- Get_Symbol --
966 ----------------
968 function Get_Symbol (Decl : Declaration_Reference) return String is
969 begin
970 return Decl.Symbol;
971 end Get_Symbol;
973 --------------
974 -- Get_Type --
975 --------------
977 function Get_Type (Decl : Declaration_Reference) return Character is
978 begin
979 return Decl.Decl_Type;
980 end Get_Type;
982 -----------------------
983 -- Grep_Source_Files --
984 -----------------------
986 procedure Grep_Source_Files is
987 Decl : Declaration_Reference := First_Declaration;
989 type Simple_Ref;
990 type Simple_Ref_Access is access Simple_Ref;
991 type Simple_Ref is record
992 Ref : Reference;
993 Next : Simple_Ref_Access;
994 end record;
995 List : Simple_Ref_Access := null;
996 -- This structure is used to speed up the parsing of Ada sources:
997 -- Every reference found by parsing the .ali files is inserted in this
998 -- list, sorted by filename and line numbers. This allows avoiding
999 -- parsing a same ada file multiple times
1001 procedure Free is new Unchecked_Deallocation
1002 (Simple_Ref, Simple_Ref_Access);
1003 -- Clear an element of the list
1005 procedure Grep_List;
1006 -- For each reference in the list, parse the file and find the
1007 -- source line
1009 procedure Insert_In_Order (Ref : Reference);
1010 -- Insert a new reference in the list, ordered by line numbers
1012 procedure Insert_List_Ref (First_Ref : Reference);
1013 -- Process a list of references
1015 ---------------
1016 -- Grep_List --
1017 ---------------
1019 procedure Grep_List is
1020 Line : String (1 .. 1024);
1021 Last : Natural;
1022 File : Ada.Text_IO.File_Type;
1023 Line_Number : Natural;
1024 Pos : Natural;
1025 Save_List : Simple_Ref_Access := List;
1026 Current_File : File_Reference;
1028 begin
1029 while List /= null loop
1031 -- Makes sure we can find and read the file
1033 Current_File := List.Ref.File;
1034 Line_Number := 0;
1036 begin
1037 Ada.Text_IO.Open (File,
1038 Ada.Text_IO.In_File,
1039 Get_File (List.Ref, True));
1041 -- Read the file and find every relevant lines
1043 while List /= null
1044 and then List.Ref.File = Current_File
1045 and then not Ada.Text_IO.End_Of_File (File)
1046 loop
1047 Ada.Text_IO.Get_Line (File, Line, Last);
1048 Line_Number := Line_Number + 1;
1050 while List /= null
1051 and then Line_Number = List.Ref.Line
1052 loop
1054 -- Skip the leading blanks on the line
1056 Pos := 1;
1057 while Line (Pos) = ' '
1058 or else Line (Pos) = ASCII.HT
1059 loop
1060 Pos := Pos + 1;
1061 end loop;
1063 List.Ref.Source_Line :=
1064 To_Unbounded_String (Line (Pos .. Last));
1066 -- Find the next element in the list
1068 List := List.Next;
1069 end loop;
1071 end loop;
1073 Ada.Text_IO.Close (File);
1075 -- If the Current_File was not found, just skip it
1077 exception
1078 when Ada.IO_Exceptions.Name_Error =>
1079 null;
1080 end;
1082 -- If the line or the file were not found
1084 while List /= null
1085 and then List.Ref.File = Current_File
1086 loop
1087 List := List.Next;
1088 end loop;
1090 end loop;
1092 -- Clear the list
1094 while Save_List /= null loop
1095 List := Save_List;
1096 Save_List := Save_List.Next;
1097 Free (List);
1098 end loop;
1099 end Grep_List;
1101 ---------------------
1102 -- Insert_In_Order --
1103 ---------------------
1105 procedure Insert_In_Order (Ref : Reference) is
1106 Iter : Simple_Ref_Access := List;
1107 Prev : Simple_Ref_Access := null;
1109 begin
1110 while Iter /= null loop
1112 -- If we have found the file, sort by lines
1114 if Iter.Ref.File = Ref.File then
1116 while Iter /= null
1117 and then Iter.Ref.File = Ref.File
1118 loop
1119 if Iter.Ref.Line > Ref.Line then
1121 if Iter = List then
1122 List := new Simple_Ref'(Ref, List);
1123 else
1124 Prev.Next := new Simple_Ref'(Ref, Iter);
1125 end if;
1126 return;
1127 end if;
1129 Prev := Iter;
1130 Iter := Iter.Next;
1131 end loop;
1133 if Iter = List then
1134 List := new Simple_Ref'(Ref, List);
1135 else
1136 Prev.Next := new Simple_Ref'(Ref, Iter);
1137 end if;
1139 return;
1140 end if;
1142 Prev := Iter;
1143 Iter := Iter.Next;
1144 end loop;
1146 -- The file was not already in the list, insert it
1148 List := new Simple_Ref'(Ref, List);
1149 end Insert_In_Order;
1151 ---------------------
1152 -- Insert_List_Ref --
1153 ---------------------
1155 procedure Insert_List_Ref (First_Ref : Reference) is
1156 Ref : Reference := First_Ref;
1158 begin
1159 while Ref /= Empty_Reference loop
1160 Insert_In_Order (Ref);
1161 Ref := Next (Ref);
1162 end loop;
1163 end Insert_List_Ref;
1165 -- Start of processing for Grep_Source_Files
1167 begin
1168 while Decl /= Empty_Declaration loop
1169 Insert_In_Order (Decl.Decl'Access);
1170 Insert_List_Ref (First_Body (Decl));
1171 Insert_List_Ref (First_Reference (Decl));
1172 Insert_List_Ref (First_Modif (Decl));
1173 Decl := Next (Decl);
1174 end loop;
1176 Grep_List;
1177 end Grep_Source_Files;
1179 -----------------------
1180 -- Longest_File_Name --
1181 -----------------------
1183 function Longest_File_Name return Natural is
1184 begin
1185 return Files.Longest_Name;
1186 end Longest_File_Name;
1188 -----------
1189 -- Match --
1190 -----------
1192 function Match
1193 (File : File_Reference;
1194 Line : Natural;
1195 Column : Natural)
1196 return Boolean
1198 Ref : Ref_In_File_Ptr := File.Lines;
1200 begin
1201 while Ref /= null loop
1202 if (Ref.Line = 0 or else Ref.Line = Line)
1203 and then (Ref.Column = 0 or else Ref.Column = Column)
1204 then
1205 return True;
1206 end if;
1208 Ref := Ref.Next;
1209 end loop;
1211 return False;
1212 end Match;
1214 -----------
1215 -- Match --
1216 -----------
1218 function Match (Decl : Declaration_Reference) return Boolean is
1219 begin
1220 return Decl.Match;
1221 end Match;
1223 ----------
1224 -- Next --
1225 ----------
1227 function Next (Decl : Declaration_Reference) return Declaration_Reference is
1228 begin
1229 return Decl.Next;
1230 end Next;
1232 ----------
1233 -- Next --
1234 ----------
1236 function Next (Ref : Reference) return Reference is
1237 begin
1238 return Ref.Next;
1239 end Next;
1241 ------------------
1242 -- Next_Obj_Dir --
1243 ------------------
1245 function Next_Obj_Dir return String is
1246 First : Integer := Directories.Obj_Dir_Index;
1247 Last : Integer := Directories.Obj_Dir_Index;
1249 begin
1250 if Last > Directories.Obj_Dir_Length then
1251 return String'(1 .. 0 => ' ');
1252 end if;
1254 while Directories.Obj_Dir (Last) /= ' ' loop
1255 Last := Last + 1;
1256 end loop;
1258 Directories.Obj_Dir_Index := Last + 1;
1259 Directories.Last_Obj_Dir_Start := First;
1260 return Directories.Obj_Dir (First .. Last - 1);
1261 end Next_Obj_Dir;
1263 ------------------
1264 -- Next_Src_Dir --
1265 ------------------
1267 function Next_Src_Dir return String is
1268 First : Integer := Directories.Src_Dir_Index;
1269 Last : Integer := Directories.Src_Dir_Index;
1271 begin
1272 if Last > Directories.Src_Dir_Length then
1273 return String'(1 .. 0 => ' ');
1274 end if;
1276 while Directories.Src_Dir (Last) /= ' ' loop
1277 Last := Last + 1;
1278 end loop;
1280 Directories.Src_Dir_Index := Last + 1;
1281 return Directories.Src_Dir (First .. Last - 1);
1282 end Next_Src_Dir;
1284 -------------------------
1285 -- Next_Unvisited_File --
1286 -------------------------
1288 function Next_Unvisited_File return File_Reference is
1289 The_Files : File_Reference := Files.Table;
1291 begin
1292 while The_Files /= null loop
1293 if not The_Files.Visited then
1294 The_Files.Visited := True;
1295 return The_Files;
1296 end if;
1298 The_Files := The_Files.Next;
1299 end loop;
1301 return Empty_File;
1302 end Next_Unvisited_File;
1304 ------------------
1305 -- Parse_Gnatls --
1306 ------------------
1308 procedure Parse_Gnatls
1309 (Gnatls_Src_Cache : out Ada.Strings.Unbounded.Unbounded_String;
1310 Gnatls_Obj_Cache : out Ada.Strings.Unbounded.Unbounded_String)
1312 begin
1313 Osint.Add_Default_Search_Dirs;
1315 for J in 1 .. Osint.Nb_Dir_In_Src_Search_Path loop
1316 if Osint.Dir_In_Src_Search_Path (J)'Length = 0 then
1317 Ada.Strings.Unbounded.Append (Gnatls_Src_Cache, "./" & ' ');
1318 else
1319 Ada.Strings.Unbounded.Append
1320 (Gnatls_Src_Cache, Osint.Dir_In_Src_Search_Path (J).all & ' ');
1321 end if;
1322 end loop;
1324 for J in 1 .. Osint.Nb_Dir_In_Obj_Search_Path loop
1325 if Osint.Dir_In_Obj_Search_Path (J)'Length = 0 then
1326 Ada.Strings.Unbounded.Append (Gnatls_Obj_Cache, "./" & ' ');
1327 else
1328 Ada.Strings.Unbounded.Append
1329 (Gnatls_Obj_Cache, Osint.Dir_In_Obj_Search_Path (J).all & ' ');
1330 end if;
1331 end loop;
1332 end Parse_Gnatls;
1334 -------------------
1335 -- Reset_Obj_Dir --
1336 -------------------
1338 procedure Reset_Obj_Dir is
1339 begin
1340 Directories.Obj_Dir_Index := 1;
1341 end Reset_Obj_Dir;
1343 -------------------
1344 -- Reset_Src_Dir --
1345 -------------------
1347 procedure Reset_Src_Dir is
1348 begin
1349 Directories.Src_Dir_Index := 1;
1350 end Reset_Src_Dir;
1352 -----------------------
1353 -- Set_Default_Match --
1354 -----------------------
1356 procedure Set_Default_Match (Value : Boolean) is
1357 begin
1358 Default_Match := Value;
1359 end Set_Default_Match;
1361 -------------------
1362 -- Set_Directory --
1363 -------------------
1365 procedure Set_Directory
1366 (File : in File_Reference;
1367 Dir : in String)
1369 begin
1370 File.Dir := new String'(Dir);
1371 end Set_Directory;
1373 -------------------
1374 -- Set_Unvisited --
1375 -------------------
1377 procedure Set_Unvisited (File_Ref : in File_Reference) is
1378 The_Files : File_Reference := Files.Table;
1380 begin
1381 while The_Files /= null loop
1382 if The_Files = File_Ref then
1383 The_Files.Visited := False;
1384 return;
1385 end if;
1387 The_Files := The_Files.Next;
1388 end loop;
1389 end Set_Unvisited;
1391 end Xr_Tabls;