1 ------------------------------------------------------------------------------
3 -- GNAT COMPILER COMPONENTS --
10 -- Copyright (C) 2000-2002 Free Software Foundation, Inc. --
12 -- GNAT is free software; you can redistribute it and/or modify it under --
13 -- terms of the GNU General Public License as published by the Free Soft- --
14 -- ware Foundation; either version 2, or (at your option) any later ver- --
15 -- sion. GNAT is distributed in the hope that it will be useful, but WITH- --
16 -- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY --
17 -- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License --
18 -- for more details. You should have received a copy of the GNU General --
19 -- Public License distributed with GNAT; see file COPYING. If not, write --
20 -- to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, --
21 -- MA 02111-1307, USA. --
23 -- GNAT was originally developed by the GNAT team at New York University. --
24 -- It is now maintained by Ada Core Technologies Inc (http://www.gnat.com). --
26 ------------------------------------------------------------------------------
31 with Namet
; use Namet
;
32 with Osint
; use Osint
;
33 with Output
; use Output
;
34 with Prj
.Com
; use Prj
.Com
;
35 with Prj
.Env
; use Prj
.Env
;
36 with Prj
.Util
; use Prj
.Util
;
37 with Snames
; use Snames
;
38 with Stringt
; use Stringt
;
39 with Types
; use Types
;
41 with Ada
.Characters
.Handling
; use Ada
.Characters
.Handling
;
42 with Ada
.Strings
; use Ada
.Strings
;
43 with Ada
.Strings
.Fixed
; use Ada
.Strings
.Fixed
;
44 with Ada
.Strings
.Maps
.Constants
; use Ada
.Strings
.Maps
.Constants
;
46 with GNAT
.Case_Util
; use GNAT
.Case_Util
;
47 with GNAT
.Directory_Operations
; use GNAT
.Directory_Operations
;
48 with GNAT
.OS_Lib
; use GNAT
.OS_Lib
;
50 package body Prj
.Nmsc
is
52 Dir_Sep
: Character renames GNAT
.OS_Lib
.Directory_Separator
;
54 Error_Report
: Put_Line_Access
:= null;
55 Current_Project
: Project_Id
:= No_Project
;
57 procedure Check_Ada_Naming_Scheme
(Naming
: Naming_Data
);
58 -- Check that the package Naming is correct.
60 procedure Check_Ada_Name
63 -- Check that a name is a valid Ada unit name.
65 procedure Error_Msg
(Msg
: String; Flag_Location
: Source_Ptr
);
66 -- Output an error message. If Error_Report is null, simply call
67 -- Errout.Error_Msg. Otherwise, disregard Flag_Location and use
70 function Get_Name_String
(S
: String_Id
) return String;
71 -- Get the string from a String_Id
76 Unit_Name
: out Name_Id
;
77 Unit_Kind
: out Spec_Or_Body
;
78 Needs_Pragma
: out Boolean);
79 -- Find out, from a file name, the unit name, the unit kind and if a
80 -- specific SFN pragma is needed. If the file name corresponds to no
81 -- unit, then Unit_Name will be No_Name.
83 function Is_Illegal_Suffix
85 Dot_Replacement_Is_A_Single_Dot
: Boolean)
87 -- Returns True if the string Suffix cannot be used as
88 -- a spec suffix, a body suffix or a separate suffix.
90 procedure Record_Source
94 Data
: in out Project_Data
;
95 Location
: Source_Ptr
;
96 Current_Source
: in out String_List_Id
);
97 -- Put a unit in the list of units of a project, if the file name
98 -- corresponds to a valid unit name.
100 procedure Show_Source_Dirs
(Project
: Project_Id
);
101 -- List all the source directories of a project.
103 function Locate_Directory
107 -- Locate a directory.
108 -- Returns No_Name if directory does not exist.
110 function Path_Name_Of
111 (File_Name
: String_Id
;
114 -- Returns the path name of a (non project) file.
115 -- Returns an empty string if file cannot be found.
122 (Project
: Project_Id
;
123 Report_Error
: Put_Line_Access
)
126 Languages
: Variable_Value
:= Nil_Variable_Value
;
128 procedure Check_Unit_Names
(List
: Array_Element_Id
);
129 -- Check that a list of unit names contains only valid names.
131 procedure Find_Sources
;
132 -- Find all the sources in all of the source directories
135 procedure Get_Path_Name_And_Record_Source
137 Location
: Source_Ptr
;
138 Current_Source
: in out String_List_Id
);
139 -- Find the path name of a source in the source directories and
140 -- record the source, if found.
142 procedure Get_Sources_From_File
144 Location
: Source_Ptr
);
145 -- Get the sources of a project from a text file
147 ----------------------
148 -- Check_Unit_Names --
149 ----------------------
151 procedure Check_Unit_Names
(List
: Array_Element_Id
) is
152 Current
: Array_Element_Id
:= List
;
153 Element
: Array_Element
;
157 -- Loop through elements of the string list
159 while Current
/= No_Array_Element
loop
160 Element
:= Array_Elements
.Table
(Current
);
162 -- Check that it contains a valid unit name
164 Check_Ada_Name
(Element
.Index
, Unit_Name
);
166 if Unit_Name
= No_Name
then
167 Errout
.Error_Msg_Name_1
:= Element
.Index
;
169 ("{ is not a valid unit name.",
170 Element
.Value
.Location
);
173 if Current_Verbosity
= High
then
174 Write_Str
(" Body_Part (""");
175 Write_Str
(Get_Name_String
(Unit_Name
));
179 Element
.Index
:= Unit_Name
;
180 Array_Elements
.Table
(Current
) := Element
;
183 Current
:= Element
.Next
;
185 end Check_Unit_Names
;
191 procedure Find_Sources
is
192 Source_Dir
: String_List_Id
:= Data
.Source_Dirs
;
193 Element
: String_Element
;
195 Current_Source
: String_List_Id
:= Nil_String
;
198 if Current_Verbosity
= High
then
199 Write_Line
("Looking for sources:");
202 -- For each subdirectory
204 while Source_Dir
/= Nil_String
loop
206 Element
:= String_Elements
.Table
(Source_Dir
);
207 if Element
.Value
/= No_String
then
209 Source_Directory
: String
210 (1 .. Integer (String_Length
(Element
.Value
)));
212 String_To_Name_Buffer
(Element
.Value
);
213 Source_Directory
:= Name_Buffer
(1 .. Name_Len
);
214 if Current_Verbosity
= High
then
215 Write_Str
("Source_Dir = ");
216 Write_Line
(Source_Directory
);
219 -- We look to every entry in the source directory
221 Open
(Dir
, Source_Directory
);
224 Read
(Dir
, Name_Buffer
, Name_Len
);
226 if Current_Verbosity
= High
then
227 Write_Str
(" Checking ");
228 Write_Line
(Name_Buffer
(1 .. Name_Len
));
231 exit when Name_Len
= 0;
234 Path_Access
: constant GNAT
.OS_Lib
.String_Access
:=
236 (Name_Buffer
(1 .. Name_Len
),
243 -- If it is a regular file
245 if Path_Access
/= null then
246 File_Name
:= Name_Find
;
247 Name_Len
:= Path_Access
'Length;
248 Name_Buffer
(1 .. Name_Len
) := Path_Access
.all;
249 Path_Name
:= Name_Find
;
251 -- We attempt to register it as a source.
252 -- However, there is no error if the file
253 -- does not contain a valid source.
254 -- But there is an error if we have a
255 -- duplicate unit name.
258 (File_Name
=> File_Name
,
259 Path_Name
=> Path_Name
,
262 Location
=> No_Location
,
263 Current_Source
=> Current_Source
);
266 if Current_Verbosity
= High
then
268 (" Not a regular file.");
279 when Directory_Error
=>
283 Source_Dir
:= Element
.Next
;
286 if Current_Verbosity
= High
then
287 Write_Line
("end Looking for sources.");
290 -- If we have looked for sources and found none, then
291 -- it is an error. If a project is not supposed to contain
292 -- any source, then we never call Find_Sources.
294 if Current_Source
= Nil_String
then
295 Error_Msg
("there are no sources in this project",
300 -------------------------------------
301 -- Get_Path_Name_And_Record_Source --
302 -------------------------------------
304 procedure Get_Path_Name_And_Record_Source
306 Location
: Source_Ptr
;
307 Current_Source
: in out String_List_Id
)
309 Source_Dir
: String_List_Id
:= Data
.Source_Dirs
;
310 Element
: String_Element
;
311 Path_Name
: GNAT
.OS_Lib
.String_Access
;
315 Found
: Boolean := False;
316 Fname
: String := File_Name
;
319 Canonical_Case_File_Name
(Fname
);
320 Name_Len
:= Fname
'Length;
321 Name_Buffer
(1 .. Name_Len
) := Fname
;
324 if Current_Verbosity
= High
then
325 Write_Str
(" Checking """);
330 -- We look in all source directories for this file name
332 while Source_Dir
/= Nil_String
loop
333 Element
:= String_Elements
.Table
(Source_Dir
);
335 if Current_Verbosity
= High
then
337 Write_Str
(Get_Name_String
(Element
.Value
));
344 Get_Name_String
(Element
.Value
));
346 if Path_Name
/= null then
347 if Current_Verbosity
= High
then
351 Name_Len
:= Path_Name
'Length;
352 Name_Buffer
(1 .. Name_Len
) := Path_Name
.all;
355 -- Register the source if it is an Ada compilation unit..
362 Location
=> Location
,
363 Current_Source
=> Current_Source
);
368 if Current_Verbosity
= High
then
372 Source_Dir
:= Element
.Next
;
376 -- It is an error if a source file names in a source list or
377 -- in a source list file is not found.
380 Errout
.Error_Msg_Name_1
:= File
;
381 Error_Msg
("source file { cannot be found", Location
);
384 end Get_Path_Name_And_Record_Source
;
386 ---------------------------
387 -- Get_Sources_From_File --
388 ---------------------------
390 procedure Get_Sources_From_File
392 Location
: Source_Ptr
)
394 File
: Prj
.Util
.Text_File
;
395 Line
: String (1 .. 250);
397 Current_Source
: String_List_Id
:= Nil_String
;
400 if Current_Verbosity
= High
then
401 Write_Str
("Opening """);
408 Prj
.Util
.Open
(File
, Path
);
410 if not Prj
.Util
.Is_Valid
(File
) then
411 Error_Msg
("file does not exist", Location
);
413 while not Prj
.Util
.End_Of_File
(File
) loop
414 Prj
.Util
.Get_Line
(File
, Line
, Last
);
416 -- If the line is not empty and does not start with "--",
417 -- then it should contain a file name. However, if the
418 -- file name does not exist, it may be for another language
419 -- and we don't fail.
422 and then (Last
= 1 or else Line
(1 .. 2) /= "--")
424 Get_Path_Name_And_Record_Source
425 (File_Name
=> Line
(1 .. Last
),
426 Location
=> Location
,
427 Current_Source
=> Current_Source
);
431 Prj
.Util
.Close
(File
);
435 -- We should have found at least one source.
436 -- If not, report an error.
438 if Current_Source
= Nil_String
then
439 Error_Msg
("this project has no source", Location
);
441 end Get_Sources_From_File
;
443 -- Start of processing for Ada_Check
446 Language_Independent_Check
(Project
, Report_Error
);
448 Error_Report
:= Report_Error
;
449 Current_Project
:= Project
;
451 Data
:= Projects
.Table
(Project
);
452 Languages
:= Prj
.Util
.Value_Of
(Name_Languages
, Data
.Decl
.Attributes
);
454 Data
.Naming
.Current_Language
:= Name_Ada
;
455 Data
.Sources_Present
:= Data
.Source_Dirs
/= Nil_String
;
457 if not Languages
.Default
then
459 Current
: String_List_Id
:= Languages
.Values
;
460 Element
: String_Element
;
461 Ada_Found
: Boolean := False;
464 Look_For_Ada
: while Current
/= Nil_String
loop
465 Element
:= String_Elements
.Table
(Current
);
466 String_To_Name_Buffer
(Element
.Value
);
467 To_Lower
(Name_Buffer
(1 .. Name_Len
));
469 if Name_Buffer
(1 .. Name_Len
) = "ada" then
474 Current
:= Element
.Next
;
475 end loop Look_For_Ada
;
477 if not Ada_Found
then
479 -- Mark the project file as having no sources for Ada
481 Data
.Sources_Present
:= False;
487 Naming_Id
: constant Package_Id
:=
488 Util
.Value_Of
(Name_Naming
, Data
.Decl
.Packages
);
490 Naming
: Package_Element
;
493 -- If there is a package Naming, we will put in Data.Naming
494 -- what is in this package Naming.
496 if Naming_Id
/= No_Package
then
497 Naming
:= Packages
.Table
(Naming_Id
);
499 if Current_Verbosity
= High
then
500 Write_Line
("Checking ""Naming"" for Ada.");
504 Bodies
: constant Array_Element_Id
:=
506 (Name_Implementation
, Naming
.Decl
.Arrays
);
508 Specifications
: constant Array_Element_Id
:=
510 (Name_Specification
, Naming
.Decl
.Arrays
);
513 if Bodies
/= No_Array_Element
then
515 -- We have elements in the array Body_Part
517 if Current_Verbosity
= High
then
518 Write_Line
("Found Bodies.");
521 Data
.Naming
.Bodies
:= Bodies
;
522 Check_Unit_Names
(Bodies
);
525 if Current_Verbosity
= High
then
526 Write_Line
("No Bodies.");
530 if Specifications
/= No_Array_Element
then
532 -- We have elements in the array Specification
534 if Current_Verbosity
= High
then
535 Write_Line
("Found Specifications.");
538 Data
.Naming
.Specifications
:= Specifications
;
539 Check_Unit_Names
(Specifications
);
542 if Current_Verbosity
= High
then
543 Write_Line
("No Specifications.");
548 -- We are now checking if variables Dot_Replacement, Casing,
549 -- Specification_Append, Body_Append and/or Separate_Append
552 -- For each variable, if it does not exist, we do nothing,
553 -- because we already have the default.
555 -- Check Dot_Replacement
558 Dot_Replacement
: constant Variable_Value
:=
560 (Name_Dot_Replacement
,
561 Naming
.Decl
.Attributes
);
564 pragma Assert
(Dot_Replacement
.Kind
= Single
,
565 "Dot_Replacement is not a single string");
567 if not Dot_Replacement
.Default
then
569 String_To_Name_Buffer
(Dot_Replacement
.Value
);
572 Error_Msg
("Dot_Replacement cannot be empty",
573 Dot_Replacement
.Location
);
576 Canonical_Case_File_Name
(Name_Buffer
(1 .. Name_Len
));
577 Data
.Naming
.Dot_Replacement
:= Name_Find
;
578 Data
.Naming
.Dot_Repl_Loc
:= Dot_Replacement
.Location
;
585 if Current_Verbosity
= High
then
586 Write_Str
(" Dot_Replacement = """);
587 Write_Str
(Get_Name_String
(Data
.Naming
.Dot_Replacement
));
595 Casing_String
: constant Variable_Value
:=
596 Util
.Value_Of
(Name_Casing
, Naming
.Decl
.Attributes
);
599 pragma Assert
(Casing_String
.Kind
= Single
,
600 "Casing is not a single string");
602 if not Casing_String
.Default
then
604 Casing_Image
: constant String :=
605 Get_Name_String
(Casing_String
.Value
);
609 Casing
: constant Casing_Type
:=
610 Value
(Casing_Image
);
613 Data
.Naming
.Casing
:= Casing
;
617 when Constraint_Error
=>
618 if Casing_Image
'Length = 0 then
619 Error_Msg
("Casing cannot be an empty string",
620 Casing_String
.Location
);
623 Name_Len
:= Casing_Image
'Length;
624 Name_Buffer
(1 .. Name_Len
) := Casing_Image
;
625 Errout
.Error_Msg_Name_1
:= Name_Find
;
627 ("{ is not a correct Casing",
628 Casing_String
.Location
);
634 if Current_Verbosity
= High
then
635 Write_Str
(" Casing = ");
636 Write_Str
(Image
(Data
.Naming
.Casing
));
641 -- Check Specification_Suffix
644 Ada_Spec_Suffix
: constant Variable_Value
:=
647 In_Array
=> Data
.Naming
.Specification_Suffix
);
650 if Ada_Spec_Suffix
.Kind
= Single
651 and then String_Length
(Ada_Spec_Suffix
.Value
) /= 0
653 String_To_Name_Buffer
(Ada_Spec_Suffix
.Value
);
654 Data
.Naming
.Current_Spec_Suffix
:= Name_Find
;
655 Data
.Naming
.Spec_Suffix_Loc
:= Ada_Spec_Suffix
.Location
;
658 Data
.Naming
.Current_Spec_Suffix
:= Default_Ada_Spec_Suffix
;
662 if Current_Verbosity
= High
then
663 Write_Str
(" Specification_Suffix = """);
664 Write_Str
(Get_Name_String
(Data
.Naming
.Current_Spec_Suffix
));
669 -- Check Implementation_Suffix
672 Ada_Impl_Suffix
: constant Variable_Value
:=
675 In_Array
=> Data
.Naming
.Implementation_Suffix
);
678 if Ada_Impl_Suffix
.Kind
= Single
679 and then String_Length
(Ada_Impl_Suffix
.Value
) /= 0
681 String_To_Name_Buffer
(Ada_Impl_Suffix
.Value
);
682 Data
.Naming
.Current_Impl_Suffix
:= Name_Find
;
683 Data
.Naming
.Impl_Suffix_Loc
:= Ada_Impl_Suffix
.Location
;
686 Data
.Naming
.Current_Impl_Suffix
:= Default_Ada_Impl_Suffix
;
690 if Current_Verbosity
= High
then
691 Write_Str
(" Implementation_Suffix = """);
692 Write_Str
(Get_Name_String
(Data
.Naming
.Current_Impl_Suffix
));
697 -- Check Separate_Suffix
700 Ada_Sep_Suffix
: constant Variable_Value
:=
702 (Variable_Name
=> Name_Separate_Suffix
,
703 In_Variables
=> Naming
.Decl
.Attributes
);
705 if Ada_Sep_Suffix
.Default
then
706 Data
.Naming
.Separate_Suffix
:=
707 Data
.Naming
.Current_Impl_Suffix
;
710 String_To_Name_Buffer
(Ada_Sep_Suffix
.Value
);
713 Error_Msg
("Separate_Suffix cannot be empty",
714 Ada_Sep_Suffix
.Location
);
717 Data
.Naming
.Separate_Suffix
:= Name_Find
;
718 Data
.Naming
.Sep_Suffix_Loc
:= Ada_Sep_Suffix
.Location
;
725 if Current_Verbosity
= High
then
726 Write_Str
(" Separate_Suffix = """);
727 Write_Str
(Get_Name_String
(Data
.Naming
.Separate_Suffix
));
732 -- Check if Data.Naming is valid
734 Check_Ada_Naming_Scheme
(Data
.Naming
);
737 Data
.Naming
.Current_Spec_Suffix
:= Default_Ada_Spec_Suffix
;
738 Data
.Naming
.Current_Impl_Suffix
:= Default_Ada_Impl_Suffix
;
739 Data
.Naming
.Separate_Suffix
:= Default_Ada_Impl_Suffix
;
743 -- If we have source directories, then find the sources
745 if Data
.Sources_Present
then
746 if Data
.Source_Dirs
= Nil_String
then
747 Data
.Sources_Present
:= False;
751 Sources
: constant Variable_Value
:=
754 Data
.Decl
.Attributes
);
756 Source_List_File
: constant Variable_Value
:=
758 (Name_Source_List_File
,
759 Data
.Decl
.Attributes
);
763 (Sources
.Kind
= List
,
764 "Source_Files is not a list");
766 (Source_List_File
.Kind
= Single
,
767 "Source_List_File is not a single string");
769 if not Sources
.Default
then
770 if not Source_List_File
.Default
then
772 ("?both variables source_files and " &
773 "source_list_file are present",
774 Source_List_File
.Location
);
777 -- Sources is a list of file names
780 Current_Source
: String_List_Id
:= Nil_String
;
781 Current
: String_List_Id
:= Sources
.Values
;
782 Element
: String_Element
;
785 Data
.Sources_Present
:= Current
/= Nil_String
;
787 while Current
/= Nil_String
loop
788 Element
:= String_Elements
.Table
(Current
);
789 String_To_Name_Buffer
(Element
.Value
);
792 File_Name
: constant String :=
793 Name_Buffer
(1 .. Name_Len
);
796 Get_Path_Name_And_Record_Source
797 (File_Name
=> File_Name
,
798 Location
=> Element
.Location
,
799 Current_Source
=> Current_Source
);
800 Current
:= Element
.Next
;
805 -- No source_files specified.
806 -- We check Source_List_File has been specified.
808 elsif not Source_List_File
.Default
then
810 -- Source_List_File is the name of the file
811 -- that contains the source file names
814 Source_File_Path_Name
: constant String :=
816 (Source_List_File
.Value
,
820 if Source_File_Path_Name
'Length = 0 then
821 String_To_Name_Buffer
(Source_List_File
.Value
);
822 Errout
.Error_Msg_Name_1
:= Name_Find
;
824 ("file with sources { does not exist",
825 Source_List_File
.Location
);
828 Get_Sources_From_File
829 (Source_File_Path_Name
,
830 Source_List_File
.Location
);
835 -- Neither Source_Files nor Source_List_File has been
837 -- Find all the files that satisfy
838 -- the naming scheme in all the source directories.
846 Projects
.Table
(Project
) := Data
;
853 procedure Check_Ada_Name
857 The_Name
: String := Get_Name_String
(Name
);
858 Need_Letter
: Boolean := True;
859 Last_Underscore
: Boolean := False;
860 OK
: Boolean := The_Name
'Length > 0;
863 for Index
in The_Name
'Range loop
866 -- We need a letter (at the beginning, and following a dot),
867 -- but we don't have one.
869 if Is_Letter
(The_Name
(Index
)) then
870 Need_Letter
:= False;
875 if Current_Verbosity
= High
then
876 Write_Int
(Types
.Int
(Index
));
878 Write_Char
(The_Name
(Index
));
879 Write_Line
("' is not a letter.");
885 elsif Last_Underscore
886 and then (The_Name
(Index
) = '_' or else The_Name
(Index
) = '.')
888 -- Two underscores are illegal, and a dot cannot follow
893 if Current_Verbosity
= High
then
894 Write_Int
(Types
.Int
(Index
));
896 Write_Char
(The_Name
(Index
));
897 Write_Line
("' is illegal here.");
902 elsif The_Name
(Index
) = '.' then
904 -- We need a letter after a dot
908 elsif The_Name
(Index
) = '_' then
909 Last_Underscore
:= True;
912 -- We need an letter or a digit
914 Last_Underscore
:= False;
916 if not Is_Alphanumeric
(The_Name
(Index
)) then
919 if Current_Verbosity
= High
then
920 Write_Int
(Types
.Int
(Index
));
922 Write_Char
(The_Name
(Index
));
923 Write_Line
("' is not alphanumeric.");
931 -- Cannot end with an underscore or a dot
933 OK
:= OK
and then not Need_Letter
and then not Last_Underscore
;
938 -- Signal a problem with No_Name
944 -----------------------------
945 -- Check_Ada_Naming_Scheme --
946 -----------------------------
948 procedure Check_Ada_Naming_Scheme
(Naming
: Naming_Data
) is
950 -- Only check if we are not using the standard naming scheme
952 if Naming
/= Standard_Naming_Data
then
954 Dot_Replacement
: constant String :=
956 (Naming
.Dot_Replacement
);
958 Specification_Suffix
: constant String :=
960 (Naming
.Current_Spec_Suffix
);
962 Implementation_Suffix
: constant String :=
964 (Naming
.Current_Impl_Suffix
);
966 Separate_Suffix
: constant String :=
968 (Naming
.Separate_Suffix
);
971 -- Dot_Replacement cannot
973 -- - start or end with an alphanumeric
975 -- - start with an '_' followed by an alphanumeric
976 -- - contain a '.' except if it is "."
978 if Dot_Replacement
'Length = 0
979 or else Is_Alphanumeric
980 (Dot_Replacement
(Dot_Replacement
'First))
981 or else Is_Alphanumeric
982 (Dot_Replacement
(Dot_Replacement
'Last))
983 or else (Dot_Replacement
(Dot_Replacement
'First) = '_'
985 (Dot_Replacement
'Length = 1
988 (Dot_Replacement
(Dot_Replacement
'First + 1))))
989 or else (Dot_Replacement
'Length > 1
991 Index
(Source
=> Dot_Replacement
,
992 Pattern
=> ".") /= 0)
995 ('"' & Dot_Replacement
&
996 """ is illegal for Dot_Replacement.",
997 Naming
.Dot_Repl_Loc
);
1002 -- - start with an alphanumeric
1003 -- - start with an '_' followed by an alphanumeric
1005 if Is_Illegal_Suffix
1006 (Specification_Suffix
, Dot_Replacement
= ".")
1008 Errout
.Error_Msg_Name_1
:= Naming
.Current_Spec_Suffix
;
1010 ("{ is illegal for Specification_Suffix",
1011 Naming
.Spec_Suffix_Loc
);
1014 if Is_Illegal_Suffix
1015 (Implementation_Suffix
, Dot_Replacement
= ".")
1017 Errout
.Error_Msg_Name_1
:= Naming
.Current_Impl_Suffix
;
1019 ("{ is illegal for Implementation_Suffix",
1020 Naming
.Impl_Suffix_Loc
);
1023 if Implementation_Suffix
/= Separate_Suffix
then
1024 if Is_Illegal_Suffix
1025 (Separate_Suffix
, Dot_Replacement
= ".")
1027 Errout
.Error_Msg_Name_1
:= Naming
.Separate_Suffix
;
1029 ("{ is illegal for Separate_Suffix",
1030 Naming
.Sep_Suffix_Loc
);
1034 -- Specification_Suffix cannot have the same termination as
1035 -- Implementation_Suffix or Separate_Suffix
1037 if Specification_Suffix
'Length <= Implementation_Suffix
'Length
1039 Implementation_Suffix
(Implementation_Suffix
'Last -
1040 Specification_Suffix
'Length + 1 ..
1041 Implementation_Suffix
'Last) = Specification_Suffix
1044 ("Implementation_Suffix (""" &
1045 Implementation_Suffix
&
1046 """) cannot end with" &
1047 "Specification_Suffix (""" &
1048 Specification_Suffix
& """).",
1049 Naming
.Impl_Suffix_Loc
);
1052 if Specification_Suffix
'Length <= Separate_Suffix
'Length
1055 (Separate_Suffix
'Last - Specification_Suffix
'Length + 1
1057 Separate_Suffix
'Last) = Specification_Suffix
1060 ("Separate_Suffix (""" &
1062 """) cannot end with" &
1063 " Specification_Suffix (""" &
1064 Specification_Suffix
& """).",
1065 Naming
.Sep_Suffix_Loc
);
1070 end Check_Ada_Naming_Scheme
;
1076 procedure Error_Msg
(Msg
: String; Flag_Location
: Source_Ptr
) is
1078 Error_Buffer
: String (1 .. 5_000
);
1079 Error_Last
: Natural := 0;
1080 Msg_Name
: Natural := 0;
1081 First
: Positive := Msg
'First;
1083 procedure Add
(C
: Character);
1084 -- Add a character to the buffer
1086 procedure Add
(S
: String);
1087 -- Add a string to the buffer
1089 procedure Add
(Id
: Name_Id
);
1090 -- Add a name to the buffer
1096 procedure Add
(C
: Character) is
1098 Error_Last
:= Error_Last
+ 1;
1099 Error_Buffer
(Error_Last
) := C
;
1102 procedure Add
(S
: String) is
1104 Error_Buffer
(Error_Last
+ 1 .. Error_Last
+ S
'Length) := S
;
1105 Error_Last
:= Error_Last
+ S
'Length;
1108 procedure Add
(Id
: Name_Id
) is
1110 Get_Name_String
(Id
);
1111 Add
(Name_Buffer
(1 .. Name_Len
));
1114 -- Start of processing for Error_Msg
1117 if Error_Report
= null then
1118 Errout
.Error_Msg
(Msg
, Flag_Location
);
1122 if Msg
(First
) = '\' then
1124 -- Continuation character, ignore.
1128 elsif Msg
(First
) = '?' then
1130 -- Warning character. It is always the first one,
1137 for Index
in First
.. Msg
'Last loop
1138 if Msg
(Index
) = '{' or else Msg
(Index
) = '%' then
1140 -- Include a name between double quotes.
1142 Msg_Name
:= Msg_Name
+ 1;
1146 when 1 => Add
(Errout
.Error_Msg_Name_1
);
1147 when 2 => Add
(Errout
.Error_Msg_Name_2
);
1148 when 3 => Add
(Errout
.Error_Msg_Name_3
);
1150 when others => null;
1161 Error_Report
(Error_Buffer
(1 .. Error_Last
), Current_Project
);
1164 ---------------------
1165 -- Get_Name_String --
1166 ---------------------
1168 function Get_Name_String
(S
: String_Id
) return String is
1170 if S
= No_String
then
1173 String_To_Name_Buffer
(S
);
1174 return Name_Buffer
(1 .. Name_Len
);
1176 end Get_Name_String
;
1183 (File_Name
: Name_Id
;
1184 Naming
: Naming_Data
;
1185 Unit_Name
: out Name_Id
;
1186 Unit_Kind
: out Spec_Or_Body
;
1187 Needs_Pragma
: out Boolean)
1189 Canonical_Case_Name
: Name_Id
;
1192 Needs_Pragma
:= False;
1193 Get_Name_String
(File_Name
);
1194 Canonical_Case_File_Name
(Name_Buffer
(1 .. Name_Len
));
1195 Canonical_Case_Name
:= Name_Find
;
1197 if Naming
.Bodies
/= No_Array_Element
then
1199 -- There are some specified file names for some bodies
1200 -- of this project. Find out if File_Name is one of these bodies.
1203 Current
: Array_Element_Id
:= Naming
.Bodies
;
1204 Element
: Array_Element
;
1207 while Current
/= No_Array_Element
loop
1208 Element
:= Array_Elements
.Table
(Current
);
1210 if Element
.Index
/= No_Name
then
1211 String_To_Name_Buffer
(Element
.Value
.Value
);
1212 Canonical_Case_File_Name
(Name_Buffer
(1 .. Name_Len
));
1214 if Canonical_Case_Name
= Name_Find
then
1216 -- File_Name corresponds to one body.
1217 -- So, we know it is a body, and we know the unit name.
1219 Unit_Kind
:= Body_Part
;
1220 Unit_Name
:= Element
.Index
;
1221 Needs_Pragma
:= True;
1226 Current
:= Element
.Next
;
1231 if Naming
.Specifications
/= No_Array_Element
then
1233 -- There are some specified file names for some bodiesspecifications
1234 -- of this project. Find out if File_Name is one of these
1238 Current
: Array_Element_Id
:= Naming
.Specifications
;
1239 Element
: Array_Element
;
1242 while Current
/= No_Array_Element
loop
1243 Element
:= Array_Elements
.Table
(Current
);
1245 if Element
.Index
/= No_Name
then
1246 String_To_Name_Buffer
(Element
.Value
.Value
);
1247 Canonical_Case_File_Name
(Name_Buffer
(1 .. Name_Len
));
1249 if Canonical_Case_Name
= Name_Find
then
1251 -- File_Name corresponds to one specification.
1252 -- So, we know it is a spec, and we know the unit name.
1254 Unit_Kind
:= Specification
;
1255 Unit_Name
:= Element
.Index
;
1256 Needs_Pragma
:= True;
1262 Current
:= Element
.Next
;
1268 File
: String := Get_Name_String
(Canonical_Case_Name
);
1269 First
: Positive := File
'First;
1270 Last
: Natural := File
'Last;
1272 Standard_GNAT
: Boolean :=
1273 Naming
.Current_Spec_Suffix
=
1274 Default_Ada_Spec_Suffix
1276 Naming
.Current_Impl_Suffix
=
1277 Default_Ada_Impl_Suffix
;
1280 -- Check if the end of the file name is Specification_Append
1282 Get_Name_String
(Naming
.Current_Spec_Suffix
);
1284 if File
'Length > Name_Len
1285 and then File
(Last
- Name_Len
+ 1 .. Last
) =
1286 Name_Buffer
(1 .. Name_Len
)
1290 Unit_Kind
:= Specification
;
1291 Last
:= Last
- Name_Len
;
1293 if Current_Verbosity
= High
then
1294 Write_Str
(" Specification: ");
1295 Write_Line
(File
(First
.. Last
));
1299 Get_Name_String
(Naming
.Current_Impl_Suffix
);
1301 -- Check if the end of the file name is Body_Append
1303 if File
'Length > Name_Len
1304 and then File
(Last
- Name_Len
+ 1 .. Last
) =
1305 Name_Buffer
(1 .. Name_Len
)
1309 Unit_Kind
:= Body_Part
;
1310 Last
:= Last
- Name_Len
;
1312 if Current_Verbosity
= High
then
1313 Write_Str
(" Body: ");
1314 Write_Line
(File
(First
.. Last
));
1317 elsif Naming
.Separate_Suffix
/= Naming
.Current_Spec_Suffix
then
1318 Get_Name_String
(Naming
.Separate_Suffix
);
1320 -- Check if the end of the file name is Separate_Append
1322 if File
'Length > Name_Len
1323 and then File
(Last
- Name_Len
+ 1 .. Last
) =
1324 Name_Buffer
(1 .. Name_Len
)
1326 -- We have a separate (a body)
1328 Unit_Kind
:= Body_Part
;
1329 Last
:= Last
- Name_Len
;
1331 if Current_Verbosity
= High
then
1332 Write_Str
(" Separate: ");
1333 Write_Line
(File
(First
.. Last
));
1347 -- This is not a source file
1349 Unit_Name
:= No_Name
;
1350 Unit_Kind
:= Specification
;
1352 if Current_Verbosity
= High
then
1353 Write_Line
(" Not a valid file name.");
1359 Get_Name_String
(Naming
.Dot_Replacement
);
1361 Standard_GNAT
and then Name_Buffer
(1 .. Name_Len
) = "-";
1363 if Name_Buffer
(1 .. Name_Len
) /= "." then
1365 -- If Dot_Replacement is not a single dot,
1366 -- then there should not be any dot in the name.
1368 for Index
in First
.. Last
loop
1369 if File
(Index
) = '.' then
1370 if Current_Verbosity
= High
then
1372 (" Not a valid file name (some dot not replaced).");
1375 Unit_Name
:= No_Name
;
1381 -- Replace the substring Dot_Replacement with dots
1384 Index
: Positive := First
;
1387 while Index
<= Last
- Name_Len
+ 1 loop
1389 if File
(Index
.. Index
+ Name_Len
- 1) =
1390 Name_Buffer
(1 .. Name_Len
)
1392 File
(Index
) := '.';
1394 if Name_Len
> 1 and then Index
< Last
then
1395 File
(Index
+ 1 .. Last
- Name_Len
+ 1) :=
1396 File
(Index
+ Name_Len
.. Last
);
1399 Last
:= Last
- Name_Len
+ 1;
1407 -- Check if the casing is right
1410 Src
: String := File
(First
.. Last
);
1413 case Naming
.Casing
is
1414 when All_Lower_Case
=>
1417 Mapping
=> Lower_Case_Map
);
1419 when All_Upper_Case
=>
1422 Mapping
=> Upper_Case_Map
);
1424 when Mixed_Case | Unknown
=>
1428 if Src
/= File
(First
.. Last
) then
1429 if Current_Verbosity
= High
then
1430 Write_Line
(" Not a valid file name (casing).");
1433 Unit_Name
:= No_Name
;
1437 -- We put the name in lower case
1441 Mapping
=> Lower_Case_Map
);
1443 -- In the standard GNAT naming scheme, check for special cases:
1444 -- children or separates of A, G, I or S, and run time sources.
1446 if Standard_GNAT
and then Src
'Length >= 3 then
1448 S1
: constant Character := Src
(Src
'First);
1449 S2
: constant Character := Src
(Src
'First + 1);
1452 if S1
= 'a' or else S1
= 'g'
1453 or else S1
= 'i' or else S1
= 's'
1455 -- Children or separates of packages A, G, I or S
1457 if (Hostparm
.OpenVMS
and then S2
= '$')
1458 or else (not Hostparm
.OpenVMS
and then S2
= '~')
1460 Src
(Src
'First + 1) := '.';
1462 -- If it is potentially a run time source, disable
1463 -- filling of the mapping file to avoid warnings.
1466 Set_Mapping_File_Initial_State_To_Empty
;
1473 if Current_Verbosity
= High
then
1478 Name_Len
:= Src
'Length;
1479 Name_Buffer
(1 .. Name_Len
) := Src
;
1481 -- Now, we check if this name is a valid unit name
1483 Check_Ada_Name
(Name
=> Name_Find
, Unit
=> Unit_Name
);
1490 -----------------------
1491 -- Is_Illegal_Suffix --
1492 -----------------------
1494 function Is_Illegal_Suffix
1496 Dot_Replacement_Is_A_Single_Dot
: Boolean)
1500 if Suffix
'Length = 0
1501 or else Is_Alphanumeric
(Suffix
(Suffix
'First))
1502 or else Index
(Suffix
, ".") = 0
1503 or else (Suffix
'Length >= 2
1504 and then Suffix
(Suffix
'First) = '_'
1505 and then Is_Alphanumeric
(Suffix
(Suffix
'First + 1)))
1510 -- If dot replacement is a single dot, and first character of
1511 -- suffix is also a dot
1513 if Dot_Replacement_Is_A_Single_Dot
1514 and then Suffix
(Suffix
'First) = '.'
1516 for Index
in Suffix
'First + 1 .. Suffix
'Last loop
1518 -- If there is another dot
1520 if Suffix
(Index
) = '.' then
1522 -- It is illegal to have a letter following the initial dot
1524 return Is_Letter
(Suffix
(Suffix
'First + 1));
1532 end Is_Illegal_Suffix
;
1534 --------------------------------
1535 -- Language_Independent_Check --
1536 --------------------------------
1538 procedure Language_Independent_Check
1539 (Project
: Project_Id
;
1540 Report_Error
: Put_Line_Access
)
1542 Last_Source_Dir
: String_List_Id
:= Nil_String
;
1543 Data
: Project_Data
:= Projects
.Table
(Project
);
1545 procedure Find_Source_Dirs
(From
: String_Id
; Location
: Source_Ptr
);
1546 -- Find one or several source directories, and add them
1547 -- to the list of source directories of the project.
1549 ----------------------
1550 -- Find_Source_Dirs --
1551 ----------------------
1553 procedure Find_Source_Dirs
(From
: String_Id
; Location
: Source_Ptr
) is
1555 Directory
: String (1 .. Integer (String_Length
(From
)));
1556 Directory_Id
: Name_Id
;
1557 Element
: String_Element
;
1559 procedure Recursive_Find_Dirs
(Path
: String_Id
);
1560 -- Find all the subdirectories (recursively) of Path
1561 -- and add them to the list of source directories
1564 -------------------------
1565 -- Recursive_Find_Dirs --
1566 -------------------------
1568 procedure Recursive_Find_Dirs
(Path
: String_Id
) is
1570 Name
: String (1 .. 250);
1572 The_Path
: String := Get_Name_String
(Path
) & Dir_Sep
;
1574 The_Path_Last
: Positive := The_Path
'Last;
1577 if The_Path
'Length > 1
1579 (The_Path
(The_Path_Last
- 1) = Dir_Sep
1580 or else The_Path
(The_Path_Last
- 1) = '/')
1582 The_Path_Last
:= The_Path_Last
- 1;
1585 Canonical_Case_File_Name
(The_Path
);
1587 if Current_Verbosity
= High
then
1589 Write_Line
(The_Path
(The_Path
'First .. The_Path_Last
));
1592 String_Elements
.Increment_Last
;
1595 Location
=> No_Location
,
1596 Next
=> Nil_String
);
1598 -- Case of first source directory
1600 if Last_Source_Dir
= Nil_String
then
1601 Data
.Source_Dirs
:= String_Elements
.Last
;
1603 -- Here we already have source directories.
1606 -- Link the previous last to the new one
1608 String_Elements
.Table
(Last_Source_Dir
).Next
:=
1609 String_Elements
.Last
;
1612 -- And register this source directory as the new last
1614 Last_Source_Dir
:= String_Elements
.Last
;
1615 String_Elements
.Table
(Last_Source_Dir
) := Element
;
1617 -- Now look for subdirectories
1619 Open
(Dir
, The_Path
(The_Path
'First .. The_Path_Last
));
1622 Read
(Dir
, Name
, Last
);
1625 if Current_Verbosity
= High
then
1626 Write_Str
(" Checking ");
1627 Write_Line
(Name
(1 .. Last
));
1630 if Name
(1 .. Last
) /= "."
1631 and then Name
(1 .. Last
) /= ".."
1636 Path_Name
: String :=
1637 The_Path
(The_Path
'First .. The_Path_Last
) &
1641 Canonical_Case_File_Name
(Path_Name
);
1643 if Is_Directory
(Path_Name
) then
1645 -- We have found a new subdirectory,
1646 -- register it and find its own subdirectories.
1649 Store_String_Chars
(Path_Name
);
1650 Recursive_Find_Dirs
(End_String
);
1659 when Directory_Error
=>
1661 end Recursive_Find_Dirs
;
1663 -- Start of processing for Find_Source_Dirs
1666 if Current_Verbosity
= High
then
1667 Write_Str
("Find_Source_Dirs (""");
1670 String_To_Name_Buffer
(From
);
1671 Canonical_Case_File_Name
(Name_Buffer
(1 .. Name_Len
));
1672 Directory
:= Name_Buffer
(1 .. Name_Len
);
1673 Directory_Id
:= Name_Find
;
1675 if Current_Verbosity
= High
then
1676 Write_Str
(Directory
);
1680 -- First, check if we are looking for a directory tree,
1681 -- indicated by "/**" at the end.
1683 if Directory
'Length >= 3
1684 and then Directory
(Directory
'Last - 1 .. Directory
'Last) = "**"
1685 and then (Directory
(Directory
'Last - 2) = '/'
1687 Directory
(Directory
'Last - 2) = Dir_Sep
)
1689 Name_Len
:= Directory
'Length - 3;
1691 if Name_Len
= 0 then
1692 -- This is the case of "/**": all directories
1693 -- in the file system.
1696 Name_Buffer
(1) := Directory
(Directory
'First);
1699 Name_Buffer
(1 .. Name_Len
) :=
1700 Directory
(Directory
'First .. Directory
'Last - 3);
1703 if Current_Verbosity
= High
then
1704 Write_Str
("Looking for all subdirectories of """);
1705 Write_Str
(Name_Buffer
(1 .. Name_Len
));
1710 Base_Dir
: constant Name_Id
:= Name_Find
;
1711 Root
: constant Name_Id
:=
1712 Locate_Directory
(Base_Dir
, Data
.Directory
);
1715 if Root
= No_Name
then
1716 Errout
.Error_Msg_Name_1
:= Base_Dir
;
1717 if Location
= No_Location
then
1718 Error_Msg
("{ is not a valid directory.", Data
.Location
);
1720 Error_Msg
("{ is not a valid directory.", Location
);
1724 -- We have an existing directory,
1725 -- we register it and all of its subdirectories.
1727 if Current_Verbosity
= High
then
1728 Write_Line
("Looking for source directories:");
1732 Store_String_Chars
(Get_Name_String
(Root
));
1733 Recursive_Find_Dirs
(End_String
);
1735 if Current_Verbosity
= High
then
1736 Write_Line
("End of looking for source directories.");
1741 -- We have a single directory
1745 Path_Name
: constant Name_Id
:=
1746 Locate_Directory
(Directory_Id
, Data
.Directory
);
1749 if Path_Name
= No_Name
then
1750 Errout
.Error_Msg_Name_1
:= Directory_Id
;
1751 if Location
= No_Location
then
1752 Error_Msg
("{ is not a valid directory", Data
.Location
);
1754 Error_Msg
("{ is not a valid directory", Location
);
1758 -- As it is an existing directory, we add it to
1759 -- the list of directories.
1761 String_Elements
.Increment_Last
;
1763 Store_String_Chars
(Get_Name_String
(Path_Name
));
1764 Element
.Value
:= End_String
;
1766 if Last_Source_Dir
= Nil_String
then
1768 -- This is the first source directory
1770 Data
.Source_Dirs
:= String_Elements
.Last
;
1773 -- We already have source directories,
1774 -- link the previous last to the new one.
1776 String_Elements
.Table
(Last_Source_Dir
).Next
:=
1777 String_Elements
.Last
;
1780 -- And register this source directory as the new last
1782 Last_Source_Dir
:= String_Elements
.Last
;
1783 String_Elements
.Table
(Last_Source_Dir
) := Element
;
1787 end Find_Source_Dirs
;
1789 -- Start of processing for Language_Independent_Check
1793 if Data
.Language_Independent_Checked
then
1797 Data
.Language_Independent_Checked
:= True;
1799 Error_Report
:= Report_Error
;
1801 if Current_Verbosity
= High
then
1802 Write_Line
("Starting to look for directories");
1805 -- Check the object directory
1808 Object_Dir
: Variable_Value
:=
1809 Util
.Value_Of
(Name_Object_Dir
, Data
.Decl
.Attributes
);
1812 pragma Assert
(Object_Dir
.Kind
= Single
,
1813 "Object_Dir is not a single string");
1815 -- We set the object directory to its default
1817 Data
.Object_Directory
:= Data
.Directory
;
1819 if not String_Equal
(Object_Dir
.Value
, Empty_String
) then
1821 String_To_Name_Buffer
(Object_Dir
.Value
);
1823 if Name_Len
= 0 then
1824 Error_Msg
("Object_Dir cannot be empty",
1825 Object_Dir
.Location
);
1828 -- We check that the specified object directory
1831 Canonical_Case_File_Name
(Name_Buffer
(1 .. Name_Len
));
1834 Dir_Id
: constant Name_Id
:= Name_Find
;
1837 Data
.Object_Directory
:=
1838 Locate_Directory
(Dir_Id
, Data
.Directory
);
1840 if Data
.Object_Directory
= No_Name
then
1841 Errout
.Error_Msg_Name_1
:= Dir_Id
;
1843 ("the object directory { cannot be found",
1851 if Current_Verbosity
= High
then
1852 if Data
.Object_Directory
= No_Name
then
1853 Write_Line
("No object directory");
1855 Write_Str
("Object directory: """);
1856 Write_Str
(Get_Name_String
(Data
.Object_Directory
));
1861 -- Check the exec directory
1864 Exec_Dir
: Variable_Value
:=
1865 Util
.Value_Of
(Name_Exec_Dir
, Data
.Decl
.Attributes
);
1868 pragma Assert
(Exec_Dir
.Kind
= Single
,
1869 "Exec_Dir is not a single string");
1871 -- We set the object directory to its default
1873 Data
.Exec_Directory
:= Data
.Object_Directory
;
1875 if not String_Equal
(Exec_Dir
.Value
, Empty_String
) then
1877 String_To_Name_Buffer
(Exec_Dir
.Value
);
1879 if Name_Len
= 0 then
1880 Error_Msg
("Exec_Dir cannot be empty",
1884 -- We check that the specified object directory
1887 Canonical_Case_File_Name
(Name_Buffer
(1 .. Name_Len
));
1890 Dir_Id
: constant Name_Id
:= Name_Find
;
1893 Data
.Exec_Directory
:=
1894 Locate_Directory
(Dir_Id
, Data
.Directory
);
1896 if Data
.Exec_Directory
= No_Name
then
1897 Errout
.Error_Msg_Name_1
:= Dir_Id
;
1899 ("the exec directory { cannot be found",
1907 if Current_Verbosity
= High
then
1908 if Data
.Exec_Directory
= No_Name
then
1909 Write_Line
("No exec directory");
1911 Write_Str
("Exec directory: """);
1912 Write_Str
(Get_Name_String
(Data
.Exec_Directory
));
1917 -- Look for the source directories
1920 Source_Dirs
: Variable_Value
:=
1921 Util
.Value_Of
(Name_Source_Dirs
, Data
.Decl
.Attributes
);
1925 if Current_Verbosity
= High
then
1926 Write_Line
("Starting to look for source directories");
1929 pragma Assert
(Source_Dirs
.Kind
= List
,
1930 "Source_Dirs is not a list");
1932 if Source_Dirs
.Default
then
1934 -- No Source_Dirs specified: the single source directory
1935 -- is the one containing the project file
1937 String_Elements
.Increment_Last
;
1938 Data
.Source_Dirs
:= String_Elements
.Last
;
1940 Store_String_Chars
(Get_Name_String
(Data
.Directory
));
1941 String_Elements
.Table
(Data
.Source_Dirs
) :=
1942 (Value
=> End_String
,
1943 Location
=> No_Location
,
1944 Next
=> Nil_String
);
1946 if Current_Verbosity
= High
then
1947 Write_Line
("(Undefined) Single object directory:");
1949 Write_Str
(Get_Name_String
(Data
.Directory
));
1953 elsif Source_Dirs
.Values
= Nil_String
then
1955 -- If Source_Dirs is an empty string list, this means
1956 -- that this project contains no source.
1958 if Data
.Object_Directory
= Data
.Directory
then
1959 Data
.Object_Directory
:= No_Name
;
1962 Data
.Source_Dirs
:= Nil_String
;
1963 Data
.Sources_Present
:= False;
1967 Source_Dir
: String_List_Id
:= Source_Dirs
.Values
;
1968 Element
: String_Element
;
1971 -- We will find the source directories for each
1972 -- element of the list
1974 while Source_Dir
/= Nil_String
loop
1975 Element
:= String_Elements
.Table
(Source_Dir
);
1976 Find_Source_Dirs
(Element
.Value
, Element
.Location
);
1977 Source_Dir
:= Element
.Next
;
1982 if Current_Verbosity
= High
then
1983 Write_Line
("Puting source directories in canonical cases");
1987 Current
: String_List_Id
:= Data
.Source_Dirs
;
1988 Element
: String_Element
;
1991 while Current
/= Nil_String
loop
1992 Element
:= String_Elements
.Table
(Current
);
1993 if Element
.Value
/= No_String
then
1994 String_To_Name_Buffer
(Element
.Value
);
1995 Canonical_Case_File_Name
(Name_Buffer
(1 .. Name_Len
));
1997 Store_String_Chars
(Name_Buffer
(1 .. Name_Len
));
1998 Element
.Value
:= End_String
;
1999 String_Elements
.Table
(Current
) := Element
;
2002 Current
:= Element
.Next
;
2007 -- Library Dir, Name, Version and Kind
2010 Attributes
: constant Prj
.Variable_Id
:= Data
.Decl
.Attributes
;
2012 Lib_Dir
: Prj
.Variable_Value
:=
2013 Prj
.Util
.Value_Of
(Snames
.Name_Library_Dir
, Attributes
);
2015 Lib_Name
: Prj
.Variable_Value
:=
2016 Prj
.Util
.Value_Of
(Snames
.Name_Library_Name
, Attributes
);
2018 Lib_Version
: Prj
.Variable_Value
:=
2020 (Snames
.Name_Library_Version
, Attributes
);
2022 The_Lib_Kind
: Prj
.Variable_Value
:=
2024 (Snames
.Name_Library_Kind
, Attributes
);
2027 pragma Assert
(Lib_Dir
.Kind
= Single
);
2029 if Lib_Dir
.Value
= Empty_String
then
2031 if Current_Verbosity
= High
then
2032 Write_Line
("No library directory");
2036 -- Find path name, check that it is a directory
2038 Stringt
.String_To_Name_Buffer
(Lib_Dir
.Value
);
2041 Dir_Id
: constant Name_Id
:= Name_Find
;
2045 Locate_Directory
(Dir_Id
, Data
.Directory
);
2047 if Data
.Library_Dir
= No_Name
then
2048 Error_Msg
("not an existing directory",
2051 elsif Data
.Library_Dir
= Data
.Object_Directory
then
2053 ("library directory cannot be the same " &
2054 "as object directory",
2056 Data
.Library_Dir
:= No_Name
;
2059 if Current_Verbosity
= High
then
2060 Write_Str
("Library directory =""");
2061 Write_Str
(Get_Name_String
(Data
.Library_Dir
));
2068 pragma Assert
(Lib_Name
.Kind
= Single
);
2070 if Lib_Name
.Value
= Empty_String
then
2071 if Current_Verbosity
= High
then
2072 Write_Line
("No library name");
2076 Stringt
.String_To_Name_Buffer
(Lib_Name
.Value
);
2078 if not Is_Letter
(Name_Buffer
(1)) then
2079 Error_Msg
("must start with a letter",
2083 Data
.Library_Name
:= Name_Find
;
2085 for Index
in 2 .. Name_Len
loop
2086 if not Is_Alphanumeric
(Name_Buffer
(Index
)) then
2087 Data
.Library_Name
:= No_Name
;
2088 Error_Msg
("only letters and digits are allowed",
2094 if Data
.Library_Name
/= No_Name
2095 and then Current_Verbosity
= High
then
2096 Write_Str
("Library name = """);
2097 Write_Str
(Get_Name_String
(Data
.Library_Name
));
2104 Data
.Library_Dir
/= No_Name
2106 Data
.Library_Name
/= No_Name
;
2108 if Data
.Library
then
2110 if not MLib
.Tgt
.Libraries_Are_Supported
then
2111 Error_Msg
("?libraries are not supported on this platform",
2113 Data
.Library
:= False;
2116 if Current_Verbosity
= High
then
2117 Write_Line
("This is a library project file");
2120 pragma Assert
(Lib_Version
.Kind
= Single
);
2122 if Lib_Version
.Value
= Empty_String
then
2123 if Current_Verbosity
= High
then
2124 Write_Line
("No library version specified");
2128 Stringt
.String_To_Name_Buffer
(Lib_Version
.Value
);
2129 Data
.Lib_Internal_Name
:= Name_Find
;
2132 pragma Assert
(The_Lib_Kind
.Kind
= Single
);
2134 if The_Lib_Kind
.Value
= Empty_String
then
2135 if Current_Verbosity
= High
then
2136 Write_Line
("No library kind specified");
2140 Stringt
.String_To_Name_Buffer
(The_Lib_Kind
.Value
);
2143 Kind_Name
: constant String :=
2144 To_Lower
(Name_Buffer
(1 .. Name_Len
));
2146 OK
: Boolean := True;
2149 if Kind_Name
= "static" then
2150 Data
.Library_Kind
:= Static
;
2152 elsif Kind_Name
= "dynamic" then
2153 Data
.Library_Kind
:= Dynamic
;
2155 elsif Kind_Name
= "relocatable" then
2156 Data
.Library_Kind
:= Relocatable
;
2160 ("illegal value for Library_Kind",
2161 The_Lib_Kind
.Location
);
2165 if Current_Verbosity
= High
and then OK
then
2166 Write_Str
("Library kind = ");
2167 Write_Line
(Kind_Name
);
2175 if Current_Verbosity
= High
then
2176 Show_Source_Dirs
(Project
);
2180 Naming_Id
: constant Package_Id
:=
2181 Util
.Value_Of
(Name_Naming
, Data
.Decl
.Packages
);
2183 Naming
: Package_Element
;
2186 -- If there is a package Naming, we will put in Data.Naming
2187 -- what is in this package Naming.
2189 if Naming_Id
/= No_Package
then
2190 Naming
:= Packages
.Table
(Naming_Id
);
2192 if Current_Verbosity
= High
then
2193 Write_Line
("Checking ""Naming"".");
2196 -- Check Specification_Suffix
2199 Spec_Suffixs
: Array_Element_Id
:=
2201 (Name_Specification_Suffix
,
2202 Naming
.Decl
.Arrays
);
2203 Suffix
: Array_Element_Id
;
2204 Element
: Array_Element
;
2205 Suffix2
: Array_Element_Id
;
2208 -- If some suffixs have been specified, we make sure that
2209 -- for each language for which a default suffix has been
2210 -- specified, there is a suffix specified, either the one
2211 -- in the project file or if there were noe, the default.
2213 if Spec_Suffixs
/= No_Array_Element
then
2214 Suffix
:= Data
.Naming
.Specification_Suffix
;
2216 while Suffix
/= No_Array_Element
loop
2217 Element
:= Array_Elements
.Table
(Suffix
);
2218 Suffix2
:= Spec_Suffixs
;
2220 while Suffix2
/= No_Array_Element
loop
2221 exit when Array_Elements
.Table
(Suffix2
).Index
=
2223 Suffix2
:= Array_Elements
.Table
(Suffix2
).Next
;
2226 -- There is a registered default suffix, but no
2227 -- suffix specified in the project file.
2228 -- Add the default to the array.
2230 if Suffix2
= No_Array_Element
then
2231 Array_Elements
.Increment_Last
;
2232 Array_Elements
.Table
(Array_Elements
.Last
) :=
2233 (Index
=> Element
.Index
,
2234 Value
=> Element
.Value
,
2235 Next
=> Spec_Suffixs
);
2236 Spec_Suffixs
:= Array_Elements
.Last
;
2239 Suffix
:= Element
.Next
;
2242 -- Put the resulting array as the specification suffixs
2244 Data
.Naming
.Specification_Suffix
:= Spec_Suffixs
;
2249 Current
: Array_Element_Id
:= Data
.Naming
.Specification_Suffix
;
2250 Element
: Array_Element
;
2253 while Current
/= No_Array_Element
loop
2254 Element
:= Array_Elements
.Table
(Current
);
2255 String_To_Name_Buffer
(Element
.Value
.Value
);
2257 if Name_Len
= 0 then
2259 ("Specification_Suffix cannot be empty",
2260 Element
.Value
.Location
);
2263 Array_Elements
.Table
(Current
) := Element
;
2264 Current
:= Element
.Next
;
2268 -- Check Implementation_Suffix
2271 Impl_Suffixs
: Array_Element_Id
:=
2273 (Name_Implementation_Suffix
,
2274 Naming
.Decl
.Arrays
);
2275 Suffix
: Array_Element_Id
;
2276 Element
: Array_Element
;
2277 Suffix2
: Array_Element_Id
;
2279 -- If some suffixs have been specified, we make sure that
2280 -- for each language for which a default suffix has been
2281 -- specified, there is a suffix specified, either the one
2282 -- in the project file or if there were noe, the default.
2284 if Impl_Suffixs
/= No_Array_Element
then
2285 Suffix
:= Data
.Naming
.Implementation_Suffix
;
2287 while Suffix
/= No_Array_Element
loop
2288 Element
:= Array_Elements
.Table
(Suffix
);
2289 Suffix2
:= Impl_Suffixs
;
2291 while Suffix2
/= No_Array_Element
loop
2292 exit when Array_Elements
.Table
(Suffix2
).Index
=
2294 Suffix2
:= Array_Elements
.Table
(Suffix2
).Next
;
2297 -- There is a registered default suffix, but no
2298 -- suffix specified in the project file.
2299 -- Add the default to the array.
2301 if Suffix2
= No_Array_Element
then
2302 Array_Elements
.Increment_Last
;
2303 Array_Elements
.Table
(Array_Elements
.Last
) :=
2304 (Index
=> Element
.Index
,
2305 Value
=> Element
.Value
,
2306 Next
=> Impl_Suffixs
);
2307 Impl_Suffixs
:= Array_Elements
.Last
;
2310 Suffix
:= Element
.Next
;
2313 -- Put the resulting array as the implementation suffixs
2315 Data
.Naming
.Implementation_Suffix
:= Impl_Suffixs
;
2320 Current
: Array_Element_Id
:= Data
.Naming
.Implementation_Suffix
;
2321 Element
: Array_Element
;
2324 while Current
/= No_Array_Element
loop
2325 Element
:= Array_Elements
.Table
(Current
);
2326 String_To_Name_Buffer
(Element
.Value
.Value
);
2328 if Name_Len
= 0 then
2330 ("Implementation_Suffix cannot be empty",
2331 Element
.Value
.Location
);
2334 Array_Elements
.Table
(Current
) := Element
;
2335 Current
:= Element
.Next
;
2339 -- Get the exceptions, if any
2341 Data
.Naming
.Specification_Exceptions
:=
2343 (Name_Specification_Exceptions
,
2344 In_Arrays
=> Naming
.Decl
.Arrays
);
2346 Data
.Naming
.Implementation_Exceptions
:=
2348 (Name_Implementation_Exceptions
,
2349 In_Arrays
=> Naming
.Decl
.Arrays
);
2353 Projects
.Table
(Project
) := Data
;
2354 end Language_Independent_Check
;
2356 ----------------------
2357 -- Locate_Directory --
2358 ----------------------
2360 function Locate_Directory
2365 The_Name
: constant String := Get_Name_String
(Name
);
2366 The_Parent
: constant String :=
2367 Get_Name_String
(Parent
) & Dir_Sep
;
2369 The_Parent_Last
: Positive := The_Parent
'Last;
2372 if The_Parent
'Length > 1
2373 and then (The_Parent
(The_Parent_Last
- 1) = Dir_Sep
2374 or else The_Parent
(The_Parent_Last
- 1) = '/')
2376 The_Parent_Last
:= The_Parent_Last
- 1;
2379 if Current_Verbosity
= High
then
2380 Write_Str
("Locate_Directory (""");
2381 Write_Str
(The_Name
);
2382 Write_Str
(""", """);
2383 Write_Str
(The_Parent
);
2387 if Is_Absolute_Path
(The_Name
) then
2388 if Is_Directory
(The_Name
) then
2394 Full_Path
: constant String :=
2395 The_Parent
(The_Parent
'First .. The_Parent_Last
) &
2399 if Is_Directory
(Full_Path
) then
2400 Name_Len
:= Full_Path
'Length;
2401 Name_Buffer
(1 .. Name_Len
) := Full_Path
;
2409 end Locate_Directory
;
2415 function Path_Name_Of
2416 (File_Name
: String_Id
;
2417 Directory
: Name_Id
)
2420 Result
: String_Access
;
2421 The_Directory
: constant String := Get_Name_String
(Directory
);
2424 String_To_Name_Buffer
(File_Name
);
2425 Result
:= Locate_Regular_File
2426 (File_Name
=> Name_Buffer
(1 .. Name_Len
),
2427 Path
=> The_Directory
);
2429 if Result
= null then
2432 Canonical_Case_File_Name
(Result
.all);
2441 procedure Record_Source
2442 (File_Name
: Name_Id
;
2443 Path_Name
: Name_Id
;
2444 Project
: Project_Id
;
2445 Data
: in out Project_Data
;
2446 Location
: Source_Ptr
;
2447 Current_Source
: in out String_List_Id
)
2449 Unit_Name
: Name_Id
;
2450 Unit_Kind
: Spec_Or_Body
;
2451 Needs_Pragma
: Boolean;
2452 The_Location
: Source_Ptr
:= Location
;
2455 -- Find out the unit name, the unit kind and if it needs
2456 -- a specific SFN pragma.
2459 (File_Name
=> File_Name
,
2460 Naming
=> Data
.Naming
,
2461 Unit_Name
=> Unit_Name
,
2462 Unit_Kind
=> Unit_Kind
,
2463 Needs_Pragma
=> Needs_Pragma
);
2465 if Unit_Name
= No_Name
then
2466 if Current_Verbosity
= High
then
2468 Write_Str
(Get_Name_String
(File_Name
));
2469 Write_Line
(""" is not a valid source file name (ignored).");
2473 -- Put the file name in the list of sources of the project
2475 String_Elements
.Increment_Last
;
2476 Get_Name_String
(File_Name
);
2478 Store_String_Chars
(Name_Buffer
(1 .. Name_Len
));
2479 String_Elements
.Table
(String_Elements
.Last
) :=
2480 (Value
=> End_String
,
2481 Location
=> No_Location
,
2482 Next
=> Nil_String
);
2484 if Current_Source
= Nil_String
then
2485 Data
.Sources
:= String_Elements
.Last
;
2488 String_Elements
.Table
(Current_Source
).Next
:=
2489 String_Elements
.Last
;
2492 Current_Source
:= String_Elements
.Last
;
2494 -- Put the unit in unit list
2497 The_Unit
: Unit_Id
:= Units_Htable
.Get
(Unit_Name
);
2498 The_Unit_Data
: Unit_Data
;
2501 if Current_Verbosity
= High
then
2502 Write_Str
("Putting ");
2503 Write_Str
(Get_Name_String
(Unit_Name
));
2504 Write_Line
(" in the unit list.");
2507 -- The unit is already in the list, but may be it is
2508 -- only the other unit kind (spec or body), or what is
2509 -- in the unit list is a unit of a project we are extending.
2511 if The_Unit
/= Prj
.Com
.No_Unit
then
2512 The_Unit_Data
:= Units
.Table
(The_Unit
);
2514 if The_Unit_Data
.File_Names
(Unit_Kind
).Name
= No_Name
2515 or else (Data
.Modifies
/= No_Project
2517 The_Unit_Data
.File_Names
(Unit_Kind
).Project
=
2520 The_Unit_Data
.File_Names
(Unit_Kind
) :=
2524 Needs_Pragma
=> Needs_Pragma
);
2525 Units
.Table
(The_Unit
) := The_Unit_Data
;
2528 -- It is an error to have two units with the same name
2529 -- and the same kind (spec or body).
2531 if The_Location
= No_Location
then
2532 The_Location
:= Projects
.Table
(Project
).Location
;
2535 Errout
.Error_Msg_Name_1
:= Unit_Name
;
2536 Error_Msg
("duplicate source {", The_Location
);
2538 Errout
.Error_Msg_Name_1
:=
2540 (The_Unit_Data
.File_Names
(Unit_Kind
).Project
).Name
;
2541 Errout
.Error_Msg_Name_2
:=
2542 The_Unit_Data
.File_Names
(Unit_Kind
).Path
;
2543 Error_Msg
("\ project file {, {", The_Location
);
2545 Errout
.Error_Msg_Name_1
:= Projects
.Table
(Project
).Name
;
2546 Errout
.Error_Msg_Name_2
:= Path_Name
;
2547 Error_Msg
("\ project file {, {", The_Location
);
2551 -- It is a new unit, create a new record
2554 Units
.Increment_Last
;
2555 The_Unit
:= Units
.Last
;
2556 Units_Htable
.Set
(Unit_Name
, The_Unit
);
2557 The_Unit_Data
.Name
:= Unit_Name
;
2558 The_Unit_Data
.File_Names
(Unit_Kind
) :=
2562 Needs_Pragma
=> Needs_Pragma
);
2563 Units
.Table
(The_Unit
) := The_Unit_Data
;
2569 ----------------------
2570 -- Show_Source_Dirs --
2571 ----------------------
2573 procedure Show_Source_Dirs
(Project
: Project_Id
) is
2574 Current
: String_List_Id
:= Projects
.Table
(Project
).Source_Dirs
;
2575 Element
: String_Element
;
2578 Write_Line
("Source_Dirs:");
2580 while Current
/= Nil_String
loop
2581 Element
:= String_Elements
.Table
(Current
);
2583 Write_Line
(Get_Name_String
(Element
.Value
));
2584 Current
:= Element
.Next
;
2587 Write_Line
("end Source_Dirs.");
2588 end Show_Source_Dirs
;