1
-------------------------------------------------------------------------------
3
-- This file is part of AdaBrowse.
5
-- <STRONG>Copyright (c) 2002 by Thomas Wolf.</STRONG>
7
-- AdaBrowse is free software; you can redistribute it and/or modify it
8
-- under the terms of the GNU General Public License as published by the
9
-- Free Software Foundation; either version 2, or (at your option) any
10
-- later version. AdaBrowse is distributed in the hope that it will be
11
-- useful, but <EM>without any warranty</EM>; without even the implied
12
-- warranty of <EM>merchantability or fitness for a particular purpose.</EM>
13
-- See the GNU General Public License for more details. You should have
14
-- received a copy of the GNU General Public License with this distribution,
15
-- see file "<A HREF="GPL.txt">GPL.txt</A>". If not, write to the Free
16
-- Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307,
21
-- Author:</STRONG><DD>
23
-- <ADDRESS><A HREF="mailto:twolf@acm.org">twolf@acm.org</A></ADDRESS></DL>
26
-- Purpose:</STRONG><DD>
27
-- Main procedure of AdaBrowse.</DL>
32
-- 02-FEB-2002 TW V1.0 First release.
33
-- 04-FEB-2002 TW V1.01 Added automatic tree file generation. Improved
34
-- some error messages. Added "-a | -all" option, which
35
-- generates HTML also for all supporters of the given
37
-- 06-FEB-2002 TW Added the "-q" and "-x" options, changed behavior of
38
-- all options taking filenames (may be in the next arg,
39
-- or immediately following the option prefix). Changed
40
-- some error handling. Added support for excluding units.
41
-- 07-FEB-2002 TW Added support for "-I" options with directories that
42
-- contain white space. Improved the Asis initialization:
43
-- it also catches inconsistencies reported by Asis now
44
-- and tries to correct them. Improved the command line
45
-- handling (new exception 'Help_Requested').
46
-- 13-MAR-2002 TW V1.3 Changed to handle several units; added "-i" option
47
-- for index creation.
48
-- 14-MAR-2002 TW Added "-is" option for nested index creation; allow
49
-- index generation also if "-all" is given.
50
-- 15-MAR-2002 TW Added an optional file name argument to "-i" and "-is".
51
-- 19-MAR-2002 TW V1.33 Corrected plausibility test of filename in -o
52
-- option: must not be done if name is "-". Minor change in
53
-- 'Recreate': pass not just the file name, but also its
54
-- path! (Allows 'Create_Unit' to automatically add that
55
-- path as a "-I" option to the compile command.)
56
-- Correction in 'Process_One_Unit': if it's *not* a
57
-- src-vs-tree inconsistency, re-raise the exception.
58
-- 26-MAR-2002 TW Added support for krunched file names.
59
-- 28-MAR-2002 TW Added "-t" and "-p" options for type and subprogram
60
-- indices. Same syntax as "-i".
61
-- 03-APR-2002 TW Uses new index package now.
62
-- 24-APR-2002 TW Uses AD.All_Units now to avoid processing the same unit
63
-- multiple times if "-all" in file input mode is given.
64
-- 02-MAY-2002 TW Added the user-defined HTML tags feature.
65
-- 03-JUL-2002 TW Added the "-g" option; added logic such that the
66
-- general context using all tree files is initialized and
67
-- opened only once, and not opened and closed for each
68
-- and every input unit. It appears that ASIS-for-GNAT has
69
-- a rather huge memory leak on closing a context, and
70
-- furthermore, opening a context is slow!
71
-- 20-AUG-2002 TW Added the "-G" option.
72
-- 28-AUG-2002 TW Added the "-l" option.
73
-- 11-NOV-2002 TW Catch Program_Error if it is an "Inconsistent versions
74
-- of GNAT and ASIS" bug, so that we don't get the "report
75
-- this error" message. I couldn't do anything about it
76
-- anyway: you'll have to rebuild AdaBrowse or use the
77
-- same GNAT as was used to build AdaBrowse itself. I know,
78
-- it's a major nuisance, but I'm not responsible for that.
79
-- Complain to ACT, if you like (but I guess they won't
80
-- make their ASIS and their tree files compiler version
82
-- 22-NOV-2002 TW Added "-private" option.
83
-- 28-APR-2003 TW Customized ASIS initialization to work around a most
84
-- annoying behavior of ASIS-for-GNAT 3.16a.
85
-- 07-JUN-2003 TW Added support for the GNAT project manager.
86
-- 12-JUN-2003 TW Changed into a package.
87
-- 30-JUN-2003 TW Adapted to new index management.
88
-- 09-JUL-2003 TW Delay processing the -f input until after the project
89
-- file has been processed. Also, don't delete the tree
90
-- files we generated if we're using a project file: in
91
-- that case, the tree directory is ours, and we may well
92
-- leave the files there for future re-use.
93
-- 18-NOV-2003 TW Added -X option for consistency with GNAT's project
95
-- 19-NOV-2003 TW Added checks that directories really exist. Additional
96
-- check in exception handling for "not compile-only" tree
99
-------------------------------------------------------------------------------
101
pragma License (GPL);
103
with Ada.Characters.Handling;
104
with Ada.Command_Line;
107
with Ada.Strings.Unbounded;
108
with Ada.Unchecked_Deallocation;
112
with Asis.Exceptions;
113
with Asis.Compilation_Units;
114
with Asis.Ada_Environments;
115
with Asis.Implementation;
127
with AD.Indices.Configuration;
131
with AD.Printers.HTML;
132
with AD.Printers.XML;
139
with AD.Text_Utilities;
146
pragma Elaborate_All (AD.Projects);
147
pragma Elaborate_All (AD.Version);
149
package body AD.Driver is
151
package ACH renames Ada.Characters.Handling;
152
package ASU renames Ada.Strings.Unbounded;
154
package AIC renames AD.Indices.Configuration;
160
use AD.Text_Utilities;
164
Help_Requested : exception;
165
Command_Line_Error : exception;
166
No_Tree_File : exception;
168
Asis_Context : Asis.Context;
169
Asis_Unit : Asis.Compilation_Unit;
170
Tree_Dirs : ASU.Unbounded_String;
171
Src_Dirs : ASU.Unbounded_String;
172
O_Option_Set : Boolean := False;
174
Has_Project : Boolean := False;
175
Project_File : ASU.Unbounded_String;
177
Pass_On_Options : ASU.Unbounded_String;
179
Print_Src_Names : Boolean := False;
181
type File_Ptr is access Ada.Text_IO.File_Type;
183
Src_Files : File_Ptr;
185
Tree_File_Name : ASU.Unbounded_String;
187
Transitive_Closure : Boolean := False;
188
Generate_Index : Boolean := False;
190
General_Context_Tried : Boolean := False;
191
General_Context_Open : Boolean := False;
193
type Printer_Kinds is
194
(HTML_Printer, XML_Printer, DocBook_Printer);
196
type Printer_Set is array (Printer_Kinds) of Boolean;
198
Enabled_Printers : Printer_Set := (others => False);
200
The_Printer : AD.Printers.Printer_Ref := null;
202
Version : constant String :=
203
AD.Version.Get_Version & AD.Projects.Project_Version &
204
" (" & AD.Version.Time & " / " & AD.Version.Get_Asis_Version & ')';
206
package Handled_Units is
217
package body Handled_Units is separate;
219
procedure Handle_Command_Line
222
use Ada.Command_Line;
224
procedure Check_Following
225
(Curr, Last : in Natural;
230
Error (Name & " option must be followed by something.");
231
raise Command_Line_Error;
236
(Idx : in AIC.Index_Type;
238
Curr : in out Natural)
241
AIC.Enter_Index (Idx);
244
Next : constant String := Argument (Curr + 1);
246
if Next = "-" or else Next (Next'First) /= '-' then
248
AIC.Set_File_Name (Idx, Next);
254
function Quote_If_Needed
259
if S'Length = 0 or else -- Empty string OR
260
S (S'First) = '"' or else -- Already quoted OR
261
Util.Strings.Next_Blank (S) = 0 -- No blanks
265
return Util.Strings.Quote (S, '"', '\');
268
procedure Handle_External_Variable_Assignment
272
if S'Length <= 1 or else
275
AD.Environment.Add (S);
277
if S (S'Last) /= '"' then
278
-- Missing final quote?
279
Error ("Unterminated quote in -X option: " & S);
280
raise Command_Line_Error;
283
(Util.Strings.Unquote (S (S'First + 1 .. S'Last - 1), '"', '\'));
286
when AD.Environment.Invalid_Variable_Assignment =>
287
Error ("Invalid -X option: " & S);
288
raise Command_Line_Error;
289
end Handle_External_Variable_Assignment;
291
procedure Add_Directory
292
(Flags : in out ASU.Unbounded_String;
297
Dir : constant String := Canonical (Path);
299
if not AD.File_Ops.Is_Directory (Dir) then
300
Error (Dir & " is an invalid directory (" & Flag & ')');
301
raise Command_Line_Error;
304
ASU.Append (Flags, ' ' & Quote_If_Needed (Flag & Dir));
306
ASU.Append (Flags, ' ' & Flag & Dir);
310
F_Input : ASU.Unbounded_String;
311
File_Name_Set : Boolean := False;
313
Print_Version : Boolean := False;
315
N : constant Natural := Argument_Count;
317
-- Used to pass to 'Set_Index' in palce of 'Curr' to suppress the
318
-- setting of the file name.
321
if N = 0 then raise Help_Requested; end if;
325
S : constant String := Argument (I);
327
if S = "-h" or else S = "-?" or else
328
S = "-help" or else S = "--help"
330
raise Help_Requested;
333
Check_Following (I, N, S);
336
Next : constant String := To_Lower (Argument (I));
338
if Next = "html" then
339
Enabled_Printers (HTML_Printer) := True;
340
elsif Next = "xml" then
341
Enabled_Printers (XML_Printer) := True;
342
-- elsif Next = "docbook" then
343
-- Enabled_Printers (DocBook_Printer) := True;
352
AD.Crossrefs.Set_Standard_Units (True);
354
AD.Printers.Set_Line_Only;
355
elsif S = "-v" or else S = "-version" or else S = "--version" then
356
Print_Version := True;
359
Check_Following (I, N, S);
361
Error ("only one -o option may be given.");
362
raise Command_Line_Error;
364
AD.Options.Set_Output_Name (Canonical (Argument (I)));
365
O_Option_Set := True;
366
elsif S'Length > 2 and then
367
S (S'First .. S'First + 1) = "-o"
370
Error ("only one -o option may be given.");
371
raise Command_Line_Error;
373
AD.Options.Set_Output_Name
374
(Canonical (S (S'First + 2 .. S'Last)));
375
O_Option_Set := True;
378
Check_Following (I, N, S);
379
if File_Name_Set then
380
Warn ("Input already set; " &
381
"ignoring option: " & S & ' ' & Argument (I));
384
ASU.To_Unbounded_String
385
(Canonical (Argument (I)));
386
File_Name_Set := True;
388
elsif S'Length > 2 and then
389
S (S'First .. S'First + 1) = "-f"
391
if File_Name_Set then
392
Warn ("Input already set; ignoring option: " & S);
395
ASU.To_Unbounded_String
396
(Canonical (S (S'First + 2 .. S'Last)));
397
File_Name_Set := True;
401
Check_Following (I, N, S);
402
AD.Config.Configure (Canonical (Argument (I)));
403
elsif S'Length > 2 and then
404
S (S'First .. S'First + 1) = "-c"
406
AD.Config.Configure (Canonical (S (S'First + 2 .. S'Last)));
408
AD.Messages.Set_Mode (AD.Messages.Only_Errors);
409
elsif S'Length = 3 and then
410
S (S'First .. S'First + 1) = "-w"
412
case S (S'First + 2) is
414
AD.Messages.Set_Mode (AD.Messages.Only_Errors);
416
AD.Messages.Set_Mode (AD.Messages.Errors_And_Warnings);
417
when '2' | 'a' | 'i' =>
418
AD.Messages.Set_Mode (AD.Messages.All_Messages);
420
AD.Messages.Set_Mode (AD.Messages.Including_Debug);
421
AD.Messages.Debug ("Debug messages activated!");
423
Error ("unknown warning level on command line.");
424
raise Command_Line_Error;
428
Check_Following (I, N, S);
429
AD.HTML.Set_Style_Sheet (Argument (I));
430
elsif S'Length > 2 and then
431
S (S'First .. S'First + 1) = "-s"
433
AD.HTML.Set_Style_Sheet (S (S'First + 2 .. S'Last));
435
Set_Index (AIC.Unit_Index, N, I);
436
AIC.Set_Structured (AIC.Unit_Index, True);
437
elsif S'Length > 3 and then
438
S (S'First .. S'First + 2) = "-is"
440
Set_Index (AIC.Unit_Index, N, Max);
441
AIC.Set_Structured (AIC.Unit_Index, True);
443
(AIC.Unit_Index, Canonical (S (S'First + 3 .. S'Last)));
445
Set_Index (AIC.Unit_Index, N, I);
446
AIC.Set_Structured (AIC.Unit_Index, False);
447
elsif S'Length > 2 and then
448
S (S'First .. S'First + 1) = "-i"
450
Set_Index (AIC.Unit_Index, N, Max);
451
AIC.Set_Structured (AIC.Unit_Index, False);
453
(AIC.Unit_Index, Canonical (S (S'First + 2 .. S'Last)));
455
Set_Index (AIC.Type_Index, N, I);
456
elsif S'Length > 2 and then
457
S (S'First .. S'First + 1) = "-t"
459
Set_Index (AIC.Type_Index, N, Max);
461
(AIC.Type_Index, Canonical (S (S'First + 2 .. S'Last)));
462
elsif S = "-private" or else S = "--private" then
463
AD.Options.Set_Private_Too (True);
465
Set_Index (AIC.Subprogram_Index, N, I);
466
elsif S'Length > 2 and then
467
S (S'First .. S'First + 1) = "-p"
469
Set_Index (AIC.Subprogram_Index, N, Max);
471
(AIC.Subprogram_Index, Canonical (S (S'First + 2 .. S'Last)));
474
Check_Following (I, N, S);
476
Error ("only one -P option may be given.");
477
raise Command_Line_Error;
481
ASU.To_Unbounded_String (Canonical (Argument (I)));
482
elsif S'Length > 2 and then
483
S (S'First .. S'First + 1) = "-P"
486
Error ("only one -P option may be given.");
487
raise Command_Line_Error;
491
ASU.To_Unbounded_String
492
(Canonical (S (S'First + 2 .. S'Last)));
494
-- External variable assignment. Applies to project files
495
-- *and* to AdaBrowse config files subsequently read.
496
-- Syntax: -X name=value or -X "name = value".
498
Check_Following (I, N, S);
499
Handle_External_Variable_Assignment (Argument (I));
500
ASU.Append (Pass_On_Options, " -X" &
501
Quote_If_Needed (Argument (I)));
502
elsif S'Length > 2 and then
503
S (S'First .. S'First + 1) = "-X"
505
Handle_External_Variable_Assignment (S (S'First + 2 .. S'Last));
506
ASU.Append (Pass_On_Options, " -X" &
507
Quote_If_Needed (S (S'First + 2 .. S'Last)));
508
elsif S = "-a" or else S = "-all" or else S = "--all" then
509
Transitive_Closure := True;
511
AD.Options.Set_Overwrite (False);
515
Check_Following (I, N, S);
516
if Next_Blank (Argument (I)) /= 0 then
517
Error ("Directories for the -T option must not contain " &
518
"white space; option = " &
519
S & " """ & Argument (I) & '"');
520
raise Command_Line_Error;
522
Add_Directory (Tree_Dirs, "-T", Argument (I), False);
523
elsif S'Length > 2 and then
524
S (S'First .. S'First + 1) = "-T"
527
if Next_Blank (S) /= 0 then
528
Error ("Directories for the -T option must not contain " &
529
"white space; option = " & S);
530
raise Command_Line_Error;
533
(Tree_Dirs, "-T", S (S'First + 2 .. S'Last), False);
537
Check_Following (I, N, S);
538
Add_Directory (Src_Dirs, "-I", Argument (I), True);
539
elsif S'Length > 2 and then
540
S (S'First .. S'First + 1) = "-I"
543
Add_Directory (Src_Dirs, "-I", S (S'First + 2 .. S'Last), True);
545
Error ("Unknown command-line option: " & S);
546
raise Command_Line_Error;
551
if Print_Version then
552
Put_Line (Current_Error,
553
"AdaBrowse " & Version &
554
"; Copyright (c) 2002, 2003 by Thomas Wolf");
562
AD.Projects.Handle_Project_File (ASU.To_String (Project_File));
564
when E : AD.Projects.Project_Error =>
565
Error (Ada.Exceptions.Exception_Message (E));
566
raise Command_Line_Error;
569
Generate_Index := AD.Indices.Has_Indices;
570
if File_Name_Set then
571
AD.Parameters.Set_Input (ASU.To_String (F_Input));
573
if not Has_Project then
574
Error ("No input file name! " &
575
"(At least one of -f or -P must be given.)");
576
raise Command_Line_Error;
578
Info ("Processing all sources in project '" &
579
ASU.To_String (Project_File) & ''');
580
Print_Src_Names := True;
581
Src_Files := new Ada.Text_IO.File_Type;
582
Ada.Text_IO.Create (Src_Files.all, Ada.Text_IO.Out_File);
583
AD.Projects.Get_Source_File_List (Src_Files.all);
584
Ada.Text_IO.Reset (Src_Files.all, Ada.Text_IO.In_File);
585
AD.Parameters.Set_Input
586
(Ada.Text_IO.File_Access'(Src_Files.all'Unchecked_Access));
587
-- Actually, I think plain 'Access should work just as well,
588
-- but unfortunately GNAT 3.15p complains.
591
if Has_Project and then not O_Option_Set then
593
Target : constant String :=
594
AD.Projects.Get_Output_Directory;
596
if Target'Length > 0 then
597
Info ("Output goes to " & Target);
598
if Util.Pathes.Name (Target)'Length > 0 then
599
AD.Options.Set_Output_Name
600
(Target & Util.Pathes.Directory_Separator);
602
AD.Options.Set_Output_Name (Target);
604
O_Option_Set := True;
608
if Generate_Index then
609
if not AD.Parameters.Is_File and then not Transitive_Closure then
610
Warn ("Index generation is only active if AdaBrowse is supposed " &
611
"to process more than one unit. " &
612
"(-f- or -f @file_name or -a or -P project_file)");
613
Generate_Index := False;
614
elsif AD.Options.Output_Name = "-" then
615
Warn ("Index generation turned off because output goes to " &
616
"stdout. (-o- was given.)");
617
Generate_Index := False;
620
-- Find out how many printers are enabled.
622
Nof_Printers : Natural := 0;
624
for I in Enabled_Printers'Range loop
625
if Enabled_Printers (I) then
626
Nof_Printers := Nof_Printers + 1;
629
if Nof_Printers = 0 then
630
-- If no "-G" option was given, enable the HTML printer by
633
Enabled_Printers (HTML_Printer) := True;
635
if AD.Options.Output_Name = "-" and then Nof_Printers > 1 then
636
Error ("Output must not go to stdout if more than one output " &
637
"format is enabled (-G option).");
638
raise Command_Line_Error;
640
if AD.Parameters.Is_File or else Nof_Printers > 1 or else
643
AD.Options.Set_Processing_Mode (AD.Options.Multiple_Files);
645
AD.Options.Set_Processing_Mode (AD.Options.Single_File);
650
Prj_Tree_Dir : constant String := AD.Projects.Get_Tree_Directory;
652
if Prj_Tree_Dir'Last >= Prj_Tree_Dir'First then
653
ASU.Append (Tree_Dirs, " -T" & Prj_Tree_Dir);
656
("Tree directory is " & Prj_Tree_Dir);
658
-- We have to change the compile command to ensure that the project
659
-- file gets passed along and the compiler thus has the environment
660
-- it needs (configuration pragmas, naming schemes, etc.)
661
-- Note: we also pass on -X options!
662
AD.Compiler.Set_Compile_Command
663
("gnat compile -c -gnatc -gnatt -P" &
664
AD.Projects.Get_Project_File_Name &
665
ASU.To_String (Pass_On_Options));
668
when Command_Line_Error =>
669
-- Check if there's a help option somewhere. If so, translate this
670
-- into a Help_Requested. (This allows the user to simply re-use a
671
-- command that previously terminated with a Command_Line_Error with
672
-- an additional help option at the end to get the help. I find this
673
-- personally useful because it saves typing; since most command
674
-- shells support a "command history", I can get the help by typing
675
-- <UP-ARROW> -?<RETURN>, which is way faster than having to type
676
-- adabrowse -?<RETURN>.)
678
-- We failed on argument I, so we only need to check the remaining
682
S : constant String := Argument (I);
684
exit when S = "-?" or else S = "-h" or else
685
S = "-help" or else S = "--help";
690
raise Help_Requested;
694
end Handle_Command_Line;
697
(Debug_Only : Boolean := False)
699
use type AD.Messages.Verbosity;
701
if not Debug_Only or else
702
AD.Messages.Get_Mode = AD.Messages.Including_Debug
704
Put_Line (Current_Error,
705
"*** Please report this error to " &
706
AD.Version.Get_Maintainer &
707
", giving the AdaBrowse version,");
708
Put_Line (Current_Error,
709
"host environment, GNAT version, and all input files" &
710
" (Ada sources, style sheets ");
711
Put_Line (Current_Error,
712
"and configuration files).");
713
Put_Line (Current_Error,
714
"This is AdaBrowse " & Version &
715
"; Copyright (c) 2002, 2003 by Thomas Wolf");
719
procedure Report_No_GNATC
720
(E : in Ada.Exceptions.Exception_Occurrence;
721
Asis_Info : in String)
724
Error ("Fatal ASIS failure. It seems like some tree files have");
725
Error ("been compiled with only ""-gnatt"" (no ""-gnatc"").");
726
Error ("Verify this, and if the error doesn't go away, re-run");
727
Error ("AdaBrowse with the ""-wD"" option to get more information.");
728
Debug (Ada.Exceptions.Exception_Information (E));
730
Report (Debug_Only => True);
735
-- Call the compiler (if any) to try to recreate the ASIS-information.
736
-- Raises 'No_Tree' if a compilation command is set, but fails. If
737
-- no compilation command is defined, nothing at all happens. Assumes
738
-- 'Asis_Context' to be closed upon entry and, if compilation was
739
-- successful, tries to open it.
740
-- Hmmm... what happens here if the command reads from stdin, or
741
-- does not return? For the time being, we just assume that compilers
742
-- don't do such nasty things!
743
Ok : Boolean := False;
745
if AD.Compiler.Get_Compile_Command /= "" then
746
Info ("Trying to recompile """ & AD.Parameters.Source_Name & """...");
747
AD.Compiler.Create_Unit
749
(AD.Parameters.Path, AD.Parameters.Source_Name),
750
Src_Dirs, Tree_Dirs, Tree_File_Name, Ok);
752
Info ("Recompilation of """ & AD.Parameters.Source_Name &
753
""" was successful.");
754
-- Success! Re-open the context and try again.
755
Asis.Ada_Environments.Associate
756
(The_Context => Asis_Context,
757
Name => "AdaBrowse_Context",
758
Parameters => To_Wide_String ("-C1 -FT -SA -T. " &
759
ASU.To_String (Tree_File_Name)));
760
Asis.Ada_Environments.Open (Asis_Context);
767
procedure Transform_Unit
768
(Unit : in Asis.Compilation_Unit)
771
AD.Scanner.Scan (Unit, The_Printer);
772
AD.User_Tags.Reset_Tags;
776
Asis.Ada_Environments.Close (Asis_Context);
777
Asis.Ada_Environments.Dissociate (Asis_Context);
778
Asis.Implementation.Finalize ("");
786
procedure Process_One_Unit
792
if ASU.Length (Tree_File_Name) > 0 and then not Has_Project then
793
-- We created a tree file: try to delete it!
794
-- (But only if we're not working from a project file: project
795
-- files have a tree directory, and that's ours!)
797
ADT_Name : constant String := ASU.To_String (Tree_File_Name);
799
AD.File_Ops.Delete (ADT_Name);
800
-- And GNAT also creates a "*.ali" file...
802
(ADT_Name (ADT_Name'First .. ADT_Name'Last - 3) & "ali");
805
Tree_File_Name := ASU.Null_Unbounded_String;
808
-- Swallow the exception!
809
Tree_File_Name := ASU.Null_Unbounded_String;
812
Skip_Unit : exception;
814
use type Ada.Exceptions.Exception_Id;
817
if Handled_Units.Exists (AD.Parameters.Unit_Name) then return; end if;
818
if Print_Src_Names then
819
Info ("Processing file """ & AD.Parameters.Source_Name & '"');
821
-- Now try to open the Asis context. This is pretty complex. By default,
822
-- we use all tree files, but if ASIS detects an inconsistency, we first
823
-- need to hack around to properly detect that, then try to recompile
824
-- the given file, and finally re-open the context with options telling
825
-- ASIS to use only that new tree file.
829
Already_Tried_To_Create : Boolean := False;
833
if not General_Context_Tried then
834
General_Context_Tried := True;
835
Asis.Ada_Environments.Associate
836
(The_Context => Asis_Context,
837
Name => "AdaBrowse_Context",
838
Parameters => To_Wide_String
840
ASU.To_String (Tree_Dirs)));
841
-- use "-FM -SA" (generate tree files as needed)?
842
-- use "-I<dir>" (directories to search for sources)
843
-- use "-T<dir>" (directories to search for trees)
845
-- Default is "-CA -FT -SA" (all tree files found, no automatic
846
-- tree generation, use all sources for consistency checks).
848
-- Note that "-FM" requires "-SA"! Also note that it is
849
-- absolutely unclear what happens with any generated tree
850
-- files when the context is closed. Neither the ASIS-for-GNAT
851
-- RM nor the UG say whether or not these files are deleted
852
-- once the last context using them is closed... They also
853
-- don't say where these files are created: in the current
854
-- directory, in a directory given by a "-T" option, or in
855
-- the system's temporary directory? Probably in the current
856
-- directory, following the "gcc" command launched internally.
858
-- Note: for the time being, we do not use "-FM": some ASIS
859
-- queries (e.g. Corresponding_Children) are implemented only
862
Asis.Ada_Environments.Open (Asis_Context);
863
General_Context_Open := True;
864
elsif not General_Context_Open then
865
Already_Tried_To_Create := True;
869
when Asis.Exceptions.ASIS_Failed =>
870
if AD.Compiler.Get_Compile_Command = "" then
873
-- ASIS-for-GNAT specific!
875
Msg : constant String :=
876
Trim (To_String (Asis.Implementation.Diagnosis));
878
Index (Msg, " is inconsistent with a tree file");
881
I := Index (Msg, "does not exist");
884
-- It *is* indeed a source-vs-tree
887
-- Close the context again and try to recreate
888
-- the ASIS info and then re-open the context.
889
if Asis.Ada_Environments.Is_Open (Asis_Context) then
890
Asis.Ada_Environments.Close (Asis_Context);
892
Asis.Ada_Environments.Dissociate (Asis_Context);
893
General_Context_Open := False;
894
Already_Tried_To_Create := True;
903
Asis.Compilation_Units.Library_Unit_Declaration
904
(To_Wide_String (AD.Parameters.Unit_Name), Asis_Context);
906
if Asis.Compilation_Units.Is_Nil (Asis_Unit) then
907
-- Hmmm... might be a krunched file name: try to find the source
908
-- file, and extract the unit name from the source!
910
Full_Name : constant String :=
913
(AD.Parameters.Path, AD.Parameters.Source_Name),
916
if Full_Name'Last >= Full_Name'First then
918
True_Name : constant String :=
919
AD.Parse.Get_Unit_Name (Full_Name);
921
if True_Name'Last >= True_Name'First and then
922
To_Lower (True_Name) /=
923
To_Lower (AD.Parameters.Unit_Name)
925
if Handled_Units.Exists (True_Name) then
928
Info ("File """ & Full_Name &
929
""" contains a unit named """ & True_Name & '"');
930
AD.Parameters.Set_Unit_Name (True_Name);
932
Asis.Compilation_Units.Library_Unit_Declaration
933
(To_Wide_String (True_Name), Asis_Context);
940
if Asis.Compilation_Units.Is_Nil (Asis_Unit) and then
941
not (Already_Tried_To_Create) and then
942
AD.Compiler.Get_Compile_Command /= ""
944
-- Not found: Close the context again and then try to generate the
945
-- tree and re-open the context.
946
Asis.Ada_Environments.Close (Asis_Context);
947
Asis.Ada_Environments.Dissociate (Asis_Context);
948
Warn ("Couldn't find unit """ & AD.Parameters.Unit_Name &
949
""" in the library.");
950
General_Context_Open := False;
954
Asis.Compilation_Units.Library_Unit_Declaration
955
(To_Wide_String (AD.Parameters.Unit_Name), Asis_Context);
959
if Asis.Compilation_Units.Is_Nil (Asis_Unit) then
960
-- Still not found: abandon!
961
Asis.Ada_Environments.Close (Asis_Context);
962
Asis.Ada_Environments.Dissociate (Asis_Context);
963
raise Asis.Exceptions.ASIS_Inappropriate_Compilation_Unit;
968
Unit_Name : constant String :=
969
To_String (Asis2.Naming.Full_Unit_Name (Asis_Unit));
971
if not Handled_Units.Exists (Unit_Name) then
972
Handled_Units.Add (Unit_Name);
973
if AD.Exclusions.Is_Excluded (To_Lower (Unit_Name)) then
975
("There's an EXCLUDE key in some configuration file for " &
976
"the given unit """ & Unit_Name & """. Unit is skipped.");
979
Transform_Unit (Asis_Unit);
982
if AD.Exclusions.Is_Excluded (To_Lower (Unit_Name)) then
988
if Transitive_Closure then
991
All_Units : constant Asis.Compilation_Unit_List :=
992
AD.Queries.Get_Dependents (Asis_Unit);
994
for I in All_Units'Range loop
996
not Asis.Compilation_Units.Is_Equal (All_Units (I), Asis_Unit)
998
-- The "if" is just paranoia; I suppose we should never get
999
-- back the unit itself.
1001
Unit_Name : constant String :=
1002
To_String (Asis2.Naming.Full_Unit_Name (All_Units (I)));
1004
if not Handled_Units.Exists (Unit_Name) then
1005
Handled_Units.Add (Unit_Name);
1006
if AD.Exclusions.Skip (To_Lower (Unit_Name)) then
1008
("The unit """ & Unit_Name & """ is excluded" &
1009
" by an EXCLUDE or NO_XREF key in some" &
1010
" configuration file.");
1012
Transform_Unit (All_Units (I));
1018
end Generate_Closure;
1021
-- No exception: successful termination
1023
if not General_Context_Open and then
1024
Asis.Ada_Environments.Is_Open (Asis_Context)
1026
Asis.Ada_Environments.Close (Asis_Context);
1027
Asis.Ada_Environments.Dissociate (Asis_Context);
1033
if not General_Context_Open and then
1034
Asis.Ada_Environments.Is_Open (Asis_Context)
1036
Asis.Ada_Environments.Close (Asis_Context);
1037
Asis.Ada_Environments.Dissociate (Asis_Context);
1040
if Ada.Exceptions.Exception_Identity (E) /= Skip_Unit'Identity then
1043
end Process_One_Unit;
1047
ASIS_Version : constant String := AD.Version.Get_Asis_Version;
1048
Pattern_GNAT : constant String := "for GNAT";
1049
Pattern_Pro : constant String := "Pro";
1052
-- Search for "for GNAT", then skip blanks, then get a sequence of
1053
-- digits and periods.
1054
I := Util.Strings.First_Index (ASIS_Version, Pattern_GNAT);
1056
-- Not an ASIS-for-GNAT?
1057
Asis.Implementation.Initialize (Parameters => "");
1061
(ASIS_Version (I + Pattern_GNAT'Length .. ASIS_Version'Last));
1062
-- Some GNAT versions may have a version string "for GNAT Pro x.yy"!
1064
Is_Prefix (ASIS_Version (I .. ASIS_Version'Last), Pattern_Pro)
1068
(ASIS_Version (I + Pattern_Pro'Length .. ASIS_Version'Last));
1071
Major_Version : Natural := 3;
1072
Minor_Version : Natural := 15;
1074
if I /= 0 and then ACH.Is_Digit (ASIS_Version (I)) then
1075
Major_Version := Natural (Character'Pos (ASIS_Version (I)) -
1076
Character'Pos ('0'));
1078
if I <= ASIS_Version'Last and then ASIS_Version (I) = '.' then
1080
J : Natural := I + 1;
1082
while J <= ASIS_Version'Last and then
1083
ACH.Is_Digit (ASIS_Version (J))
1089
Natural'Value (ASIS_Version (I + 1 .. J - 1));
1094
if Major_Version < 3 or else
1095
(Major_Version = 3 and then Minor_Version <= 15)
1097
Asis.Implementation.Initialize (Parameters => "-ws");
1098
-- "-ws" means "suppress all warnings". In particular, we want
1099
-- to suppress the warnings about some body tree files not
1100
-- being present. As we process only specs, we don't care:
1101
-- the body trees needed for generic instantiations are
1102
-- included in the specs containing these instantiations
1105
-- Use from GNAT 3.16 on (3.16, 3.17, 5.00, ...)
1106
Asis.Implementation.Initialize (Parameters => "-ws -k -nbb");
1107
-- "-k" means keep going; never, ever make the program quit.
1108
-- Hey, it's awful library design if a library can force the
1109
-- program using it to quit. Sergey, you'd better undo that
1112
-- "-nbb" tells ASIS not to generate a GNAT-style bug-box on
1113
-- stderr, giving instructions how to submit a bug report to
1114
-- ACT. For heaven's sake, what kind of nonsense is this?! It's
1115
-- the application using ASIS-for-GNAT that has the sole right
1116
-- to decide what to do in the presence of fatal errors, such
1117
-- as bugs in ASIS. Maybe it can work around the bugs, or tell
1118
-- the users to submit bug reports somewhere else (e.g., to
1119
-- report them to me!).
1126
(Normal : in Boolean)
1129
if Asis.Ada_Environments.Is_Open (Asis_Context) then
1130
-- Must be the general context...
1131
Asis.Ada_Environments.Close (Asis_Context);
1132
Asis.Ada_Environments.Dissociate (Asis_Context);
1135
if Normal and then Generate_Index then
1136
AD.Indices.Write (The_Printer);
1139
AD.Parameters.Close;
1140
Asis.Implementation.Finalize ("");
1142
AD.Printers.Free (The_Printer);
1145
use type Ada.Text_IO.File_Access;
1148
new Ada.Unchecked_Deallocation
1149
(Ada.Text_IO.File_Type, File_Ptr);
1151
if Src_Files /= null then
1152
if Ada.Text_IO.Is_Open (Src_Files.all) then
1153
Ada.Text_IO.Close (Src_Files.all);
1160
AD.Projects.Reset (On_Error => False);
1161
Ada.Command_Line.Set_Exit_Status (Ada.Command_Line.Success);
1163
AD.Projects.Reset (On_Error => True);
1164
Ada.Command_Line.Set_Exit_Status (Ada.Command_Line.Failure);
1171
begin -- AdaBrowse Main routine
1173
AD.Crossrefs.Set_Standard_Units (False);
1175
AD.Projects.Initialize;
1177
Parse_Command_Line :
1181
Handle_Command_Line (Quit);
1183
Ada.Command_Line.Set_Exit_Status (Ada.Command_Line.Success);
1186
end Parse_Command_Line;
1188
AD.User_Tags.Verify;
1190
-- Set up the enabled printers.
1192
for I in Enabled_Printers'Range loop
1193
if Enabled_Printers (I) then
1195
when HTML_Printer =>
1197
The_Printer + Printer_Ref'(new AD.Printers.HTML.Printer);
1200
The_Printer + Printer_Ref'(new AD.Printers.XML.Printer);
1201
when DocBook_Printer =>
1203
-- The_Printer + new AD.Printers.DocBook_Printer;
1209
-- Now initialize Asis. This is highly GNAT-specific!
1213
-- Set up index management.
1215
if Generate_Index then
1221
-- Set the output directory.
1223
if AD.Options.Output_Directory = "" and then
1224
AD.Parameters.Path /= ""
1226
AD.Options.Set_Output_Directory (AD.Parameters.Path);
1229
-- Process the input files.
1233
exit when not AD.Parameters.Advance_Input;
1245
when E : AD.Printers.Open_Failed |
1246
AD.Printers.Cannot_Overwrite |
1247
AD.Config.Invalid_Config |
1248
AD.Parameters.Input_Error |
1249
AD.Filters.Recursive_Expansion =>
1250
Error (Ada.Exceptions.Exception_Message (E));
1252
when No_Tree_File =>
1254
("Couldn't find unit """ & AD.Parameters.Unit_Name &
1255
""" in the library.");
1256
if AD.Compiler.Get_Compile_Command /= "" then
1257
if Index (AD.Version.Get_Version, "GNAT") > 0 then
1258
Error ("Couldn't find nor generate a tree " &
1259
"file. Try generating one ");
1260
Error ("using the command """ & AD.Setup.GNAT_Name &
1261
" -c -gnatc -gnatt ...""");
1263
Error ("Couldn't generate the necessary info " &
1265
AD.Compiler.Get_Compile_Command &
1270
when Asis.Exceptions.ASIS_Inappropriate_Compilation_Unit =>
1271
Error ("Couldn't find unit """ & AD.Parameters.Unit_Name &
1272
""" in the library, or");
1273
Error ("the file """ & AD.Parameters.Source_Name &
1274
""" does not contain any Ada spec.");
1275
Put_Line (Current_Error,
1276
"Type ""adabrowse -?"" for more information.");
1278
when Command_Line_Error =>
1279
Put_Line (Current_Error,
1280
"Type ""adabrowse -?"" for more information.");
1282
when Help_Requested =>
1283
AD.Messages.Help_Text;
1288
Handled : Boolean := False;
1290
if Exception_Identity (E) =
1291
Asis.Exceptions.ASIS_Failed'Identity
1296
case Asis.Implementation.Status is
1297
when Asis.Errors.Use_Error |
1298
Obsolete_Reference_Error =>
1299
-- ASIS-for-GNAT specific!
1301
Msg : constant String :=
1304
(Asis.Implementation.Diagnosis));
1307
" is inconsistent with a tree file")
1312
elsif Index (Msg, "not compile-only") > 0 then
1314
Report_No_GNATC (E, Trim (Msg));
1318
when Parameter_Error =>
1322
(To_String (Asis.Implementation.Diagnosis)));
1324
when Not_Implemented_Error =>
1326
Error ("ASIS doesn't implement a query!");
1327
Error (Ada.Exceptions.Exception_Information (E));
1330
(To_String (Asis.Implementation.Diagnosis)));
1335
Msg : constant String :=
1336
To_String (Asis.Implementation.Diagnosis);
1339
(To_Lower (Msg), "constraint_error") > 0
1342
(To_Lower (Msg), "namet.adb") > 0)
1346
"internal_implementation_error") > 0
1349
(To_Lower (Msg), "a4g-contt-ut.adb") > 0)
1352
Report_No_GNATC (E, Trim (Msg));
1358
elsif Exception_Identity (E) = Program_Error'Identity then
1360
Msg : constant String := Exception_Message (E);
1362
if Is_Prefix (Msg, "Inconsistent versions") then
1367
"**** AdaBrowse has been compiled for " &
1368
AD.Version.Get_Asis_Version & ',');
1371
"but some tree file has been generated by " &
1372
"some other compiler.");
1375
"Make sure that the tree files are generated " &
1376
"by the compiler above,");
1379
"or rebuild AdaBrowse from the sources with " &
1380
"your other compiler.");
1385
Error ("An unexpected error occurred!");
1386
Error (Ada.Exceptions.Exception_Information (E));
1387
Error (Trim (To_String (Asis.Implementation.Diagnosis)));
1391
end Exception_Handler;