1717-- ----------------------------------------------------------------------------
1818
1919with Ada.Characters.Handling ;
20- with Ada.Characters.Latin_1 ;
2120with Ada.Containers ; use Ada.Containers;
2221with Ada.Directories ; use Ada.Directories;
2322with Ada.Text_IO ; use Ada.Text_IO;
@@ -30,6 +29,7 @@ with GNAT.OS_Lib; use GNAT.OS_Lib;
3029with GNAT.Regpat ; use GNAT.Regpat;
3130
3231with GNATCOLL.VFS ;
32+ with GNATCOLL.Mmap ;
3333
3434with Interfaces ; use Interfaces;
3535with Interfaces.C ; use Interfaces.C;
@@ -3838,10 +3838,10 @@ package body Instrument.C is
38383838 -- ----------------------------------
38393839
38403840 overriding procedure Replace_Manual_Dump_Indication
3841- (Self : in out C_Family_Instrumenter_Type;
3842- Done : in out Boolean ;
3843- Prj : in out Prj_Desc ;
3844- Source : GNATCOLL.Projects.File_Info )
3841+ (Self : in out C_Family_Instrumenter_Type;
3842+ Prj : in out Prj_Desc ;
3843+ Source : GNATCOLL.Projects.File_Info ;
3844+ Has_Manual_Indication : out Boolean )
38453845 is
38463846 use GNATCOLL.VFS;
38473847 Orig_Filename : constant String := +Source.File.Full_Name;
@@ -3851,16 +3851,15 @@ package body Instrument.C is
38513851 declare
38523852 Options : Analysis_Options;
38533853 PP_Filename : Unbounded_String;
3854- File : Ada.Text_IO.File_Type;
38553854 Dummy_Main : Compilation_Unit_Part;
38563855 Dump_Pat : constant Pattern_Matcher :=
3857- Compile (" ^[\t ]*\/\* GNATCOV_DUMP_BUFFERS \*\/[ \t]*" );
3856+ Compile
3857+ (" ^[\t ]*\/\* GNATCOV_DUMP_BUFFERS \*\/[ \t]*" ,
3858+ Flags => Multiple_Lines);
38583859 Matches : Match_Array (0 .. 1 );
38593860 Dump_Procedure : constant String :=
38603861 Dump_Procedure_Symbol
38613862 (Main => Dummy_Main, Manual => True, Prj_Name => +Prj.Prj_Name);
3862- Contents : Unbounded_String :=
3863- +(" extern void " & Dump_Procedure & " (void);" );
38643863 begin
38653864 -- Preprocess the source, keeping the comment to look for the manual
38663865 -- dump indication later.
@@ -3887,47 +3886,84 @@ package body Instrument.C is
38873886 end loop ;
38883887 end ;
38893888
3890- -- Look for the manual dump indication in the preprocessed file
3889+ -- Look for the manual dump indication in the preprocessed file. Use
3890+ -- the GNATCOLL.Mmap API to map the file contents in memory, as we
3891+ -- may need to rewrite it to the source file, with the manual dump
3892+ -- indication replaced by an actual call to the dump buffers
3893+ -- function.
38913894
3892- Ada.Text_IO.Open
3893- (File => File,
3894- Mode => In_File,
3895- Name => (+PP_Filename));
3896-
3897- while not Ada.Text_IO.End_Of_File (File) loop
3898- declare
3899- Line : constant String := Get_Line (File);
3900- begin
3901- Match (Dump_Pat, Line, Matches);
3895+ declare
3896+ use GNATCOLL.Mmap;
3897+ File : Mapped_File := Open_Read (To_String (PP_Filename));
3898+ Region : Mapped_Region := Read (File);
3899+ Raw_Str : constant Str_Access := Data (Region);
3900+ Raw_Str_Last : constant Natural := Last (Region);
3901+ Str : String renames Raw_Str (1 .. Raw_Str_Last);
3902+
3903+ Tmp_Filename : constant String := +PP_Filename & " .tmp" ;
3904+ Output_File : Ada.Text_IO.File_Type;
3905+ -- Temporary file containing the new version of the original file,
3906+ -- with inserted calls to dump buffers. The original file is then
3907+ -- overwritten by this temporary file.
3908+
3909+ Index : Positive := 1 ;
3910+ -- Starting index, or last index of the previous match in the
3911+ -- original file.
39023912
3903- if Matches (0 ) /= No_Match then
3904- Contents := Contents & Dump_Procedure & " ();" ;
3905- Done := True;
3906- else
3907- Contents := Contents & Line;
3913+ begin
3914+ Has_Manual_Indication := False;
3915+ while Index in Str'Range loop
3916+ Match (Dump_Pat, Str (Index .. Str'Last), Matches);
3917+ exit when Matches (0 ) = No_Match;
3918+
3919+ -- Open the output file if this is the first match we find,
3920+ -- then forward the source code that appear before the match
3921+ -- unchanged.
3922+
3923+ if not Has_Manual_Indication then
3924+ Create (Output_File, Out_File, Tmp_Filename);
3925+ Has_Manual_Indication := True;
39083926 end if ;
3927+ Put (Output_File, Str (Index .. Matches (0 ).First));
39093928
3910- Contents := Contents & Ada.Characters.Latin_1.LF;
3911- end ;
3912- end loop ;
3929+ -- Replace the match with the call to the dump procedure
3930+
3931+ Put (Output_File, Dump_Procedure & " ();" );
3932+ Index := Matches (0 ).Last + 1 ;
3933+ end loop ;
39133934
3914- Ada.Text_IO.Close (File);
3935+ -- If we had a manual indication, and thus wrote a modified source
3936+ -- file, overwrite the original source file with it.
39153937
3916- if Done then
3917- -- Content now holds the text of the original file with calls to
3918- -- the manual dump procedure where the indications and its extern
3919- -- declaration were. Replace the original content of the file with
3920- -- Content.
3938+ if Has_Manual_Indication then
3939+ declare
3940+ Tmp_File : constant Virtual_File := Create (+Tmp_Filename);
3941+ Success : Boolean;
3942+ begin
3943+ -- Flush the rest of the file contents
39213944
3922- Ada.Text_IO.Open
3923- (File => File,
3924- Mode => Out_File,
3925- Name => (+PP_Filename));
3945+ Ada.Text_IO.Put (Output_File, Str (Index .. Str'Last));
3946+ Ada.Text_IO.Close (Output_File);
39263947
3927- Ada.Text_IO.Put_Line (File, (+Contents));
3948+ Free (Region);
3949+ Close (File);
39283950
3929- Ada.Text_IO.Close (File);
3930- end if ;
3951+ -- Overwrite the original file with its newer version
3952+
3953+ Tmp_File.Rename
3954+ (Full_Name => Create (+(+PP_Filename)),
3955+ Success => Success);
3956+ if not Success then
3957+ Outputs.Fatal_Error
3958+ (" Failed to replace manual dump indication for Source "
3959+ & (+Source.File.Full_Name));
3960+ end if ;
3961+ end ;
3962+ else
3963+ Free (Region);
3964+ Close (File);
3965+ end if ;
3966+ end ;
39313967 end ;
39323968 end Replace_Manual_Dump_Indication ;
39333969
0 commit comments