76b4158b8f
This patch refactors the forced elaboration order functionality, reintegrates it in Binde, and impelements it in Bindo. ------------ -- Source -- ------------ -- server.ads package Server is end Server; -- client.ads with Server; package Client is end Client; -- main.adb with Client; procedure Main is begin null; end Main; -- duplicate_1.txt server (spec) client (spec) server (spec) -- error_unit_1.txt no such unit client (spec) -- error_unit_2.txt no such unit client (spec) -- error_unit_3.txt no such unit -- comment client (spec) -- error_unit_4.txt no such unit -- comment client (spec) -- error_unit_5.txt no such unit (body) client (spec) -- error_unit_6.txt no such unit (body) client (spec) -- error_unit_7.txt no such unit (body) -- comment client (spec) -- error_unit_8.txt no such unit (body)-- comment client (spec) -- error_unit_9.txt no such unit-- comment client (spec) -- no_unit_1.txt -- no_unit_2.txt -- no_unit_3.txt -- comment -- no_unit_4.txt -- no_unit_5.txt -- no_unit_6.txt -- comment -- no_unit_7.txt -- no_unit_8.txt -- comment -- comment -- ok_unit_1.txt server (spec) client (spec) -- ok_unit_2.txt server (spec) client (spec) -- ok_unit_3.txt server (spec) client (spec) -- ok_unit_4.txt server (spec) -- comment client (spec) -- ok_unit_5.txt server (spec) client (spec) -- ok_unit_6.txt server (spec) client (spec) -- comment -- ok_unit_7.txt server (spec) client (spec) -- comment -- ok_unit_8.txt -- comment -- comment server (spec) -- comment -- comment client (spec) -- comment -- ok_unit_9.txt server (spec)-- comment client (spec) ---------------------------- -- Compilation and output -- ---------------------------- $ gnatmake -q main.adb $ gnatbind -fno_unit_1.txt main.ali $ gnatbind -fno_unit_2.txt main.ali $ gnatbind -fno_unit_3.txt main.ali $ gnatbind -fno_unit_4.txt main.ali $ gnatbind -fno_unit_5.txt main.ali $ gnatbind -fno_unit_6.txt main.ali $ gnatbind -fno_unit_7.txt main.ali $ gnatbind -fno_unit_8.txt main.ali $ gnatbind -ferror_unit_1.txt main.ali $ gnatbind -ferror_unit_2.txt main.ali $ gnatbind -ferror_unit_3.txt main.ali $ gnatbind -ferror_unit_4.txt main.ali $ gnatbind -ferror_unit_5.txt main.ali $ gnatbind -ferror_unit_6.txt main.ali $ gnatbind -ferror_unit_7.txt main.ali $ gnatbind -ferror_unit_8.txt main.ali $ gnatbind -ferror_unit_9.txt main.ali $ gnatbind -fduplicate_1.txt main.ali $ gnatbind -fok_unit_1.txt main.ali $ gnatbind -fok_unit_2.txt main.ali $ gnatbind -fok_unit_3.txt main.ali $ gnatbind -fok_unit_4.txt main.ali $ gnatbind -fok_unit_5.txt main.ali $ gnatbind -fok_unit_6.txt main.ali $ gnatbind -fok_unit_7.txt main.ali $ gnatbind -fok_unit_8.txt main.ali $ gnatbind -fok_unit_9.txt main.ali "no such unit": not present; ignored "no such unit": not present; ignored "no such unit": not present; ignored "no such unit": not present; ignored "no such unit%b": not present; ignored "no such unit%b": not present; ignored "no such unit%b": not present; ignored "no such unit%b": not present; ignored "no such unit": not present; ignored server (spec) <-- client (spec) error: duplicate_1.txt:3: duplicate unit name "server (spec)" from line 1 server (spec) <-- client (spec) server (spec) <-- client (spec) server (spec) <-- client (spec) server (spec) <-- client (spec) server (spec) <-- client (spec) server (spec) <-- client (spec) server (spec) <-- client (spec) server (spec) <-- client (spec) server (spec) <-- client (spec) 2019-07-03 Hristian Kirtchev <kirtchev@adacore.com> gcc/ada/ * binde.adb: Remove with clause for System.OS_Lib. (Force_Elab_Order): Refactor the majority of the code in Butil. Use the new forced units iterator to obtain unit names. * bindo-builders.adb: Add with and use clauses for Binderr, Butil, Opt, Output, Types, GNAT, and GNAT.Dynamic_HTables. Add a hash table which maps units to line number in the forced elaboration order file. (Add_Unit): New routine. (Build_Library_Graph): Create forced edges between pairs of units listed in the forced elaboration order file. (Create_Forced_Edge, Create_Forced_Edges, Destroy_Line_Number, Duplicate_Unit_Error, Hash_Unit, Internal_Unit_Info, Is_Duplicate_Unit, Missing_Unit_Info): New routines. * bindo-graphs.adb (Is_Internal_Unit, Is_Predefined_Unit): Refactor some of the behavior to Bindo-Units. * bindo-graphs.ads: Enable the enumeration literal for forced edges. * bindo-units.adb, bindo-units.ads (Is_Internal_Unit, Is_Predefined_Unit): New routines. * butil.adb: Add with and use clauses for Opt, GNAT, and System.OS_Lib. Add with clause for Unchecked_Deallocation. (Has_Next, Iterate_Forced_Units, Next, Parse_Next_Unit_Name, Read_Forced_Elab_Order_File): New routines. * butil.ads: Add with and use clauses for Types. Add new iterator over the units listed in the forced elaboration order file. (Has_Next, Iterate_Forced_Units, Next): New routine. * namet.adb, namet.ads (Present): New routine. From-SVN: r272987
648 lines
19 KiB
Ada
648 lines
19 KiB
Ada
------------------------------------------------------------------------------
|
|
-- --
|
|
-- GNAT COMPILER COMPONENTS --
|
|
-- --
|
|
-- B U T I L --
|
|
-- --
|
|
-- B o d y --
|
|
-- --
|
|
-- Copyright (C) 1992-2019, Free Software Foundation, Inc. --
|
|
-- --
|
|
-- GNAT is free software; you can redistribute it and/or modify it under --
|
|
-- terms of the GNU General Public License as published by the Free Soft- --
|
|
-- ware Foundation; either version 3, or (at your option) any later ver- --
|
|
-- sion. GNAT is distributed in the hope that it will be useful, but WITH- --
|
|
-- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY --
|
|
-- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License --
|
|
-- for more details. You should have received a copy of the GNU General --
|
|
-- Public License distributed with GNAT; see file COPYING3. If not, go to --
|
|
-- http://www.gnu.org/licenses for a complete copy of the license. --
|
|
-- --
|
|
-- GNAT was originally developed by the GNAT team at New York University. --
|
|
-- Extensive contributions were provided by Ada Core Technologies Inc. --
|
|
-- --
|
|
------------------------------------------------------------------------------
|
|
|
|
with Opt; use Opt;
|
|
with Output; use Output;
|
|
with Unchecked_Deallocation;
|
|
|
|
with GNAT; use GNAT;
|
|
|
|
with System.OS_Lib; use System.OS_Lib;
|
|
|
|
package body Butil is
|
|
|
|
-----------------------
|
|
-- Local subprograms --
|
|
-----------------------
|
|
|
|
procedure Parse_Next_Unit_Name (Iter : in out Forced_Units_Iterator);
|
|
-- Parse the name of the next available unit accessible through iterator
|
|
-- Iter and save it in the iterator.
|
|
|
|
function Read_Forced_Elab_Order_File return String_Ptr;
|
|
-- Read the contents of the forced-elaboration-order file supplied to the
|
|
-- binder via switch -f and return them as a string. Return null if the
|
|
-- file is not available.
|
|
|
|
--------------
|
|
-- Has_Next --
|
|
--------------
|
|
|
|
function Has_Next (Iter : Forced_Units_Iterator) return Boolean is
|
|
begin
|
|
return Present (Iter.Unit_Name);
|
|
end Has_Next;
|
|
|
|
----------------------
|
|
-- Is_Internal_Unit --
|
|
----------------------
|
|
|
|
-- Note: the reason we do not use the Fname package for this function
|
|
-- is that it would drag too much junk into the binder.
|
|
|
|
function Is_Internal_Unit return Boolean is
|
|
begin
|
|
return Is_Predefined_Unit
|
|
or else (Name_Len > 4 and then (Name_Buffer (1 .. 5) = "gnat%"
|
|
or else
|
|
Name_Buffer (1 .. 5) = "gnat."));
|
|
end Is_Internal_Unit;
|
|
|
|
------------------------
|
|
-- Is_Predefined_Unit --
|
|
------------------------
|
|
|
|
-- Note: the reason we do not use the Fname package for this function
|
|
-- is that it would drag too much junk into the binder.
|
|
|
|
function Is_Predefined_Unit return Boolean is
|
|
L : Natural renames Name_Len;
|
|
B : String renames Name_Buffer;
|
|
begin
|
|
return (L > 3 and then B (1 .. 4) = "ada.")
|
|
or else (L > 6 and then B (1 .. 7) = "system.")
|
|
or else (L > 10 and then B (1 .. 11) = "interfaces.")
|
|
or else (L > 3 and then B (1 .. 4) = "ada%")
|
|
or else (L > 8 and then B (1 .. 9) = "calendar%")
|
|
or else (L > 9 and then B (1 .. 10) = "direct_io%")
|
|
or else (L > 10 and then B (1 .. 11) = "interfaces%")
|
|
or else (L > 13 and then B (1 .. 14) = "io_exceptions%")
|
|
or else (L > 12 and then B (1 .. 13) = "machine_code%")
|
|
or else (L > 13 and then B (1 .. 14) = "sequential_io%")
|
|
or else (L > 6 and then B (1 .. 7) = "system%")
|
|
or else (L > 7 and then B (1 .. 8) = "text_io%")
|
|
or else (L > 20 and then B (1 .. 21) = "unchecked_conversion%")
|
|
or else (L > 22 and then B (1 .. 23) = "unchecked_deallocation%")
|
|
or else (L > 4 and then B (1 .. 5) = "gnat%")
|
|
or else (L > 4 and then B (1 .. 5) = "gnat.");
|
|
end Is_Predefined_Unit;
|
|
|
|
--------------------------
|
|
-- Iterate_Forced_Units --
|
|
--------------------------
|
|
|
|
function Iterate_Forced_Units return Forced_Units_Iterator is
|
|
Iter : Forced_Units_Iterator;
|
|
|
|
begin
|
|
Iter.Order := Read_Forced_Elab_Order_File;
|
|
Parse_Next_Unit_Name (Iter);
|
|
|
|
return Iter;
|
|
end Iterate_Forced_Units;
|
|
|
|
----------
|
|
-- Next --
|
|
----------
|
|
|
|
procedure Next
|
|
(Iter : in out Forced_Units_Iterator;
|
|
Unit_Name : out Unit_Name_Type;
|
|
Unit_Line : out Logical_Line_Number)
|
|
is
|
|
begin
|
|
if not Has_Next (Iter) then
|
|
raise Iterator_Exhausted;
|
|
end if;
|
|
|
|
Unit_Line := Iter.Unit_Line;
|
|
Unit_Name := Iter.Unit_Name;
|
|
pragma Assert (Present (Unit_Name));
|
|
|
|
Parse_Next_Unit_Name (Iter);
|
|
end Next;
|
|
|
|
--------------------------
|
|
-- Parse_Next_Unit_Name --
|
|
--------------------------
|
|
|
|
procedure Parse_Next_Unit_Name (Iter : in out Forced_Units_Iterator) is
|
|
Body_Suffix : constant String := " (body)";
|
|
Body_Type : constant String := "%b";
|
|
Body_Length : constant Positive := Body_Suffix'Length;
|
|
Body_Offset : constant Natural := Body_Length - 1;
|
|
|
|
Comment_Header : constant String := "--";
|
|
Comment_Offset : constant Natural := Comment_Header'Length - 1;
|
|
|
|
Spec_Suffix : constant String := " (spec)";
|
|
Spec_Type : constant String := "%s";
|
|
Spec_Length : constant Positive := Spec_Suffix'Length;
|
|
Spec_Offset : constant Natural := Spec_Length - 1;
|
|
|
|
Index : Positive renames Iter.Order_Index;
|
|
Line : Logical_Line_Number renames Iter.Order_Line;
|
|
Order : String_Ptr renames Iter.Order;
|
|
|
|
function At_Comment return Boolean;
|
|
pragma Inline (At_Comment);
|
|
-- Determine whether iterator Iter is positioned over the start of a
|
|
-- comment.
|
|
|
|
function At_Terminator return Boolean;
|
|
pragma Inline (At_Terminator);
|
|
-- Determine whether iterator Iter is positioned over a line terminator
|
|
-- character.
|
|
|
|
function At_Whitespace return Boolean;
|
|
pragma Inline (At_Whitespace);
|
|
-- Determine whether iterator Iter is positioned over a whitespace
|
|
-- character.
|
|
|
|
function Is_Terminator (C : Character) return Boolean;
|
|
pragma Inline (Is_Terminator);
|
|
-- Determine whether character C denotes a line terminator
|
|
|
|
function Is_Whitespace (C : Character) return Boolean;
|
|
pragma Inline (Is_Whitespace);
|
|
-- Determine whether character C denotes a whitespace
|
|
|
|
procedure Parse_Unit_Name;
|
|
pragma Inline (Parse_Unit_Name);
|
|
-- Find and parse the first available unit name
|
|
|
|
procedure Skip_Comment;
|
|
pragma Inline (Skip_Comment);
|
|
-- Skip a comment by reaching a line terminator
|
|
|
|
procedure Skip_Terminator;
|
|
pragma Inline (Skip_Terminator);
|
|
-- Skip a line terminator and deal with the logical line numbering
|
|
|
|
procedure Skip_Whitespace;
|
|
pragma Inline (Skip_Whitespace);
|
|
-- Skip whitespace
|
|
|
|
function Within_Order
|
|
(Low_Offset : Natural := 0;
|
|
High_Offset : Natural := 0) return Boolean;
|
|
pragma Inline (Within_Order);
|
|
-- Determine whether index of iterator Iter is still within the range of
|
|
-- the order string. Low_Offset may be used to inspect the area that is
|
|
-- less than the index. High_Offset may be used to inspect the area that
|
|
-- is greater than the index.
|
|
|
|
----------------
|
|
-- At_Comment --
|
|
----------------
|
|
|
|
function At_Comment return Boolean is
|
|
begin
|
|
-- The interator is over a comment when the index is positioned over
|
|
-- the start of a comment header.
|
|
--
|
|
-- unit (spec) -- comment
|
|
-- ^
|
|
-- Index
|
|
|
|
return
|
|
Within_Order (High_Offset => Comment_Offset)
|
|
and then Order (Index .. Index + Comment_Offset) = Comment_Header;
|
|
end At_Comment;
|
|
|
|
-------------------
|
|
-- At_Terminator --
|
|
-------------------
|
|
|
|
function At_Terminator return Boolean is
|
|
begin
|
|
return Within_Order and then Is_Terminator (Order (Index));
|
|
end At_Terminator;
|
|
|
|
-------------------
|
|
-- At_Whitespace --
|
|
-------------------
|
|
|
|
function At_Whitespace return Boolean is
|
|
begin
|
|
return Within_Order and then Is_Whitespace (Order (Index));
|
|
end At_Whitespace;
|
|
|
|
-------------------
|
|
-- Is_Terminator --
|
|
-------------------
|
|
|
|
function Is_Terminator (C : Character) return Boolean is
|
|
begin
|
|
-- Carriage return is treated intentionally as whitespace since it
|
|
-- appears only on certain targets, while line feed is consistent on
|
|
-- all of them.
|
|
|
|
return C = ASCII.LF;
|
|
end Is_Terminator;
|
|
|
|
-------------------
|
|
-- Is_Whitespace --
|
|
-------------------
|
|
|
|
function Is_Whitespace (C : Character) return Boolean is
|
|
begin
|
|
return
|
|
C = ' '
|
|
or else C = ASCII.CR -- carriage return
|
|
or else C = ASCII.FF -- form feed
|
|
or else C = ASCII.HT -- horizontal tab
|
|
or else C = ASCII.VT; -- vertical tab
|
|
end Is_Whitespace;
|
|
|
|
---------------------
|
|
-- Parse_Unit_Name --
|
|
---------------------
|
|
|
|
procedure Parse_Unit_Name is
|
|
pragma Assert (not At_Comment);
|
|
pragma Assert (not At_Terminator);
|
|
pragma Assert (not At_Whitespace);
|
|
pragma Assert (Within_Order);
|
|
|
|
procedure Find_End_Index_Of_Unit_Name;
|
|
pragma Inline (Find_End_Index_Of_Unit_Name);
|
|
-- Position the index of iterator Iter at the last character of the
|
|
-- first available unit name.
|
|
|
|
---------------------------------
|
|
-- Find_End_Index_Of_Unit_Name --
|
|
---------------------------------
|
|
|
|
procedure Find_End_Index_Of_Unit_Name is
|
|
begin
|
|
-- At this point the index points at the start of a unit name. The
|
|
-- unit name may be legal, in which case it appears as:
|
|
--
|
|
-- unit (body)
|
|
--
|
|
-- However, it may also be illegal:
|
|
--
|
|
-- unit without suffix
|
|
-- unit with multiple prefixes (spec)
|
|
--
|
|
-- In order to handle both forms, find the construct following the
|
|
-- unit name. This is either a comment, a terminator, or the end
|
|
-- of the order:
|
|
--
|
|
-- unit (body) -- comment
|
|
-- unit without suffix <terminator>
|
|
-- unit with multiple prefixes (spec)<end of order>
|
|
--
|
|
-- Once the construct is found, truncate the unit name by skipping
|
|
-- all white space between the construct and the end of the unit
|
|
-- name.
|
|
|
|
-- Find the construct that follows the unit name
|
|
|
|
while Within_Order loop
|
|
if At_Comment then
|
|
exit;
|
|
|
|
elsif At_Terminator then
|
|
exit;
|
|
end if;
|
|
|
|
Index := Index + 1;
|
|
end loop;
|
|
|
|
-- Position the index prior to the construct that follows the unit
|
|
-- name.
|
|
|
|
Index := Index - 1;
|
|
|
|
-- Truncate towards the end of the unit name
|
|
|
|
while Within_Order loop
|
|
if At_Whitespace then
|
|
Index := Index - 1;
|
|
else
|
|
exit;
|
|
end if;
|
|
end loop;
|
|
end Find_End_Index_Of_Unit_Name;
|
|
|
|
-- Local variables
|
|
|
|
Start_Index : constant Positive := Index;
|
|
|
|
End_Index : Positive;
|
|
Is_Body : Boolean := False;
|
|
Is_Spec : Boolean := False;
|
|
|
|
-- Start of processing for Parse_Unit_Name
|
|
|
|
begin
|
|
Find_End_Index_Of_Unit_Name;
|
|
End_Index := Index;
|
|
|
|
pragma Assert (Start_Index <= End_Index);
|
|
|
|
-- At this point the indices are positioned as follows:
|
|
--
|
|
-- End_Index
|
|
-- Index
|
|
-- v
|
|
-- unit (spec) -- comment
|
|
-- ^
|
|
-- Start_Index
|
|
|
|
-- Rewind the index, skipping over the legal suffixes
|
|
--
|
|
-- Index End_Index
|
|
-- v v
|
|
-- unit (spec) -- comment
|
|
-- ^
|
|
-- Start_Index
|
|
|
|
if Within_Order (Low_Offset => Body_Offset)
|
|
and then Order (Index - Body_Offset .. Index) = Body_Suffix
|
|
then
|
|
Is_Body := True;
|
|
Index := Index - Body_Length;
|
|
|
|
elsif Within_Order (Low_Offset => Spec_Offset)
|
|
and then Order (Index - Spec_Offset .. Index) = Spec_Suffix
|
|
then
|
|
Is_Spec := True;
|
|
Index := Index - Spec_Length;
|
|
end if;
|
|
|
|
-- Capture the line where the unit name is defined
|
|
|
|
Iter.Unit_Line := Line;
|
|
|
|
-- Transform the unit name to match the format recognized by the
|
|
-- name table.
|
|
|
|
if Is_Body then
|
|
Iter.Unit_Name :=
|
|
Name_Find (Order (Start_Index .. Index) & Body_Type);
|
|
|
|
elsif Is_Spec then
|
|
Iter.Unit_Name :=
|
|
Name_Find (Order (Start_Index .. Index) & Spec_Type);
|
|
|
|
-- Otherwise the unit name is illegal, so leave it as is
|
|
|
|
else
|
|
Iter.Unit_Name := Name_Find (Order (Start_Index .. Index));
|
|
end if;
|
|
|
|
-- Advance the index past the unit name
|
|
--
|
|
-- End_IndexIndex
|
|
-- vv
|
|
-- unit (spec) -- comment
|
|
-- ^
|
|
-- Start_Index
|
|
|
|
Index := End_Index + 1;
|
|
end Parse_Unit_Name;
|
|
|
|
------------------
|
|
-- Skip_Comment --
|
|
------------------
|
|
|
|
procedure Skip_Comment is
|
|
begin
|
|
pragma Assert (At_Comment);
|
|
|
|
while Within_Order loop
|
|
if At_Terminator then
|
|
exit;
|
|
end if;
|
|
|
|
Index := Index + 1;
|
|
end loop;
|
|
end Skip_Comment;
|
|
|
|
---------------------
|
|
-- Skip_Terminator --
|
|
---------------------
|
|
|
|
procedure Skip_Terminator is
|
|
begin
|
|
pragma Assert (At_Terminator);
|
|
|
|
Index := Index + 1;
|
|
Line := Line + 1;
|
|
end Skip_Terminator;
|
|
|
|
---------------------
|
|
-- Skip_Whitespace --
|
|
---------------------
|
|
|
|
procedure Skip_Whitespace is
|
|
begin
|
|
while Within_Order loop
|
|
if At_Whitespace then
|
|
Index := Index + 1;
|
|
else
|
|
exit;
|
|
end if;
|
|
end loop;
|
|
end Skip_Whitespace;
|
|
|
|
------------------
|
|
-- Within_Order --
|
|
------------------
|
|
|
|
function Within_Order
|
|
(Low_Offset : Natural := 0;
|
|
High_Offset : Natural := 0) return Boolean
|
|
is
|
|
begin
|
|
return
|
|
Order /= null
|
|
and then Index - Low_Offset >= Order'First
|
|
and then Index + High_Offset <= Order'Last;
|
|
end Within_Order;
|
|
|
|
-- Start of processing for Parse_Next_Unit_Name
|
|
|
|
begin
|
|
-- A line in the forced-elaboration-order file has the following
|
|
-- grammar:
|
|
--
|
|
-- LINE ::=
|
|
-- [WHITESPACE] UNIT_NAME [WHITESPACE] [COMMENT] TERMINATOR
|
|
--
|
|
-- WHITESPACE ::=
|
|
-- <any whitespace character>
|
|
-- | <carriage return>
|
|
--
|
|
-- UNIT_NAME ::=
|
|
-- UNIT_PREFIX [WHITESPACE] UNIT_SUFFIX
|
|
--
|
|
-- UNIT_PREFIX ::=
|
|
-- <any string>
|
|
--
|
|
-- UNIT_SUFFIX ::=
|
|
-- (body)
|
|
-- | (spec)
|
|
--
|
|
-- COMMENT ::=
|
|
-- -- <any string>
|
|
--
|
|
-- TERMINATOR ::=
|
|
-- <line feed>
|
|
-- <end of file>
|
|
--
|
|
-- Items in <> brackets are semantic notions
|
|
|
|
-- Assume that the order has no remaining units
|
|
|
|
Iter.Unit_Line := No_Line_Number;
|
|
Iter.Unit_Name := No_Unit_Name;
|
|
|
|
-- Try to find the first available unit name from the current position
|
|
-- of iteration.
|
|
|
|
while Within_Order loop
|
|
Skip_Whitespace;
|
|
|
|
if At_Comment then
|
|
Skip_Comment;
|
|
|
|
elsif not Within_Order then
|
|
exit;
|
|
|
|
elsif At_Terminator then
|
|
Skip_Terminator;
|
|
|
|
else
|
|
Parse_Unit_Name;
|
|
exit;
|
|
end if;
|
|
end loop;
|
|
end Parse_Next_Unit_Name;
|
|
|
|
---------------------------------
|
|
-- Read_Forced_Elab_Order_File --
|
|
---------------------------------
|
|
|
|
function Read_Forced_Elab_Order_File return String_Ptr is
|
|
procedure Free is new Unchecked_Deallocation (String, String_Ptr);
|
|
|
|
Descr : File_Descriptor;
|
|
Len : Natural;
|
|
Len_Read : Natural;
|
|
Result : String_Ptr;
|
|
Success : Boolean;
|
|
|
|
begin
|
|
if Force_Elab_Order_File = null then
|
|
return null;
|
|
end if;
|
|
|
|
-- Obtain and sanitize a descriptor to the elaboration-order file
|
|
|
|
Descr := Open_Read (Force_Elab_Order_File.all, Binary);
|
|
|
|
if Descr = Invalid_FD then
|
|
return null;
|
|
end if;
|
|
|
|
-- Determine the size of the file, allocate a result large enough to
|
|
-- house its contents, and read it.
|
|
|
|
Len := Natural (File_Length (Descr));
|
|
|
|
if Len = 0 then
|
|
return null;
|
|
end if;
|
|
|
|
Result := new String (1 .. Len);
|
|
Len_Read := Read (Descr, Result (1)'Address, Len);
|
|
|
|
-- The read failed to acquire the whole content of the file
|
|
|
|
if Len_Read /= Len then
|
|
Free (Result);
|
|
return null;
|
|
end if;
|
|
|
|
Close (Descr, Success);
|
|
|
|
-- The file failed to close
|
|
|
|
if not Success then
|
|
Free (Result);
|
|
return null;
|
|
end if;
|
|
|
|
return Result;
|
|
end Read_Forced_Elab_Order_File;
|
|
|
|
----------------
|
|
-- Uname_Less --
|
|
----------------
|
|
|
|
function Uname_Less (U1, U2 : Unit_Name_Type) return Boolean is
|
|
begin
|
|
Get_Name_String (U1);
|
|
|
|
declare
|
|
U1_Name : constant String (1 .. Name_Len) :=
|
|
Name_Buffer (1 .. Name_Len);
|
|
Min_Length : Natural;
|
|
|
|
begin
|
|
Get_Name_String (U2);
|
|
|
|
if Name_Len < U1_Name'Last then
|
|
Min_Length := Name_Len;
|
|
else
|
|
Min_Length := U1_Name'Last;
|
|
end if;
|
|
|
|
for J in 1 .. Min_Length loop
|
|
if U1_Name (J) > Name_Buffer (J) then
|
|
return False;
|
|
elsif U1_Name (J) < Name_Buffer (J) then
|
|
return True;
|
|
end if;
|
|
end loop;
|
|
|
|
return U1_Name'Last < Name_Len;
|
|
end;
|
|
end Uname_Less;
|
|
|
|
---------------------
|
|
-- Write_Unit_Name --
|
|
---------------------
|
|
|
|
procedure Write_Unit_Name (U : Unit_Name_Type) is
|
|
begin
|
|
Get_Name_String (U);
|
|
Write_Str (Name_Buffer (1 .. Name_Len - 2));
|
|
|
|
if Name_Buffer (Name_Len) = 's' then
|
|
Write_Str (" (spec)");
|
|
else
|
|
Write_Str (" (body)");
|
|
end if;
|
|
|
|
Name_Len := Name_Len + 5;
|
|
end Write_Unit_Name;
|
|
|
|
end Butil;
|