OSDN Git Service

2003-12-11 Ed Falis <falis@gnat.com>
[pf3gnuchains/gcc-fork.git] / gcc / ada / xr_tabls.adb
1 ------------------------------------------------------------------------------
2 --                                                                          --
3 --                         GNAT COMPILER COMPONENTS                         --
4 --                                                                          --
5 --                             X R  _ T A B L S                             --
6 --                                                                          --
7 --                                 B o d y                                  --
8 --                                                                          --
9 --          Copyright (C) 1998-2003 Free Software Foundation, Inc.          --
10 --                                                                          --
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,  59 Temple Place - Suite 330,  Boston, --
20 -- MA 02111-1307, USA.                                                      --
21 --                                                                          --
22 -- GNAT was originally developed  by the GNAT team at  New York University. --
23 -- Extensive contributions were provided by Ada Core Technologies Inc.      --
24 --                                                                          --
25 ------------------------------------------------------------------------------
26
27 with Types;    use Types;
28 with Osint;
29 with Hostparm;
30
31 with Ada.Unchecked_Conversion;
32 with Ada.Unchecked_Deallocation;
33 with Ada.Strings.Fixed;
34 with Ada.Strings;
35 with Ada.Text_IO;
36 with Ada.Characters.Handling;   use Ada.Characters.Handling;
37 with Ada.Strings.Unbounded;     use Ada.Strings.Unbounded;
38
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;
43
44 package body Xr_Tabls is
45
46    type HTable_Headers is range 1 .. 10000;
47
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.
55
56    package File_HTable is new GNAT.HTable.Static_HTable
57      (Header_Num => HTable_Headers,
58       Element    => File_Record,
59       Elmt_Ptr   => File_Reference,
60       Null_Ptr   => null,
61       Set_Next   => Set_Next,
62       Next       => Next,
63       Key        => Cst_String_Access,
64       Get_Key    => Get_Key,
65       Hash       => Hash,
66       Equal      => Equal);
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
71
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;
77    end record;
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.
81
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
87
88    package Entities_HTable is new GNAT.HTable.Static_HTable
89      (Header_Num => HTable_Headers,
90       Element    => Declaration_Record,
91       Elmt_Ptr   => Declaration_Reference,
92       Null_Ptr   => null,
93       Set_Next   => Set_Next,
94       Next       => Next,
95       Key        => Cst_String_Access,
96       Get_Key    => Get_Key,
97       Hash       => Hash,
98       Equal      => Equal);
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.
105
106    Entities_Count : Natural := 0;
107    --  Number of entities in Entities_HTable. This is used in the end
108    --  when sorting the table.
109
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 ???
115
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).
120
121    function Parse_Gnatls_Obj return String;
122    --  Return the standard object directories (taking into account the
123    --  ADA_OBJECTS_PATH environment variable).
124
125    function Key_From_Ref
126      (File_Ref  : File_Reference;
127       Line      : Natural;
128       Column    : Natural)
129       return      String;
130    --  Return a key for the symbol declared at File_Ref, Line,
131    --  Column. This key should be used for lookup in Entity_HTable
132
133    function Is_Less_Than (Decl1, Decl2 : Declaration_Reference) return Boolean;
134    --  Compare two declarations. The comparison is case-insensitive.
135
136    function Is_Less_Than (Ref1, Ref2 : Reference) return Boolean;
137    --  Compare two references
138
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
149    --  stored.
150    --  Constraint_Error will be raised if Arr is not big enough.
151
152    procedure Sort (Arr : in out Reference_Array);
153    --  Sort an array of references.
154    --  Arr'First must be 1.
155
156    --------------
157    -- Set_Next --
158    --------------
159
160    procedure Set_Next (E : File_Reference; Next : File_Reference) is
161    begin
162       E.Next := Next;
163    end Set_Next;
164
165    procedure Set_Next
166      (E : Declaration_Reference; Next : Declaration_Reference) is
167    begin
168       E.Next := Next;
169    end Set_Next;
170
171    -------------
172    -- Get_Key --
173    -------------
174
175    function Get_Key (E : File_Reference) return Cst_String_Access is
176    begin
177       return E.File;
178    end Get_Key;
179
180    function Get_Key (E : Declaration_Reference) return Cst_String_Access is
181    begin
182       return E.Key;
183    end Get_Key;
184
185    ----------
186    -- Hash --
187    ----------
188
189    function Hash (F : Cst_String_Access) return HTable_Headers is
190       function H is new GNAT.HTable.Hash (HTable_Headers);
191
192    begin
193       return H (F.all);
194    end Hash;
195
196    -----------
197    -- Equal --
198    -----------
199
200    function Equal (F1, F2 : Cst_String_Access) return Boolean is
201    begin
202       return F1.all = F2.all;
203    end Equal;
204
205    ------------------
206    -- Key_From_Ref --
207    ------------------
208
209    function Key_From_Ref
210      (File_Ref : File_Reference;
211       Line     : Natural;
212       Column   : Natural)
213       return     String
214    is
215    begin
216       return File_Ref.File.all & Natural'Image (Line) & Natural'Image (Column);
217    end Key_From_Ref;
218
219    ---------------------
220    -- Add_Declaration --
221    ---------------------
222
223    function Add_Declaration
224      (File_Ref     : File_Reference;
225       Symbol       : String;
226       Line         : Natural;
227       Column       : Natural;
228       Decl_Type    : Character;
229       Remove_Only  : Boolean := False;
230       Symbol_Match : Boolean := True)
231       return         Declaration_Reference
232    is
233       procedure Unchecked_Free is new Ada.Unchecked_Deallocation
234         (Declaration_Record, Declaration_Reference);
235
236       Key : aliased constant String := Key_From_Ref (File_Ref, Line, Column);
237
238       New_Decl : Declaration_Reference :=
239                    Entities_HTable.Get (Key'Unchecked_Access);
240
241       Is_Parameter : Boolean := False;
242
243    begin
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.
247
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;
252          Free (New_Decl.Key);
253          Unchecked_Free (New_Decl);
254          New_Decl := null;
255       end if;
256
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
259       --  pointing to it.
260
261       if New_Decl = null
262         and then not Remove_Only
263       then
264          New_Decl :=
265            new Declaration_Record'
266              (Symbol_Length => Symbol'Length,
267               Symbol        => Symbol,
268               Key           => new String'(Key),
269               Decl          => new Reference_Record'
270                                      (File          => File_Ref,
271                                       Line          => Line,
272                                       Column        => Column,
273                                       Source_Line   => null,
274                                       Next          => null),
275               Is_Parameter  => Is_Parameter,
276               Decl_Type     => Decl_Type,
277               Body_Ref      => null,
278               Ref_Ref       => null,
279               Modif_Ref     => null,
280               Match         => Symbol_Match
281                                  and then
282                                    (Default_Match
283                                      or else Match (File_Ref, Line, Column)),
284               Par_Symbol    => null,
285               Next          => null);
286
287          Entities_HTable.Set (New_Decl);
288          Entities_Count := Entities_Count + 1;
289
290          if New_Decl.Match then
291             Longest_File_Name_In_Table :=
292               Natural'Max (File_Ref.File'Length, Longest_File_Name_In_Table);
293          end if;
294
295       elsif New_Decl /= null
296         and then not New_Decl.Match
297       then
298          New_Decl.Match := Default_Match
299            or else Match (File_Ref, Line, Column);
300       end if;
301
302       return New_Decl;
303    end Add_Declaration;
304
305    ----------------------
306    -- Add_To_Xref_File --
307    ----------------------
308
309    function Add_To_Xref_File
310      (File_Name       : String;
311       Visited         : Boolean := True;
312       Emit_Warning    : Boolean := False;
313       Gnatchop_File   : String  := "";
314       Gnatchop_Offset : Integer := 0) return File_Reference
315    is
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;
320
321    begin
322       --  Do we have a directory name as well?
323
324       if File_Name /= Base then
325          Dir_Acc := new String'(Dir);
326       end if;
327
328       Ref := File_HTable.Get (Base'Unchecked_Access);
329       if Ref = null then
330          Ref := new File_Record'
331            (File            => new String'(Base),
332             Dir             => Dir_Acc,
333             Lines           => null,
334             Visited         => Visited,
335             Emit_Warning    => Emit_Warning,
336             Gnatchop_File   => new String'(Gnatchop_File),
337             Gnatchop_Offset => Gnatchop_Offset,
338             Next            => null);
339          File_HTable.Set (Ref);
340
341          if not Visited then
342
343             --  Keep a separate list for faster access
344
345             Set_Unvisited (Ref);
346          end if;
347       end if;
348       return Ref;
349    end Add_To_Xref_File;
350
351    --------------
352    -- Add_Line --
353    --------------
354
355    procedure Add_Line
356      (File   : File_Reference;
357       Line   : Natural;
358       Column : Natural)
359    is
360    begin
361       File.Lines := new Ref_In_File'(Line   => Line,
362                                      Column => Column,
363                                      Next   => File.Lines);
364    end Add_Line;
365
366    ----------------
367    -- Add_Parent --
368    ----------------
369
370    procedure Add_Parent
371      (Declaration : in out Declaration_Reference;
372       Symbol      : String;
373       Line        : Natural;
374       Column      : Natural;
375       File_Ref    : File_Reference)
376    is
377    begin
378       Declaration.Par_Symbol :=
379         Add_Declaration
380           (File_Ref, Symbol, Line, Column,
381            Decl_Type    => ' ',
382            Symbol_Match => False);
383    end Add_Parent;
384
385    -------------------
386    -- Add_Reference --
387    -------------------
388
389    procedure Add_Reference
390      (Declaration   : Declaration_Reference;
391       File_Ref      : File_Reference;
392       Line          : Natural;
393       Column        : Natural;
394       Ref_Type      : Character;
395       Labels_As_Ref : Boolean)
396    is
397       New_Ref : Reference;
398
399    begin
400       case Ref_Type is
401          when 'b' | 'c' | 'm' | 'r' | 'i' | ' ' | 'x' =>
402             null;
403
404          when 'l' | 'w' =>
405             if not Labels_As_Ref then
406                return;
407             end if;
408
409          when '=' | '<' | '>' | '^' =>
410
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.
414
415             declare
416                Key      : constant String :=
417                             Key_From_Ref (File_Ref, Line, Column);
418                New_Decl : Declaration_Reference;
419
420             begin
421                New_Decl := new Declaration_Record'
422                  (Symbol_Length => 0,
423                   Symbol        => "",
424                   Key           => new String'(Key),
425                   Decl          => null,
426                   Is_Parameter  => True,
427                   Decl_Type     => ' ',
428                   Body_Ref      => null,
429                   Ref_Ref       => null,
430                   Modif_Ref     => null,
431                   Match         => False,
432                   Par_Symbol    => null,
433                   Next          => null);
434                Entities_HTable.Set (New_Decl);
435                Entities_Count := Entities_Count + 1;
436             end;
437
438          when 'e' | 'z' | 't' | 'p' | 'P' | 'k' | 'd' =>
439             return;
440
441          when others    =>
442             Ada.Text_IO.Put_Line ("Unknown reference type: " & Ref_Type);
443             return;
444       end case;
445
446       New_Ref := new Reference_Record'
447         (File        => File_Ref,
448          Line        => Line,
449          Column      => Column,
450          Source_Line => null,
451          Next        => null);
452
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
457       --  if it exists.
458
459       case Ref_Type is
460          when 'b' | 'c' =>
461             New_Ref.Next          := Declaration.Body_Ref;
462             Declaration.Body_Ref  := New_Ref;
463
464          when 'r' | 'i' | 'l' | ' ' | 'x' | 'w' =>
465             New_Ref.Next          := Declaration.Ref_Ref;
466             Declaration.Ref_Ref   := New_Ref;
467
468          when 'm' =>
469             New_Ref.Next          := Declaration.Modif_Ref;
470             Declaration.Modif_Ref := New_Ref;
471
472          when others =>
473             null;
474       end case;
475
476       if not Declaration.Match then
477          Declaration.Match := Match (File_Ref, Line, Column);
478       end if;
479
480       if Declaration.Match then
481          Longest_File_Name_In_Table :=
482            Natural'Max (File_Ref.File'Length, Longest_File_Name_In_Table);
483       end if;
484    end Add_Reference;
485
486    -------------------
487    -- ALI_File_Name --
488    -------------------
489
490    function ALI_File_Name (Ada_File_Name : String) return String is
491
492       --  ??? Should ideally be based on the naming scheme defined in
493       --  project files.
494
495       Index : constant Natural :=
496                 Ada.Strings.Fixed.Index
497                   (Ada_File_Name, ".", Going => Ada.Strings.Backward);
498
499    begin
500       if Index /= 0 then
501          return Ada_File_Name (Ada_File_Name'First .. Index) & "ali";
502       else
503          return Ada_File_Name & ".ali";
504       end if;
505    end ALI_File_Name;
506
507    ------------------
508    -- Is_Less_Than --
509    ------------------
510
511    function Is_Less_Than (Ref1, Ref2 : Reference) return Boolean is
512    begin
513       if Ref1 = null then
514          return False;
515       elsif Ref2 = null then
516          return True;
517       end if;
518
519       if Ref1.File.File.all < Ref2.File.File.all then
520          return True;
521
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));
526       end if;
527
528       return False;
529    end Is_Less_Than;
530
531    ------------------
532    -- Is_Less_Than --
533    ------------------
534
535    function Is_Less_Than (Decl1, Decl2 : Declaration_Reference) return Boolean
536    is
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
539       --  display later on.
540
541       S1 : constant String := To_Lower (Decl1.Symbol);
542       S2 : constant String := To_Lower (Decl2.Symbol);
543
544    begin
545       if S1 < S2 then
546          return True;
547       elsif S1 > S2 then
548          return False;
549       end if;
550
551       return Decl1.Key.all < Decl2.Key.all;
552    end Is_Less_Than;
553
554    -------------------------
555    -- Create_Project_File --
556    -------------------------
557
558    procedure Create_Project_File (Name : String) is
559       use Ada.Strings.Unbounded;
560
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'("");
564
565       F           : File_Descriptor;
566       Len         : Positive;
567       File_Name   : aliased String := Name & ASCII.NUL;
568
569    begin
570       --  Read the size of the file
571
572       F := Open_Read (File_Name'Address, Text);
573
574       --  Project file not found
575
576       if F /= Invalid_FD then
577          Len := Positive (File_Length (F));
578
579          declare
580             Buffer : String (1 .. Len);
581             Index  : Positive := Buffer'First;
582             Last   : Positive;
583
584          begin
585             Len := Read (F, Buffer'Address, Len);
586             Close (F);
587
588             --  First, look for Build_Dir, since all the source and object
589             --  path are relative to it.
590
591             while Index <= Buffer'Last loop
592
593                --  Find the end of line
594
595                Last := Index;
596                while Last <= Buffer'Last
597                  and then Buffer (Last) /= ASCII.LF
598                  and then Buffer (Last) /= ASCII.CR
599                loop
600                   Last := Last + 1;
601                end loop;
602
603                if Index <= Buffer'Last - 9
604                  and then Buffer (Index .. Index + 9) = "build_dir="
605                then
606                   Index := Index + 10;
607                   while Index <= Last
608                     and then (Buffer (Index) = ' '
609                               or else Buffer (Index) = ASCII.HT)
610                   loop
611                      Index := Index + 1;
612                   end loop;
613
614                   Free (Build_Dir);
615                   Build_Dir := new String'(Buffer (Index .. Last - 1));
616                end if;
617
618                Index := Last + 1;
619
620                --  In case we had a ASCII.CR/ASCII.LF end of line, skip the
621                --  remaining symbol
622
623                if Index <= Buffer'Last
624                  and then Buffer (Index) = ASCII.LF
625                then
626                   Index := Index + 1;
627                end if;
628             end loop;
629
630             --  Now parse the source and object paths
631
632             Index := Buffer'First;
633             while Index <= Buffer'Last loop
634
635                --  Find the end of line
636
637                Last := Index;
638                while Last <= Buffer'Last
639                  and then Buffer (Last) /= ASCII.LF
640                  and then Buffer (Last) /= ASCII.CR
641                loop
642                   Last := Last + 1;
643                end loop;
644
645                if Index <= Buffer'Last - 7
646                  and then Buffer (Index .. Index + 7) = "src_dir="
647                then
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);
652
653                elsif Index <= Buffer'Last - 7
654                  and then Buffer (Index .. Index + 7) = "obj_dir="
655                then
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);
660                end if;
661
662                --  In case we had a ASCII.CR/ASCII.LF end of line, skip the
663                --  remaining symbol
664                Index := Last + 1;
665
666                if Index <= Buffer'Last
667                  and then Buffer (Index) = ASCII.LF
668                then
669                   Index := Index + 1;
670                end if;
671             end loop;
672          end;
673       end if;
674
675       Osint.Add_Default_Search_Dirs;
676
677       declare
678          Src : constant String := Parse_Gnatls_Src;
679          Obj : constant String := Parse_Gnatls_Obj;
680
681       begin
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,
687             Src_Dir_Index      => 1,
688             Obj_Dir_Index      => 1,
689             Last_Obj_Dir_Start => 0);
690       end;
691
692       Free (Build_Dir);
693    end Create_Project_File;
694
695    ---------------------
696    -- Current_Obj_Dir --
697    ---------------------
698
699    function Current_Obj_Dir return String is
700    begin
701       return Directories.Obj_Dir
702         (Directories.Last_Obj_Dir_Start .. Directories.Obj_Dir_Index - 2);
703    end Current_Obj_Dir;
704
705    ----------------
706    -- Get_Column --
707    ----------------
708
709    function Get_Column (Decl : Declaration_Reference) return String is
710    begin
711       return Ada.Strings.Fixed.Trim (Natural'Image (Decl.Decl.Column),
712                                      Ada.Strings.Left);
713    end Get_Column;
714
715    function Get_Column (Ref : Reference) return String is
716    begin
717       return Ada.Strings.Fixed.Trim (Natural'Image (Ref.Column),
718                                      Ada.Strings.Left);
719    end Get_Column;
720
721    ---------------------
722    -- Get_Declaration --
723    ---------------------
724
725    function Get_Declaration
726      (File_Ref : File_Reference;
727       Line     : Natural;
728       Column   : Natural)
729       return     Declaration_Reference
730    is
731       Key : aliased constant String := Key_From_Ref (File_Ref, Line, Column);
732
733    begin
734       return Entities_HTable.Get (Key'Unchecked_Access);
735    end Get_Declaration;
736
737    ----------------------
738    -- Get_Emit_Warning --
739    ----------------------
740
741    function Get_Emit_Warning (File : File_Reference) return Boolean is
742    begin
743       return File.Emit_Warning;
744    end Get_Emit_Warning;
745
746    --------------
747    -- Get_File --
748    --------------
749
750    function Get_File
751      (Decl     : Declaration_Reference;
752       With_Dir : Boolean := False)
753       return     String
754    is
755    begin
756       return Get_File (Decl.Decl.File, With_Dir);
757    end Get_File;
758
759    function Get_File
760      (Ref      : Reference;
761       With_Dir : Boolean := False)
762       return     String
763    is
764    begin
765       return Get_File (Ref.File, With_Dir);
766    end Get_File;
767
768    function Get_File
769      (File     : File_Reference;
770       With_Dir : in Boolean := False;
771       Strip    : Natural    := 0)
772       return     String
773    is
774       Tmp : GNAT.OS_Lib.String_Access;
775
776       function Internal_Strip (Full_Name : String) return String;
777       --  Internal function to process the Strip parameter
778
779       --------------------
780       -- Internal_Strip --
781       --------------------
782
783       function Internal_Strip (Full_Name : String) return String is
784          Unit_End        : Natural;
785          Extension_Start : Natural;
786          S               : Natural;
787
788       begin
789          if Strip = 0 then
790             return Full_Name;
791          end if;
792
793          --  Isolate the file extension
794
795          Extension_Start := Full_Name'Last;
796          while Extension_Start >= Full_Name'First
797            and then Full_Name (Extension_Start) /= '.'
798          loop
799             Extension_Start := Extension_Start - 1;
800          end loop;
801
802          --  Strip the right number of subunit_names
803
804          S := Strip;
805          Unit_End := Extension_Start - 1;
806          while Unit_End >= Full_Name'First
807            and then S > 0
808          loop
809             if Full_Name (Unit_End) = '-' then
810                S := S - 1;
811             end if;
812
813             Unit_End := Unit_End - 1;
814          end loop;
815
816          if Unit_End < Full_Name'First then
817             return "";
818          else
819             return Full_Name (Full_Name'First .. Unit_End)
820               & Full_Name (Extension_Start .. Full_Name'Last);
821          end if;
822       end Internal_Strip;
823
824    --  Start of processing for Get_File;
825
826    begin
827       --  If we do not want the full path name
828
829       if not With_Dir then
830          return Internal_Strip (File.File.all);
831       end if;
832
833       if File.Dir = null then
834          if Ada.Strings.Fixed.Tail (File.File.all, 3) = "ali" then
835             Tmp := Locate_Regular_File
836               (Internal_Strip (File.File.all), Directories.Obj_Dir);
837          else
838             Tmp := Locate_Regular_File
839               (File.File.all, Directories.Src_Dir);
840          end if;
841
842          if Tmp = null then
843             File.Dir := new String'("");
844          else
845             File.Dir := new String'(Dir_Name (Tmp.all));
846             Free (Tmp);
847          end if;
848       end if;
849
850       return Internal_Strip (File.Dir.all & File.File.all);
851    end Get_File;
852
853    ------------------
854    -- Get_File_Ref --
855    ------------------
856
857    function Get_File_Ref (Ref : Reference) return File_Reference is
858    begin
859       return Ref.File;
860    end Get_File_Ref;
861
862    -----------------------
863    -- Get_Gnatchop_File --
864    -----------------------
865
866    function Get_Gnatchop_File
867      (File     : File_Reference;
868       With_Dir : Boolean := False)
869       return     String
870    is
871    begin
872       if File.Gnatchop_File.all = "" then
873          return Get_File (File, With_Dir);
874       else
875          return File.Gnatchop_File.all;
876       end if;
877    end Get_Gnatchop_File;
878
879    function Get_Gnatchop_File
880      (Ref      : Reference;
881       With_Dir : Boolean := False)
882       return     String
883    is
884    begin
885       return Get_Gnatchop_File (Ref.File, With_Dir);
886    end Get_Gnatchop_File;
887
888    function Get_Gnatchop_File
889      (Decl     : Declaration_Reference;
890       With_Dir : Boolean := False)
891       return     String
892    is
893    begin
894       return Get_Gnatchop_File (Decl.Decl.File, With_Dir);
895    end Get_Gnatchop_File;
896
897    --------------
898    -- Get_Line --
899    --------------
900
901    function Get_Line (Decl : Declaration_Reference) return String is
902    begin
903       return Ada.Strings.Fixed.Trim (Natural'Image (Decl.Decl.Line),
904                                      Ada.Strings.Left);
905    end Get_Line;
906
907    function Get_Line (Ref : Reference) return String is
908    begin
909       return Ada.Strings.Fixed.Trim (Natural'Image (Ref.Line),
910                                      Ada.Strings.Left);
911    end Get_Line;
912
913    ----------------
914    -- Get_Parent --
915    ----------------
916
917    function Get_Parent
918      (Decl : Declaration_Reference)
919       return Declaration_Reference
920    is
921    begin
922       return Decl.Par_Symbol;
923    end Get_Parent;
924
925    ---------------------
926    -- Get_Source_Line --
927    ---------------------
928
929    function Get_Source_Line (Ref : Reference) return String is
930    begin
931       if Ref.Source_Line /= null then
932          return Ref.Source_Line.all;
933       else
934          return "";
935       end if;
936    end Get_Source_Line;
937
938    function Get_Source_Line (Decl : Declaration_Reference) return String is
939    begin
940       if Decl.Decl.Source_Line /= null then
941          return Decl.Decl.Source_Line.all;
942       else
943          return "";
944       end if;
945    end Get_Source_Line;
946
947    ----------------
948    -- Get_Symbol --
949    ----------------
950
951    function Get_Symbol (Decl : Declaration_Reference) return String is
952    begin
953       return Decl.Symbol;
954    end Get_Symbol;
955
956    --------------
957    -- Get_Type --
958    --------------
959
960    function Get_Type (Decl : Declaration_Reference) return Character is
961    begin
962       return Decl.Decl_Type;
963    end Get_Type;
964
965    ----------
966    -- Sort --
967    ----------
968
969    procedure Sort (Arr : in out Reference_Array) is
970       Tmp : Reference;
971
972       function Lt (Op1, Op2 : Natural) return Boolean;
973       procedure Move (From, To : Natural);
974       --  See GNAT.Heap_Sort_G
975
976       --------
977       -- Lt --
978       --------
979
980       function Lt (Op1, Op2 : Natural) return Boolean is
981       begin
982          if Op1 = 0 then
983             return Is_Less_Than (Tmp, Arr (Op2));
984          elsif Op2 = 0 then
985             return Is_Less_Than (Arr (Op1), Tmp);
986          else
987             return Is_Less_Than (Arr (Op1), Arr (Op2));
988          end if;
989       end Lt;
990
991       ----------
992       -- Move --
993       ----------
994
995       procedure Move (From, To : Natural) is
996       begin
997          if To = 0 then
998             Tmp := Arr (From);
999          elsif From = 0 then
1000             Arr (To) := Tmp;
1001          else
1002             Arr (To) := Arr (From);
1003          end if;
1004       end Move;
1005
1006       package Ref_Sort is new GNAT.Heap_Sort_G (Move, Lt);
1007
1008    --  Start of processing for Sort
1009
1010    begin
1011       Ref_Sort.Sort (Arr'Last);
1012    end Sort;
1013
1014    -----------------------
1015    -- Grep_Source_Files --
1016    -----------------------
1017
1018    procedure Grep_Source_Files is
1019       Length       : Natural := 0;
1020       Decl         : Declaration_Reference := Entities_HTable.Get_First;
1021       Arr          : Reference_Array_Access;
1022       Index        : Natural;
1023       End_Index    : Natural;
1024       Current_File : File_Reference;
1025       Current_Line : Cst_String_Access;
1026       Buffer       : GNAT.OS_Lib.String_Access;
1027       Ref          : Reference;
1028       Line         : Natural;
1029
1030    begin
1031       --  Create a temporary array, where all references will be
1032       --  sorted by files. This way, we only have to read the source
1033       --  files once.
1034
1035       while Decl /= null loop
1036
1037          --  Add 1 for the declaration itself
1038
1039          Length := Length + References_Count (Decl, True, True, True) + 1;
1040          Decl := Entities_HTable.Get_Next;
1041       end loop;
1042
1043       Arr := new Reference_Array (1 .. Length);
1044       Index := Arr'First;
1045
1046       Decl := Entities_HTable.Get_First;
1047       while Decl /= null loop
1048          Store_References (Decl, True, True, True, True, Arr.all, Index);
1049          Decl := Entities_HTable.Get_Next;
1050       end loop;
1051
1052       Sort (Arr.all);
1053
1054       --  Now traverse the whole array and find the appropriate source
1055       --  lines.
1056
1057       for R in Arr'Range loop
1058          Ref := Arr (R);
1059
1060          if Ref.File /= Current_File then
1061             Free (Buffer);
1062             begin
1063                Read_File (Get_File (Ref.File, With_Dir => True), Buffer);
1064                End_Index := Buffer'First - 1;
1065                Line := 0;
1066             exception
1067                when Ada.Text_IO.Name_Error | Ada.Text_IO.End_Error =>
1068                   Line := Natural'Last;
1069             end;
1070             Current_File := Ref.File;
1071          end if;
1072
1073          if Ref.Line > Line then
1074
1075             --  Do not free Current_Line, it is referenced by the last
1076             --  Ref we processed.
1077
1078             loop
1079                Index := End_Index + 1;
1080
1081                loop
1082                   End_Index := End_Index + 1;
1083                   exit when End_Index > Buffer'Last
1084                     or else Buffer (End_Index) = ASCII.LF;
1085                end loop;
1086
1087                --  Skip spaces at beginning of line
1088
1089                while Index < End_Index and then
1090                  (Buffer (Index) = ' ' or else Buffer (Index) = ASCII.HT)
1091                loop
1092                   Index := Index + 1;
1093                end loop;
1094
1095                Line := Line + 1;
1096                exit when Ref.Line = Line;
1097             end loop;
1098
1099             Current_Line := new String'(Buffer (Index .. End_Index - 1));
1100          end if;
1101
1102          Ref.Source_Line := Current_Line;
1103       end loop;
1104
1105       Free (Buffer);
1106       Free (Arr);
1107    end Grep_Source_Files;
1108
1109    ---------------
1110    -- Read_File --
1111    ---------------
1112
1113    procedure Read_File
1114      (File_Name : String;
1115       Contents  : out GNAT.OS_Lib.String_Access)
1116    is
1117       Name_0 : constant String := File_Name & ASCII.NUL;
1118       FD     : constant File_Descriptor := Open_Read (Name_0'Address, Binary);
1119       Length : Natural;
1120
1121    begin
1122       if FD = Invalid_FD then
1123          raise Ada.Text_IO.Name_Error;
1124       end if;
1125
1126       --  Include room for EOF char
1127
1128       Length := Natural (File_Length (FD));
1129
1130       declare
1131          Buffer    : String (1 .. Length + 1);
1132          This_Read : Integer;
1133          Read_Ptr  : Natural := 1;
1134
1135       begin
1136          loop
1137             This_Read := Read (FD,
1138                                A => Buffer (Read_Ptr)'Address,
1139                                N => Length + 1 - Read_Ptr);
1140             Read_Ptr := Read_Ptr + Integer'Max (This_Read, 0);
1141             exit when This_Read <= 0;
1142          end loop;
1143
1144          Buffer (Read_Ptr) := EOF;
1145          Contents := new String'(Buffer (1 .. Read_Ptr));
1146
1147          --  Things are not simple on VMS due to the plethora of file types
1148          --  and organizations. It seems clear that there shouldn't be more
1149          --  bytes read than are contained in the file though.
1150
1151          if (Hostparm.OpenVMS and then Read_Ptr > Length + 1)
1152            or else (not Hostparm.OpenVMS and then Read_Ptr /= Length + 1)
1153          then
1154             raise Ada.Text_IO.End_Error;
1155          end if;
1156
1157          Close (FD);
1158       end;
1159    end Read_File;
1160
1161    -----------------------
1162    -- Longest_File_Name --
1163    -----------------------
1164
1165    function Longest_File_Name return Natural is
1166    begin
1167       return Longest_File_Name_In_Table;
1168    end Longest_File_Name;
1169
1170    -----------
1171    -- Match --
1172    -----------
1173
1174    function Match
1175      (File   : File_Reference;
1176       Line   : Natural;
1177       Column : Natural)
1178       return   Boolean
1179    is
1180       Ref : Ref_In_File_Ptr := File.Lines;
1181
1182    begin
1183       while Ref /= null loop
1184          if (Ref.Line = 0 or else Ref.Line = Line)
1185            and then (Ref.Column = 0 or else Ref.Column = Column)
1186          then
1187             return True;
1188          end if;
1189
1190          Ref := Ref.Next;
1191       end loop;
1192
1193       return False;
1194    end Match;
1195
1196    -----------
1197    -- Match --
1198    -----------
1199
1200    function Match (Decl : Declaration_Reference) return Boolean is
1201    begin
1202       return Decl.Match;
1203    end Match;
1204
1205    ----------
1206    -- Next --
1207    ----------
1208
1209    function Next (E : File_Reference) return File_Reference is
1210    begin
1211       return E.Next;
1212    end Next;
1213
1214    function Next (E : Declaration_Reference) return Declaration_Reference is
1215    begin
1216       return E.Next;
1217    end Next;
1218
1219    ------------------
1220    -- Next_Obj_Dir --
1221    ------------------
1222
1223    function Next_Obj_Dir return String is
1224       First : constant Integer := Directories.Obj_Dir_Index;
1225       Last  : Integer;
1226
1227    begin
1228       Last := Directories.Obj_Dir_Index;
1229
1230       if Last > Directories.Obj_Dir_Length then
1231          return String'(1 .. 0 => ' ');
1232       end if;
1233
1234       while Directories.Obj_Dir (Last) /= Path_Separator loop
1235          Last := Last + 1;
1236       end loop;
1237
1238       Directories.Obj_Dir_Index := Last + 1;
1239       Directories.Last_Obj_Dir_Start := First;
1240       return Directories.Obj_Dir (First .. Last - 1);
1241    end Next_Obj_Dir;
1242
1243    -------------------------
1244    -- Next_Unvisited_File --
1245    -------------------------
1246
1247    function Next_Unvisited_File return File_Reference is
1248       procedure Unchecked_Free is new Ada.Unchecked_Deallocation
1249         (Unvisited_Files_Record, Unvisited_Files_Access);
1250
1251       Ref : File_Reference;
1252       Tmp : Unvisited_Files_Access;
1253
1254    begin
1255       if Unvisited_Files = null then
1256          return Empty_File;
1257       else
1258          Tmp := Unvisited_Files;
1259          Ref := Unvisited_Files.File;
1260          Unvisited_Files := Unvisited_Files.Next;
1261          Unchecked_Free (Tmp);
1262          return Ref;
1263       end if;
1264    end Next_Unvisited_File;
1265
1266    ----------------------
1267    -- Parse_Gnatls_Src --
1268    ----------------------
1269
1270    function Parse_Gnatls_Src return String is
1271       Length : Natural;
1272
1273    begin
1274       Length := 0;
1275       for J in 1 .. Osint.Nb_Dir_In_Src_Search_Path loop
1276          if Osint.Dir_In_Src_Search_Path (J)'Length = 0 then
1277             Length := Length + 2;
1278          else
1279             Length := Length + Osint.Dir_In_Src_Search_Path (J)'Length + 1;
1280          end if;
1281       end loop;
1282
1283       declare
1284          Result : String (1 .. Length);
1285          L      : Natural;
1286
1287       begin
1288          L := Result'First;
1289          for J in 1 .. Osint.Nb_Dir_In_Src_Search_Path loop
1290             if Osint.Dir_In_Src_Search_Path (J)'Length = 0 then
1291                Result (L .. L + 1) := "." & Path_Separator;
1292                L := L + 2;
1293
1294             else
1295                Result (L .. L + Osint.Dir_In_Src_Search_Path (J)'Length - 1) :=
1296                  Osint.Dir_In_Src_Search_Path (J).all;
1297                L := L + Osint.Dir_In_Src_Search_Path (J)'Length;
1298                Result (L) := Path_Separator;
1299                L := L + 1;
1300             end if;
1301          end loop;
1302
1303          return Result;
1304       end;
1305    end Parse_Gnatls_Src;
1306
1307    ----------------------
1308    -- Parse_Gnatls_Obj --
1309    ----------------------
1310
1311    function Parse_Gnatls_Obj return String is
1312       Length : Natural;
1313
1314    begin
1315       Length := 0;
1316       for J in 1 .. Osint.Nb_Dir_In_Obj_Search_Path loop
1317          if Osint.Dir_In_Obj_Search_Path (J)'Length = 0 then
1318             Length := Length + 2;
1319          else
1320             Length := Length + Osint.Dir_In_Obj_Search_Path (J)'Length + 1;
1321          end if;
1322       end loop;
1323
1324       declare
1325          Result : String (1 .. Length);
1326          L      : Natural;
1327
1328       begin
1329          L := Result'First;
1330          for J in 1 .. Osint.Nb_Dir_In_Obj_Search_Path loop
1331             if Osint.Dir_In_Obj_Search_Path (J)'Length = 0 then
1332                Result (L .. L + 1) := "." & Path_Separator;
1333                L := L + 2;
1334             else
1335                Result (L .. L + Osint.Dir_In_Obj_Search_Path (J)'Length - 1) :=
1336                  Osint.Dir_In_Obj_Search_Path (J).all;
1337                L := L + Osint.Dir_In_Obj_Search_Path (J)'Length;
1338                Result (L) := Path_Separator;
1339                L := L + 1;
1340             end if;
1341          end loop;
1342
1343          return Result;
1344       end;
1345    end Parse_Gnatls_Obj;
1346
1347    -------------------
1348    -- Reset_Obj_Dir --
1349    -------------------
1350
1351    procedure Reset_Obj_Dir is
1352    begin
1353       Directories.Obj_Dir_Index := 1;
1354    end Reset_Obj_Dir;
1355
1356    -----------------------
1357    -- Set_Default_Match --
1358    -----------------------
1359
1360    procedure Set_Default_Match (Value : Boolean) is
1361    begin
1362       Default_Match := Value;
1363    end Set_Default_Match;
1364
1365    ----------
1366    -- Free --
1367    ----------
1368
1369    procedure Free (Str : in out Cst_String_Access) is
1370       function Convert is new Ada.Unchecked_Conversion
1371         (Cst_String_Access, GNAT.OS_Lib.String_Access);
1372
1373       S : GNAT.OS_Lib.String_Access := Convert (Str);
1374
1375    begin
1376       Free (S);
1377       Str := null;
1378    end Free;
1379
1380    ---------------------
1381    -- Reset_Directory --
1382    ---------------------
1383
1384    procedure Reset_Directory (File : File_Reference) is
1385    begin
1386       Free (File.Dir);
1387    end Reset_Directory;
1388
1389    -------------------
1390    -- Set_Unvisited --
1391    -------------------
1392
1393    procedure Set_Unvisited (File_Ref : File_Reference) is
1394       F : constant String := Get_File (File_Ref, With_Dir => False);
1395
1396    begin
1397       File_Ref.Visited := False;
1398
1399       --  ??? Do not add a source file to the list. This is true at
1400       --  least for gnatxref, and probably for gnatfind as wel
1401
1402       if F'Length > 4
1403         and then F (F'Last - 3 .. F'Last) = ".ali"
1404       then
1405          Unvisited_Files := new Unvisited_Files_Record'
1406            (File => File_Ref,
1407             Next => Unvisited_Files);
1408       end if;
1409    end Set_Unvisited;
1410
1411    ----------------------
1412    -- Get_Declarations --
1413    ----------------------
1414
1415    function Get_Declarations
1416      (Sorted : Boolean := True)
1417       return   Declaration_Array_Access
1418    is
1419       Arr   : Declaration_Array_Access :=
1420                 new Declaration_Array (1 .. Entities_Count);
1421       Decl  : Declaration_Reference := Entities_HTable.Get_First;
1422       Index : Natural               := Arr'First;
1423       Tmp   : Declaration_Reference;
1424
1425       procedure Move (From : Natural; To : Natural);
1426       function Lt (Op1, Op2 : Natural) return Boolean;
1427       --  See GNAT.Heap_Sort_G
1428
1429       --------
1430       -- Lt --
1431       --------
1432
1433       function Lt (Op1, Op2 : Natural) return Boolean is
1434       begin
1435          if Op1 = 0 then
1436             return Is_Less_Than (Tmp, Arr (Op2));
1437          elsif Op2 = 0 then
1438             return Is_Less_Than (Arr (Op1), Tmp);
1439          else
1440             return Is_Less_Than (Arr (Op1), Arr (Op2));
1441          end if;
1442       end Lt;
1443
1444       ----------
1445       -- Move --
1446       ----------
1447
1448       procedure Move (From : Natural; To : Natural) is
1449       begin
1450          if To = 0 then
1451             Tmp := Arr (From);
1452          elsif From = 0 then
1453             Arr (To) := Tmp;
1454          else
1455             Arr (To) := Arr (From);
1456          end if;
1457       end Move;
1458
1459       package Decl_Sort is new GNAT.Heap_Sort_G (Move, Lt);
1460
1461    --  Start of processing for Get_Declarations
1462
1463    begin
1464       while Decl /= null loop
1465          Arr (Index) := Decl;
1466          Index := Index + 1;
1467          Decl := Entities_HTable.Get_Next;
1468       end loop;
1469
1470       if Sorted and then Arr'Length /= 0 then
1471          Decl_Sort.Sort (Entities_Count);
1472       end if;
1473
1474       return Arr;
1475    end Get_Declarations;
1476
1477    ----------------------
1478    -- References_Count --
1479    ----------------------
1480
1481    function References_Count
1482      (Decl       : Declaration_Reference;
1483       Get_Reads  : Boolean := False;
1484       Get_Writes : Boolean := False;
1485       Get_Bodies : Boolean := False)
1486       return       Natural
1487    is
1488       function List_Length (E : Reference) return Natural;
1489       --  Return the number of references in E
1490
1491       -----------------
1492       -- List_Length --
1493       -----------------
1494
1495       function List_Length (E : Reference) return Natural is
1496          L  : Natural := 0;
1497          E1 : Reference := E;
1498
1499       begin
1500          while E1 /= null loop
1501             L := L + 1;
1502             E1 := E1.Next;
1503          end loop;
1504
1505          return L;
1506       end List_Length;
1507
1508       Length : Natural := 0;
1509
1510    --  Start of processing for References_Count
1511
1512    begin
1513       if Get_Reads then
1514          Length := List_Length (Decl.Ref_Ref);
1515       end if;
1516
1517       if Get_Writes then
1518          Length := Length + List_Length (Decl.Modif_Ref);
1519       end if;
1520
1521       if Get_Bodies then
1522          Length := Length + List_Length (Decl.Body_Ref);
1523       end if;
1524
1525       return Length;
1526    end References_Count;
1527
1528    ----------------------
1529    -- Store_References --
1530    ----------------------
1531
1532    procedure Store_References
1533      (Decl            : Declaration_Reference;
1534       Get_Writes      : Boolean := False;
1535       Get_Reads       : Boolean := False;
1536       Get_Bodies      : Boolean := False;
1537       Get_Declaration : Boolean := False;
1538       Arr             : in out Reference_Array;
1539       Index           : in out Natural)
1540    is
1541       procedure Add (List : Reference);
1542       --  Add all the references in List to Arr
1543
1544       ---------
1545       -- Add --
1546       ---------
1547
1548       procedure Add (List : Reference) is
1549          E : Reference := List;
1550       begin
1551          while E /= null loop
1552             Arr (Index) := E;
1553             Index := Index + 1;
1554             E := E.Next;
1555          end loop;
1556       end Add;
1557
1558    --  Start of processing for Store_References
1559
1560    begin
1561       if Get_Declaration then
1562          Add (Decl.Decl);
1563       end if;
1564
1565       if Get_Reads then
1566          Add (Decl.Ref_Ref);
1567       end if;
1568
1569       if Get_Writes then
1570          Add (Decl.Modif_Ref);
1571       end if;
1572
1573       if Get_Bodies then
1574          Add (Decl.Body_Ref);
1575       end if;
1576    end Store_References;
1577
1578    --------------------
1579    -- Get_References --
1580    --------------------
1581
1582    function Get_References
1583      (Decl : Declaration_Reference;
1584       Get_Reads  : Boolean := False;
1585       Get_Writes : Boolean := False;
1586       Get_Bodies : Boolean := False)
1587       return       Reference_Array_Access
1588    is
1589       Length : constant Natural :=
1590                  References_Count (Decl, Get_Reads, Get_Writes, Get_Bodies);
1591
1592       Arr : constant Reference_Array_Access :=
1593               new Reference_Array (1 .. Length);
1594
1595       Index : Natural := Arr'First;
1596
1597    begin
1598       Store_References
1599         (Decl            => Decl,
1600          Get_Writes      => Get_Writes,
1601          Get_Reads       => Get_Reads,
1602          Get_Bodies      => Get_Bodies,
1603          Get_Declaration => False,
1604          Arr             => Arr.all,
1605          Index           => Index);
1606
1607       if Arr'Length /= 0 then
1608          Sort (Arr.all);
1609       end if;
1610
1611       return Arr;
1612    end Get_References;
1613
1614    ----------
1615    -- Free --
1616    ----------
1617
1618    procedure Free (Arr : in out Reference_Array_Access) is
1619       procedure Internal is new Ada.Unchecked_Deallocation
1620         (Reference_Array, Reference_Array_Access);
1621    begin
1622       Internal (Arr);
1623    end Free;
1624
1625    ------------------
1626    -- Is_Parameter --
1627    ------------------
1628
1629    function Is_Parameter (Decl : Declaration_Reference) return Boolean is
1630    begin
1631       return Decl.Is_Parameter;
1632    end Is_Parameter;
1633
1634 end Xr_Tabls;