1 ------------------------------------------------------------------------------
3 -- GNAT COMPILER COMPONENTS --
10 -- Copyright (C) 1992-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 -- Extensive contributions were provided by Ada Core Technologies Inc. --
26 ------------------------------------------------------------------------------
28 with Binderr
; use Binderr
;
29 with Namet
; use Namet
;
31 with Osint
; use Osint
;
35 with System
.Address_To_Access_Conversions
;
37 package body ALI
.Util
is
39 -----------------------
40 -- Local Subprograms --
41 -----------------------
43 procedure Accumulate_Checksum
(C
: Character; Csum
: in out Word
);
44 pragma Inline
(Accumulate_Checksum
);
45 -- This routine accumulates the checksum given character C. During the
46 -- scanning of a source file, this routine is called with every character
47 -- in the source, excluding blanks, and all control characters (except
48 -- that ESC is included in the checksum). Upper case letters not in string
49 -- literals are folded by the caller. See Sinput spec for the documentation
50 -- of the checksum algorithm. Note: checksum values are only used if we
51 -- generate code, so it is not necessary to worry about making the right
52 -- sequence of calls in any error situation.
54 procedure Initialize_Checksum
(Csum
: out Word
);
55 -- Sets initial value of Csum before any calls to Accumulate_Checksum
57 -------------------------
58 -- Accumulate_Checksum --
59 -------------------------
61 procedure Accumulate_Checksum
(C
: Character; Csum
: in out Word
) is
63 System
.CRC32
.Update
(System
.CRC32
.CRC32
(Csum
), C
);
64 end Accumulate_Checksum
;
70 function Checksums_Match
(Checksum1
, Checksum2
: Word
) return Boolean is
72 return Checksum1
= Checksum2
and then Checksum1
/= Checksum_Error
;
75 -----------------------
76 -- Get_File_Checksum --
77 -----------------------
79 function Get_File_Checksum
(Fname
: Name_Id
) return Word
is
80 Src
: Source_Buffer_Ptr
;
86 -- Raised if file not found, or file format error
89 -- Make control characters visible
91 procedure Free_Source
;
92 -- Free source file buffer
94 procedure Free_Source
is
97 new System
.Address_To_Access_Conversions
(Big_Source_Buffer
);
100 System
.Memory
.Free
(SB
.To_Address
(SB
.Object_Pointer
(Src
)));
103 -- Start of processing for Get_File_Checksum
106 Read_Source_File
(Fname
, 0, Hi
, Src
);
108 -- If we cannot find the file, then return an impossible checksum,
109 -- impossible becaues checksums have the high order bit zero, so
110 -- that checksums do not match.
116 Initialize_Checksum
(Csum
);
122 -- Spaces and formatting information are ignored in checksum
124 when ' ' | CR | LF | VT | FF | HT
=>
127 -- EOF is ignored unless it is the last character
137 -- Non-blank characters that are included in the checksum
139 when '#' |
'&' |
'*' |
':' |
'(' |
',' |
'.' |
'=' |
'>' |
140 '<' |
')' |
'/' |
';' |
'|' |
'!' |
'+' |
'_' |
141 '0' .. '9' |
'a' .. 'z'
143 Accumulate_Checksum
(Src
(Ptr
), Csum
);
146 -- Upper case letters, fold to lower case
150 (Character'Val (Character'Pos (Src
(Ptr
)) + 32), Csum
);
153 -- Left bracket, really should do wide character thing here,
154 -- but for now, don't bother.
159 -- Minus, could be comment
162 if Src
(Ptr
+ 1) = '-' then
165 while Src
(Ptr
) >= ' ' or else Src
(Ptr
) = HT
loop
170 Accumulate_Checksum
('-', Csum
);
174 -- String delimited by double quote
177 Accumulate_Checksum
('"', Csum
);
181 exit when Src
(Ptr
) = '"';
183 if Src
(Ptr
) < ' ' then
187 Accumulate_Checksum
(Src
(Ptr
), Csum
);
190 Accumulate_Checksum
('"', Csum
);
193 -- String delimited by percent
196 Accumulate_Checksum
('%', Csum
);
200 exit when Src
(Ptr
) = '%';
202 if Src
(Ptr
) < ' ' then
206 Accumulate_Checksum
(Src
(Ptr
), Csum
);
209 Accumulate_Checksum
('%', Csum
);
212 -- Quote, could be character constant
215 Accumulate_Checksum
(''', Csum
);
217 if Src
(Ptr
+ 2) = ''' then
218 Accumulate_Checksum
(Src
(Ptr
+ 1), Csum
);
219 Accumulate_Checksum
(''', Csum
);
222 -- Otherwise assume attribute char. We should deal with wide
223 -- character cases here, but that's hard, so forget it.
229 -- Upper half character, more to be done here, we should worry
230 -- about folding Latin-1, folding other character sets, and
231 -- dealing with the nasty case of upper half wide encoding.
233 when Upper_Half_Character
=>
234 Accumulate_Checksum
(Src
(Ptr
), Csum
);
237 -- Escape character, we should do the wide character thing here,
238 -- but for now, do not bother.
243 -- Invalid control characters
245 when NUL | SOH | STX | ETX | EOT | ENQ | ACK | BEL | BS | SO |
246 SI | DLE | DC1 | DC2 | DC3 | DC4 | NAK | SYN | ETB | CAN |
247 EM | FS | GS | RS | US | DEL
251 -- Invalid graphic characters
253 when '$' |
'?' |
'@' |
'`' |
'\' |
254 '^' |
'~' |
']' |
'{' |
'}'
264 return Checksum_Error
;
266 end Get_File_Checksum
;
268 ---------------------------
269 -- Initialize_ALI_Source --
270 ---------------------------
272 procedure Initialize_ALI_Source
is
274 -- When (re)initializing ALI data structures the ALI user expects to
275 -- get a fresh set of data structures. Thus we first need to erase the
276 -- marks put in the name table by the previous set of ALI routine calls.
277 -- This loop is empty and harmless the first time in.
279 for J
in Source
.First
.. Source
.Last
loop
280 Set_Name_Table_Info
(Source
.Table
(J
).Sfile
, 0);
281 Source
.Table
(J
).Source_Found
:= False;
285 end Initialize_ALI_Source
;
287 -------------------------
288 -- Initialize_Checksum --
289 -------------------------
291 procedure Initialize_Checksum
(Csum
: out Word
) is
293 System
.CRC32
.Initialize
(System
.CRC32
.CRC32
(Csum
));
294 end Initialize_Checksum
;
300 procedure Read_ALI
(Id
: ALI_Id
) is
301 Afile
: File_Name_Type
;
302 Text
: Text_Buffer_Ptr
;
306 for I
in ALIs
.Table
(Id
).First_Unit
.. ALIs
.Table
(Id
).Last_Unit
loop
307 for J
in Units
.Table
(I
).First_With
.. Units
.Table
(I
).Last_With
loop
309 Afile
:= Withs
.Table
(J
).Afile
;
311 -- Only process if not a generic (Afile /= No_File) and if
312 -- file has not been processed already.
314 if Afile
/= No_File
and then Get_Name_Table_Info
(Afile
) = 0 then
316 Text
:= Read_Library_Info
(Afile
);
319 Error_Msg_Name_1
:= Afile
;
320 Error_Msg_Name_2
:= Withs
.Table
(J
).Sfile
;
321 Error_Msg
("% not found, % must be compiled");
322 Set_Name_Table_Info
(Afile
, Int
(No_Unit_Id
));
330 Ignore_ED
=> Force_RM_Elaboration_Order
,
335 if ALIs
.Table
(Idread
).Compile_Errors
then
336 Error_Msg_Name_1
:= Withs
.Table
(J
).Sfile
;
337 Error_Msg
("% had errors, must be fixed, and recompiled");
338 Set_Name_Table_Info
(Afile
, Int
(No_Unit_Id
));
340 elsif ALIs
.Table
(Idread
).No_Object
then
341 Error_Msg_Name_1
:= Withs
.Table
(J
).Sfile
;
342 Error_Msg
("% must be recompiled");
343 Set_Name_Table_Info
(Afile
, Int
(No_Unit_Id
));
346 -- Recurse to get new dependents
355 ----------------------
356 -- Set_Source_Table --
357 ----------------------
359 procedure Set_Source_Table
(A
: ALI_Id
) is
362 Stamp
: Time_Stamp_Type
;
366 ALIs
.Table
(A
).First_Sdep
.. ALIs
.Table
(A
).Last_Sdep
368 F
:= Sdep
.Table
(D
).Sfile
;
370 -- If this is the first time we are seeing this source file,
371 -- then make a new entry in the source table.
373 if Get_Name_Table_Info
(F
) = 0 then
374 Source
.Increment_Last
;
376 Set_Name_Table_Info
(F
, Int
(S
));
377 Source
.Table
(S
).Sfile
:= F
;
378 Source
.Table
(S
).All_Timestamps_Match
:= True;
380 -- Initialize checksum fields
382 Source
.Table
(S
).Checksum
:= Sdep
.Table
(D
).Checksum
;
383 Source
.Table
(S
).All_Checksums_Match
:= True;
385 -- In check source files mode, try to get time stamp from file
387 if Opt
.Check_Source_Files
then
388 Stamp
:= Source_File_Stamp
(F
);
390 -- If we got the stamp, then set the stamp in the source
391 -- table entry and mark it as set from the source so that
392 -- it does not get subsequently changed.
394 if Stamp
(Stamp
'First) /= ' ' then
395 Source
.Table
(S
).Stamp
:= Stamp
;
396 Source
.Table
(S
).Source_Found
:= True;
398 -- If we could not find the file, then the stamp is set
399 -- from the dependency table entry (to be possibly reset
400 -- if we find a later stamp in subsequent processing)
403 Source
.Table
(S
).Stamp
:= Sdep
.Table
(D
).Stamp
;
404 Source
.Table
(S
).Source_Found
:= False;
406 -- In All_Sources mode, flag error of file not found
408 if Opt
.All_Sources
then
409 Error_Msg_Name_1
:= F
;
410 Error_Msg
("cannot locate %");
414 -- First time for this source file, but Check_Source_Files
415 -- is off, so simply initialize the stamp from the Sdep entry
418 Source
.Table
(S
).Source_Found
:= False;
419 Source
.Table
(S
).Stamp
:= Sdep
.Table
(D
).Stamp
;
422 -- Here if this is not the first time for this source file,
423 -- so that the source table entry is already constructed.
426 S
:= Source_Id
(Get_Name_Table_Info
(F
));
428 -- Update checksum flag
430 if not Checksums_Match
431 (Sdep
.Table
(D
).Checksum
, Source
.Table
(S
).Checksum
)
433 Source
.Table
(S
).All_Checksums_Match
:= False;
436 -- Check for time stamp mismatch
438 if Sdep
.Table
(D
).Stamp
/= Source
.Table
(S
).Stamp
then
439 Source
.Table
(S
).All_Timestamps_Match
:= False;
441 -- When we have a time stamp mismatch, we go look for the
442 -- source file even if Check_Source_Files is false, since
443 -- if we find it, then we can use it to resolve which of the
444 -- two timestamps in the ALI files is likely to be correct.
446 if not Check_Source_Files
then
447 Stamp
:= Source_File_Stamp
(F
);
449 if Stamp
(Stamp
'First) /= ' ' then
450 Source
.Table
(S
).Stamp
:= Stamp
;
451 Source
.Table
(S
).Source_Found
:= True;
455 -- If the stamp in the source table entry was set from the
456 -- source file, then we do not change it (the stamp in the
457 -- source file is always taken as the "right" one).
459 if Source
.Table
(S
).Source_Found
then
462 -- Otherwise, we have no source file available, so we guess
463 -- that the later of the two timestamps is the right one.
464 -- Note that this guess only affects which error messages
465 -- are issued later on, not correct functionality.
468 if Sdep
.Table
(D
).Stamp
> Source
.Table
(S
).Stamp
then
469 Source
.Table
(S
).Stamp
:= Sdep
.Table
(D
).Stamp
;
475 -- Set the checksum value in the source table
477 S
:= Source_Id
(Get_Name_Table_Info
(F
));
478 Source
.Table
(S
).Checksum
:= Sdep
.Table
(D
).Checksum
;
482 end Set_Source_Table
;
484 ----------------------
485 -- Set_Source_Table --
486 ----------------------
488 procedure Set_Source_Table
is
490 for A
in ALIs
.First
.. ALIs
.Last
loop
491 Set_Source_Table
(A
);
494 end Set_Source_Table
;
496 -------------------------
497 -- Time_Stamp_Mismatch --
498 -------------------------
500 function Time_Stamp_Mismatch
(A
: ALI_Id
) return File_Name_Type
is
502 -- Source file Id for the current Sdep entry
505 for D
in ALIs
.Table
(A
).First_Sdep
.. ALIs
.Table
(A
).Last_Sdep
loop
506 Src
:= Source_Id
(Get_Name_Table_Info
(Sdep
.Table
(D
).Sfile
));
508 if Opt
.Minimal_Recompilation
509 and then Sdep
.Table
(D
).Stamp
/= Source
.Table
(Src
).Stamp
512 -- If minimal recompilation is in action, replace the stamp
513 -- of the source file in the table if checksums match.
515 -- ??? It is probably worth updating the ALI file with a new
516 -- field to avoid recomputing it each time.
519 (Get_File_Checksum
(Sdep
.Table
(D
).Sfile
),
520 Source
.Table
(Src
).Checksum
)
522 Sdep
.Table
(D
).Stamp
:= Source
.Table
(Src
).Stamp
;
527 if not Source
.Table
(Src
).Source_Found
528 or else Sdep
.Table
(D
).Stamp
/= Source
.Table
(Src
).Stamp
530 return Source
.Table
(Src
).Sfile
;
536 end Time_Stamp_Mismatch
;