1------------------------------------------------------------------------------ 2-- -- 3-- GNAT COMPILER COMPONENTS -- 4-- -- 5-- M A K E _ U T I L -- 6-- -- 7-- B o d y -- 8-- -- 9-- Copyright (C) 2004-2018, Free Software Foundation, Inc. -- 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 3, 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 COPYING3. If not, go to -- 19-- http://www.gnu.org/licenses for a complete copy of the license. -- 20-- -- 21-- GNAT was originally developed by the GNAT team at New York University. -- 22-- Extensive contributions were provided by Ada Core Technologies Inc. -- 23-- -- 24------------------------------------------------------------------------------ 25 26with Atree; use Atree; 27with Debug; 28with Errutil; 29with Osint; use Osint; 30with Output; use Output; 31with Opt; use Opt; 32with Table; 33 34with Ada.Command_Line; use Ada.Command_Line; 35 36with GNAT.Case_Util; use GNAT.Case_Util; 37with GNAT.Directory_Operations; use GNAT.Directory_Operations; 38with GNAT.HTable; 39 40package body Make_Util is 41 42 --------- 43 -- Add -- 44 --------- 45 46 procedure Add 47 (Option : String_Access; 48 To : in out String_List_Access; 49 Last : in out Natural) 50 is 51 begin 52 if Last = To'Last then 53 declare 54 New_Options : constant String_List_Access := 55 new String_List (1 .. To'Last * 2); 56 57 begin 58 New_Options (To'Range) := To.all; 59 60 -- Set all elements of the original options to null to avoid 61 -- deallocation of copies. 62 63 To.all := (others => null); 64 65 Free (To); 66 To := New_Options; 67 end; 68 end if; 69 70 Last := Last + 1; 71 To (Last) := Option; 72 end Add; 73 74 procedure Add 75 (Option : String; 76 To : in out String_List_Access; 77 Last : in out Natural) 78 is 79 begin 80 Add (Option => new String'(Option), To => To, Last => Last); 81 end Add; 82 83 ------------------------- 84 -- Base_Name_Index_For -- 85 ------------------------- 86 87 function Base_Name_Index_For 88 (Main : String; 89 Main_Index : Int; 90 Index_Separator : Character) return File_Name_Type 91 is 92 Result : File_Name_Type; 93 94 begin 95 Name_Len := 0; 96 Add_Str_To_Name_Buffer (Base_Name (Main)); 97 98 -- Remove the extension, if any, that is the last part of the base name 99 -- starting with a dot and following some characters. 100 101 for J in reverse 2 .. Name_Len loop 102 if Name_Buffer (J) = '.' then 103 Name_Len := J - 1; 104 exit; 105 end if; 106 end loop; 107 108 -- Add the index info, if index is different from 0 109 110 if Main_Index > 0 then 111 Add_Char_To_Name_Buffer (Index_Separator); 112 113 declare 114 Img : constant String := Main_Index'Img; 115 begin 116 Add_Str_To_Name_Buffer (Img (2 .. Img'Last)); 117 end; 118 end if; 119 120 Result := Name_Find; 121 return Result; 122 end Base_Name_Index_For; 123 124 ----------------- 125 -- Create_Name -- 126 ----------------- 127 128 function Create_Name (Name : String) return File_Name_Type is 129 begin 130 Name_Len := 0; 131 Add_Str_To_Name_Buffer (Name); 132 return Name_Find; 133 end Create_Name; 134 135 function Create_Name (Name : String) return Name_Id is 136 begin 137 Name_Len := 0; 138 Add_Str_To_Name_Buffer (Name); 139 return Name_Find; 140 end Create_Name; 141 142 function Create_Name (Name : String) return Path_Name_Type is 143 begin 144 Name_Len := 0; 145 Add_Str_To_Name_Buffer (Name); 146 return Name_Find; 147 end Create_Name; 148 149 --------------------------- 150 -- Ensure_Absolute_Path -- 151 --------------------------- 152 153 procedure Ensure_Absolute_Path 154 (Switch : in out String_Access; 155 Parent : String; 156 Do_Fail : Fail_Proc; 157 For_Gnatbind : Boolean := False; 158 Including_Non_Switch : Boolean := True; 159 Including_RTS : Boolean := False) 160 is 161 begin 162 if Switch /= null then 163 declare 164 Sw : String (1 .. Switch'Length); 165 Start : Positive; 166 167 begin 168 Sw := Switch.all; 169 170 if Sw (1) = '-' then 171 if Sw'Length >= 3 172 and then (Sw (2) = 'I' 173 or else (not For_Gnatbind 174 and then (Sw (2) = 'L' 175 or else 176 Sw (2) = 'A'))) 177 then 178 Start := 3; 179 180 if Sw = "-I-" then 181 return; 182 end if; 183 184 elsif Sw'Length >= 4 185 and then 186 (Sw (2 .. 3) = "aL" or else 187 Sw (2 .. 3) = "aO" or else 188 Sw (2 .. 3) = "aI" 189 or else (For_Gnatbind and then Sw (2 .. 3) = "A=")) 190 then 191 Start := 4; 192 193 elsif Including_RTS 194 and then Sw'Length >= 7 195 and then Sw (2 .. 6) = "-RTS=" 196 then 197 Start := 7; 198 199 else 200 return; 201 end if; 202 203 -- Because relative path arguments to --RTS= may be relative to 204 -- the search directory prefix, those relative path arguments 205 -- are converted only when they include directory information. 206 207 if not Is_Absolute_Path (Sw (Start .. Sw'Last)) then 208 if Parent'Length = 0 then 209 Do_Fail 210 ("relative search path switches (""" 211 & Sw 212 & """) are not allowed"); 213 214 elsif Including_RTS then 215 for J in Start .. Sw'Last loop 216 if Sw (J) = Directory_Separator then 217 Switch := 218 new String' 219 (Sw (1 .. Start - 1) 220 & Parent 221 & Directory_Separator 222 & Sw (Start .. Sw'Last)); 223 return; 224 end if; 225 end loop; 226 227 else 228 Switch := 229 new String' 230 (Sw (1 .. Start - 1) 231 & Parent 232 & Directory_Separator 233 & Sw (Start .. Sw'Last)); 234 end if; 235 end if; 236 237 elsif Including_Non_Switch then 238 if not Is_Absolute_Path (Sw) then 239 if Parent'Length = 0 then 240 Do_Fail 241 ("relative paths (""" & Sw & """) are not allowed"); 242 else 243 Switch := new String'(Parent & Directory_Separator & Sw); 244 end if; 245 end if; 246 end if; 247 end; 248 end if; 249 end Ensure_Absolute_Path; 250 251 ---------------------------- 252 -- Executable_Prefix_Path -- 253 ---------------------------- 254 255 function Executable_Prefix_Path return String is 256 Exec_Name : constant String := Command_Name; 257 258 function Get_Install_Dir (S : String) return String; 259 -- S is the executable name preceded by the absolute or relative path, 260 -- e.g. "c:\usr\bin\gcc.exe". Returns the absolute directory where "bin" 261 -- lies (in the example "C:\usr"). If the executable is not in a "bin" 262 -- directory, return "". 263 264 --------------------- 265 -- Get_Install_Dir -- 266 --------------------- 267 268 function Get_Install_Dir (S : String) return String is 269 Exec : String := S; 270 Path_Last : Integer := 0; 271 272 begin 273 for J in reverse Exec'Range loop 274 if Exec (J) = Directory_Separator then 275 Path_Last := J - 1; 276 exit; 277 end if; 278 end loop; 279 280 if Path_Last >= Exec'First + 2 then 281 To_Lower (Exec (Path_Last - 2 .. Path_Last)); 282 end if; 283 284 if Path_Last < Exec'First + 2 285 or else Exec (Path_Last - 2 .. Path_Last) /= "bin" 286 or else (Path_Last - 3 >= Exec'First 287 and then Exec (Path_Last - 3) /= Directory_Separator) 288 then 289 return ""; 290 end if; 291 292 return Normalize_Pathname 293 (Exec (Exec'First .. Path_Last - 4), 294 Resolve_Links => Opt.Follow_Links_For_Dirs) 295 & Directory_Separator; 296 end Get_Install_Dir; 297 298 -- Beginning of Executable_Prefix_Path 299 300 begin 301 -- First determine if a path prefix was placed in front of the 302 -- executable name. 303 304 for J in reverse Exec_Name'Range loop 305 if Exec_Name (J) = Directory_Separator then 306 return Get_Install_Dir (Exec_Name); 307 end if; 308 end loop; 309 310 -- If we get here, the user has typed the executable name with no 311 -- directory prefix. 312 313 declare 314 Path : String_Access := Locate_Exec_On_Path (Exec_Name); 315 begin 316 if Path = null then 317 return ""; 318 else 319 declare 320 Dir : constant String := Get_Install_Dir (Path.all); 321 begin 322 Free (Path); 323 return Dir; 324 end; 325 end if; 326 end; 327 end Executable_Prefix_Path; 328 329 ------------------ 330 -- Fail_Program -- 331 ------------------ 332 333 procedure Fail_Program 334 (S : String; 335 Flush_Messages : Boolean := True) 336 is 337 begin 338 if Flush_Messages and not No_Exit_Message then 339 if Total_Errors_Detected /= 0 or else Warnings_Detected /= 0 then 340 Errutil.Finalize; 341 end if; 342 end if; 343 344 Finish_Program (E_Fatal, S => S); 345 end Fail_Program; 346 347 -------------------- 348 -- Finish_Program -- 349 -------------------- 350 351 procedure Finish_Program 352 (Exit_Code : Osint.Exit_Code_Type := Osint.E_Success; 353 S : String := "") 354 is 355 begin 356 if S'Length > 0 then 357 if Exit_Code /= E_Success then 358 if No_Exit_Message then 359 Osint.Exit_Program (E_Fatal); 360 else 361 Osint.Fail (S); 362 end if; 363 364 elsif not No_Exit_Message then 365 Write_Str (S); 366 end if; 367 end if; 368 369 -- Output Namet statistics 370 371 Namet.Finalize; 372 373 Exit_Program (Exit_Code); 374 end Finish_Program; 375 376 ---------- 377 -- Hash -- 378 ---------- 379 380 function Hash is new GNAT.HTable.Hash (Header_Num => Header_Num); 381 -- Used in implementation of other functions Hash below 382 383 ---------- 384 -- Hash -- 385 ---------- 386 387 function Hash (Name : File_Name_Type) return Header_Num is 388 begin 389 return Hash (Get_Name_String (Name)); 390 end Hash; 391 392 function Hash (Name : Name_Id) return Header_Num is 393 begin 394 return Hash (Get_Name_String (Name)); 395 end Hash; 396 397 function Hash (Name : Path_Name_Type) return Header_Num is 398 begin 399 return Hash (Get_Name_String (Name)); 400 end Hash; 401 402 ------------ 403 -- Inform -- 404 ------------ 405 406 procedure Inform (N : File_Name_Type; Msg : String) is 407 begin 408 Inform (Name_Id (N), Msg); 409 end Inform; 410 411 procedure Inform (N : Name_Id := No_Name; Msg : String) is 412 begin 413 Osint.Write_Program_Name; 414 415 Write_Str (": "); 416 417 if N /= No_Name then 418 Write_Str (""""); 419 420 declare 421 Name : constant String := Get_Name_String (N); 422 begin 423 if Debug.Debug_Flag_F and then Is_Absolute_Path (Name) then 424 Write_Str (File_Name (Name)); 425 else 426 Write_Str (Name); 427 end if; 428 end; 429 430 Write_Str (""" "); 431 end if; 432 433 Write_Str (Msg); 434 Write_Eol; 435 end Inform; 436 437 ----------- 438 -- Mains -- 439 ----------- 440 441 package body Mains is 442 443 package Names is new Table.Table 444 (Table_Component_Type => Main_Info, 445 Table_Index_Type => Integer, 446 Table_Low_Bound => 1, 447 Table_Initial => 10, 448 Table_Increment => 100, 449 Table_Name => "Makeutl.Mains.Names"); 450 -- The table that stores the mains 451 452 Current : Natural := 0; 453 -- The index of the last main retrieved from the table 454 455 Count_Of_Mains_With_No_Tree : Natural := 0; 456 -- Number of main units for which we do not know the project tree 457 458 -------------- 459 -- Add_Main -- 460 -------------- 461 462 procedure Add_Main (Name : String; Index : Int := 0) is 463 begin 464 Name_Len := 0; 465 Add_Str_To_Name_Buffer (Name); 466 Canonical_Case_File_Name (Name_Buffer (1 .. Name_Len)); 467 468 Names.Increment_Last; 469 Names.Table (Names.Last) := (Name_Find, Index); 470 471 Mains.Count_Of_Mains_With_No_Tree := 472 Mains.Count_Of_Mains_With_No_Tree + 1; 473 end Add_Main; 474 475 ------------ 476 -- Delete -- 477 ------------ 478 479 procedure Delete is 480 begin 481 Names.Set_Last (0); 482 Mains.Reset; 483 end Delete; 484 485 --------------- 486 -- Next_Main -- 487 --------------- 488 489 function Next_Main return String is 490 Info : constant Main_Info := Next_Main; 491 begin 492 if Info = No_Main_Info then 493 return ""; 494 else 495 return Get_Name_String (Info.File); 496 end if; 497 end Next_Main; 498 499 function Next_Main return Main_Info is 500 begin 501 if Current >= Names.Last then 502 return No_Main_Info; 503 else 504 Current := Current + 1; 505 506 declare 507 Orig_Main : constant File_Name_Type := 508 Names.Table (Current).File; 509 Current_Main : File_Name_Type; 510 511 begin 512 if Strip_Suffix (Orig_Main) = Orig_Main then 513 Get_Name_String (Orig_Main); 514 Add_Str_To_Name_Buffer (".adb"); 515 Current_Main := Name_Find; 516 517 if Full_Source_Name (Current_Main) = No_File then 518 Get_Name_String (Orig_Main); 519 Add_Str_To_Name_Buffer (".ads"); 520 Current_Main := Name_Find; 521 522 if Full_Source_Name (Current_Main) /= No_File then 523 Names.Table (Current).File := Current_Main; 524 end if; 525 526 else 527 Names.Table (Current).File := Current_Main; 528 end if; 529 end if; 530 end; 531 532 return Names.Table (Current); 533 end if; 534 end Next_Main; 535 536 --------------------- 537 -- Number_Of_Mains -- 538 --------------------- 539 540 function Number_Of_Mains return Natural is 541 begin 542 return Names.Last; 543 end Number_Of_Mains; 544 545 ----------- 546 -- Reset -- 547 ----------- 548 549 procedure Reset is 550 begin 551 Current := 0; 552 end Reset; 553 554 -------------------------- 555 -- Set_Multi_Unit_Index -- 556 -------------------------- 557 558 procedure Set_Multi_Unit_Index 559 (Index : Int := 0) 560 is 561 begin 562 if Index /= 0 then 563 if Names.Last = 0 then 564 Fail_Program 565 ("cannot specify a multi-unit index but no main " 566 & "on the command line"); 567 568 elsif Names.Last > 1 then 569 Fail_Program 570 ("cannot specify several mains with a multi-unit index"); 571 572 else 573 Names.Table (Names.Last).Index := Index; 574 end if; 575 end if; 576 end Set_Multi_Unit_Index; 577 578 end Mains; 579 580 ----------------------- 581 -- Path_Or_File_Name -- 582 ----------------------- 583 584 function Path_Or_File_Name (Path : Path_Name_Type) return String is 585 Path_Name : constant String := Get_Name_String (Path); 586 begin 587 if Debug.Debug_Flag_F then 588 return File_Name (Path_Name); 589 else 590 return Path_Name; 591 end if; 592 end Path_Or_File_Name; 593 594 ------------------- 595 -- Unit_Index_Of -- 596 ------------------- 597 598 function Unit_Index_Of (ALI_File : File_Name_Type) return Int is 599 Start : Natural; 600 Finish : Natural; 601 Result : Int := 0; 602 603 begin 604 Get_Name_String (ALI_File); 605 606 -- First, find the last dot 607 608 Finish := Name_Len; 609 610 while Finish >= 1 and then Name_Buffer (Finish) /= '.' loop 611 Finish := Finish - 1; 612 end loop; 613 614 if Finish = 1 then 615 return 0; 616 end if; 617 618 -- Now check that the dot is preceded by digits 619 620 Start := Finish; 621 Finish := Finish - 1; 622 while Start >= 1 and then Name_Buffer (Start - 1) in '0' .. '9' loop 623 Start := Start - 1; 624 end loop; 625 626 -- If there are no digits, or if the digits are not preceded by the 627 -- character that precedes a unit index, this is not the ALI file of 628 -- a unit in a multi-unit source. 629 630 if Start > Finish 631 or else Start = 1 632 or else Name_Buffer (Start - 1) /= Multi_Unit_Index_Character 633 then 634 return 0; 635 end if; 636 637 -- Build the index from the digit(s) 638 639 while Start <= Finish loop 640 Result := Result * 10 + 641 Character'Pos (Name_Buffer (Start)) - Character'Pos ('0'); 642 Start := Start + 1; 643 end loop; 644 645 return Result; 646 end Unit_Index_Of; 647 648 ----------------- 649 -- Verbose_Msg -- 650 ----------------- 651 652 procedure Verbose_Msg 653 (N1 : Name_Id; 654 S1 : String; 655 N2 : Name_Id := No_Name; 656 S2 : String := ""; 657 Prefix : String := " -> "; 658 Minimum_Verbosity : Opt.Verbosity_Level_Type := Opt.Low) 659 is 660 begin 661 if not Opt.Verbose_Mode 662 or else Minimum_Verbosity > Opt.Verbosity_Level 663 then 664 return; 665 end if; 666 667 Write_Str (Prefix); 668 Write_Str (""""); 669 Write_Name (N1); 670 Write_Str (""" "); 671 Write_Str (S1); 672 673 if N2 /= No_Name then 674 Write_Str (" """); 675 Write_Name (N2); 676 Write_Str (""" "); 677 end if; 678 679 Write_Str (S2); 680 Write_Eol; 681 end Verbose_Msg; 682 683 procedure Verbose_Msg 684 (N1 : File_Name_Type; 685 S1 : String; 686 N2 : File_Name_Type := No_File; 687 S2 : String := ""; 688 Prefix : String := " -> "; 689 Minimum_Verbosity : Opt.Verbosity_Level_Type := Opt.Low) 690 is 691 begin 692 Verbose_Msg 693 (Name_Id (N1), S1, Name_Id (N2), S2, Prefix, Minimum_Verbosity); 694 end Verbose_Msg; 695 696 ----------- 697 -- Queue -- 698 ----------- 699 700 package body Queue is 701 702 type Q_Record is record 703 Info : Source_Info; 704 Processed : Boolean; 705 end record; 706 707 package Q is new Table.Table 708 (Table_Component_Type => Q_Record, 709 Table_Index_Type => Natural, 710 Table_Low_Bound => 1, 711 Table_Initial => 1000, 712 Table_Increment => 100, 713 Table_Name => "Makeutl.Queue.Q"); 714 -- This is the actual Queue 715 716 type Mark_Key is record 717 File : File_Name_Type; 718 Index : Int; 719 end record; 720 -- Identify either a mono-unit source (when Index = 0) or a specific 721 -- unit (index = 1's origin index of unit) in a multi-unit source. 722 723 Max_Mask_Num : constant := 2048; 724 subtype Mark_Num is Union_Id range 0 .. Max_Mask_Num - 1; 725 726 function Hash (Key : Mark_Key) return Mark_Num; 727 728 package Marks is new GNAT.HTable.Simple_HTable 729 (Header_Num => Mark_Num, 730 Element => Boolean, 731 No_Element => False, 732 Key => Mark_Key, 733 Hash => Hash, 734 Equal => "="); 735 -- A hash table to keep tracks of the marked units. 736 -- These are the units that have already been processed, when using the 737 -- gnatmake format. When using the gprbuild format, we can directly 738 -- store in the source_id whether the file has already been processed. 739 740 procedure Mark (Source_File : File_Name_Type; Index : Int := 0); 741 -- Mark a unit, identified by its source file and, when Index is not 0, 742 -- the index of the unit in the source file. Marking is used to signal 743 -- that the unit has already been inserted in the Q. 744 745 function Is_Marked 746 (Source_File : File_Name_Type; 747 Index : Int := 0) return Boolean; 748 -- Returns True if the unit was previously marked 749 750 Q_Processed : Natural := 0; 751 Q_Initialized : Boolean := False; 752 753 Q_First : Natural := 1; 754 -- Points to the first valid element in the queue 755 756 procedure Debug_Display (S : Source_Info); 757 -- A debug display for S 758 759 function Was_Processed (S : Source_Info) return Boolean; 760 -- Whether S has already been processed. This marks the source as 761 -- processed, if it hasn't already been processed. 762 763 ------------------- 764 -- Was_Processed -- 765 ------------------- 766 767 function Was_Processed (S : Source_Info) return Boolean is 768 begin 769 if Is_Marked (S.File, S.Index) then 770 return True; 771 end if; 772 773 Mark (S.File, Index => S.Index); 774 775 return False; 776 end Was_Processed; 777 778 ------------------- 779 -- Debug_Display -- 780 ------------------- 781 782 procedure Debug_Display (S : Source_Info) is 783 begin 784 Write_Name (S.File); 785 786 if S.Index /= 0 then 787 Write_Str (", "); 788 Write_Int (S.Index); 789 end if; 790 end Debug_Display; 791 792 ---------- 793 -- Hash -- 794 ---------- 795 796 function Hash (Key : Mark_Key) return Mark_Num is 797 begin 798 return Union_Id (Key.File) mod Max_Mask_Num; 799 end Hash; 800 801 --------------- 802 -- Is_Marked -- 803 --------------- 804 805 function Is_Marked 806 (Source_File : File_Name_Type; 807 Index : Int := 0) return Boolean 808 is 809 begin 810 return Marks.Get (K => (File => Source_File, Index => Index)); 811 end Is_Marked; 812 813 ---------- 814 -- Mark -- 815 ---------- 816 817 procedure Mark (Source_File : File_Name_Type; Index : Int := 0) is 818 begin 819 Marks.Set (K => (File => Source_File, Index => Index), E => True); 820 end Mark; 821 822 ------------- 823 -- Extract -- 824 ------------- 825 826 procedure Extract 827 (Found : out Boolean; 828 Source : out Source_Info) 829 is 830 begin 831 Found := False; 832 833 if Q_First <= Q.Last then 834 Source := Q.Table (Q_First).Info; 835 Q.Table (Q_First).Processed := True; 836 Q_First := Q_First + 1; 837 Found := True; 838 end if; 839 840 if Found then 841 Q_Processed := Q_Processed + 1; 842 end if; 843 844 if Found and then Debug.Debug_Flag_Q then 845 Write_Str (" Q := Q - [ "); 846 Debug_Display (Source); 847 Write_Str (" ]"); 848 Write_Eol; 849 850 Write_Str (" Q_First ="); 851 Write_Int (Int (Q_First)); 852 Write_Eol; 853 854 Write_Str (" Q.Last ="); 855 Write_Int (Int (Q.Last)); 856 Write_Eol; 857 end if; 858 end Extract; 859 860 --------------- 861 -- Processed -- 862 --------------- 863 864 function Processed return Natural is 865 begin 866 return Q_Processed; 867 end Processed; 868 869 ---------------- 870 -- Initialize -- 871 ---------------- 872 873 procedure Initialize (Force : Boolean := False) is 874 begin 875 if Force or else not Q_Initialized then 876 Q_Initialized := True; 877 Q.Init; 878 Q_Processed := 0; 879 Q_First := 1; 880 end if; 881 end Initialize; 882 883 ------------ 884 -- Insert -- 885 ------------ 886 887 function Insert (Source : Source_Info) return Boolean is 888 begin 889 -- Only insert in the Q if it is not already done, to avoid 890 -- simultaneous compilations if -jnnn is used. 891 892 if Was_Processed (Source) then 893 return False; 894 end if; 895 896 Q.Append (New_Val => (Info => Source, Processed => False)); 897 898 if Debug.Debug_Flag_Q then 899 Write_Str (" Q := Q + [ "); 900 Debug_Display (Source); 901 Write_Str (" ] "); 902 Write_Eol; 903 904 Write_Str (" Q_First ="); 905 Write_Int (Int (Q_First)); 906 Write_Eol; 907 908 Write_Str (" Q.Last ="); 909 Write_Int (Int (Q.Last)); 910 Write_Eol; 911 end if; 912 913 return True; 914 end Insert; 915 916 procedure Insert (Source : Source_Info) is 917 Discard : Boolean; 918 begin 919 Discard := Insert (Source); 920 end Insert; 921 922 -------------- 923 -- Is_Empty -- 924 -------------- 925 926 function Is_Empty return Boolean is 927 begin 928 return Q_Processed >= Q.Last; 929 end Is_Empty; 930 931 ---------- 932 -- Size -- 933 ---------- 934 935 function Size return Natural is 936 begin 937 return Q.Last; 938 end Size; 939 940 ------------- 941 -- Element -- 942 ------------- 943 944 function Element (Rank : Positive) return File_Name_Type is 945 begin 946 if Rank <= Q.Last then 947 return Q.Table (Rank).Info.File; 948 else 949 return No_File; 950 end if; 951 end Element; 952 953 ------------------ 954 -- Remove_Marks -- 955 ------------------ 956 957 procedure Remove_Marks is 958 begin 959 Marks.Reset; 960 end Remove_Marks; 961 962 end Queue; 963 964end Make_Util; 965