home *** CD-ROM | disk | FTP | other *** search
/ Geek Gadgets 1 / ADE-1.bin / ade-dist / gnat-2.06-src.tgz / tar.out / fsf / gnat / ada / osint.adb < prev    next >
Text File  |  1996-09-28  |  47KB  |  1,439 lines

  1. ------------------------------------------------------------------------------
  2. --                                                                          --
  3. --                         GNAT COMPILER COMPONENTS                         --
  4. --                                                                          --
  5. --                                O S I N T                                 --
  6. --                                                                          --
  7. --                                 B o d y                                  --
  8. --                                                                          --
  9. --                            $Revision: 1.127 $                            --
  10. --                                                                          --
  11. --        Copyright (c) 1992,1993,1994,1995 NYU, All Rights Reserved        --
  12. --                                                                          --
  13. -- GNAT is free software;  you can  redistribute it  and/or modify it under --
  14. -- terms of the  GNU General Public License as published  by the Free Soft- --
  15. -- ware  Foundation;  either version 2,  or (at your option) any later ver- --
  16. -- sion.  GNAT is distributed in the hope that it will be useful, but WITH- --
  17. -- OUT ANY WARRANTY;  without even the  implied warranty of MERCHANTABILITY --
  18. -- or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License --
  19. -- for  more details.  You should have  received  a copy of the GNU General --
  20. -- Public License  distributed with GNAT;  see file COPYING.  If not, write --
  21. -- to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. --
  22. --                                                                          --
  23. ------------------------------------------------------------------------------
  24.  
  25. with Namet;         use Namet;
  26. with Output;        use Output;
  27. with Switch;        use Switch;
  28. with Opt;           use Opt;
  29. with GNAT.OS_Lib;   use GNAT.OS_Lib;
  30. with Sdefault;      use Sdefault;
  31. with Table;
  32. with Tree_IO;       use Tree_IO;
  33. with Unchecked_Conversion;
  34.  
  35. package body Osint is
  36.  
  37.    -----------------------
  38.    -- Local Subprograms --
  39.    -----------------------
  40.  
  41.    function OS_Time_To_GNAT_Time (T : OS_Time) return Time_Stamp_Type;
  42.    --  Convert OS format time to GNAT format time stamp
  43.  
  44.    procedure Create_File_And_Check
  45.      (Fdesc : out File_Descriptor;
  46.       Fmode : Mode);
  47.    --  Create file whose name (NUL terminated) is in Name_Buffer (with the
  48.    --  length in Name_Len), and place the resulting descriptor in Fdesc.
  49.    --  Issue message and exit with fatal error if file cannot be created.
  50.    --  The Fmode parameter is set to either Text or Binary (see description
  51.    --  of GNAT.OS_Lib.Create_File).
  52.  
  53.    procedure Write_With_Check (A  : Address; N  : Integer);
  54.    --  Writes N bytes from buffer starting at address A to file whose FD
  55.    --  is stored in Output_FD, and whose file name is stored as a Name_Id
  56.    --  in Output_File_Name. A check is made for disk full, and if this is
  57.    --  detected, the file being written is deleted, and a fatal error is
  58.    --  signalled.
  59.  
  60.    function Normalize_Directory_Name (Directory : String) return String_Ptr;
  61.    --  Verify and normalize a directory name. If directory name is invalid,
  62.    --  this will return an empty string. Otherwise it will insure a trailing
  63.    --  slash and make other normalizations.
  64.  
  65.    function Src_Locate_File
  66.      (Dir_Index : Natural;
  67.       File_Name : String)
  68.       return      Name_Id;
  69.    --  See if the file whose name is File_Name exists in the directory
  70.    --  Src_Search_Directories indexed by Dir_Index. Returns the Name_Id
  71.    --  of he full file name if file found, or No_Name if not found.
  72.  
  73.    function Lib_Locate_File
  74.      (Dir_Index : Natural;
  75.       File_Name : String)
  76.       return      Name_Id;
  77.    --  Same as above for library files except that the Dir_Index is an
  78.    --  index in Lib_Searc_Directories.
  79.  
  80.    function Find_Source_File (N : File_Name_Type) return Name_Id;
  81.    --  Find a source file following the directory search order rules unless
  82.    --  N is the name of the file just read with Next_Main_Source, in which
  83.    --  case just look in the Primary_Directory. Returns Name_Id of the full
  84.    --  file name if found, No_Name if file not found.
  85.  
  86.    -------------------------
  87.    -- Command Line Access --
  88.    -------------------------
  89.  
  90.    --  Direct interface to command line parameters. (We don't want to use
  91.    --  the predefined command line package because it defines functions
  92.    --  returning string)
  93.  
  94.    function Arg_Count return Natural;
  95.    pragma Import (C, Arg_Count, "arg_count");
  96.    --  Get number of arguments (note: optional globbing may be enabled)
  97.  
  98.    procedure Fill_Arg (A : System.Address; Arg_Num : Integer);
  99.    pragma Import (C, Fill_Arg, "fill_arg");
  100.    --  Store one argument
  101.  
  102.    function Len_Arg (Arg_Num : Integer) return Integer;
  103.    pragma Import (C, Len_Arg, "len_arg");
  104.    --  Get length of argument
  105.  
  106.    ------------------------------
  107.    -- Other Local Declarations --
  108.    ------------------------------
  109.  
  110.    Argument_Count : constant Integer := Arg_Count - 1;
  111.    --  Number of arguments (excluding program name)
  112.  
  113.    File_Names : array (Int range 1 .. Int (Argument_Count)) of String_Ptr;
  114.    --  As arguments are scanned in Initialize, filenames are stored
  115.    --  in this array. The string does not contain a terminating NUL.
  116.  
  117.    Number_File_Names : Int := 0;
  118.    --  The total number of filenames found on command line and placed in
  119.    --  File_Names.
  120.  
  121.    Current_File_Name_Index : Int := 0;
  122.    --  The index in File_Names of the last file opened by Next_Main_Source
  123.    --  or Next_Main_Lib_File. The value 0 indicates that no files have been
  124.    --  opened yet.
  125.  
  126.    In_Binder   : Boolean := False;
  127.    In_Compiler : Boolean := False;
  128.    In_Make     : Boolean := False;
  129.    --  Exactly one of these flags is set True to indicate which program
  130.    --  is bound and executing with Osint, which is used by all these programs.
  131.  
  132.    Source_Time_Stamp : Time_Stamp_Type;
  133.    --  Time stamp for current source file
  134.  
  135.    Output_FD : File_Descriptor;
  136.    --  The file descriptor for the current library info, tree or binder output
  137.  
  138.    Output_File_Name : Name_Id;
  139.    --  Name_Id for name of open file whose FD is in Output_FD, the name
  140.    --  stored does not include the trailing NUL character.
  141.  
  142.    EOL : constant Character := Ascii.LF;
  143.    --  End of line character
  144.  
  145.    Output_Filename : String_Ptr := null;
  146.    --  The name after the -o option
  147.  
  148.    Save_Main_File_Name : File_Name_Type;
  149.    --  Used to save a simple file name between calls to Next_Main_Source and
  150.    --  Read_Source_File. If the file name argument to Read_Source_File is
  151.    --  No_File, that indicates that the file whose name was returned by the
  152.    --  last call to Next_Main_Source (and stored here) is to be read.
  153.  
  154.    Src_Save_Full_File_Name : Name_Id := No_Name;
  155.    --  Set to full name of source file read by the most recent call to
  156.    --  Read_Source_File (result returned by Full_Source_Name).
  157.  
  158.    Lib_Save_Full_File_Name : Name_Id := No_Name;
  159.    --  Set to full name of library information file read by the
  160.    --  most recent call to Read_Library_Info (result returned by
  161.    --  Full_Library_Info_Name).
  162.  
  163.    Primary_Directory : Natural := 0;
  164.    --  This is index in the tables created below for the first directory to
  165.    --  search in for source or library information files. For the compiler
  166.    --  (looking for sources) it is the directory containing the main unit.
  167.    --  For the binder (looking for library information files) it is the
  168.    --  current working directory.
  169.  
  170.    package Src_Search_Directories is new Table (
  171.      Table_Component_Type => String_Ptr,
  172.      Table_Index_Type     => Natural,
  173.      Table_Low_Bound      => Primary_Directory,
  174.      Table_Initial        => 12,
  175.      Table_Increment      => 100,
  176.      Table_Name           => "Osint.Src_Search_Directories");
  177.    --  Table of names of directories in which to search for source (Compiler)
  178.    --  files. This table is filled in the order in which the directories are
  179.    --  to be searched, and then used in that order.
  180.  
  181.    package Lib_Search_Directories is new Table (
  182.      Table_Component_Type => String_Ptr,
  183.      Table_Index_Type     => Natural,
  184.      Table_Low_Bound      => Primary_Directory,
  185.      Table_Initial        => 12,
  186.      Table_Increment      => 100,
  187.      Table_Name           => "Osint.Lib_Search_Directories");
  188.    --  Table of names of directories in which to search for library (Binder)
  189.    --  files. This table is filled in the order in which the directories are
  190.    --  to be searched and then used in that order. The reason for having two
  191.    --  distinct tables is that we need them both in gnatmake.
  192.  
  193.    -------------------------
  194.    -- Close_Binder_Output --
  195.    -------------------------
  196.  
  197.    procedure Close_Binder_Output is
  198.    begin
  199.       pragma Assert (In_Binder);
  200.       Close (Output_FD);
  201.    end Close_Binder_Output;
  202.  
  203.    -----------------------
  204.    -- Close_Stub_Output --
  205.    -----------------------
  206.  
  207.    procedure Close_Stub_Output is
  208.    begin
  209.       pragma Assert (In_Compiler);
  210.       Close (Output_FD);
  211.       Restore_Output_FD;
  212.    end Close_Stub_Output;
  213.  
  214.    -------------------------------
  215.    -- Close_Output_Library_Info --
  216.    -------------------------------
  217.  
  218.    procedure Close_Output_Library_Info is
  219.    begin
  220.       pragma Assert (In_Compiler);
  221.       Close (Output_FD);
  222.    end Close_Output_Library_Info;
  223.  
  224.    -----------------------
  225.    -- Close_Xref_Output --
  226.    -----------------------
  227.  
  228.    procedure Close_Xref_Output is
  229.    begin
  230.       pragma Assert (In_Compiler);
  231.       Close (Output_FD);
  232.    end Close_Xref_Output;
  233.  
  234.    --------------------------
  235.    -- Create_Binder_Output --
  236.    --------------------------
  237.  
  238.    procedure Create_Binder_Output is
  239.       File_Name : String_Ptr;
  240.       Findex1   : Natural;
  241.       Findex2   : Natural;
  242.       Flength   : Natural;
  243.  
  244.    begin
  245.       pragma Assert (In_Binder);
  246.  
  247.       if (Output_Filename_Present) then
  248.  
  249.          if Output_Filename /= null then
  250.             Name_Buffer (Output_Filename'Range) := Output_Filename.all;
  251.             Name_Buffer (Output_Filename'Last + 1) := Ascii.NUL;
  252.             Name_Len := Output_Filename'Last;
  253.          else
  254.             Write_Str ("Output filename missing after -o");
  255.             Write_Eol;
  256.             Exit_Program (E_Fatal);
  257.          end if;
  258.  
  259.       else
  260.          File_Name := File_Names (Current_File_Name_Index);
  261.          Findex1 := File_Name'First;
  262.  
  263.          --  The ali file might be specified by a full path name. However,
  264.          --  the binder generated file should always be created in the
  265.          --  current directory, so the path might need to be stripped away.
  266.          --  In addition to the default directory_separator allow the '/' to
  267.          --  act as separator since this is allowed in MS-DOS and OS2 ports.
  268.  
  269.          for J in reverse File_Name'Range loop
  270.             if File_Name (J) = Directory_Separator
  271.               or else File_Name (J) = '/'
  272.             then
  273.                Findex1 := J + 1;
  274.                exit;
  275.             end if;
  276.          end loop;
  277.  
  278.          Findex2 := Findex1;
  279.          while File_Name (Findex2) /=  '.' loop
  280.             Findex2 := Findex2 + 1;
  281.          end loop;
  282.  
  283.          Name_Buffer (1 .. 2) := "b_";
  284.          Flength := Findex2 - Findex1;
  285.          Name_Buffer (3 .. Flength + 2) := File_Name (Findex1 .. Findex2 - 1);
  286.          Name_Buffer (Flength + 3) := '.';
  287.          Name_Buffer (Flength + 4) := 'c';
  288.          Name_Buffer (Flength + 5) := Ascii.NUL;
  289.          Name_Len := Flength + 4;
  290.       end if;
  291.  
  292.       Create_File_And_Check (Output_FD, Text);
  293.  
  294.    end Create_Binder_Output;
  295.  
  296.    ---------------------------
  297.    -- Create_File_And_Check --
  298.    ---------------------------
  299.  
  300.    procedure Create_File_And_Check
  301.      (Fdesc : out File_Descriptor;
  302.       Fmode : Mode)
  303.    is
  304.    begin
  305.       Output_File_Name := Name_Enter;
  306.       Fdesc := Create_File (Name_Buffer'Address, Fmode);
  307.  
  308.       if Fdesc = Invalid_FD then
  309.          Write_Str ("Cannot create: ");
  310.          Write_Str (Name_Buffer);
  311.          Write_Eol;
  312.          Exit_Program (E_Fatal);
  313.       end if;
  314.    end Create_File_And_Check;
  315.  
  316.    --------------------------------
  317.    -- Create_Output_Library_Info --
  318.    --------------------------------
  319.  
  320.    procedure Create_Output_Library_Info is
  321.       --  ??? Needs to be coordinated with -o option
  322.       Dot_Index : Natural;
  323.  
  324.    begin
  325.       pragma Assert (In_Compiler);
  326.       Get_Name_String (Save_Main_File_Name);
  327.  
  328.       Dot_Index := 0;
  329.       for J in reverse 1 .. Name_Len loop
  330.          if Name_Buffer (J) = '.' then
  331.             Dot_Index := J;
  332.             exit;
  333.          end if;
  334.       end loop;
  335.  
  336.       --  Should be impossible to not have an extension
  337.  
  338.       if Dot_Index = 0 then
  339.          null;
  340.          pragma Assert (False);
  341.       end if;
  342.  
  343.       Name_Buffer (Dot_Index + 1 .. Dot_Index + 3) := "ali";
  344.       Name_Buffer (Dot_Index + 4) := Ascii.NUL;
  345.       Name_Len := Dot_Index + 3;
  346.       Create_File_And_Check (Output_FD, Text);
  347.  
  348.    end Create_Output_Library_Info;
  349.  
  350.    -----------------------
  351.    -- Create_Req_Output --
  352.    -----------------------
  353.  
  354.    procedure Create_Req_Output is
  355.    begin
  356.       pragma Assert (In_Compiler);
  357.       Create_File_And_Check (Output_FD, Text);
  358.    end Create_Req_Output;
  359.  
  360.    ------------------------
  361.    -- Create_Stub_Output --
  362.    ------------------------
  363.  
  364.    procedure Create_Stub_Output is
  365.       FD : File_Descriptor;
  366.  
  367.    begin
  368.       pragma Assert (In_Compiler);
  369.       Create_File_And_Check (FD, Text);
  370.       Set_Output_FD (FD);
  371.    end Create_Stub_Output;
  372.  
  373.    ------------------------
  374.    -- Create_Xref_Output --
  375.    ------------------------
  376.  
  377.    procedure Create_Xref_Output (Global_Xref_File : Boolean) is
  378.  
  379.    begin
  380.       pragma Assert (In_Compiler);
  381.  
  382.       --  For now, always use X.ref, since cannot reference Lib ???
  383.  
  384.       if not Global_Xref_File then
  385.          Get_Name_String (Save_Main_File_Name);
  386.          Name_Buffer (Name_Len - 2 .. Name_Len - 1) := "xr";
  387.          Name_Buffer (Name_Len + 1) := Ascii.NUL;
  388.       else
  389.          Name_Buffer (1 .. 5) := "X.ref";
  390.          Name_Buffer (6) := Ascii.NUL;
  391.          Name_Len := 5;
  392.       end if;
  393.  
  394.       Create_File_And_Check (Output_FD, Text);
  395.    end Create_Xref_Output;
  396.  
  397.    -------------------------------
  398.    -- Current_Source_File_Stamp --
  399.    -------------------------------
  400.  
  401.    function Current_Source_File_Stamp return Time_Stamp_Type is
  402.    begin
  403.       return Source_Time_Stamp;
  404.    end Current_Source_File_Stamp;
  405.  
  406.    ------------------
  407.    -- Exit_Program --
  408.    ------------------
  409.  
  410.    procedure Exit_Program (Exit_Code : Exit_Code_Type) is
  411.    begin
  412.       case Exit_Code is
  413.          when E_Success    => OS_Exit (0);
  414.          when E_Warnings   => OS_Exit (0);
  415.          when E_Errors     => OS_Exit (1);
  416.          when E_Fatal      => OS_Exit (2);
  417.          when E_Abort      => OS_Abort;
  418.       end case;
  419.    end Exit_Program;
  420.  
  421.    ----------------------
  422.    -- Find_Source_File --
  423.    ----------------------
  424.  
  425.    function Find_Source_File (N : File_Name_Type) return Name_Id is
  426.       Is_Main_Unit : constant Boolean := (N = Save_Main_File_Name);
  427.       File_Located : Name_Id;
  428.  
  429.    begin
  430.       --  The first place to look is in the directory of the main
  431.       --  unit. If the file is the main unit and it is not found
  432.       --  in the directory specified for it, it is an error.
  433.  
  434.       Get_Name_String (N);
  435.  
  436.       File_Located :=
  437.         Src_Locate_File (Primary_Directory, Name_Buffer (1 .. Name_Len));
  438.  
  439.       if File_Located = No_Name then
  440.  
  441.          if Is_Main_Unit then
  442.  
  443.             --  An error. Main unit was not found in its specified directory
  444.  
  445.             Get_Name_String (N);
  446.             Write_Str ("Cannot find: ");
  447.             Write_Str (Name_Buffer (1 .. Name_Len));
  448.             Write_Eol;
  449.             Exit_Program (E_Fatal);
  450.  
  451.          else
  452.             --  This is not the main unit, so look for it in the other
  453.             --  places on the search path.
  454.  
  455.             for Dir_Index in
  456.               Primary_Directory + 1 .. Src_Search_Directories.Last
  457.             loop
  458.                File_Located :=
  459.                  Src_Locate_File (Dir_Index, Name_Buffer (1 .. Name_Len));
  460.                exit when File_Located /= No_Name;
  461.             end loop;
  462.          end if;
  463.       end if;
  464.  
  465.       return File_Located;
  466.  
  467.    end Find_Source_File;
  468.  
  469.    ----------------------------
  470.    -- Full_Library_Info_Name --
  471.    ----------------------------
  472.  
  473.    function Full_Library_Info_Name return Name_Id is
  474.    begin
  475.       return Lib_Save_Full_File_Name;
  476.    end Full_Library_Info_Name;
  477.  
  478.    ---------------------------
  479.    -- Full_Object_File_Name --
  480.    ---------------------------
  481.  
  482.    function Full_Object_File_Name return Name_Id is
  483.       J             : Positive;
  484.       ALI_Suffix    : constant String_Ptr := new String'("ali");
  485.       Object_Suffix : String (1 .. 10);
  486.       --  10 should be sufficient till this code gets cleaned up ???
  487.  
  488.       procedure Get_Object_Suffix (str : Address);
  489.       pragma Import (C, Get_Object_Suffix, "Get_Object_Suffix");
  490.       --  The filename suffixes for ALI and object files
  491.       --  ??? Should do with interfaces or something nicer
  492.  
  493.    begin
  494.       Get_Name_String (Full_Library_Info_Name);
  495.       Name_Len := Name_Len - ALI_Suffix'Length;
  496.       Get_Object_Suffix (Object_Suffix'Address);
  497.  
  498.       J := Object_Suffix'First;
  499.       while Object_Suffix (J) /= ASCII.Nul loop
  500.          Name_Len := Name_Len + 1;
  501.          Name_Buffer (Name_Len) := Object_Suffix (J);
  502.          J := J + 1;
  503.       end loop;
  504.  
  505.       return Name_Enter;
  506.    end Full_Object_File_Name;
  507.  
  508.    ----------------------
  509.    -- Full_Source_Name --
  510.    ----------------------
  511.  
  512.    function Full_Source_Name (N : File_Name_Type := No_File) return Name_Id is
  513.    begin
  514.       if N = No_File then
  515.          return Src_Save_Full_File_Name;
  516.       else
  517.          return Find_Source_File (N);
  518.       end if;
  519.    end Full_Source_Name;
  520.  
  521.    ----------------
  522.    -- Initialize --
  523.    ----------------
  524.  
  525.    procedure Initialize (P : Program_Type) is
  526.       Already_Seen      : Boolean := False;
  527.       Search_Path_Value : String_Access;
  528.       Next_Arg          : Positive;
  529.  
  530.       function Get_Default_Identifier_Character_Set return Character;
  531.       pragma Import (C, Get_Default_Identifier_Character_Set,
  532.                        "Get_Default_Identifier_Character_Set");
  533.       --  Function to determine the default identifier character set,
  534.       --  which is system dependent. See Opt package spec for a list of
  535.       --  the possible character codes and their interpretations.
  536.  
  537.       function Get_Maximum_File_Name_Length return Int;
  538.       pragma Import (C, Get_Maximum_File_Name_Length,
  539.                     "Get_Maximum_File_Name_Length");
  540.       --  Function to get maximum file name length for system
  541.  
  542.    begin
  543.       Program := P;
  544.  
  545.       case Program is
  546.          when Binder   => In_Binder   := True;
  547.          when Compiler => In_Compiler := True;
  548.          when Make     => In_Make     := True;
  549.       end case;
  550.  
  551.       Src_Search_Directories.Init;
  552.       Lib_Search_Directories.Init;
  553.  
  554.       Gcc_Switches.Init;
  555.       Binder_Switches.Init;
  556.       Linker_Switches.Init;
  557.       --  Needed only for gnatmake
  558.  
  559.       Identifier_Character_Set :=
  560.         Get_Default_Identifier_Character_Set;
  561.  
  562.       Maximum_File_Name_Length := Get_Maximum_File_Name_Length;
  563.  
  564.       --  Following should be removed by having above function return
  565.       --  Integer'Last as indication of no maximum instead of -1 ???
  566.  
  567.       if Maximum_File_Name_Length = -1 then
  568.          Maximum_File_Name_Length := Int'Last;
  569.       end if;
  570.  
  571.       Suppress_Options.Access_Checks        := False;
  572.       Suppress_Options.Accessibility_Checks := False;
  573.       Suppress_Options.Discriminant_Checks  := False;
  574.       Suppress_Options.Division_Checks      := False;
  575.       Suppress_Options.Index_Checks         := False;
  576.       Suppress_Options.Length_Checks        := False;
  577.       Suppress_Options.Overflow_Checks      := False;
  578.       Suppress_Options.Range_Checks         := False;
  579.       Suppress_Options.Division_Checks      := False;
  580.       Suppress_Options.Length_Checks        := False;
  581.       Suppress_Options.Range_Checks         := False;
  582.       Suppress_Options.Storage_Checks       := False;
  583.       Suppress_Options.Tag_Checks           := False;
  584.  
  585.       --  Set software overflow check flag. For now all targets require the
  586.       --  use of software overflow checks. Later on, this will have to be
  587.       --  specialized to the backend target. Also, if software overflow
  588.       --  checking mode is set, then the default for suppressing overflow
  589.       --  checks is True, since the software approach is expensive.
  590.  
  591.       Software_Overflow_Checking := True;
  592.       Suppress_Options.Overflow_Checks := True;
  593.  
  594.       --  Similarly, the default is elaboration checks off
  595.  
  596.       Suppress_Options.Elaboration_Checks   := True;
  597.  
  598.       --  Reserve the first slot in the search paths table. For the compiler
  599.       --  this is the directory of the main source file and is filled in by
  600.       --  each call to Next_Main_Source. For the binder, this is always empty
  601.       --  so the current working directory is searched first.
  602.  
  603.       Src_Search_Directories.Set_Last (Primary_Directory);
  604.       Src_Search_Directories.Table (Primary_Directory) := new String'("");
  605.       --  Overriden in Next_Main_Source if Next_Main_Source is ever called
  606.  
  607.       Lib_Search_Directories.Set_Last (Primary_Directory);
  608.       Lib_Search_Directories.Table (Primary_Directory) := new String'("");
  609.  
  610.       --  Loop through command line arguments, storing them for later access
  611.  
  612.       Scan_Args : declare
  613.          In_Gcc_Args    : Boolean := False;
  614.          In_Binder_Args : Boolean := False;
  615.          In_Linker_Args : Boolean := False;
  616.          --  These three flags are used to indicate if we are scanning gcc,
  617.          --  gnatbind, or gnatbl options within the gnatmake command line.
  618.  
  619.          Compiler_Opts : constant String_Ptr := new String'("-cargs");
  620.          Binder_Opts   : constant String_Ptr := new String'("-bargs");
  621.          Linker_Opts   : constant String_Ptr := new String'("-largs");
  622.          --  Needed in gnatmake to search for the gcc, gnatbind and gnatbl
  623.          --  options put on the gnatmake command line
  624.  
  625.       begin
  626.          Next_Arg := 1;
  627.  
  628.          loop
  629.             exit when Next_Arg > Argument_Count;
  630.  
  631.             declare
  632.                Next_Argv : String (1 .. Len_Arg (Next_Arg));
  633.  
  634.             begin
  635.                Fill_Arg (Next_Argv'Address, Next_Arg);
  636.  
  637.                if Next_Argv'Length /= 0
  638.                  and then (Next_Argv (1) = Switch_Character
  639.                             or else Next_Argv (1) = '-')
  640.                then
  641.                   --  If we are processing a switch of the form "-Idirname"
  642.                   --  add "dirname" to the source and library search paths.
  643.  
  644.                   if Next_Argv'Length >= 2 and then Next_Argv (2) = 'I' then
  645.                      Src_Search_Directories.Increment_Last;
  646.                      Src_Search_Directories.Table
  647.                        (Src_Search_Directories.Last) :=
  648.                          Normalize_Directory_Name
  649.                            (Next_Argv (3 .. Next_Argv'Length));
  650.  
  651.                      Lib_Search_Directories.Increment_Last;
  652.                      Lib_Search_Directories.Table
  653.                        (Lib_Search_Directories.Last) :=
  654.                          Normalize_Directory_Name
  655.                            (Next_Argv (3 .. Next_Argv'Length));
  656.  
  657.                      --  When executing "gnatmake", add the -I switch
  658.                      --  to both the compiler and binder switches.
  659.  
  660.                      if Program = Make then
  661.                         Gcc_Switches.Increment_Last;
  662.                         Gcc_Switches.Table (Gcc_Switches.Last) :=
  663.                          new String'(Next_Argv);
  664.  
  665.                         Binder_Switches.Increment_Last;
  666.                         Binder_Switches.Table (Binder_Switches.Last) :=
  667.                          new String'(Next_Argv);
  668.                      end if;
  669.  
  670.                   --  Processing of gnatmake -[cbl]args arguments.
  671.  
  672.                   elsif Program = Make and then
  673.                     Next_Argv = Compiler_Opts.all
  674.                   then
  675.                      In_Gcc_Args    := True;
  676.                      In_Binder_Args := False;
  677.                      In_Linker_Args := False;
  678.  
  679.                   elsif Program = Make and then
  680.                     Next_Argv = Binder_Opts.all
  681.                   then
  682.                      In_Gcc_Args    := False;
  683.                      In_Binder_Args := True;
  684.                      In_Linker_Args := False;
  685.  
  686.                   elsif Program = Make and then
  687.                     Next_Argv = Linker_Opts.all
  688.                   then
  689.                      In_Gcc_Args    := False;
  690.                      In_Binder_Args := False;
  691.                      In_Linker_Args := True;
  692.  
  693.                   elsif Program = Make and then In_Gcc_Args then
  694.                      Gcc_Switches.Increment_Last;
  695.                      Gcc_Switches.Table (Gcc_Switches.Last) :=
  696.                       new String'(Next_Argv);
  697.  
  698.                   elsif Program = Make and then In_Binder_Args then
  699.                      Binder_Switches.Increment_Last;
  700.                      Binder_Switches.Table (Binder_Switches.Last) :=
  701.                       new String'(Next_Argv);
  702.  
  703.                   elsif Program = Make and then In_Linker_Args then
  704.                      Linker_Switches.Increment_Last;
  705.                      Linker_Switches.Table (Linker_Switches.Last) :=
  706.                       new String'(Next_Argv);
  707.  
  708.                   --  All other options are single character and are handled
  709.                   --  by Scan_Switches.
  710.  
  711.                   else
  712.                      Scan_Switches (Next_Argv);
  713.                   end if;
  714.  
  715.                --  Not a switch, so must be a filename (if non-empty)
  716.  
  717.                elsif Program = Make and then
  718.                  Next_Argv'Length /= 0 and then In_Gcc_Args
  719.                then
  720.                   Gcc_Switches.Increment_Last;
  721.                   Gcc_Switches.Table (Gcc_Switches.Last) :=
  722.                    new String'(Next_Argv);
  723.  
  724.                elsif Program = Make and then
  725.                  Next_Argv'Length /= 0 and then In_Binder_Args
  726.                then
  727.                   Binder_Switches.Increment_Last;
  728.                   Binder_Switches.Table (Binder_Switches.Last) :=
  729.                                                 new String'(Next_Argv);
  730.  
  731.                elsif Program = Make and then
  732.                  Next_Argv'Length /= 0 and then In_Linker_Args
  733.                then
  734.                   Linker_Switches.Increment_Last;
  735.                   Linker_Switches.Table (Linker_Switches.Last) :=
  736.                                                 new String'(Next_Argv);
  737.  
  738.                elsif Next_Argv'Length /= 0 then
  739.  
  740.                   if Output_Filename_Present and not Already_Seen then
  741.                      Already_Seen := True;
  742.                      Output_Filename := new String'(Next_Argv);
  743.  
  744.                   else
  745.                      Number_File_Names := Number_File_Names + 1;
  746.                      File_Names (Number_File_Names) := new String'(Next_Argv);
  747.                   end if;
  748.                end if;
  749.             end;
  750.  
  751.             Next_Arg := Next_Arg + 1;
  752.          end loop;
  753.       end Scan_Args;
  754.  
  755.       --  After the locations specified on the command line, the next places
  756.       --  to look for files are the directories specified by the appropriate
  757.       --  environment variable. Get this value, extract the directory names
  758.       --  and store in the table.
  759.  
  760.       for Additional_Source_Dir in False .. True loop
  761.  
  762.          if Additional_Source_Dir then
  763.             Search_Path_Value := Getenv ("ADA_INCLUDE_PATH");
  764.          else
  765.             Search_Path_Value := Getenv ("ADA_OBJECTS_PATH");
  766.          end if;
  767.  
  768.          if Search_Path_Value'Length > 0 then
  769.             declare
  770.                Lower_Bound : Positive := 1;
  771.                Upper_Bound : Positive;
  772.  
  773.             begin
  774.                loop
  775.                   while Lower_Bound <= Search_Path_Value'Last
  776.                     and then
  777.                       Search_Path_Value.all (Lower_Bound) = Path_Separator
  778.                   loop
  779.                      Lower_Bound := Lower_Bound + 1;
  780.                   end loop;
  781.  
  782.                   exit when Lower_Bound > Search_Path_Value'Last;
  783.  
  784.                   Upper_Bound := Lower_Bound;
  785.                   while Upper_Bound <= Search_Path_Value'Last
  786.                     and then
  787.                       Search_Path_Value.all (Upper_Bound) /= Path_Separator
  788.                   loop
  789.                      Upper_Bound := Upper_Bound + 1;
  790.                   end loop;
  791.  
  792.                   if Additional_Source_Dir then
  793.                      Src_Search_Directories.Increment_Last;
  794.                      Src_Search_Directories.Table
  795.                        (Src_Search_Directories.Last) :=
  796.                          Normalize_Directory_Name
  797.                            (Search_Path_Value.all
  798.                              (Lower_Bound .. Upper_Bound - 1));
  799.                   else
  800.                      Lib_Search_Directories.Increment_Last;
  801.                      Lib_Search_Directories.Table
  802.                        (Lib_Search_Directories.Last) :=
  803.                          Normalize_Directory_Name
  804.                            (Search_Path_Value.all
  805.                              (Lower_Bound .. Upper_Bound - 1));
  806.                   end if;
  807.  
  808.                   Lower_Bound := Upper_Bound + 1;
  809.                end loop;
  810.             end;
  811.          end if;
  812.       end loop;
  813.  
  814.       --  The last place to look are the defaults.
  815.  
  816.       Src_Search_Directories.Increment_Last;
  817.       Lib_Search_Directories.Increment_Last;
  818.  
  819.       Src_Search_Directories.Table (Src_Search_Directories.Last) :=
  820.                                              Include_Dir_Default_Name;
  821.       Lib_Search_Directories.Table (Lib_Search_Directories.Last) :=
  822.                                              Object_Dir_Default_Name;
  823.  
  824.    end Initialize;
  825.  
  826.    -------------------
  827.    -- Lib_File_Name --
  828.    -------------------
  829.  
  830.    function Lib_File_Name
  831.      (Source_File : File_Name_Type)
  832.       return        File_Name_Type
  833.    is
  834.       Fptr : Natural;
  835.       --  Pointer to location to set extension in place
  836.  
  837.    begin
  838.       Get_Name_String (Source_File);
  839.       Fptr := Name_Len + 1;
  840.  
  841.       for J in reverse 1 .. Name_Len loop
  842.          if Name_Buffer (J) = '.' then
  843.             Fptr := J;
  844.             exit;
  845.          end if;
  846.       end loop;
  847.  
  848.       Name_Buffer (Fptr .. Fptr + 3) := ".ali";
  849.       Name_Buffer (Fptr + 4) := Ascii.NUL;
  850.       Name_Len := Fptr + 3;
  851.       return Name_Find;
  852.    end Lib_File_Name;
  853.  
  854.    ---------------------
  855.    -- Lib_Locate_File --
  856.    ---------------------
  857.  
  858.    function Lib_Locate_File
  859.      (Dir_Index : Natural;
  860.       File_Name : String)
  861.       return      Name_Id
  862.    is
  863.       Dir_Name_Length : Natural :=
  864.                           Lib_Search_Directories.Table (Dir_Index)'Length;
  865.  
  866.       Full_Name : String (1 .. Dir_Name_Length + File_Name'Length);
  867.  
  868.    begin
  869.       Full_Name (1 .. Dir_Name_Length) :=
  870.         Lib_Search_Directories.Table (Dir_Index).all;
  871.       Full_Name (Dir_Name_Length + 1 .. Full_Name'Length) := File_Name;
  872.  
  873.       if not Is_Regular_File (Full_Name) then
  874.          return No_Name;
  875.       else
  876.          Name_Len := Full_Name'Length;
  877.          Name_Buffer (1 .. Name_Len) := Full_Name;
  878.          return Name_Enter;
  879.       end if;
  880.  
  881.    end Lib_Locate_File;
  882.  
  883.    --------------------
  884.    -- More_Lib_Files --
  885.    --------------------
  886.  
  887.    function More_Lib_Files return Boolean is
  888.    begin
  889.       pragma Assert (In_Binder);
  890.       return (Current_File_Name_Index < Number_File_Names);
  891.    end More_Lib_Files;
  892.  
  893.    -----------------------
  894.    -- More_Source_Files --
  895.    -----------------------
  896.  
  897.    function More_Source_Files return Boolean is
  898.    begin
  899.       pragma Assert (In_Compiler or else In_Make);
  900.       return (Current_File_Name_Index < Number_File_Names);
  901.    end More_Source_Files;
  902.  
  903.    ------------------------
  904.    -- Next_Main_Lib_File --
  905.    ------------------------
  906.  
  907.    function Next_Main_Lib_File return File_Name_Type is
  908.       File_Name : String_Ptr;
  909.       Fptr      : Natural;
  910.  
  911.    begin
  912.       pragma Assert (In_Binder);
  913.       Current_File_Name_Index := Current_File_Name_Index + 1;
  914.  
  915.       --  Fatal error if no more files (should call More_Lib_Files)
  916.  
  917.       pragma Assert (Current_File_Name_Index <= Number_File_Names);
  918.  
  919.       --  Otherwise return name of the file
  920.  
  921.       File_Name := File_Names (Current_File_Name_Index);
  922.       Fptr := File_Name'First;
  923.  
  924.       for J in reverse File_Name'Range loop
  925.          if File_Name (J) = Directory_Separator then
  926.             Fptr := J + 1;
  927.             exit;
  928.          end if;
  929.       end loop;
  930.  
  931.       Name_Len := File_Name'Last - Fptr + 1;
  932.  
  933.       Name_Buffer (1 .. Name_Len) := File_Name (Fptr .. File_Name'Last);
  934.       return File_Name_Type (Name_Find);
  935.    end Next_Main_Lib_File;
  936.  
  937.    ----------------------
  938.    -- Next_Main_Source --
  939.    ----------------------
  940.  
  941.    function Next_Main_Source return File_Name_Type is
  942.       File_Name : String_Ptr;
  943.       Fptr      : Natural;
  944.  
  945.    begin
  946.       pragma Assert (In_Compiler or else In_Make);
  947.       Current_File_Name_Index := Current_File_Name_Index + 1;
  948.  
  949.       --  Fatal error if no more files (should call More_Source_Files)
  950.  
  951.       pragma Assert (Current_File_Name_Index <= Number_File_Names);
  952.  
  953.       --  Otherwise return name of the file
  954.  
  955.       File_Name := File_Names (Current_File_Name_Index);
  956.       Fptr := File_Name'First;
  957.  
  958.       for J in reverse File_Name'Range loop
  959.          if File_Name (J) = Directory_Separator then
  960.             if J = File_Name'Last then
  961.                Write_Str ("File name missing");
  962.                Write_Eol;
  963.                Exit_Program (E_Fatal);
  964.             end if;
  965.  
  966.             Fptr := J + 1;
  967.             exit;
  968.          end if;
  969.       end loop;
  970.  
  971.       --  Save name of directory in which main unit resides for use in
  972.       --  locating other units
  973.  
  974.       Src_Search_Directories.Table (Primary_Directory) :=
  975.         new String'(File_Name (File_Name'First .. Fptr - 1));
  976.  
  977.       Name_Len := File_Name'Last - Fptr + 1;
  978.  
  979.       Name_Buffer (1 .. Name_Len) := File_Name (Fptr .. File_Name'Last);
  980.       Save_Main_File_Name := File_Name_Type (Name_Find);
  981.       return Save_Main_File_Name;
  982.    end Next_Main_Source;
  983.  
  984.    ------------------------------
  985.    -- Normalize_Directory_Name --
  986.    ------------------------------
  987.  
  988.    function Normalize_Directory_Name (Directory : String) return String_Ptr is
  989.       Result : String_Ptr;
  990.  
  991.    begin
  992.       --  For now this just insures that the string is terminated with
  993.       --  the directory separator character. Add more later?
  994.  
  995.       if Directory (Directory'Last) = Directory_Separator then
  996.          Result := new String'(Directory);
  997.  
  998.       else
  999.          Result := new String (1 .. Directory'Length + 1);
  1000.          Result (1 .. Directory'Length) := Directory;
  1001.          Result (Directory'Length + 1) := Directory_Separator;
  1002.       end if;
  1003.  
  1004.       return Result;
  1005.    end Normalize_Directory_Name;
  1006.  
  1007.    ---------------------
  1008.    -- Number_Of_Files --
  1009.    ---------------------
  1010.  
  1011.    function Number_Of_Files return Int is
  1012.    begin
  1013.       return Number_File_Names;
  1014.    end Number_Of_Files;
  1015.  
  1016.    --------------------------
  1017.    -- OS_Time_To_GNAT_Time --
  1018.    --------------------------
  1019.  
  1020.    function OS_Time_To_GNAT_Time (T : OS_Time) return Time_Stamp_Type is
  1021.       GNAT_Time : Time_Stamp_Type;
  1022.  
  1023.       Y  : Year_Type;
  1024.       Mo : Month_Type;
  1025.       D  : Day_Type;
  1026.       H  : Hour_Type;
  1027.       Mn : Minute_Type;
  1028.       S  : Second_Type;
  1029.  
  1030.       Z : constant := Character'Pos ('0');
  1031.  
  1032.    begin
  1033.       GM_Split (T, Y, Mo, D, H, Mn, S);
  1034.       GNAT_Time (1)  := Character'Val (Z + (Y / 10) mod 10);
  1035.       GNAT_Time (2)  := Character'Val (Z + Y mod 10);
  1036.       GNAT_Time (3)  := Character'Val (Z + Mo / 10);
  1037.       GNAT_Time (4)  := Character'Val (Z + Mo mod 10);
  1038.       GNAT_Time (5)  := Character'Val (Z + D / 10);
  1039.       GNAT_Time (6)  := Character'Val (Z + D mod 10);
  1040.       GNAT_Time (7)  := Character'Val (Z + H / 10);
  1041.       GNAT_Time (8)  := Character'Val (Z + H mod 10);
  1042.       GNAT_Time (9)  := Character'Val (Z + Mn / 10);
  1043.       GNAT_Time (10) := Character'Val (Z + Mn mod 10);
  1044.       GNAT_Time (11) := Character'Val (Z + S / 10);
  1045.       GNAT_Time (12) := Character'Val (Z + S mod 10);
  1046.  
  1047.       return GNAT_Time;
  1048.  
  1049.    end OS_Time_To_GNAT_Time;
  1050.  
  1051.    -----------------------
  1052.    -- Read_Library_Info --
  1053.    -----------------------
  1054.  
  1055.    function Read_Library_Info
  1056.      (Lib_File  : File_Name_Type;
  1057.       Fatal_Err : Boolean := False)
  1058.       return      Text_Buffer_Ptr
  1059.    is
  1060.       Lib_FD : File_Descriptor;
  1061.       --  The file descriptor for the current library file. A negative value
  1062.       --  indicates failure to open the specified source file.
  1063.  
  1064.       Text : Text_Buffer_Ptr;
  1065.       --  Allocated text buffer.
  1066.  
  1067.       File_Located : Name_Id;
  1068.  
  1069.    begin
  1070.       if Lib_File = No_File then
  1071.          Name_Len := File_Names (Current_File_Name_Index)'Length;
  1072.          Name_Buffer (1 .. Name_Len) :=
  1073.            File_Names (Current_File_Name_Index).all;
  1074.          File_Located :=
  1075.            Lib_Locate_File (Primary_Directory, Name_Buffer (1 .. Name_Len));
  1076.  
  1077.       else
  1078.          Get_Name_String (Lib_File);
  1079.  
  1080.          for Dir_Index in
  1081.            Lib_Search_Directories.First .. Lib_Search_Directories.Last
  1082.          loop
  1083.             File_Located :=
  1084.               Lib_Locate_File (Dir_Index, Name_Buffer (1 .. Name_Len));
  1085.             exit when File_Located /= No_Name;
  1086.          end loop;
  1087.       end if;
  1088.  
  1089.       Lib_Save_Full_File_Name := File_Located;
  1090.  
  1091.       if File_Located = No_Name then
  1092.          if Fatal_Err then
  1093.             Write_Str ("Cannot find: ");
  1094.             Write_Str (Name_Buffer (1 .. Name_Len));
  1095.             Write_Eol;
  1096.             Exit_Program (E_Fatal);
  1097.  
  1098.          else
  1099.             return null;
  1100.          end if;
  1101.       end if;
  1102.  
  1103.       Get_Name_String (Lib_Save_Full_File_Name);
  1104.       Name_Buffer (Name_Len + 1) := Ascii.NUL;
  1105.  
  1106.       --  Open the library FD, note that we open in binary mode, because as
  1107.       --  documented in the spec, the caller is expected to handle either
  1108.       --  DOS or Unix mode files, and there is no point in wasting time on
  1109.       --  text translation when it is not required.
  1110.  
  1111.       Lib_FD := Open_Read (Name_Buffer'Address, Binary);
  1112.  
  1113.       if Lib_FD = Invalid_FD then
  1114.          if Fatal_Err then
  1115.             Write_Str ("Cannot open: ");
  1116.             Write_Str (Name_Buffer (1 .. Name_Len));
  1117.             Write_Eol;
  1118.             Exit_Program (E_Fatal);
  1119.          else
  1120.             return null;
  1121.          end if;
  1122.       end if;
  1123.  
  1124.       --  Read data from the file
  1125.  
  1126.       declare
  1127.          Len : Integer := Integer (File_Length (Lib_FD));
  1128.          --  Length of source file text. If it doesn't fit in an integer
  1129.          --  we're probably stuck anyway (>2 gigs of source seems a lot!)
  1130.  
  1131.          Lo : Text_Ptr := 0;
  1132.          --  Low bound for allocated text buffer
  1133.  
  1134.          Hi : Text_Ptr := Text_Ptr (Len);
  1135.          --  High bound for allocated text buffer. Note length is Len + 1
  1136.          --  which allows for extra EOF character at the end of the buffer.
  1137.  
  1138.       begin
  1139.          --  Allocate text buffer. Note extra character at end for EOF
  1140.  
  1141.          Text := new Text_Buffer (Lo .. Hi);
  1142.  
  1143.          if Read (Lib_FD, Text (Lo)'Address, Len) < Len then
  1144.             null;  -- ??? should do something here
  1145.          end if;
  1146.  
  1147.          Text (Hi) := EOF;
  1148.       end;
  1149.  
  1150.       --  Read is complete, close file and we are done
  1151.  
  1152.       Close (Lib_FD);
  1153.       return Text;
  1154.  
  1155.    end Read_Library_Info;
  1156.  
  1157.    ----------------------
  1158.    -- Read_Source_File --
  1159.    ----------------------
  1160.  
  1161.    procedure Read_Source_File
  1162.      (N   : File_Name_Type;
  1163.       Lo  : in Source_Ptr;
  1164.       Hi  : out Source_Ptr;
  1165.       Src : out Source_Buffer_Ptr)
  1166.    is
  1167.       Source_File_FD : File_Descriptor;
  1168.       --  The file descriptor for the current source file. A negative value
  1169.       --  indicates failure to open the specified source file.
  1170.  
  1171.       Len : Integer;
  1172.       --  Length of file. Assume no more than 2 gigabytes of source!
  1173.  
  1174.    begin
  1175.       Src_Save_Full_File_Name := Find_Source_File (N);
  1176.  
  1177.       if Src_Save_Full_File_Name = No_Name then
  1178.          Src := null;
  1179.          return;
  1180.       end if;
  1181.  
  1182.       Get_Name_String (Src_Save_Full_File_Name);
  1183.       Name_Buffer (Name_Len + 1) := Ascii.NUL;
  1184.  
  1185.       --  Open the source FD, note that we open in binary mode, because as
  1186.       --  documented in the spec, the caller is expected to handle either
  1187.       --  DOS or Unix mode files, and there is no point in wasting time on
  1188.       --  text translation when it is not required.
  1189.  
  1190.       Source_File_FD := Open_Read (Name_Buffer'Address, Binary);
  1191.  
  1192.       if Source_File_FD = Invalid_FD then
  1193.          Src := null;
  1194.          return;
  1195.       end if;
  1196.  
  1197.       --  Prepare to read data from the file
  1198.  
  1199.       Len := Integer (File_Length (Source_File_FD));
  1200.  
  1201.       --  Set Hi so that length is one more than the physical length,
  1202.       --  allowing for the extra EOF character at the end of the buffer
  1203.  
  1204.       Hi := Lo + Source_Ptr (Len);
  1205.  
  1206.       --  Do the actual read operation
  1207.  
  1208.       declare
  1209.          subtype Actual_Source_Buffer is Source_Buffer (Lo .. Hi);
  1210.          --  Physical buffer allocated
  1211.  
  1212.          type Actual_Source_Ptr is access Actual_Source_Buffer;
  1213.          --  This is the pointer type for the physical buffer allocated
  1214.  
  1215.          Actual_Ptr : Actual_Source_Ptr := new Actual_Source_Buffer;
  1216.          --  And this is the actual physical buffer
  1217.  
  1218.       begin
  1219.          --  Allocate source buffer, allowing extra character at end for EOF
  1220.  
  1221.          if Read (Source_File_FD, Actual_Ptr (Lo)'Address, Len) < Len then
  1222.             null;  -- ??? should do something here
  1223.          end if;
  1224.  
  1225.          Actual_Ptr (Hi) := EOF;
  1226.  
  1227.          --  Now we need to work out the proper virtual origin pointer to
  1228.          --  return. This is exactly Actual_Ptr (0)'Address, but we have
  1229.          --  to be careful to suppress checks to compute this address.
  1230.  
  1231.          declare
  1232.             pragma Suppress (All_Checks);
  1233.  
  1234.             function To_Source_Buffer_Ptr is new
  1235.               Unchecked_Conversion (Address, Source_Buffer_Ptr);
  1236.  
  1237.          begin
  1238.             Src := To_Source_Buffer_Ptr (Actual_Ptr (0)'Address);
  1239.          end;
  1240.       end;
  1241.  
  1242.       --  Read is complete, get time stamp and close file and we are done
  1243.  
  1244.       Source_Time_Stamp :=
  1245.         OS_Time_To_GNAT_Time (File_Time_Stamp (Source_File_FD));
  1246.       Close (Source_File_FD);
  1247.  
  1248.    end Read_Source_File;
  1249.  
  1250.    -----------------------
  1251.    -- Source_File_Stamp --
  1252.    -----------------------
  1253.  
  1254.    function Source_File_Stamp
  1255.      (Name : File_Name_Type)
  1256.       return Time_Stamp_Type
  1257.    is
  1258.       File_Located : Name_Id := Find_Source_File (Name);
  1259.    begin
  1260.       if File_Located = No_Name then
  1261.          return "            ";
  1262.       else
  1263.          Get_Name_String (File_Located);
  1264.          Name_Buffer (Name_Len + 1) := Ascii.NUL;
  1265.          return OS_Time_To_GNAT_Time (File_Time_Stamp (Name_Buffer));
  1266.       end if;
  1267.    end Source_File_Stamp;
  1268.  
  1269.    ---------------------
  1270.    -- Src_Locate_File --
  1271.    ---------------------
  1272.  
  1273.    function Src_Locate_File
  1274.      (Dir_Index : Natural;
  1275.       File_Name : String)
  1276.       return      Name_Id
  1277.    is
  1278.       Dir_Name_Length : Natural :=
  1279.                           Src_Search_Directories.Table (Dir_Index)'Length;
  1280.  
  1281.       Full_Name : String (1 .. Dir_Name_Length + File_Name'Length);
  1282.  
  1283.    begin
  1284.       Full_Name (1 .. Dir_Name_Length) :=
  1285.         Src_Search_Directories.Table (Dir_Index).all;
  1286.  
  1287.       Full_Name (Dir_Name_Length + 1 .. Full_Name'Length) := File_Name;
  1288.  
  1289.       if not Is_Regular_File (Full_Name) then
  1290.          return No_Name;
  1291.  
  1292.       else
  1293.          Name_Len := Full_Name'Length;
  1294.          Name_Buffer (1 .. Name_Len) := Full_Name;
  1295.          return Name_Enter;
  1296.       end if;
  1297.  
  1298.    end Src_Locate_File;
  1299.  
  1300.    -----------------------
  1301.    -- Stub_Output_Start --
  1302.    -----------------------
  1303.  
  1304.    --  For now does nothing, should process -o switch ???
  1305.  
  1306.    procedure Stub_Output_Start is
  1307.    begin
  1308.       null;
  1309.    end Stub_Output_Start;
  1310.  
  1311.    ----------------------
  1312.    -- Stub_Output_Stop --
  1313.    ----------------------
  1314.  
  1315.    --  For now does nothing, should process -o switch ???
  1316.  
  1317.    procedure Stub_Output_Stop is
  1318.    begin
  1319.       null;
  1320.    end Stub_Output_Stop;
  1321.  
  1322.    -----------------
  1323.    -- Tree_Create --
  1324.    -----------------
  1325.  
  1326.    procedure Tree_Create is
  1327.       Dot_Index : Natural;
  1328.  
  1329.    begin
  1330.       pragma Assert (In_Compiler);
  1331.       Get_Name_String (Save_Main_File_Name);
  1332.  
  1333.       Dot_Index := 0;
  1334.       for J in reverse 1 .. Name_Len loop
  1335.          if Name_Buffer (J) = '.' then
  1336.             Dot_Index := J;
  1337.             exit;
  1338.          end if;
  1339.       end loop;
  1340.  
  1341.       --  Should be impossible to not have an extension
  1342.  
  1343.       if Dot_Index = 0 then
  1344.          null;
  1345.          pragma Assert (False);
  1346.       end if;
  1347.  
  1348.       --  Change *.ads to *.ats and *.adb to *.atb
  1349.  
  1350.       Name_Buffer (Dot_Index + 2) := 't';
  1351.       Name_Buffer (Dot_Index + 4) := Ascii.NUL;
  1352.       Name_Len := Dot_Index + 3;
  1353.       Create_File_And_Check (Output_FD, Binary);
  1354.  
  1355.       Tree_Write_Initialize (Output_FD);
  1356.    end Tree_Create;
  1357.  
  1358.    ----------------
  1359.    -- Tree_Close --
  1360.    ----------------
  1361.  
  1362.    procedure Tree_Close is
  1363.    begin
  1364.       pragma Assert (In_Compiler);
  1365.       Tree_Write_Terminate;
  1366.       Close (Output_FD);
  1367.    end Tree_Close;
  1368.  
  1369.    -----------------------
  1370.    -- Write_Binder_Info --
  1371.    -----------------------
  1372.  
  1373.    procedure Write_Binder_Info (Info : String) is
  1374.    begin
  1375.       pragma Assert (In_Binder);
  1376.       Write_With_Check (Info'Address, Info'Length);
  1377.       Write_With_Check (EOL'Address, 1);
  1378.    end Write_Binder_Info;
  1379.  
  1380.    ------------------------
  1381.    -- Write_Library_Info --
  1382.    ------------------------
  1383.  
  1384.    procedure Write_Library_Info (Info : String) is
  1385.    begin
  1386.       pragma Assert (In_Compiler);
  1387.       Write_With_Check (Info'Address, Info'Length);
  1388.       Write_With_Check (EOL'Address, 1);
  1389.    end Write_Library_Info;
  1390.  
  1391.    ------------------------
  1392.    -- Write_Program_Name --
  1393.    ------------------------
  1394.  
  1395.    procedure Write_Program_Name is
  1396.       Command_Name : String (1 .. Len_Arg (0));
  1397.    begin
  1398.       Fill_Arg (Command_Name'Address, 0);
  1399.       Write_Str (Command_Name);
  1400.    end Write_Program_Name;
  1401.  
  1402.    ----------------------
  1403.    -- Write_With_Check --
  1404.    ----------------------
  1405.  
  1406.    procedure Write_With_Check (A  : Address; N  : Integer) is
  1407.       Ignore : Boolean;
  1408.  
  1409.    begin
  1410.       if N = Write (Output_FD, A, N) then
  1411.          return;
  1412.  
  1413.       else
  1414.          Write_Str ("error: disk full writing ");
  1415.          Write_Name_Decoded (Output_File_Name);
  1416.          Write_Eol;
  1417.          Name_Len := Name_Len + 1;
  1418.          Name_Buffer (Name_Len) := Ascii.Nul;
  1419.          Delete_File (Name_Buffer'Address, Ignore);
  1420.          Exit_Program (E_Fatal);
  1421.       end if;
  1422.    end Write_With_Check;
  1423.  
  1424.    -----------------------
  1425.    -- Write_Xref_Output --
  1426.    -----------------------
  1427.  
  1428.    procedure Write_Xref_Info (Info : String; Eol : Boolean := True) is
  1429.    begin
  1430.       pragma Assert (In_Compiler);
  1431.       Write_With_Check (Info'Address, Info'Length);
  1432.  
  1433.       if Eol then
  1434.          Write_With_Check (Osint.EOL'Address, 1);
  1435.       end if;
  1436.    end Write_Xref_Info;
  1437.  
  1438. end Osint;
  1439.