]> git.ipfire.org Git - thirdparty/gcc.git/blame - gcc/ada/ali-util.adb
3psoccon.ads, [...]: Files added.
[thirdparty/gcc.git] / gcc / ada / ali-util.adb
CommitLineData
d23b8f57
RK
1------------------------------------------------------------------------------
2-- --
3-- GNAT COMPILER COMPONENTS --
4-- --
5-- A L I . U T I L --
6-- --
7-- B o d y --
8-- --
bcea76b6 9-- Copyright (C) 1992-2003 Free Software Foundation, Inc. --
d23b8f57
RK
10-- --
11-- GNAT is free software; you can redistribute it and/or modify it under --
12-- terms of the GNU General Public License as published by the Free Soft- --
13-- ware Foundation; either version 2, or (at your option) any later ver- --
14-- sion. GNAT is distributed in the hope that it will be useful, but WITH- --
15-- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY --
16-- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License --
17-- for more details. You should have received a copy of the GNU General --
18-- Public License distributed with GNAT; see file COPYING. If not, write --
19-- to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, --
20-- MA 02111-1307, USA. --
21-- --
22-- GNAT was originally developed by the GNAT team at New York University. --
71ff80dc 23-- Extensive contributions were provided by Ada Core Technologies Inc. --
d23b8f57
RK
24-- --
25------------------------------------------------------------------------------
26
fbf5a39b 27with Debug; use Debug;
d23b8f57 28with Binderr; use Binderr;
fbf5a39b 29with Lib; use Lib;
d23b8f57
RK
30with Namet; use Namet;
31with Opt; use Opt;
fbf5a39b 32with Output; use Output;
d23b8f57
RK
33with Osint; use Osint;
34
cfac6e9f 35with System.CRC32;
07fc65c4 36with System.Memory;
cfac6e9f 37
d23b8f57
RK
38package body ALI.Util is
39
fbf5a39b
AC
40 type Header_Num is range 0 .. 1_000;
41
42 function Hash (F : File_Name_Type) return Header_Num;
43 -- Function used to compute hash of ALI file name
44
45 package Interfaces is new Simple_HTable (
46 Header_Num => Header_Num,
47 Element => Boolean,
48 No_Element => False,
49 Key => File_Name_Type,
50 Hash => Hash,
51 Equal => "=");
52
d23b8f57
RK
53 -----------------------
54 -- Local Subprograms --
55 -----------------------
56
57 procedure Accumulate_Checksum (C : Character; Csum : in out Word);
58 pragma Inline (Accumulate_Checksum);
59 -- This routine accumulates the checksum given character C. During the
60 -- scanning of a source file, this routine is called with every character
61 -- in the source, excluding blanks, and all control characters (except
62 -- that ESC is included in the checksum). Upper case letters not in string
63 -- literals are folded by the caller. See Sinput spec for the documentation
64 -- of the checksum algorithm. Note: checksum values are only used if we
65 -- generate code, so it is not necessary to worry about making the right
66 -- sequence of calls in any error situation.
67
de4bf6cb 68 procedure Initialize_Checksum (Csum : out Word);
cfac6e9f
PO
69 -- Sets initial value of Csum before any calls to Accumulate_Checksum
70
d23b8f57
RK
71 -------------------------
72 -- Accumulate_Checksum --
73 -------------------------
74
75 procedure Accumulate_Checksum (C : Character; Csum : in out Word) is
76 begin
cfac6e9f 77 System.CRC32.Update (System.CRC32.CRC32 (Csum), C);
d23b8f57
RK
78 end Accumulate_Checksum;
79
cfac6e9f
PO
80 ---------------------
81 -- Checksums_Match --
82 ---------------------
83
84 function Checksums_Match (Checksum1, Checksum2 : Word) return Boolean is
85 begin
86 return Checksum1 = Checksum2 and then Checksum1 /= Checksum_Error;
87 end Checksums_Match;
88
d23b8f57
RK
89 -----------------------
90 -- Get_File_Checksum --
91 -----------------------
92
93 function Get_File_Checksum (Fname : Name_Id) return Word is
94 Src : Source_Buffer_Ptr;
95 Hi : Source_Ptr;
96 Csum : Word;
97 Ptr : Source_Ptr;
98
99 Bad : exception;
100 -- Raised if file not found, or file format error
101
102 use ASCII;
103 -- Make control characters visible
104
d23b8f57
RK
105 begin
106 Read_Source_File (Fname, 0, Hi, Src);
107
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.
111
112 if Src = null then
113 raise Bad;
114 end if;
115
cfac6e9f 116 Initialize_Checksum (Csum);
d23b8f57
RK
117 Ptr := 0;
118
119 loop
120 case Src (Ptr) is
121
122 -- Spaces and formatting information are ignored in checksum
123
124 when ' ' | CR | LF | VT | FF | HT =>
125 Ptr := Ptr + 1;
126
127 -- EOF is ignored unless it is the last character
128
129 when EOF =>
130 if Ptr = Hi then
fbf5a39b 131 System.Memory.Free (Src.all'Address);
d23b8f57
RK
132 return Csum;
133 else
134 Ptr := Ptr + 1;
135 end if;
136
137 -- Non-blank characters that are included in the checksum
138
139 when '#' | '&' | '*' | ':' | '(' | ',' | '.' | '=' | '>' |
140 '<' | ')' | '/' | ';' | '|' | '!' | '+' | '_' |
141 '0' .. '9' | 'a' .. 'z'
142 =>
143 Accumulate_Checksum (Src (Ptr), Csum);
144 Ptr := Ptr + 1;
145
146 -- Upper case letters, fold to lower case
147
148 when 'A' .. 'Z' =>
149 Accumulate_Checksum
150 (Character'Val (Character'Pos (Src (Ptr)) + 32), Csum);
151 Ptr := Ptr + 1;
152
153 -- Left bracket, really should do wide character thing here,
154 -- but for now, don't bother.
155
156 when '[' =>
157 raise Bad;
158
159 -- Minus, could be comment
160
161 when '-' =>
162 if Src (Ptr + 1) = '-' then
163 Ptr := Ptr + 2;
164
165 while Src (Ptr) >= ' ' or else Src (Ptr) = HT loop
166 Ptr := Ptr + 1;
167 end loop;
168
169 else
170 Accumulate_Checksum ('-', Csum);
171 Ptr := Ptr + 1;
172 end if;
173
174 -- String delimited by double quote
175
176 when '"' =>
177 Accumulate_Checksum ('"', Csum);
178
179 loop
180 Ptr := Ptr + 1;
181 exit when Src (Ptr) = '"';
182
183 if Src (Ptr) < ' ' then
184 raise Bad;
185 end if;
186
187 Accumulate_Checksum (Src (Ptr), Csum);
188 end loop;
189
190 Accumulate_Checksum ('"', Csum);
191 Ptr := Ptr + 1;
192
193 -- String delimited by percent
194
195 when '%' =>
196 Accumulate_Checksum ('%', Csum);
197
198 loop
199 Ptr := Ptr + 1;
200 exit when Src (Ptr) = '%';
201
202 if Src (Ptr) < ' ' then
203 raise Bad;
204 end if;
205
206 Accumulate_Checksum (Src (Ptr), Csum);
207 end loop;
208
209 Accumulate_Checksum ('%', Csum);
210 Ptr := Ptr + 1;
211
212 -- Quote, could be character constant
213
214 when ''' =>
215 Accumulate_Checksum (''', Csum);
216
217 if Src (Ptr + 2) = ''' then
218 Accumulate_Checksum (Src (Ptr + 1), Csum);
219 Accumulate_Checksum (''', Csum);
220 Ptr := Ptr + 3;
221
222 -- Otherwise assume attribute char. We should deal with wide
223 -- character cases here, but that's hard, so forget it.
224
225 else
226 Ptr := Ptr + 1;
227 end if;
228
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.
232
233 when Upper_Half_Character =>
234 Accumulate_Checksum (Src (Ptr), Csum);
235 Ptr := Ptr + 1;
236
237 -- Escape character, we should do the wide character thing here,
238 -- but for now, do not bother.
239
240 when ESC =>
241 raise Bad;
242
243 -- Invalid control characters
244
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
248 =>
249 raise Bad;
250
251 -- Invalid graphic characters
252
253 when '$' | '?' | '@' | '`' | '\' |
254 '^' | '~' | ']' | '{' | '}'
255 =>
256 raise Bad;
257
258 end case;
259 end loop;
260
261 exception
262 when Bad =>
fbf5a39b 263 System.Memory.Free (Src.all'Address);
cfac6e9f 264 return Checksum_Error;
d23b8f57
RK
265 end Get_File_Checksum;
266
fbf5a39b
AC
267 ----------
268 -- Hash --
269 ----------
270
271 function Hash (F : File_Name_Type) return Header_Num is
272 begin
273 return Header_Num (Int (F) rem Header_Num'Range_Length);
274 end Hash;
275
d23b8f57
RK
276 ---------------------------
277 -- Initialize_ALI_Source --
278 ---------------------------
279
280 procedure Initialize_ALI_Source is
281 begin
282 -- When (re)initializing ALI data structures the ALI user expects to
283 -- get a fresh set of data structures. Thus we first need to erase the
284 -- marks put in the name table by the previous set of ALI routine calls.
285 -- This loop is empty and harmless the first time in.
286
287 for J in Source.First .. Source.Last loop
288 Set_Name_Table_Info (Source.Table (J).Sfile, 0);
289 Source.Table (J).Source_Found := False;
290 end loop;
291
292 Source.Init;
fbf5a39b 293 Interfaces.Reset;
d23b8f57
RK
294 end Initialize_ALI_Source;
295
cfac6e9f
PO
296 -------------------------
297 -- Initialize_Checksum --
298 -------------------------
299
de4bf6cb 300 procedure Initialize_Checksum (Csum : out Word) is
cfac6e9f
PO
301 begin
302 System.CRC32.Initialize (System.CRC32.CRC32 (Csum));
303 end Initialize_Checksum;
304
d23b8f57
RK
305 --------------
306 -- Read_ALI --
307 --------------
308
309 procedure Read_ALI (Id : ALI_Id) is
310 Afile : File_Name_Type;
311 Text : Text_Buffer_Ptr;
312 Idread : ALI_Id;
313
314 begin
fbf5a39b 315 -- Process all dependent units
d23b8f57 316
fbf5a39b
AC
317 for U in ALIs.Table (Id).First_Unit .. ALIs.Table (Id).Last_Unit loop
318 for
319 W in Units.Table (U).First_With .. Units.Table (U).Last_With
320 loop
321 Afile := Withs.Table (W).Afile;
d23b8f57
RK
322
323 -- Only process if not a generic (Afile /= No_File) and if
324 -- file has not been processed already.
325
fbf5a39b
AC
326 if Afile /= No_File
327 and then Get_Name_Table_Info (Afile) = 0
328 then
d23b8f57
RK
329 Text := Read_Library_Info (Afile);
330
fbf5a39b
AC
331 -- Return with an error if source cannot be found and if this
332 -- is not a library generic (now we can, but does not have to
333 -- compile library generics)
334
d23b8f57 335 if Text = null then
fbf5a39b
AC
336 if Generic_Separately_Compiled (Withs.Table (W).Sfile) then
337 Error_Msg_Name_1 := Afile;
338 Error_Msg_Name_2 := Withs.Table (W).Sfile;
339 Error_Msg ("% not found, % must be compiled");
340 Set_Name_Table_Info (Afile, Int (No_Unit_Id));
341 return;
342
343 else
344 goto Skip_Library_Generics;
345 end if;
d23b8f57
RK
346 end if;
347
fbf5a39b
AC
348 -- Enter in ALIs table
349
d23b8f57
RK
350 Idread :=
351 Scan_ALI
352 (F => Afile,
353 T => Text,
354 Ignore_ED => Force_RM_Elaboration_Order,
355 Err => False);
356
357 Free (Text);
358
359 if ALIs.Table (Idread).Compile_Errors then
fbf5a39b 360 Error_Msg_Name_1 := Withs.Table (W).Sfile;
d23b8f57
RK
361 Error_Msg ("% had errors, must be fixed, and recompiled");
362 Set_Name_Table_Info (Afile, Int (No_Unit_Id));
363
364 elsif ALIs.Table (Idread).No_Object then
fbf5a39b 365 Error_Msg_Name_1 := Withs.Table (W).Sfile;
d23b8f57
RK
366 Error_Msg ("% must be recompiled");
367 Set_Name_Table_Info (Afile, Int (No_Unit_Id));
368 end if;
369
fbf5a39b
AC
370 -- If the Unit is an Interface to a Stand-Alone Library,
371 -- set the Interface flag in the Withs table, so that its
372 -- dependant are not considered for elaboration order.
373
374 if ALIs.Table (Idread).Interface then
375 Withs.Table (W).Interface := True;
376 Interface_Library_Unit := True;
d23b8f57 377
fbf5a39b
AC
378 -- Set the entry in the Interfaces hash table, so that other
379 -- units that import this unit will set the flag in their
380 -- entry in the Withs table.
381
382 Interfaces.Set (Afile, True);
383
384 else
385 -- Otherwise, recurse to get new dependents
386
387 Read_ALI (Idread);
388 end if;
389
390 <<Skip_Library_Generics>> null;
391
392 -- If the ALI file has already been processed and is an interface,
393 -- set the flag in the entry of the Withs table.
394
395 elsif Interface_Library_Unit and then Interfaces.Get (Afile) then
396 Withs.Table (W).Interface := True;
d23b8f57
RK
397 end if;
398 end loop;
399 end loop;
d23b8f57
RK
400 end Read_ALI;
401
402 ----------------------
403 -- Set_Source_Table --
404 ----------------------
405
406 procedure Set_Source_Table (A : ALI_Id) is
407 F : File_Name_Type;
408 S : Source_Id;
409 Stamp : Time_Stamp_Type;
410
411 begin
412 Sdep_Loop : for D in
413 ALIs.Table (A).First_Sdep .. ALIs.Table (A).Last_Sdep
414 loop
415 F := Sdep.Table (D).Sfile;
416
fbf5a39b 417 if F /= No_Name then
d23b8f57 418
fbf5a39b
AC
419 -- If this is the first time we are seeing this source file,
420 -- then make a new entry in the source table.
d23b8f57 421
fbf5a39b
AC
422 if Get_Name_Table_Info (F) = 0 then
423 Source.Increment_Last;
424 S := Source.Last;
425 Set_Name_Table_Info (F, Int (S));
426 Source.Table (S).Sfile := F;
427 Source.Table (S).All_Timestamps_Match := True;
d23b8f57 428
fbf5a39b 429 -- Initialize checksum fields
d23b8f57 430
fbf5a39b
AC
431 Source.Table (S).Checksum := Sdep.Table (D).Checksum;
432 Source.Table (S).All_Checksums_Match := True;
d23b8f57 433
fbf5a39b 434 -- In check source files mode, try to get time stamp from file
d23b8f57 435
fbf5a39b
AC
436 if Opt.Check_Source_Files then
437 Stamp := Source_File_Stamp (F);
d23b8f57 438
fbf5a39b
AC
439 -- If we got the stamp, then set the stamp in the source
440 -- table entry and mark it as set from the source so that
441 -- it does not get subsequently changed.
d23b8f57 442
fbf5a39b
AC
443 if Stamp (Stamp'First) /= ' ' then
444 Source.Table (S).Stamp := Stamp;
445 Source.Table (S).Source_Found := True;
d23b8f57 446
fbf5a39b
AC
447 -- If we could not find the file, then the stamp is set
448 -- from the dependency table entry (to be possibly reset
449 -- if we find a later stamp in subsequent processing)
450
451 else
452 Source.Table (S).Stamp := Sdep.Table (D).Stamp;
453 Source.Table (S).Source_Found := False;
d23b8f57 454
fbf5a39b 455 -- In All_Sources mode, flag error of file not found
d23b8f57 456
fbf5a39b
AC
457 if Opt.All_Sources then
458 Error_Msg_Name_1 := F;
459 Error_Msg ("cannot locate %");
460 end if;
d23b8f57 461 end if;
d23b8f57 462
fbf5a39b
AC
463 -- First time for this source file, but Check_Source_Files
464 -- is off, so simply initialize the stamp from the Sdep entry
d23b8f57 465
fbf5a39b
AC
466 else
467 Source.Table (S).Source_Found := False;
468 Source.Table (S).Stamp := Sdep.Table (D).Stamp;
469 end if;
d23b8f57 470
fbf5a39b
AC
471 -- Here if this is not the first time for this source file,
472 -- so that the source table entry is already constructed.
d23b8f57 473
fbf5a39b
AC
474 else
475 S := Source_Id (Get_Name_Table_Info (F));
d23b8f57 476
fbf5a39b 477 -- Update checksum flag
d23b8f57 478
fbf5a39b
AC
479 if not Checksums_Match
480 (Sdep.Table (D).Checksum, Source.Table (S).Checksum)
481 then
482 Source.Table (S).All_Checksums_Match := False;
483 end if;
d23b8f57 484
fbf5a39b 485 -- Check for time stamp mismatch
d23b8f57 486
fbf5a39b
AC
487 if Sdep.Table (D).Stamp /= Source.Table (S).Stamp then
488 Source.Table (S).All_Timestamps_Match := False;
d23b8f57 489
fbf5a39b
AC
490 -- When we have a time stamp mismatch, we go look for the
491 -- source file even if Check_Source_Files is false, since
492 -- if we find it, then we can use it to resolve which of the
493 -- two timestamps in the ALI files is likely to be correct.
d23b8f57 494
fbf5a39b
AC
495 if not Check_Source_Files then
496 Stamp := Source_File_Stamp (F);
d23b8f57 497
fbf5a39b
AC
498 if Stamp (Stamp'First) /= ' ' then
499 Source.Table (S).Stamp := Stamp;
500 Source.Table (S).Source_Found := True;
501 end if;
d23b8f57 502 end if;
d23b8f57 503
fbf5a39b
AC
504 -- If the stamp in the source table entry was set from the
505 -- source file, then we do not change it (the stamp in the
506 -- source file is always taken as the "right" one).
d23b8f57 507
fbf5a39b
AC
508 if Source.Table (S).Source_Found then
509 null;
d23b8f57 510
fbf5a39b
AC
511 -- Otherwise, we have no source file available, so we guess
512 -- that the later of the two timestamps is the right one.
513 -- Note that this guess only affects which error messages
514 -- are issued later on, not correct functionality.
d23b8f57 515
fbf5a39b
AC
516 else
517 if Sdep.Table (D).Stamp > Source.Table (S).Stamp then
518 Source.Table (S).Stamp := Sdep.Table (D).Stamp;
519 end if;
d23b8f57
RK
520 end if;
521 end if;
522 end if;
d23b8f57 523
fbf5a39b 524 -- Set the checksum value in the source table
d23b8f57 525
fbf5a39b
AC
526 S := Source_Id (Get_Name_Table_Info (F));
527 Source.Table (S).Checksum := Sdep.Table (D).Checksum;
528 end if;
d23b8f57
RK
529
530 end loop Sdep_Loop;
d23b8f57
RK
531 end Set_Source_Table;
532
533 ----------------------
534 -- Set_Source_Table --
535 ----------------------
536
537 procedure Set_Source_Table is
538 begin
539 for A in ALIs.First .. ALIs.Last loop
540 Set_Source_Table (A);
541 end loop;
d23b8f57
RK
542 end Set_Source_Table;
543
544 -------------------------
545 -- Time_Stamp_Mismatch --
546 -------------------------
547
fbf5a39b
AC
548 function Time_Stamp_Mismatch
549 (A : ALI_Id;
550 Read_Only : Boolean := False)
551 return File_Name_Type
552 is
d23b8f57
RK
553 Src : Source_Id;
554 -- Source file Id for the current Sdep entry
555
556 begin
557 for D in ALIs.Table (A).First_Sdep .. ALIs.Table (A).Last_Sdep loop
558 Src := Source_Id (Get_Name_Table_Info (Sdep.Table (D).Sfile));
559
560 if Opt.Minimal_Recompilation
561 and then Sdep.Table (D).Stamp /= Source.Table (Src).Stamp
562 then
d23b8f57
RK
563 -- If minimal recompilation is in action, replace the stamp
564 -- of the source file in the table if checksums match.
565
566 -- ??? It is probably worth updating the ALI file with a new
567 -- field to avoid recomputing it each time.
568
cfac6e9f
PO
569 if Checksums_Match
570 (Get_File_Checksum (Sdep.Table (D).Sfile),
571 Source.Table (Src).Checksum)
d23b8f57
RK
572 then
573 Sdep.Table (D).Stamp := Source.Table (Src).Stamp;
574 end if;
575
576 end if;
577
fbf5a39b
AC
578 if (not Read_Only) or else Source.Table (Src).Source_Found then
579 if not Source.Table (Src).Source_Found
580 or else Sdep.Table (D).Stamp /= Source.Table (Src).Stamp
581 then
582 -- If -t debug flag set, output time stamp found/expected
583
584 if Source.Table (Src).Source_Found and Debug_Flag_T then
585 Write_Str ("Source: """);
586 Get_Name_String (Sdep.Table (D).Sfile);
587 Write_Str (Name_Buffer (1 .. Name_Len));
588 Write_Line ("""");
589
590 Write_Str (" time stamp expected: ");
591 Write_Line (String (Sdep.Table (D).Stamp));
592
593 Write_Str (" time stamp found: ");
594 Write_Line (String (Source.Table (Src).Stamp));
595 end if;
596
597 -- Return the source file
598
599 return Source.Table (Src).Sfile;
600 end if;
d23b8f57
RK
601 end if;
602 end loop;
603
604 return No_File;
d23b8f57
RK
605 end Time_Stamp_Mismatch;
606
607end ALI.Util;