OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-dev/] [or1k-gcc/] [gcc/] [ada/] [xref_lib.adb] - Blame information for rev 778

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 706 jeremybenn
------------------------------------------------------------------------------
2
--                                                                          --
3
--                         GNAT COMPILER COMPONENTS                         --
4
--                                                                          --
5
--                             X R E F _ L I B                              --
6
--                                                                          --
7
--                                 B o d y                                  --
8
--                                                                          --
9
--          Copyright (C) 1998-2011, 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 Osint;
27
with Output; use Output;
28
with Types;  use Types;
29
 
30
with Unchecked_Deallocation;
31
 
32
with Ada.Strings.Fixed; use Ada.Strings.Fixed;
33
with Ada.Text_IO;       use Ada.Text_IO;
34
 
35
with GNAT.Command_Line; use GNAT.Command_Line;
36
with GNAT.IO_Aux;       use GNAT.IO_Aux;
37
 
38
package body Xref_Lib is
39
 
40
   Type_Position : constant := 50;
41
   --  Column for label identifying type of entity
42
 
43
   ---------------------
44
   -- Local Variables --
45
   ---------------------
46
 
47
   Pipe : constant Character := '|';
48
   --  First character on xref lines in the .ali file
49
 
50
   No_Xref_Information : exception;
51
   --  Exception raised when there is no cross-referencing information in
52
   --  the .ali files.
53
 
54
   procedure Parse_EOL
55
     (Source                 : not null access String;
56
      Ptr                    : in out Positive;
57
      Skip_Continuation_Line : Boolean := False);
58
   --  On return Source (Ptr) is the first character of the next line
59
   --  or EOF. Source.all must be terminated by EOF.
60
   --
61
   --  If Skip_Continuation_Line is True, this subprogram skips as many
62
   --  lines as required when the second or more lines starts with '.'
63
   --  (continuation lines in ALI files).
64
 
65
   function Current_Xref_File (File : ALI_File) return File_Reference;
66
   --  Return the file matching the last 'X' line we found while parsing
67
   --  the ALI file.
68
 
69
   function File_Name (File : ALI_File; Num : Positive) return File_Reference;
70
   --  Returns the dependency file name number Num
71
 
72
   function Get_Full_Type (Decl : Declaration_Reference) return String;
73
   --  Returns the full type corresponding to a type letter as found in
74
   --  the .ali files.
75
 
76
   procedure Open
77
     (Name         : String;
78
      File         : out ALI_File;
79
      Dependencies : Boolean := False);
80
   --  Open a new ALI file. If Dependencies is True, the insert every library
81
   --  file 'with'ed in the files database (used for gnatxref)
82
 
83
   procedure Parse_Identifier_Info
84
     (Pattern       : Search_Pattern;
85
      File          : in out ALI_File;
86
      Local_Symbols : Boolean;
87
      Der_Info      : Boolean := False;
88
      Type_Tree     : Boolean := False;
89
      Wide_Search   : Boolean := True;
90
      Labels_As_Ref : Boolean := True);
91
   --  Output the file and the line where the identifier was referenced,
92
   --  If Local_Symbols is False then only the publicly visible symbols
93
   --  will be processed.
94
   --
95
   --  If Labels_As_Ref is true, then the references to the entities after
96
   --  the end statements ("end Foo") will be counted as actual references.
97
   --  The entity will never be reported as unreferenced by gnatxref -u
98
 
99
   procedure Parse_Token
100
     (Source    : not null access String;
101
      Ptr       : in out Positive;
102
      Token_Ptr : out Positive);
103
   --  Skips any separators and stores the start of the token in Token_Ptr.
104
   --  Then stores the position of the next separator in Ptr. On return
105
   --  Source (Token_Ptr .. Ptr - 1) is the token. Separators are space
106
   --  and ASCII.HT. Parse_Token will never skip to the next line.
107
 
108
   procedure Parse_Number
109
     (Source : not null access String;
110
      Ptr    : in out Positive;
111
      Number : out Natural);
112
   --  Skips any separators and parses Source up to the first character that
113
   --  is not a decimal digit. Returns value of parsed digits or 0 if none.
114
 
115
   procedure Parse_X_Filename (File : in out ALI_File);
116
   --  Reads and processes "X..." lines in the ALI file
117
   --  and updates the File.X_File information.
118
 
119
   procedure Skip_To_First_X_Line
120
     (File    : in out ALI_File;
121
      D_Lines : Boolean;
122
      W_Lines : Boolean);
123
   --  Skip the lines in the ALI file until the first cross-reference line
124
   --  (^X...) is found. Search is started from the beginning of the file.
125
   --  If not such line is found, No_Xref_Information is raised.
126
   --  If W_Lines is false, then the lines "^W" are not parsed.
127
   --  If D_Lines is false, then the lines "^D" are not parsed.
128
 
129
   ----------------
130
   -- Add_Entity --
131
   ----------------
132
 
133
   procedure Add_Entity
134
     (Pattern : in out Search_Pattern;
135
      Entity  : String;
136
      Glob    : Boolean := False)
137
   is
138
      File_Start : Natural;
139
      Line_Start : Natural;
140
      Col_Start  : Natural;
141
      Line_Num   : Natural := 0;
142
      Col_Num    : Natural := 0;
143
 
144
      File_Ref : File_Reference := Empty_File;
145
      pragma Warnings (Off, File_Ref);
146
 
147
   begin
148
      --  Find the end of the first item in Entity (pattern or file?)
149
      --  If there is no ':', we only have a pattern
150
 
151
      File_Start := Index (Entity, ":");
152
 
153
      --  If the regular expression is invalid, just consider it as a string
154
 
155
      if File_Start = 0 then
156
         begin
157
            Pattern.Entity := Compile (Entity, Glob, False);
158
            Pattern.Initialized := True;
159
 
160
         exception
161
            when Error_In_Regexp =>
162
 
163
               --  The basic idea is to insert a \ before every character
164
 
165
               declare
166
                  Tmp_Regexp : String (1 .. 2 * Entity'Length);
167
                  Index      : Positive := 1;
168
 
169
               begin
170
                  for J in Entity'Range loop
171
                     Tmp_Regexp (Index) := '\';
172
                     Tmp_Regexp (Index + 1) := Entity (J);
173
                     Index := Index + 2;
174
                  end loop;
175
 
176
                  Pattern.Entity := Compile (Tmp_Regexp, True, False);
177
                  Pattern.Initialized := True;
178
               end;
179
         end;
180
 
181
         Set_Default_Match (True);
182
         return;
183
      end if;
184
 
185
      --  If there is a dot in the pattern, then it is a file name
186
 
187
      if (Glob and then
188
           Index (Entity (Entity'First .. File_Start - 1), ".") /= 0)
189
             or else
190
              (not Glob
191
                 and then Index (Entity (Entity'First .. File_Start - 1),
192
                                   "\.") /= 0)
193
      then
194
         Pattern.Entity      := Compile (".*", False);
195
         Pattern.Initialized := True;
196
         File_Start          := Entity'First;
197
 
198
      else
199
         --  If the regular expression is invalid, just consider it as a string
200
 
201
         begin
202
            Pattern.Entity :=
203
              Compile (Entity (Entity'First .. File_Start - 1), Glob, False);
204
            Pattern.Initialized := True;
205
 
206
         exception
207
            when Error_In_Regexp =>
208
 
209
               --  The basic idea is to insert a \ before every character
210
 
211
               declare
212
                  Tmp_Regexp : String (1 .. 2 * (File_Start - Entity'First));
213
                  Index      : Positive := 1;
214
 
215
               begin
216
                  for J in Entity'First .. File_Start - 1 loop
217
                     Tmp_Regexp (Index) := '\';
218
                     Tmp_Regexp (Index + 1) := Entity (J);
219
                     Index := Index + 2;
220
                  end loop;
221
 
222
                  Pattern.Entity := Compile (Tmp_Regexp, True, False);
223
                  Pattern.Initialized := True;
224
               end;
225
         end;
226
 
227
         File_Start := File_Start + 1;
228
      end if;
229
 
230
      --  Parse the file name
231
 
232
      Line_Start := Index (Entity (File_Start .. Entity'Last), ":");
233
 
234
      --  Check if it was a disk:\directory item (for Windows)
235
 
236
      if File_Start = Line_Start - 1
237
        and then Line_Start < Entity'Last
238
        and then Entity (Line_Start + 1) = '\'
239
      then
240
         Line_Start := Index (Entity (Line_Start + 1 .. Entity'Last), ":");
241
      end if;
242
 
243
      if Line_Start = 0 then
244
         Line_Start := Entity'Length + 1;
245
 
246
      elsif Line_Start /= Entity'Last then
247
         Col_Start := Index (Entity (Line_Start + 1 .. Entity'Last), ":");
248
 
249
         if Col_Start = 0 then
250
            Col_Start := Entity'Last + 1;
251
         end if;
252
 
253
         if Col_Start > Line_Start + 1 then
254
            begin
255
               Line_Num := Natural'Value
256
                 (Entity (Line_Start + 1 .. Col_Start - 1));
257
 
258
            exception
259
               when Constraint_Error =>
260
                  raise Invalid_Argument;
261
            end;
262
         end if;
263
 
264
         if Col_Start < Entity'Last then
265
            begin
266
               Col_Num := Natural'Value (Entity
267
                                         (Col_Start + 1 .. Entity'Last));
268
 
269
            exception
270
               when Constraint_Error => raise Invalid_Argument;
271
            end;
272
         end if;
273
      end if;
274
 
275
      File_Ref :=
276
        Add_To_Xref_File
277
          (Entity (File_Start .. Line_Start - 1), Visited => True);
278
      Pattern.File_Ref := File_Ref;
279
 
280
      Add_Line (Pattern.File_Ref, Line_Num, Col_Num);
281
 
282
      File_Ref :=
283
        Add_To_Xref_File
284
          (ALI_File_Name (Entity (File_Start .. Line_Start - 1)),
285
           Visited      => False,
286
           Emit_Warning => True);
287
   end Add_Entity;
288
 
289
   -------------------
290
   -- Add_Xref_File --
291
   -------------------
292
 
293
   procedure Add_Xref_File (File : String) is
294
      File_Ref : File_Reference := Empty_File;
295
      pragma Unreferenced (File_Ref);
296
 
297
      Iterator : Expansion_Iterator;
298
 
299
      procedure Add_Xref_File_Internal (File : String);
300
      --  Do the actual addition of the file
301
 
302
      ----------------------------
303
      -- Add_Xref_File_Internal --
304
      ----------------------------
305
 
306
      procedure Add_Xref_File_Internal (File : String) is
307
      begin
308
         --  Case where we have an ALI file, accept it even though this is
309
         --  not official usage, since the intention is obvious
310
 
311
         if Tail (File, 4) = "." & Osint.ALI_Suffix.all then
312
            File_Ref := Add_To_Xref_File
313
                          (File, Visited => False, Emit_Warning => True);
314
 
315
         --  Normal non-ali file case
316
 
317
         else
318
            File_Ref := Add_To_Xref_File (File, Visited => True);
319
 
320
            File_Ref := Add_To_Xref_File
321
                         (ALI_File_Name (File),
322
                          Visited => False, Emit_Warning => True);
323
         end if;
324
      end Add_Xref_File_Internal;
325
 
326
   --  Start of processing for Add_Xref_File
327
 
328
   begin
329
      --  Check if we need to do the expansion
330
 
331
      if Ada.Strings.Fixed.Index (File, "*") /= 0
332
        or else Ada.Strings.Fixed.Index (File, "?") /= 0
333
      then
334
         Start_Expansion (Iterator, File);
335
 
336
         loop
337
            declare
338
               S : constant String := Expansion (Iterator);
339
 
340
            begin
341
               exit when S'Length = 0;
342
               Add_Xref_File_Internal (S);
343
            end;
344
         end loop;
345
 
346
      else
347
         Add_Xref_File_Internal (File);
348
      end if;
349
   end Add_Xref_File;
350
 
351
   -----------------------
352
   -- Current_Xref_File --
353
   -----------------------
354
 
355
   function Current_Xref_File (File : ALI_File) return File_Reference is
356
   begin
357
      return File.X_File;
358
   end Current_Xref_File;
359
 
360
   --------------------------
361
   -- Default_Project_File --
362
   --------------------------
363
 
364
   function Default_Project_File (Dir_Name : String) return String is
365
      My_Dir  : Dir_Type;
366
      Dir_Ent : File_Name_String;
367
      Last    : Natural;
368
 
369
   begin
370
      Open (My_Dir, Dir_Name);
371
 
372
      loop
373
         Read (My_Dir, Dir_Ent, Last);
374
         exit when Last = 0;
375
 
376
         if Tail (Dir_Ent (1 .. Last), 4) = ".adp" then
377
 
378
            --  The first project file found is the good one
379
 
380
            Close (My_Dir);
381
            return Dir_Ent (1 .. Last);
382
         end if;
383
      end loop;
384
 
385
      Close (My_Dir);
386
      return String'(1 .. 0 => ' ');
387
 
388
   exception
389
      when Directory_Error => return String'(1 .. 0 => ' ');
390
   end Default_Project_File;
391
 
392
   ---------------
393
   -- File_Name --
394
   ---------------
395
 
396
   function File_Name
397
     (File : ALI_File;
398
      Num  : Positive) return File_Reference
399
   is
400
   begin
401
      return File.Dep.Table (Num);
402
   end File_Name;
403
 
404
   --------------------
405
   -- Find_ALI_Files --
406
   --------------------
407
 
408
   procedure Find_ALI_Files is
409
      My_Dir  : Rec_DIR;
410
      Dir_Ent : File_Name_String;
411
      Last    : Natural;
412
 
413
      File_Ref : File_Reference;
414
      pragma Unreferenced (File_Ref);
415
 
416
      function Open_Next_Dir return Boolean;
417
      --  Tries to open the next object directory, and return False if
418
      --  the directory cannot be opened.
419
 
420
      -------------------
421
      -- Open_Next_Dir --
422
      -------------------
423
 
424
      function Open_Next_Dir return Boolean is
425
      begin
426
         --  Until we are able to open a new directory
427
 
428
         loop
429
            declare
430
               Obj_Dir : constant String := Next_Obj_Dir;
431
 
432
            begin
433
               --  Case of no more Obj_Dir lines
434
 
435
               if Obj_Dir'Length = 0 then
436
                  return False;
437
               end if;
438
 
439
               Open (My_Dir.Dir, Obj_Dir);
440
               exit;
441
 
442
            exception
443
 
444
               --  Could not open the directory
445
 
446
               when Directory_Error => null;
447
            end;
448
         end loop;
449
 
450
         return True;
451
      end Open_Next_Dir;
452
 
453
   --  Start of processing for Find_ALI_Files
454
 
455
   begin
456
      Reset_Obj_Dir;
457
 
458
      if Open_Next_Dir then
459
         loop
460
            Read (My_Dir.Dir, Dir_Ent, Last);
461
 
462
            if Last = 0 then
463
               Close (My_Dir.Dir);
464
 
465
               if not Open_Next_Dir then
466
                  return;
467
               end if;
468
 
469
            elsif Last > 4
470
              and then Dir_Ent (Last - 3 .. Last) = "." & Osint.ALI_Suffix.all
471
            then
472
               File_Ref :=
473
                 Add_To_Xref_File (Dir_Ent (1 .. Last), Visited => False);
474
            end if;
475
         end loop;
476
      end if;
477
   end Find_ALI_Files;
478
 
479
   -------------------
480
   -- Get_Full_Type --
481
   -------------------
482
 
483
   function Get_Full_Type (Decl : Declaration_Reference) return String is
484
 
485
      function Param_String return String;
486
      --  Return the string to display depending on whether Decl is a parameter
487
 
488
      ------------------
489
      -- Param_String --
490
      ------------------
491
 
492
      function Param_String return String is
493
      begin
494
         if Is_Parameter (Decl) then
495
            return "parameter ";
496
         else
497
            return "";
498
         end if;
499
      end Param_String;
500
 
501
   --  Start of processing for Get_Full_Type
502
 
503
   begin
504
      case Get_Type (Decl) is
505
         when 'A' => return "array type";
506
         when 'B' => return "boolean type";
507
         when 'C' => return "class-wide type";
508
         when 'D' => return "decimal type";
509
         when 'E' => return "enumeration type";
510
         when 'F' => return "float type";
511
         when 'H' => return "abstract type";
512
         when 'I' => return "integer type";
513
         when 'M' => return "modular type";
514
         when 'O' => return "fixed type";
515
         when 'P' => return "access type";
516
         when 'R' => return "record type";
517
         when 'S' => return "string type";
518
         when 'T' => return "task type";
519
         when 'W' => return "protected type";
520
 
521
         when 'a' => return Param_String & "array object";
522
         when 'b' => return Param_String & "boolean object";
523
         when 'c' => return Param_String & "class-wide object";
524
         when 'd' => return Param_String & "decimal object";
525
         when 'e' => return Param_String & "enumeration object";
526
         when 'f' => return Param_String & "float object";
527
         when 'i' => return Param_String & "integer object";
528
         when 'j' => return Param_String & "class object";
529
         when 'm' => return Param_String & "modular object";
530
         when 'o' => return Param_String & "fixed object";
531
         when 'p' => return Param_String & "access object";
532
         when 'r' => return Param_String & "record object";
533
         when 's' => return Param_String & "string object";
534
         when 't' => return Param_String & "task object";
535
         when 'w' => return Param_String & "protected object";
536
         when 'x' => return Param_String & "abstract procedure";
537
         when 'y' => return Param_String & "abstract function";
538
 
539
         when 'h' => return "interface";
540
         when 'g' => return "macro";
541
         when 'J' => return "class";
542
         when 'K' => return "package";
543
         when 'k' => return "generic package";
544
         when 'L' => return "statement label";
545
         when 'l' => return "loop label";
546
         when 'N' => return "named number";
547
         when 'n' => return "enumeration literal";
548
         when 'q' => return "block label";
549
         when 'Q' => return "include file";
550
         when 'U' => return "procedure";
551
         when 'u' => return "generic procedure";
552
         when 'V' => return "function";
553
         when 'v' => return "generic function";
554
         when 'X' => return "exception";
555
         when 'Y' => return "entry";
556
 
557
         when '+' => return "private type";
558
         when '*' => return "private variable";
559
 
560
         --  The above should be the only possibilities, but for this kind
561
         --  of informational output, we don't want to bomb if we find
562
         --  something else, so just return three question marks when we
563
         --  have an unknown Abbrev value
564
 
565
         when others =>
566
            if Is_Parameter (Decl) then
567
               return "parameter";
568
            else
569
               return "??? (" & Get_Type (Decl) & ")";
570
            end if;
571
      end case;
572
   end Get_Full_Type;
573
 
574
   --------------------------
575
   -- Skip_To_First_X_Line --
576
   --------------------------
577
 
578
   procedure Skip_To_First_X_Line
579
     (File    : in out ALI_File;
580
      D_Lines : Boolean;
581
      W_Lines : Boolean)
582
   is
583
      Ali              : String_Access renames File.Buffer;
584
      Token            : Positive;
585
      Ptr              : Positive := Ali'First;
586
      Num_Dependencies : Natural  := 0;
587
      File_Start       : Positive;
588
      File_End         : Positive;
589
      Gnatchop_Offset  : Integer;
590
      Gnatchop_Name    : Positive;
591
 
592
      File_Ref : File_Reference;
593
      pragma Unreferenced (File_Ref);
594
 
595
   begin
596
      --  Read all the lines possibly processing with-clauses and dependency
597
      --  information and exit on finding the first Xref line.
598
      --  A fall-through of the loop means that there is no xref information
599
      --  which is an error condition.
600
 
601
      while Ali (Ptr) /= EOF loop
602
         if D_Lines and then Ali (Ptr) = 'D' then
603
 
604
            --  Found dependency information. Format looks like:
605
            --  D src-nam time-stmp checksum [subunit-name] [line:file-name]
606
 
607
            --  Skip the D and parse the filenam
608
 
609
            Ptr := Ptr + 1;
610
            Parse_Token (Ali, Ptr, Token);
611
            File_Start := Token;
612
            File_End := Ptr - 1;
613
 
614
            Num_Dependencies := Num_Dependencies + 1;
615
            Set_Last (File.Dep, Num_Dependencies);
616
 
617
            Parse_Token (Ali, Ptr, Token); --  Skip time-stamp
618
            Parse_Token (Ali, Ptr, Token); --  Skip checksum
619
            Parse_Token (Ali, Ptr, Token); --  Read next entity on the line
620
 
621
            if not (Ali (Token) in '0' .. '9') then
622
               Parse_Token (Ali, Ptr, Token); --  Was a subunit name
623
            end if;
624
 
625
            --  Did we have a gnatchop-ed file with a pragma Source_Reference ?
626
 
627
            Gnatchop_Offset := 0;
628
 
629
            if Ali (Token) in '0' .. '9' then
630
               Gnatchop_Name := Token;
631
               while Ali (Gnatchop_Name) /= ':' loop
632
                  Gnatchop_Name := Gnatchop_Name + 1;
633
               end loop;
634
 
635
               Gnatchop_Offset :=
636
                 2 - Natural'Value (Ali (Token .. Gnatchop_Name - 1));
637
               Token := Gnatchop_Name + 1;
638
            end if;
639
 
640
            File.Dep.Table (Num_Dependencies) := Add_To_Xref_File
641
              (Ali (File_Start .. File_End),
642
               Gnatchop_File => Ali (Token .. Ptr - 1),
643
               Gnatchop_Offset => Gnatchop_Offset);
644
 
645
         elsif W_Lines and then Ali (Ptr) = 'W' then
646
 
647
            --  Found with-clause information. Format looks like:
648
            --     "W debug%s               debug.adb               debug.ali"
649
 
650
            --  Skip the W and parse the .ali filename (3rd token)
651
 
652
            Parse_Token (Ali, Ptr, Token);
653
            Parse_Token (Ali, Ptr, Token);
654
            Parse_Token (Ali, Ptr, Token);
655
 
656
            File_Ref :=
657
              Add_To_Xref_File (Ali (Token .. Ptr - 1), Visited => False);
658
 
659
         elsif Ali (Ptr) = 'X' then
660
 
661
            --  Found a cross-referencing line - stop processing
662
 
663
            File.Current_Line := Ptr;
664
            File.Xref_Line    := Ptr;
665
            return;
666
         end if;
667
 
668
         Parse_EOL (Ali, Ptr);
669
      end loop;
670
 
671
      raise No_Xref_Information;
672
   end Skip_To_First_X_Line;
673
 
674
   ----------
675
   -- Open --
676
   ----------
677
 
678
   procedure Open
679
     (Name         : String;
680
      File         : out ALI_File;
681
      Dependencies : Boolean := False)
682
   is
683
      Ali : String_Access renames File.Buffer;
684
      pragma Warnings (Off, Ali);
685
 
686
   begin
687
      if File.Buffer /= null then
688
         Free (File.Buffer);
689
      end if;
690
 
691
      Init (File.Dep);
692
 
693
      begin
694
         Read_File (Name, Ali);
695
 
696
      exception
697
         when Ada.Text_IO.Name_Error | Ada.Text_IO.End_Error =>
698
            raise No_Xref_Information;
699
      end;
700
 
701
      Skip_To_First_X_Line (File, D_Lines => True, W_Lines => Dependencies);
702
   end Open;
703
 
704
   ---------------
705
   -- Parse_EOL --
706
   ---------------
707
 
708
   procedure Parse_EOL
709
     (Source                 : not null access String;
710
      Ptr                    : in out Positive;
711
      Skip_Continuation_Line : Boolean := False)
712
   is
713
   begin
714
      loop
715
         --  Skip to end of line
716
 
717
         while Source (Ptr) /= ASCII.CR and then Source (Ptr) /= ASCII.LF
718
           and then Source (Ptr) /= EOF
719
         loop
720
            Ptr := Ptr + 1;
721
         end loop;
722
 
723
         --  Skip CR or LF if not at end of file
724
 
725
         if Source (Ptr) /= EOF then
726
            Ptr := Ptr + 1;
727
         end if;
728
 
729
         --  Skip past CR/LF or LF/CR combination
730
 
731
         if (Source (Ptr) = ASCII.CR or else Source (Ptr) = ASCII.LF)
732
           and then Source (Ptr) /= Source (Ptr - 1)
733
         then
734
            Ptr := Ptr + 1;
735
         end if;
736
 
737
         exit when not Skip_Continuation_Line or else Source (Ptr) /= '.';
738
      end loop;
739
   end Parse_EOL;
740
 
741
   ---------------------------
742
   -- Parse_Identifier_Info --
743
   ---------------------------
744
 
745
   procedure Parse_Identifier_Info
746
     (Pattern       : Search_Pattern;
747
      File          : in out ALI_File;
748
      Local_Symbols : Boolean;
749
      Der_Info      : Boolean := False;
750
      Type_Tree     : Boolean := False;
751
      Wide_Search   : Boolean := True;
752
      Labels_As_Ref : Boolean := True)
753
   is
754
      Ptr      : Positive renames File.Current_Line;
755
      Ali      : String_Access renames File.Buffer;
756
 
757
      E_Line   : Natural;   --  Line number of current entity
758
      E_Col    : Natural;   --  Column number of current entity
759
      E_Type   : Character; --  Type of current entity
760
      E_Name   : Positive;  --  Pointer to begin of entity name
761
      E_Global : Boolean;   --  True iff entity is global
762
 
763
      R_Line   : Natural;   --  Line number of current reference
764
      R_Col    : Natural;   --  Column number of current reference
765
      R_Type   : Character; --  Type of current reference
766
 
767
      Decl_Ref : Declaration_Reference;
768
      File_Ref : File_Reference := Current_Xref_File (File);
769
 
770
      function Get_Symbol_Name (Eun, Line, Col : Natural) return String;
771
      --  Returns the symbol name for the entity defined at the specified
772
      --  line and column in the dependent unit number Eun. For this we need
773
      --  to parse the ali file again because the parent entity is not in
774
      --  the declaration table if it did not match the search pattern.
775
 
776
      procedure Skip_To_Matching_Closing_Bracket;
777
      --  When Ptr points to an opening square bracket, moves it to the
778
      --  character following the matching closing bracket
779
 
780
      ---------------------
781
      -- Get_Symbol_Name --
782
      ---------------------
783
 
784
      function Get_Symbol_Name (Eun, Line, Col : Natural) return String is
785
         Ptr    : Positive := 1;
786
         E_Eun  : Positive;   --  Unit number of current entity
787
         E_Line : Natural;    --  Line number of current entity
788
         E_Col  : Natural;    --  Column number of current entity
789
         E_Name : Positive;   --  Pointer to begin of entity name
790
 
791
      begin
792
         --  Look for the X lines corresponding to unit Eun
793
 
794
         loop
795
            if Ali (Ptr) = 'X' then
796
               Ptr := Ptr + 1;
797
               Parse_Number (Ali, Ptr, E_Eun);
798
               exit when E_Eun = Eun;
799
            end if;
800
 
801
            Parse_EOL (Ali, Ptr, Skip_Continuation_Line => True);
802
         end loop;
803
 
804
         --  Here we are in the right Ali section, we now look for the entity
805
         --  declared at position (Line, Col).
806
 
807
         loop
808
            Parse_Number (Ali, Ptr, E_Line);
809
            exit when Ali (Ptr) = EOF;
810
            Ptr := Ptr + 1;
811
            Parse_Number (Ali, Ptr, E_Col);
812
            exit when Ali (Ptr) = EOF;
813
            Ptr := Ptr + 1;
814
 
815
            if Line = E_Line and then Col = E_Col then
816
               Parse_Token (Ali, Ptr, E_Name);
817
               return Ali (E_Name .. Ptr - 1);
818
            end if;
819
 
820
            Parse_EOL (Ali, Ptr, Skip_Continuation_Line => True);
821
            exit when Ali (Ptr) = EOF;
822
         end loop;
823
 
824
         --  We were not able to find the symbol, this should not happen but
825
         --  since we don't want to stop here we return a string of three
826
         --  question marks as the symbol name.
827
 
828
         return "???";
829
      end Get_Symbol_Name;
830
 
831
      --------------------------------------
832
      -- Skip_To_Matching_Closing_Bracket --
833
      --------------------------------------
834
 
835
      procedure Skip_To_Matching_Closing_Bracket is
836
         Num_Brackets : Natural;
837
 
838
      begin
839
         Num_Brackets := 1;
840
         while Num_Brackets /= 0 loop
841
            Ptr := Ptr + 1;
842
            if Ali (Ptr) = '[' then
843
               Num_Brackets := Num_Brackets + 1;
844
            elsif Ali (Ptr) = ']' then
845
               Num_Brackets := Num_Brackets - 1;
846
            end if;
847
         end loop;
848
 
849
         Ptr := Ptr + 1;
850
      end Skip_To_Matching_Closing_Bracket;
851
 
852
   --  Start of processing for Parse_Identifier_Info
853
 
854
   begin
855
      --  The identifier info looks like:
856
      --     "38U9*Debug 12|36r6 36r19"
857
 
858
      --  Extract the line, column and entity name information
859
 
860
      Parse_Number (Ali, Ptr, E_Line);
861
 
862
      if Ali (Ptr) > ' ' then
863
         E_Type := Ali (Ptr);
864
         Ptr := Ptr + 1;
865
      end if;
866
 
867
      --  Ignore some of the entities (labels,...)
868
 
869
      case E_Type is
870
         when 'l' | 'L' | 'q' =>
871
            Parse_EOL (Ali, Ptr, Skip_Continuation_Line => True);
872
            return;
873
 
874
         when others =>
875
            null;
876
      end case;
877
 
878
      Parse_Number (Ali, Ptr, E_Col);
879
 
880
      E_Global := False;
881
      if Ali (Ptr) >= ' ' then
882
         E_Global := (Ali (Ptr) = '*');
883
         Ptr := Ptr + 1;
884
      end if;
885
 
886
      Parse_Token (Ali, Ptr, E_Name);
887
 
888
      --  Exit if the symbol does not match
889
      --  or if we have a local symbol and we do not want it
890
 
891
      if (not Local_Symbols and not E_Global)
892
        or else (Pattern.Initialized
893
                  and then not Match (Ali (E_Name .. Ptr - 1), Pattern.Entity))
894
        or else (E_Name >= Ptr)
895
      then
896
         Decl_Ref := Add_Declaration
897
           (File.X_File, Ali (E_Name .. Ptr - 1), E_Line, E_Col, E_Type,
898
            Remove_Only => True);
899
         Parse_EOL (Ali, Ptr, Skip_Continuation_Line => True);
900
         return;
901
      end if;
902
 
903
      --  Insert the declaration in the table
904
 
905
      Decl_Ref := Add_Declaration
906
        (File.X_File, Ali (E_Name .. Ptr - 1), E_Line, E_Col, E_Type);
907
 
908
      if Ali (Ptr) = '[' then
909
         Skip_To_Matching_Closing_Bracket;
910
      end if;
911
 
912
      --  Skip any renaming indication
913
 
914
      if Ali (Ptr) = '=' then
915
         declare
916
            P_Line, P_Column : Natural;
917
            pragma Warnings (Off, P_Line);
918
            pragma Warnings (Off, P_Column);
919
         begin
920
            Ptr := Ptr + 1;
921
            Parse_Number (Ali, Ptr, P_Line);
922
            Ptr := Ptr + 1;
923
            Parse_Number (Ali, Ptr, P_Column);
924
         end;
925
      end if;
926
 
927
      if Ali (Ptr) = '<'
928
        or else Ali (Ptr) = '('
929
        or else Ali (Ptr) = '{'
930
      then
931
         --  Here we have a type derivation information. The format is
932
         --  <3|12I45> which means that the current entity is derived from the
933
         --  type defined in unit number 3, line 12 column 45. The pipe and
934
         --  unit number is optional. It is specified only if the parent type
935
         --  is not defined in the current unit.
936
 
937
         --  We also have the format for generic instantiations, as in
938
         --  7a5*Uid(3|5I8[4|2]) 2|4r74
939
 
940
         --  We could also have something like
941
         --  16I9*I<integer>
942
         --  that indicates that I derives from the predefined type integer.
943
 
944
         Ptr := Ptr + 1;
945
 
946
         if Ali (Ptr) in '0' .. '9' then
947
            Parse_Derived_Info : declare
948
               P_Line   : Natural;          --  parent entity line
949
               P_Column : Natural;          --  parent entity column
950
               P_Eun    : Positive;         --  parent entity file number
951
 
952
            begin
953
               Parse_Number (Ali, Ptr, P_Line);
954
 
955
               --  If we have a pipe then the first number was the unit number
956
 
957
               if Ali (Ptr) = '|' then
958
                  P_Eun := P_Line;
959
                  Ptr := Ptr + 1;
960
 
961
                  --  Now we have the line number
962
 
963
                  Parse_Number (Ali, Ptr, P_Line);
964
 
965
               else
966
                  --  We don't have a unit number specified, so we set P_Eun to
967
                  --  the current unit.
968
 
969
                  for K in Dependencies_Tables.First .. Last (File.Dep) loop
970
                     P_Eun := K;
971
                     exit when File.Dep.Table (K) = File_Ref;
972
                  end loop;
973
               end if;
974
 
975
               --  Then parse the type and column number
976
 
977
               Ptr := Ptr + 1;
978
               Parse_Number (Ali, Ptr, P_Column);
979
 
980
               --  Skip the information for generics instantiations
981
 
982
               if Ali (Ptr) = '[' then
983
                  Skip_To_Matching_Closing_Bracket;
984
               end if;
985
 
986
               --  Skip '>', or ')' or '>'
987
 
988
               Ptr := Ptr + 1;
989
 
990
               --  The derived info is needed only is the derived info mode is
991
               --  on or if we want to output the type hierarchy
992
 
993
               if Der_Info or else Type_Tree then
994
                  declare
995
                     Symbol : constant String :=
996
                                Get_Symbol_Name (P_Eun, P_Line, P_Column);
997
                  begin
998
                     if Symbol /= "???" then
999
                        Add_Parent
1000
                          (Decl_Ref,
1001
                           Symbol,
1002
                           P_Line,
1003
                           P_Column,
1004
                           File.Dep.Table (P_Eun));
1005
                     end if;
1006
                  end;
1007
               end if;
1008
 
1009
               if Type_Tree
1010
                 and then (Pattern.File_Ref = Empty_File
1011
                             or else
1012
                           Pattern.File_Ref = Current_Xref_File (File))
1013
               then
1014
                  Search_Parent_Tree : declare
1015
                     Pattern         : Search_Pattern;  --  Parent type pattern
1016
                     File_Pos_Backup : Positive;
1017
 
1018
                  begin
1019
                     Add_Entity
1020
                       (Pattern,
1021
                        Get_Symbol_Name (P_Eun, P_Line, P_Column)
1022
                        & ':' & Get_Gnatchop_File (File.Dep.Table (P_Eun))
1023
                        & ':' & Get_Line (Get_Parent (Decl_Ref))
1024
                        & ':' & Get_Column (Get_Parent (Decl_Ref)),
1025
                        False);
1026
 
1027
                     --  No default match is needed to look for the parent type
1028
                     --  since we are using the fully qualified symbol name:
1029
                     --  symbol:file:line:column
1030
 
1031
                     Set_Default_Match (False);
1032
 
1033
                     --  The parent hierarchy is defined in the same unit as
1034
                     --  the derived type. So we want to revisit the unit.
1035
 
1036
                     File_Pos_Backup   := File.Current_Line;
1037
 
1038
                     Skip_To_First_X_Line
1039
                       (File, D_Lines => False, W_Lines => False);
1040
 
1041
                     while File.Buffer (File.Current_Line) /= EOF loop
1042
                        Parse_X_Filename (File);
1043
                        Parse_Identifier_Info
1044
                          (Pattern       => Pattern,
1045
                           File          => File,
1046
                           Local_Symbols => False,
1047
                           Der_Info      => Der_Info,
1048
                           Type_Tree     => True,
1049
                           Wide_Search   => False,
1050
                           Labels_As_Ref => Labels_As_Ref);
1051
                     end loop;
1052
 
1053
                     File.Current_Line := File_Pos_Backup;
1054
                  end Search_Parent_Tree;
1055
               end if;
1056
            end Parse_Derived_Info;
1057
 
1058
         else
1059
            while Ali (Ptr) /= '>'
1060
              and then Ali (Ptr) /= ')'
1061
              and then Ali (Ptr) /= '}'
1062
            loop
1063
               Ptr := Ptr + 1;
1064
            end loop;
1065
            Ptr := Ptr + 1;
1066
         end if;
1067
      end if;
1068
 
1069
      --  To find the body, we will have to parse the file too
1070
 
1071
      if Wide_Search then
1072
         declare
1073
            File_Ref : File_Reference;
1074
            pragma Unreferenced (File_Ref);
1075
            File_Name : constant String := Get_Gnatchop_File (File.X_File);
1076
         begin
1077
            File_Ref := Add_To_Xref_File (ALI_File_Name (File_Name), False);
1078
         end;
1079
      end if;
1080
 
1081
      --  Parse references to this entity.
1082
      --  Ptr points to next reference with leading blanks
1083
 
1084
      loop
1085
         --  Process references on current line
1086
 
1087
         while Ali (Ptr) = ' ' or else Ali (Ptr) = ASCII.HT loop
1088
 
1089
            --  For every reference read the line, type and column,
1090
            --  optionally preceded by a file number and a pipe symbol.
1091
 
1092
            Parse_Number (Ali, Ptr, R_Line);
1093
 
1094
            if Ali (Ptr) = Pipe then
1095
               Ptr := Ptr + 1;
1096
               File_Ref := File_Name (File, R_Line);
1097
 
1098
               Parse_Number (Ali, Ptr, R_Line);
1099
            end if;
1100
 
1101
            if Ali (Ptr) > ' ' then
1102
               R_Type := Ali (Ptr);
1103
               Ptr := Ptr + 1;
1104
            end if;
1105
 
1106
            --  Imported entities might special indication as to their external
1107
            --  name:
1108
            --    5U14*Foo2 5>20 6b<c,myfoo2>22
1109
 
1110
            if R_Type = 'b'
1111
              and then Ali (Ptr) = '<'
1112
            then
1113
               while Ptr <= Ali'Last
1114
                 and then Ali (Ptr) /= '>'
1115
               loop
1116
                  Ptr := Ptr + 1;
1117
               end loop;
1118
               Ptr := Ptr + 1;
1119
            end if;
1120
 
1121
            Parse_Number (Ali, Ptr, R_Col);
1122
 
1123
            --  Insert the reference or body in the table
1124
 
1125
            Add_Reference
1126
              (Decl_Ref, File_Ref, R_Line, R_Col, R_Type, Labels_As_Ref);
1127
 
1128
            --  Skip generic information, if any
1129
 
1130
            if Ali (Ptr) = '[' then
1131
               declare
1132
                  Num_Nested : Integer := 1;
1133
 
1134
               begin
1135
                  Ptr := Ptr + 1;
1136
                  while Num_Nested /= 0 loop
1137
                     if Ali (Ptr) = ']' then
1138
                        Num_Nested := Num_Nested - 1;
1139
                     elsif Ali (Ptr) = '[' then
1140
                        Num_Nested := Num_Nested + 1;
1141
                     end if;
1142
 
1143
                     Ptr := Ptr + 1;
1144
                  end loop;
1145
               end;
1146
            end if;
1147
 
1148
         end loop;
1149
 
1150
         Parse_EOL (Ali, Ptr);
1151
 
1152
         --   Loop until new line is no continuation line
1153
 
1154
         exit when Ali (Ptr) /= '.';
1155
         Ptr := Ptr + 1;
1156
      end loop;
1157
   end Parse_Identifier_Info;
1158
 
1159
   ------------------
1160
   -- Parse_Number --
1161
   ------------------
1162
 
1163
   procedure Parse_Number
1164
     (Source : not null access String;
1165
      Ptr    : in out Positive;
1166
      Number : out Natural)
1167
   is
1168
   begin
1169
      --  Skip separators
1170
 
1171
      while Source (Ptr) = ' ' or else Source (Ptr) = ASCII.HT loop
1172
         Ptr := Ptr + 1;
1173
      end loop;
1174
 
1175
      Number := 0;
1176
      while Source (Ptr) in '0' .. '9' loop
1177
         Number :=
1178
           10 * Number + (Character'Pos (Source (Ptr)) - Character'Pos ('0'));
1179
         Ptr := Ptr + 1;
1180
      end loop;
1181
   end Parse_Number;
1182
 
1183
   -----------------
1184
   -- Parse_Token --
1185
   -----------------
1186
 
1187
   procedure Parse_Token
1188
     (Source    : not null access String;
1189
      Ptr       : in out Positive;
1190
      Token_Ptr : out Positive)
1191
   is
1192
      In_Quotes : Character := ASCII.NUL;
1193
 
1194
   begin
1195
      --  Skip separators
1196
 
1197
      while Source (Ptr) = ' ' or else Source (Ptr) = ASCII.HT loop
1198
         Ptr := Ptr + 1;
1199
      end loop;
1200
 
1201
      Token_Ptr := Ptr;
1202
 
1203
      --  Find end-of-token
1204
 
1205
      while (In_Quotes /= ASCII.NUL or else
1206
               not (Source (Ptr) = ' '
1207
                     or else Source (Ptr) = ASCII.HT
1208
                     or else Source (Ptr) = '<'
1209
                     or else Source (Ptr) = '{'
1210
                     or else Source (Ptr) = '['
1211
                     or else Source (Ptr) = '='
1212
                     or else Source (Ptr) = '('))
1213
        and then Source (Ptr) >= ' '
1214
      loop
1215
         --  Double-quotes are used for operators
1216
         --  Simple-quotes are used for character constants, for instance when
1217
         --  they are found in an enumeration type "type A is ('+', '-');"
1218
 
1219
         case Source (Ptr) is
1220
            when '"' | ''' =>
1221
               if In_Quotes = Source (Ptr) then
1222
                  In_Quotes := ASCII.NUL;
1223
               elsif In_Quotes = ASCII.NUL then
1224
                  In_Quotes := Source (Ptr);
1225
               end if;
1226
 
1227
            when others =>
1228
               null;
1229
         end case;
1230
 
1231
         Ptr := Ptr + 1;
1232
      end loop;
1233
   end Parse_Token;
1234
 
1235
   ----------------------
1236
   -- Parse_X_Filename --
1237
   ----------------------
1238
 
1239
   procedure Parse_X_Filename (File : in out ALI_File) is
1240
      Ali     : String_Access renames File.Buffer;
1241
      Ptr     : Positive renames File.Current_Line;
1242
      File_Nr : Natural;
1243
 
1244
   begin
1245
      while Ali (Ptr) = 'X' loop
1246
 
1247
         --  The current line is the start of a new Xref file section,
1248
         --  whose format looks like:
1249
 
1250
         --     " X 1 debug.ads"
1251
 
1252
         --  Skip the X and read the file number for the new X_File
1253
 
1254
         Ptr := Ptr + 1;
1255
         Parse_Number (Ali, Ptr, File_Nr);
1256
 
1257
         if File_Nr > 0 then
1258
            File.X_File := File.Dep.Table (File_Nr);
1259
         end if;
1260
 
1261
         Parse_EOL (Ali, Ptr);
1262
      end loop;
1263
   end Parse_X_Filename;
1264
 
1265
   --------------------
1266
   -- Print_Gnatfind --
1267
   --------------------
1268
 
1269
   procedure Print_Gnatfind
1270
     (References     : Boolean;
1271
      Full_Path_Name : Boolean)
1272
   is
1273
      Decls : constant Declaration_Array_Access := Get_Declarations;
1274
      Decl  : Declaration_Reference;
1275
      Arr   : Reference_Array_Access;
1276
 
1277
      procedure Print_Ref
1278
        (Ref : Reference;
1279
         Msg : String := "      ");
1280
      --  Print a reference, according to the extended tag of the output
1281
 
1282
      ---------------
1283
      -- Print_Ref --
1284
      ---------------
1285
 
1286
      procedure Print_Ref
1287
        (Ref : Reference;
1288
         Msg : String := "      ")
1289
      is
1290
         F : String_Access :=
1291
               Osint.To_Host_File_Spec
1292
                (Get_Gnatchop_File (Ref, Full_Path_Name));
1293
 
1294
         Buffer : constant String :=
1295
                    F.all &
1296
                    ":" & Get_Line (Ref)   &
1297
                    ":" & Get_Column (Ref) &
1298
                    ": ";
1299
 
1300
         Num_Blanks : Integer := Longest_File_Name + 10 - Buffer'Length;
1301
 
1302
      begin
1303
         Free (F);
1304
         Num_Blanks := Integer'Max (0, Num_Blanks);
1305
         Write_Line
1306
           (Buffer
1307
            & String'(1 .. Num_Blanks => ' ')
1308
            & Msg & " " & Get_Symbol (Decl));
1309
 
1310
         if Get_Source_Line (Ref)'Length /= 0 then
1311
            Write_Line ("   " & Get_Source_Line (Ref));
1312
         end if;
1313
      end Print_Ref;
1314
 
1315
   --  Start of processing for Print_Gnatfind
1316
 
1317
   begin
1318
      for D in Decls'Range loop
1319
         Decl := Decls (D);
1320
 
1321
         if Match (Decl) then
1322
 
1323
            --  Output the declaration
1324
 
1325
            declare
1326
               Parent : constant Declaration_Reference := Get_Parent (Decl);
1327
 
1328
               F : String_Access :=
1329
                     Osint.To_Host_File_Spec
1330
                      (Get_Gnatchop_File (Decl, Full_Path_Name));
1331
 
1332
               Buffer : constant String :=
1333
                          F.all &
1334
                          ":" & Get_Line (Decl)   &
1335
                          ":" & Get_Column (Decl) &
1336
                          ": ";
1337
 
1338
               Num_Blanks : Integer := Longest_File_Name + 10 - Buffer'Length;
1339
 
1340
            begin
1341
               Free (F);
1342
               Num_Blanks := Integer'Max (0, Num_Blanks);
1343
               Write_Line
1344
                 (Buffer & String'(1 .. Num_Blanks => ' ')
1345
                  & "(spec) " & Get_Symbol (Decl));
1346
 
1347
               if Parent /= Empty_Declaration then
1348
                  F := Osint.To_Host_File_Spec (Get_Gnatchop_File (Parent));
1349
                  Write_Line
1350
                    (Buffer & String'(1 .. Num_Blanks => ' ')
1351
                     & "   derived from " & Get_Symbol (Parent)
1352
                     & " ("
1353
                     & F.all
1354
                     & ':' & Get_Line (Parent)
1355
                     & ':' & Get_Column (Parent) & ')');
1356
                  Free (F);
1357
               end if;
1358
            end;
1359
 
1360
            if Get_Source_Line (Decl)'Length /= 0 then
1361
               Write_Line ("   " & Get_Source_Line (Decl));
1362
            end if;
1363
 
1364
            --  Output the body (sorted)
1365
 
1366
            Arr := Get_References (Decl, Get_Bodies => True);
1367
 
1368
            for R in Arr'Range loop
1369
               Print_Ref (Arr (R), "(body)");
1370
            end loop;
1371
 
1372
            Free (Arr);
1373
 
1374
            if References then
1375
               Arr := Get_References
1376
                 (Decl, Get_Writes => True, Get_Reads => True);
1377
 
1378
               for R in Arr'Range loop
1379
                  Print_Ref (Arr (R));
1380
               end loop;
1381
 
1382
               Free (Arr);
1383
            end if;
1384
         end if;
1385
      end loop;
1386
   end Print_Gnatfind;
1387
 
1388
   ------------------
1389
   -- Print_Unused --
1390
   ------------------
1391
 
1392
   procedure Print_Unused (Full_Path_Name : Boolean) is
1393
      Decls : constant Declaration_Array_Access := Get_Declarations;
1394
      Decl  : Declaration_Reference;
1395
      Arr   : Reference_Array_Access;
1396
      F     : String_Access;
1397
 
1398
   begin
1399
      for D in Decls'Range loop
1400
         Decl := Decls (D);
1401
 
1402
         if References_Count
1403
             (Decl, Get_Reads => True, Get_Writes => True) = 0
1404
         then
1405
            F := Osint.To_Host_File_Spec
1406
              (Get_Gnatchop_File (Decl, Full_Path_Name));
1407
            Write_Str (Get_Symbol (Decl)
1408
                        & " ("
1409
                        & Get_Full_Type (Decl)
1410
                        & ") "
1411
                        & F.all
1412
                        & ':'
1413
                        & Get_Line (Decl)
1414
                        & ':'
1415
                        & Get_Column (Decl));
1416
            Free (F);
1417
 
1418
            --  Print the body if any
1419
 
1420
            Arr := Get_References (Decl, Get_Bodies => True);
1421
 
1422
            for R in Arr'Range loop
1423
               F := Osint.To_Host_File_Spec
1424
                      (Get_Gnatchop_File (Arr (R), Full_Path_Name));
1425
               Write_Str (' '
1426
                           & F.all
1427
                           & ':' & Get_Line (Arr (R))
1428
                           & ':' & Get_Column (Arr (R)));
1429
               Free (F);
1430
            end loop;
1431
 
1432
            Write_Eol;
1433
            Free (Arr);
1434
         end if;
1435
      end loop;
1436
   end Print_Unused;
1437
 
1438
   --------------
1439
   -- Print_Vi --
1440
   --------------
1441
 
1442
   procedure Print_Vi (Full_Path_Name : Boolean) is
1443
      Tab   : constant Character := ASCII.HT;
1444
      Decls : constant Declaration_Array_Access :=
1445
                Get_Declarations (Sorted => False);
1446
      Decl  : Declaration_Reference;
1447
      Arr   : Reference_Array_Access;
1448
      F     : String_Access;
1449
 
1450
   begin
1451
      for D in Decls'Range loop
1452
         Decl := Decls (D);
1453
 
1454
         F := Osint.To_Host_File_Spec (Get_File (Decl, Full_Path_Name));
1455
         Write_Line (Get_Symbol (Decl) & Tab & F.all & Tab & Get_Line (Decl));
1456
         Free (F);
1457
 
1458
         --  Print the body if any
1459
 
1460
         Arr := Get_References (Decl, Get_Bodies => True);
1461
 
1462
         for R in Arr'Range loop
1463
            F := Osint.To_Host_File_Spec (Get_File (Arr (R), Full_Path_Name));
1464
            Write_Line
1465
              (Get_Symbol (Decl) & Tab & F.all & Tab  & Get_Line (Arr (R)));
1466
            Free (F);
1467
         end loop;
1468
 
1469
         Free (Arr);
1470
 
1471
         --  Print the modifications
1472
 
1473
         Arr := Get_References (Decl, Get_Writes => True, Get_Reads => True);
1474
 
1475
         for R in Arr'Range loop
1476
            F := Osint.To_Host_File_Spec (Get_File (Arr (R), Full_Path_Name));
1477
            Write_Line
1478
              (Get_Symbol (Decl) & Tab & F.all & Tab & Get_Line (Arr (R)));
1479
            Free (F);
1480
         end loop;
1481
 
1482
         Free (Arr);
1483
      end loop;
1484
   end Print_Vi;
1485
 
1486
   ----------------
1487
   -- Print_Xref --
1488
   ----------------
1489
 
1490
   procedure Print_Xref (Full_Path_Name : Boolean) is
1491
      Decls : constant Declaration_Array_Access := Get_Declarations;
1492
      Decl : Declaration_Reference;
1493
 
1494
      Margin : constant := 10;
1495
      --  Column where file names start
1496
 
1497
      procedure New_Line80;
1498
      --  Go to start of new line
1499
 
1500
      procedure Print80 (S : String);
1501
      --  Print the text, respecting the 80 columns rule
1502
 
1503
      procedure Print_Ref (Line, Column : String);
1504
      --  The beginning of the output is aligned on a column multiple of 9
1505
 
1506
      procedure Print_List
1507
        (Decl       : Declaration_Reference;
1508
         Msg        : String;
1509
         Get_Reads  : Boolean := False;
1510
         Get_Writes : Boolean := False;
1511
         Get_Bodies : Boolean := False);
1512
      --  Print a list of references. If the list is not empty, Msg will
1513
      --  be printed prior to the list.
1514
 
1515
      ----------------
1516
      -- New_Line80 --
1517
      ----------------
1518
 
1519
      procedure New_Line80 is
1520
      begin
1521
         Write_Eol;
1522
         Write_Str (String'(1 .. Margin - 1 => ' '));
1523
      end New_Line80;
1524
 
1525
      -------------
1526
      -- Print80 --
1527
      -------------
1528
 
1529
      procedure Print80 (S : String) is
1530
         Align : Natural := Margin - (Integer (Column) mod Margin);
1531
 
1532
      begin
1533
         if Align = Margin then
1534
            Align := 0;
1535
         end if;
1536
 
1537
         Write_Str (String'(1 .. Align => ' ') & S);
1538
      end Print80;
1539
 
1540
      ---------------
1541
      -- Print_Ref --
1542
      ---------------
1543
 
1544
      procedure Print_Ref (Line, Column : String) is
1545
         Line_Align : constant Integer := 4 - Line'Length;
1546
 
1547
         S : constant String := String'(1 .. Line_Align => ' ')
1548
                                  & Line & ':' & Column;
1549
 
1550
         Align : Natural := Margin - (Integer (Output.Column) mod Margin);
1551
 
1552
      begin
1553
         if Align = Margin then
1554
            Align := 0;
1555
         end if;
1556
 
1557
         if Integer (Output.Column) + Align + S'Length > 79 then
1558
            New_Line80;
1559
            Align := 0;
1560
         end if;
1561
 
1562
         Write_Str (String'(1 .. Align => ' ') & S);
1563
      end Print_Ref;
1564
 
1565
      ----------------
1566
      -- Print_List --
1567
      ----------------
1568
 
1569
      procedure Print_List
1570
        (Decl       : Declaration_Reference;
1571
         Msg        : String;
1572
         Get_Reads  : Boolean := False;
1573
         Get_Writes : Boolean := False;
1574
         Get_Bodies : Boolean := False)
1575
      is
1576
         Arr : Reference_Array_Access :=
1577
                 Get_References
1578
                   (Decl,
1579
                    Get_Writes => Get_Writes,
1580
                    Get_Reads  => Get_Reads,
1581
                    Get_Bodies => Get_Bodies);
1582
         File : File_Reference := Empty_File;
1583
         F    : String_Access;
1584
 
1585
      begin
1586
         if Arr'Length /= 0 then
1587
            Write_Eol;
1588
            Write_Str (Msg);
1589
         end if;
1590
 
1591
         for R in Arr'Range loop
1592
            if Get_File_Ref (Arr (R)) /= File then
1593
               if File /= Empty_File then
1594
                  New_Line80;
1595
               end if;
1596
 
1597
               File := Get_File_Ref (Arr (R));
1598
               F := Osint.To_Host_File_Spec
1599
                 (Get_Gnatchop_File (Arr (R), Full_Path_Name));
1600
 
1601
               if F = null then
1602
                  Write_Str ("<unknown> ");
1603
               else
1604
                  Write_Str (F.all & ' ');
1605
                  Free (F);
1606
               end if;
1607
            end if;
1608
 
1609
            Print_Ref (Get_Line (Arr (R)), Get_Column (Arr (R)));
1610
         end loop;
1611
 
1612
         Free (Arr);
1613
      end Print_List;
1614
 
1615
      F : String_Access;
1616
 
1617
   --  Start of processing for Print_Xref
1618
 
1619
   begin
1620
      for D in Decls'Range loop
1621
         Decl := Decls (D);
1622
 
1623
         Write_Str (Get_Symbol (Decl));
1624
 
1625
         --  Put the declaration type in column Type_Position, but if the
1626
         --  declaration name is too long, put at least one space between its
1627
         --  name and its type.
1628
 
1629
         while Column < Type_Position - 1 loop
1630
            Write_Char (' ');
1631
         end loop;
1632
 
1633
         Write_Char (' ');
1634
 
1635
         Write_Line (Get_Full_Type (Decl));
1636
 
1637
         Write_Parent_Info : declare
1638
            Parent : constant Declaration_Reference := Get_Parent (Decl);
1639
 
1640
         begin
1641
            if Parent /= Empty_Declaration then
1642
               Write_Str ("  Ptype: ");
1643
               F := Osint.To_Host_File_Spec (Get_Gnatchop_File (Parent));
1644
               Print80 (F.all);
1645
               Free (F);
1646
               Print_Ref (Get_Line (Parent), Get_Column (Parent));
1647
               Print80 ("  " & Get_Symbol (Parent));
1648
               Write_Eol;
1649
            end if;
1650
         end Write_Parent_Info;
1651
 
1652
         Write_Str ("  Decl:  ");
1653
         F := Osint.To_Host_File_Spec
1654
               (Get_Gnatchop_File (Decl, Full_Path_Name));
1655
 
1656
         if F = null then
1657
            Print80 ("<unknown> ");
1658
         else
1659
            Print80 (F.all & ' ');
1660
            Free (F);
1661
         end if;
1662
 
1663
         Print_Ref (Get_Line (Decl), Get_Column (Decl));
1664
 
1665
         Print_List
1666
           (Decl, "  Body:  ", Get_Bodies => True);
1667
         Print_List
1668
           (Decl, "  Modi:  ", Get_Writes => True);
1669
         Print_List
1670
           (Decl, "  Ref:   ", Get_Reads => True);
1671
         Write_Eol;
1672
      end loop;
1673
   end Print_Xref;
1674
 
1675
   ------------
1676
   -- Search --
1677
   ------------
1678
 
1679
   procedure Search
1680
     (Pattern       : Search_Pattern;
1681
      Local_Symbols : Boolean;
1682
      Wide_Search   : Boolean;
1683
      Read_Only     : Boolean;
1684
      Der_Info      : Boolean;
1685
      Type_Tree     : Boolean)
1686
   is
1687
      type String_Access is access String;
1688
      procedure Free is new Unchecked_Deallocation (String, String_Access);
1689
 
1690
      ALIfile   : ALI_File;
1691
      File_Ref  : File_Reference;
1692
      Strip_Num : Natural := 0;
1693
      Ali_Name  : String_Access;
1694
 
1695
   begin
1696
      --  If we want all the .ali files, then find them
1697
 
1698
      if Wide_Search then
1699
         Find_ALI_Files;
1700
      end if;
1701
 
1702
      loop
1703
         --  Get the next unread ali file
1704
 
1705
         File_Ref := Next_Unvisited_File;
1706
 
1707
         exit when File_Ref = Empty_File;
1708
 
1709
         --  Find the ALI file to use. Most of the time, it will be the unit
1710
         --  name, with a different extension. However, when dealing with
1711
         --  separates the ALI file is in fact the parent's ALI file (and this
1712
         --  is recursive, in case the parent itself is a separate).
1713
 
1714
         Strip_Num := 0;
1715
         loop
1716
            Free (Ali_Name);
1717
            Ali_Name := new String'
1718
              (Get_File (File_Ref, With_Dir => True, Strip => Strip_Num));
1719
 
1720
            --  Stripped too many things...
1721
 
1722
            if Ali_Name.all = "" then
1723
               if Get_Emit_Warning (File_Ref) then
1724
                  Set_Standard_Error;
1725
                  Write_Line
1726
                    ("warning : file " & Get_File (File_Ref, With_Dir => True)
1727
                     & " not found");
1728
                  Set_Standard_Output;
1729
               end if;
1730
               Free (Ali_Name);
1731
               exit;
1732
 
1733
            --  If not found, try the parent's ALI file (this is needed for
1734
            --  separate units and subprograms).
1735
 
1736
            --  Reset the cached directory first, in case the separate's
1737
            --  ALI file is not in the same directory.
1738
 
1739
            elsif not File_Exists (Ali_Name.all) then
1740
               Strip_Num := Strip_Num + 1;
1741
               Reset_Directory (File_Ref);
1742
 
1743
            --  Else we finally found it
1744
 
1745
            else
1746
               exit;
1747
            end if;
1748
         end loop;
1749
 
1750
         --  If we had to get the parent's ALI, insert it in the list as usual.
1751
         --  This is to avoid parsing it twice in case it has already been
1752
         --  parsed.
1753
 
1754
         if Ali_Name /= null and then Strip_Num /= 0 then
1755
            File_Ref := Add_To_Xref_File
1756
              (File_Name => Ali_Name.all,
1757
               Visited   => False);
1758
 
1759
         --  Now that we have a file name, parse it to find any reference to
1760
         --  the entity.
1761
 
1762
         elsif Ali_Name /= null
1763
           and then (Read_Only or else Is_Writable_File (Ali_Name.all))
1764
         then
1765
            begin
1766
               Open (Ali_Name.all, ALIfile);
1767
 
1768
               --  The cross-reference section in the ALI file may be followed
1769
               --  by other sections, which can be identified by the starting
1770
               --  character of every line, which should neither be 'X' nor a
1771
               --  figure in '1' .. '9'.
1772
 
1773
               --  The loop tests below also take into account the end-of-file
1774
               --  possibility.
1775
 
1776
               while ALIfile.Buffer (ALIfile.Current_Line) = 'X' loop
1777
                  Parse_X_Filename (ALIfile);
1778
 
1779
                  while ALIfile.Buffer (ALIfile.Current_Line) in '1' .. '9'
1780
                  loop
1781
                     Parse_Identifier_Info
1782
                       (Pattern, ALIfile, Local_Symbols, Der_Info, Type_Tree,
1783
                        Wide_Search, Labels_As_Ref => True);
1784
                  end loop;
1785
               end loop;
1786
 
1787
            exception
1788
               when No_Xref_Information   =>
1789
                  if Get_Emit_Warning (File_Ref) then
1790
                     Set_Standard_Error;
1791
                     Write_Line
1792
                       ("warning : No cross-referencing information in  "
1793
                        & Ali_Name.all);
1794
                     Set_Standard_Output;
1795
                  end if;
1796
            end;
1797
         end if;
1798
      end loop;
1799
 
1800
      Free (Ali_Name);
1801
   end Search;
1802
 
1803
   -----------------
1804
   -- Search_Xref --
1805
   -----------------
1806
 
1807
   procedure Search_Xref
1808
     (Local_Symbols : Boolean;
1809
      Read_Only     : Boolean;
1810
      Der_Info      : Boolean)
1811
   is
1812
      ALIfile      : ALI_File;
1813
      File_Ref     : File_Reference;
1814
      Null_Pattern : Search_Pattern;
1815
 
1816
   begin
1817
      Null_Pattern.Initialized := False;
1818
 
1819
      loop
1820
         --  Find the next unvisited file
1821
 
1822
         File_Ref := Next_Unvisited_File;
1823
         exit when File_Ref = Empty_File;
1824
 
1825
         --  Search the object directories for the .ali file
1826
 
1827
         declare
1828
            F : constant String := Get_File (File_Ref, With_Dir => True);
1829
 
1830
         begin
1831
            if Read_Only or else Is_Writable_File (F) then
1832
               Open (F, ALIfile, True);
1833
 
1834
               --  The cross-reference section in the ALI file may be followed
1835
               --  by other sections, which can be identified by the starting
1836
               --  character of every line, which should neither be 'X' nor a
1837
               --  figure in '1' .. '9'.
1838
 
1839
               --  The loop tests below also take into account the end-of-file
1840
               --  possibility.
1841
 
1842
               while ALIfile.Buffer (ALIfile.Current_Line) = 'X' loop
1843
                  Parse_X_Filename (ALIfile);
1844
 
1845
                  while ALIfile.Buffer (ALIfile.Current_Line) in '1' .. '9'
1846
                  loop
1847
                     Parse_Identifier_Info
1848
                       (Null_Pattern, ALIfile, Local_Symbols, Der_Info,
1849
                        Labels_As_Ref => False);
1850
                  end loop;
1851
               end loop;
1852
            end if;
1853
 
1854
         exception
1855
            when No_Xref_Information =>  null;
1856
         end;
1857
      end loop;
1858
   end Search_Xref;
1859
 
1860
end Xref_Lib;

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.