OSDN Git Service

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