1 ------------------------------------------------------------------------------
3 -- GNAT COMPILER COMPONENTS --
9 -- Copyright (C) 1992-2005 Free Software Foundation, Inc. --
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, 51 Franklin Street, Fifth Floor, --
20 -- Boston, MA 02110-1301, USA. --
22 -- GNAT was originally developed by the GNAT team at New York University. --
23 -- Extensive contributions were provided by Ada Core Technologies Inc. --
25 ------------------------------------------------------------------------------
28 with Gnatvsn; use Gnatvsn;
30 with Namet; use Namet;
32 with Output; use Output;
33 with Sdefault; use Sdefault;
36 with System.Case_Util; use System.Case_Util;
38 with Unchecked_Conversion;
44 Running_Program : Program_Type := Unspecified;
45 -- comment required here ???
47 Program_Set : Boolean := False;
48 -- comment required here ???
50 Std_Prefix : String_Ptr;
51 -- Standard prefix, computed dynamically the first time Relocate_Path
52 -- is called, and cached for subsequent calls.
54 Empty : aliased String := "";
55 No_Dir : constant String_Ptr := Empty'Access;
56 -- Used in Locate_File as a fake directory when Name is already an
59 -------------------------------------
60 -- Use of Name_Find and Name_Enter --
61 -------------------------------------
63 -- This package creates a number of source, ALI and object file names
64 -- that are used to locate the actual file and for the purpose of
65 -- message construction. These names need not be accessible by Name_Find,
66 -- and can be therefore created by using routine Name_Enter. The files in
67 -- question are file names with a prefix directory (ie the files not
68 -- in the current directory). File names without a prefix directory are
69 -- entered with Name_Find because special values might be attached to
70 -- the various Info fields of the corresponding name table entry.
72 -----------------------
73 -- Local Subprograms --
74 -----------------------
76 function Append_Suffix_To_File_Name
78 Suffix : String) return Name_Id;
79 -- Appends Suffix to Name and returns the new name.
81 function OS_Time_To_GNAT_Time (T : OS_Time) return Time_Stamp_Type;
82 -- Convert OS format time to GNAT format time stamp
84 function Concat (String_One : String; String_Two : String) return String;
85 -- Concatenates 2 strings and returns the result of the concatenation
87 function Executable_Prefix return String_Ptr;
88 -- Returns the name of the root directory where the executable is stored.
89 -- The executable must be located in a directory called "bin", or
90 -- under root/lib/gcc-lib/..., or under root/libexec/gcc/... Thus, if
91 -- the executable is stored in directory "/foo/bar/bin", this routine
92 -- returns "/foo/bar/". Return "" if the location is not recognized
93 -- as described above.
95 function Update_Path (Path : String_Ptr) return String_Ptr;
96 -- Update the specified path to replace the prefix with the location
97 -- where GNAT is installed. See the file prefix.c in GCC for details.
99 procedure Write_With_Check (A : Address; N : Integer);
100 -- Writes N bytes from buffer starting at address A to file whose FD is
101 -- stored in Output_FD, and whose file name is stored as a File_Name_Type
102 -- in Output_File_Name. A check is made for disk full, and if this is
103 -- detected, the file being written is deleted, and a fatal error is
110 Name : String) return File_Name_Type;
111 -- See if the file N whose name is Name exists in directory Dir. Dir is
112 -- an index into the Lib_Search_Directories table if T = Library.
113 -- Otherwise if T = Source, Dir is an index into the
114 -- Src_Search_Directories table. Returns the File_Name_Type of the
115 -- full file name if file found, or No_File if not found.
117 function C_String_Length (S : Address) return Integer;
118 -- Returns length of a C string. Returns zero for a null address.
120 function To_Path_String_Access
121 (Path_Addr : Address;
122 Path_Len : Integer) return String_Access;
123 -- Converts a C String to an Ada String. Are we doing this to avoid
124 -- withing Interfaces.C.Strings ???
126 ------------------------------
127 -- Other Local Declarations --
128 ------------------------------
130 EOL : constant Character := ASCII.LF;
131 -- End of line character
133 Number_File_Names : Int := 0;
134 -- The total number of file names found on command line and placed in
137 Look_In_Primary_Directory_For_Current_Main : Boolean := False;
138 -- When this variable is True, Find_File will only look in
139 -- the Primary_Directory for the Current_Main file.
140 -- This variable is always True for the compiler.
141 -- It is also True for gnatmake, when the soucr name given
142 -- on the command line has directory information.
144 Current_Full_Source_Name : File_Name_Type := No_File;
145 Current_Full_Source_Stamp : Time_Stamp_Type := Empty_Time_Stamp;
146 Current_Full_Lib_Name : File_Name_Type := No_File;
147 Current_Full_Lib_Stamp : Time_Stamp_Type := Empty_Time_Stamp;
148 Current_Full_Obj_Name : File_Name_Type := No_File;
149 Current_Full_Obj_Stamp : Time_Stamp_Type := Empty_Time_Stamp;
150 -- Respectively full name (with directory info) and time stamp of
151 -- the latest source, library and object files opened by Read_Source_File
152 -- and Read_Library_Info.
158 Primary_Directory : constant := 0;
159 -- This is index in the tables created below for the first directory to
160 -- search in for source or library information files. This is the
161 -- directory containing the latest main input file (a source file for
162 -- the compiler or a library file for the binder).
164 package Src_Search_Directories is new Table.Table (
165 Table_Component_Type => String_Ptr,
166 Table_Index_Type => Natural,
167 Table_Low_Bound => Primary_Directory,
169 Table_Increment => 100,
170 Table_Name => "Osint.Src_Search_Directories");
171 -- Table of names of directories in which to search for source (Compiler)
172 -- files. This table is filled in the order in which the directories are
173 -- to be searched, and then used in that order.
175 package Lib_Search_Directories is new Table.Table (
176 Table_Component_Type => String_Ptr,
177 Table_Index_Type => Natural,
178 Table_Low_Bound => Primary_Directory,
180 Table_Increment => 100,
181 Table_Name => "Osint.Lib_Search_Directories");
182 -- Table of names of directories in which to search for library (Binder)
183 -- files. This table is filled in the order in which the directories are
184 -- to be searched and then used in that order. The reason for having two
185 -- distinct tables is that we need them both in gnatmake.
187 ---------------------
188 -- File Hash Table --
189 ---------------------
191 -- The file hash table is provided to free the programmer from any
192 -- efficiency concern when retrieving full file names or time stamps of
193 -- source files. If the programmer calls Source_File_Data (Cache => True)
194 -- he is guaranteed that the price to retrieve the full name (ie with
195 -- directory info) or time stamp of the file will be payed only once,
196 -- the first time the full name is actually searched (or the first time
197 -- the time stamp is actually retrieved). This is achieved by employing
198 -- a hash table that stores as a key the File_Name_Type of the file and
199 -- associates to that File_Name_Type the full file name of the file and its
202 File_Cache_Enabled : Boolean := False;
203 -- Set to true if you want the enable the file data caching mechanism.
205 type File_Hash_Num is range 0 .. 1020;
207 function File_Hash (F : File_Name_Type) return File_Hash_Num;
208 -- Compute hash index for use by Simple_HTable
210 package File_Name_Hash_Table is new GNAT.HTable.Simple_HTable (
211 Header_Num => File_Hash_Num,
212 Element => File_Name_Type,
213 No_Element => No_File,
214 Key => File_Name_Type,
218 package File_Stamp_Hash_Table is new GNAT.HTable.Simple_HTable (
219 Header_Num => File_Hash_Num,
220 Element => Time_Stamp_Type,
221 No_Element => Empty_Time_Stamp,
222 Key => File_Name_Type,
226 function Smart_Find_File
228 T : File_Type) return File_Name_Type;
229 -- Exactly like Find_File except that if File_Cache_Enabled is True this
230 -- routine looks first in the hash table to see if the full name of the
231 -- file is already available.
233 function Smart_File_Stamp
235 T : File_Type) return Time_Stamp_Type;
236 -- Takes the same parameter as the routine above (N is a file name
237 -- without any prefix directory information) and behaves like File_Stamp
238 -- except that if File_Cache_Enabled is True this routine looks first in
239 -- the hash table to see if the file stamp of the file is already
242 -----------------------------
243 -- Add_Default_Search_Dirs --
244 -----------------------------
246 procedure Add_Default_Search_Dirs is
247 Search_Dir : String_Access;
248 Search_Path : String_Access;
249 Path_File_Name : String_Access;
251 procedure Add_Search_Dir
252 (Search_Dir : String;
253 Additional_Source_Dir : Boolean);
254 procedure Add_Search_Dir
255 (Search_Dir : String_Access;
256 Additional_Source_Dir : Boolean);
257 -- Add a source search dir or a library search dir, depending on the
258 -- value of Additional_Source_Dir.
260 procedure Get_Dirs_From_File (Additional_Source_Dir : Boolean);
261 -- Open a path file and read the directory to search, one per line
263 function Get_Libraries_From_Registry return String_Ptr;
264 -- On Windows systems, get the list of installed standard libraries
265 -- from the registry key:
266 -- HKEY_LOCAL_MACHINE\SOFTWARE\Ada Core Technologies\
267 -- GNAT\Standard Libraries
268 -- Return an empty string on other systems
274 procedure Add_Search_Dir
275 (Search_Dir : String;
276 Additional_Source_Dir : Boolean)
279 if Additional_Source_Dir then
280 Add_Src_Search_Dir (Search_Dir);
282 Add_Lib_Search_Dir (Search_Dir);
286 procedure Add_Search_Dir
287 (Search_Dir : String_Access;
288 Additional_Source_Dir : Boolean)
291 if Additional_Source_Dir then
292 Add_Src_Search_Dir (Search_Dir.all);
294 Add_Lib_Search_Dir (Search_Dir.all);
298 ------------------------
299 -- Get_Dirs_From_File --
300 ------------------------
302 procedure Get_Dirs_From_File (Additional_Source_Dir : Boolean) is
303 File_FD : File_Descriptor;
304 Buffer : String (1 .. Path_File_Name'Length + 1);
306 Actual_Len : Natural;
313 -- For the call to Close
316 -- Construct a C compatible character string buffer
318 Buffer (1 .. Buffer'Last - 1) := Path_File_Name.all;
319 Buffer (Buffer'Last) := ASCII.NUL;
321 File_FD := Open_Read (Buffer'Address, Binary);
323 -- If we cannot open the file, we ignore it, we don't fail
325 if File_FD = Invalid_FD then
329 Len := Integer (File_Length (File_FD));
331 S := new String (1 .. Len);
333 -- Read the file. Note that the loop is not necessary since the
334 -- whole file is read at once except on VMS.
338 while Curr <= Len and then Actual_Len /= 0 loop
339 Actual_Len := Read (File_FD, S (Curr)'Address, Len);
340 Curr := Curr + Actual_Len;
343 -- We are done with the file, so we close it
345 Close (File_FD, Status);
346 -- We ignore any error here, because we have successfully read the
349 -- Now, we read line by line
354 while Curr < Len loop
357 if Ch = ASCII.CR or else Ch = ASCII.LF
358 or else Ch = ASCII.FF or else Ch = ASCII.VT
360 if First <= Curr then
361 Add_Search_Dir (S (First .. Curr), Additional_Source_Dir);
370 -- Last line is a special case, if the file does not end with
371 -- an end of line mark.
373 if First <= S'Last then
374 Add_Search_Dir (S (First .. S'Last), Additional_Source_Dir);
376 end Get_Dirs_From_File;
378 ---------------------------------
379 -- Get_Libraries_From_Registry --
380 ---------------------------------
382 function Get_Libraries_From_Registry return String_Ptr is
383 function C_Get_Libraries_From_Registry return Address;
384 pragma Import (C, C_Get_Libraries_From_Registry,
385 "__gnat_get_libraries_from_registry");
386 function Strlen (Str : Address) return Integer;
387 pragma Import (C, Strlen, "strlen");
388 procedure Strncpy (X : Address; Y : Address; Length : Integer);
389 pragma Import (C, Strncpy, "strncpy");
390 Result_Ptr : Address;
391 Result_Length : Integer;
392 Out_String : String_Ptr;
395 Result_Ptr := C_Get_Libraries_From_Registry;
396 Result_Length := Strlen (Result_Ptr);
398 Out_String := new String (1 .. Result_Length);
399 Strncpy (Out_String.all'Address, Result_Ptr, Result_Length);
401 end Get_Libraries_From_Registry;
403 -- Start of processing for Add_Default_Search_Dirs
406 -- After the locations specified on the command line, the next places
407 -- to look for files are the directories specified by the appropriate
408 -- environment variable. Get this value, extract the directory names
409 -- and store in the tables.
411 -- Check for eventual project path file env vars
413 Path_File_Name := Getenv (Project_Include_Path_File);
415 if Path_File_Name'Length > 0 then
416 Get_Dirs_From_File (Additional_Source_Dir => True);
419 Path_File_Name := Getenv (Project_Objects_Path_File);
421 if Path_File_Name'Length > 0 then
422 Get_Dirs_From_File (Additional_Source_Dir => False);
425 -- On VMS, don't expand the logical name (e.g. environment variable),
426 -- just put it into Unix (e.g. canonical) format. System services
427 -- will handle the expansion as part of the file processing.
429 for Additional_Source_Dir in False .. True loop
431 if Additional_Source_Dir then
432 Search_Path := Getenv (Ada_Include_Path);
433 if Search_Path'Length > 0 then
434 if Hostparm.OpenVMS then
435 Search_Path := To_Canonical_Path_Spec ("ADA_INCLUDE_PATH:");
437 Search_Path := To_Canonical_Path_Spec (Search_Path.all);
441 Search_Path := Getenv (Ada_Objects_Path);
442 if Search_Path'Length > 0 then
443 if Hostparm.OpenVMS then
444 Search_Path := To_Canonical_Path_Spec ("ADA_OBJECTS_PATH:");
446 Search_Path := To_Canonical_Path_Spec (Search_Path.all);
451 Get_Next_Dir_In_Path_Init (Search_Path);
453 Search_Dir := Get_Next_Dir_In_Path (Search_Path);
454 exit when Search_Dir = null;
455 Add_Search_Dir (Search_Dir, Additional_Source_Dir);
459 -- For the compiler, if --RTS= was specified, add the runtime
462 if RTS_Src_Path_Name /= null and then
463 RTS_Lib_Path_Name /= null
465 Add_Search_Dirs (RTS_Src_Path_Name, Include);
466 Add_Search_Dirs (RTS_Lib_Path_Name, Objects);
469 if not Opt.No_Stdinc then
471 -- For WIN32 systems, look for any system libraries defined in
472 -- the registry. These are added to both source and object
475 Search_Path := String_Access (Get_Libraries_From_Registry);
477 Get_Next_Dir_In_Path_Init (Search_Path);
479 Search_Dir := Get_Next_Dir_In_Path (Search_Path);
480 exit when Search_Dir = null;
481 Add_Search_Dir (Search_Dir, False);
482 Add_Search_Dir (Search_Dir, True);
485 -- The last place to look are the defaults
488 Read_Default_Search_Dirs
489 (String_Access (Update_Path (Search_Dir_Prefix)),
491 String_Access (Update_Path (Include_Dir_Default_Name)));
493 Get_Next_Dir_In_Path_Init (Search_Path);
495 Search_Dir := Get_Next_Dir_In_Path (Search_Path);
496 exit when Search_Dir = null;
497 Add_Search_Dir (Search_Dir, True);
501 if not Opt.No_Stdlib and not Opt.RTS_Switch then
503 Read_Default_Search_Dirs
504 (String_Access (Update_Path (Search_Dir_Prefix)),
506 String_Access (Update_Path (Object_Dir_Default_Name)));
508 Get_Next_Dir_In_Path_Init (Search_Path);
510 Search_Dir := Get_Next_Dir_In_Path (Search_Path);
511 exit when Search_Dir = null;
512 Add_Search_Dir (Search_Dir, False);
516 end Add_Default_Search_Dirs;
522 procedure Add_File (File_Name : String; Index : Int := No_Index) is
524 Number_File_Names := Number_File_Names + 1;
526 -- As Add_File may be called for mains specified inside
527 -- a project file, File_Names may be too short and needs
530 if Number_File_Names > File_Names'Last then
531 File_Names := new File_Name_Array'(File_Names.all & File_Names.all);
533 new File_Index_Array'(File_Indexes.all & File_Indexes.all);
536 File_Names (Number_File_Names) := new String'(File_Name);
537 File_Indexes (Number_File_Names) := Index;
540 ------------------------
541 -- Add_Lib_Search_Dir --
542 ------------------------
544 procedure Add_Lib_Search_Dir (Dir : String) is
546 if Dir'Length = 0 then
547 Fail ("missing library directory name");
550 Lib_Search_Directories.Increment_Last;
551 Lib_Search_Directories.Table (Lib_Search_Directories.Last) :=
552 Normalize_Directory_Name (Dir);
553 end Add_Lib_Search_Dir;
555 ---------------------
556 -- Add_Search_Dirs --
557 ---------------------
559 procedure Add_Search_Dirs
560 (Search_Path : String_Ptr;
561 Path_Type : Search_File_Type)
563 Current_Search_Path : String_Access;
566 Get_Next_Dir_In_Path_Init (String_Access (Search_Path));
568 Current_Search_Path :=
569 Get_Next_Dir_In_Path (String_Access (Search_Path));
570 exit when Current_Search_Path = null;
572 if Path_Type = Include then
573 Add_Src_Search_Dir (Current_Search_Path.all);
575 Add_Lib_Search_Dir (Current_Search_Path.all);
580 ------------------------
581 -- Add_Src_Search_Dir --
582 ------------------------
584 procedure Add_Src_Search_Dir (Dir : String) is
586 if Dir'Length = 0 then
587 Fail ("missing source directory name");
590 Src_Search_Directories.Increment_Last;
591 Src_Search_Directories.Table (Src_Search_Directories.Last) :=
592 Normalize_Directory_Name (Dir);
593 end Add_Src_Search_Dir;
595 --------------------------------
596 -- Append_Suffix_To_File_Name --
597 --------------------------------
599 function Append_Suffix_To_File_Name
601 Suffix : String) return Name_Id
604 Get_Name_String (Name);
605 Name_Buffer (Name_Len + 1 .. Name_Len + Suffix'Length) := Suffix;
606 Name_Len := Name_Len + Suffix'Length;
608 end Append_Suffix_To_File_Name;
610 ---------------------
611 -- C_String_Length --
612 ---------------------
614 function C_String_Length (S : Address) return Integer is
615 function Strlen (S : Address) return Integer;
616 pragma Import (C, Strlen, "strlen");
618 if S = Null_Address then
625 ------------------------------
626 -- Canonical_Case_File_Name --
627 ------------------------------
629 -- For now, we only deal with the case of a-z. Eventually we should
630 -- worry about other Latin-1 letters on systems that support this ???
632 procedure Canonical_Case_File_Name (S : in out String) is
634 if not File_Names_Case_Sensitive then
635 for J in S'Range loop
636 if S (J) in 'A' .. 'Z' then
637 S (J) := Character'Val (
638 Character'Pos (S (J)) +
639 Character'Pos ('a') -
640 Character'Pos ('A'));
644 end Canonical_Case_File_Name;
650 function Concat (String_One : String; String_Two : String) return String is
651 Buffer : String (1 .. String_One'Length + String_Two'Length);
653 Buffer (1 .. String_One'Length) := String_One;
654 Buffer (String_One'Length + 1 .. Buffer'Last) := String_Two;
658 ---------------------------
659 -- Create_File_And_Check --
660 ---------------------------
662 procedure Create_File_And_Check
663 (Fdesc : out File_Descriptor;
667 Output_File_Name := Name_Enter;
668 Fdesc := Create_File (Name_Buffer'Address, Fmode);
670 if Fdesc = Invalid_FD then
671 Fail ("Cannot create: ", Name_Buffer (1 .. Name_Len));
673 end Create_File_And_Check;
675 ------------------------
676 -- Current_File_Index --
677 ------------------------
679 function Current_File_Index return Int is
681 return File_Indexes (Current_File_Name_Index);
682 end Current_File_Index;
684 --------------------------------
685 -- Current_Library_File_Stamp --
686 --------------------------------
688 function Current_Library_File_Stamp return Time_Stamp_Type is
690 return Current_Full_Lib_Stamp;
691 end Current_Library_File_Stamp;
693 -------------------------------
694 -- Current_Object_File_Stamp --
695 -------------------------------
697 function Current_Object_File_Stamp return Time_Stamp_Type is
699 return Current_Full_Obj_Stamp;
700 end Current_Object_File_Stamp;
702 -------------------------------
703 -- Current_Source_File_Stamp --
704 -------------------------------
706 function Current_Source_File_Stamp return Time_Stamp_Type is
708 return Current_Full_Source_Stamp;
709 end Current_Source_File_Stamp;
711 ----------------------------
712 -- Dir_In_Obj_Search_Path --
713 ----------------------------
715 function Dir_In_Obj_Search_Path (Position : Natural) return String_Ptr is
717 if Opt.Look_In_Primary_Dir then
719 Lib_Search_Directories.Table (Primary_Directory + Position - 1);
721 return Lib_Search_Directories.Table (Primary_Directory + Position);
723 end Dir_In_Obj_Search_Path;
725 ----------------------------
726 -- Dir_In_Src_Search_Path --
727 ----------------------------
729 function Dir_In_Src_Search_Path (Position : Natural) return String_Ptr is
731 if Opt.Look_In_Primary_Dir then
733 Src_Search_Directories.Table (Primary_Directory + Position - 1);
735 return Src_Search_Directories.Table (Primary_Directory + Position);
737 end Dir_In_Src_Search_Path;
739 ---------------------
740 -- Executable_Name --
741 ---------------------
743 function Executable_Name (Name : File_Name_Type) return File_Name_Type is
744 Exec_Suffix : String_Access;
747 if Name = No_File then
751 Get_Name_String (Name);
752 Exec_Suffix := Get_Executable_Suffix;
754 for J in Exec_Suffix'Range loop
755 Name_Len := Name_Len + 1;
756 Name_Buffer (Name_Len) := Exec_Suffix (J);
764 -----------------------
765 -- Executable_Prefix --
766 -----------------------
768 function Executable_Prefix return String_Ptr is
769 function Get_Install_Dir (Exec : String) return String_Ptr;
770 -- S is the executable name preceeded by the absolute or relative
771 -- path, e.g. "c:\usr\bin\gcc.exe" or "..\bin\gcc".
773 ---------------------
774 -- Get_Install_Dir --
775 ---------------------
777 function Get_Install_Dir (Exec : String) return String_Ptr is
779 for J in reverse Exec'Range loop
780 if Is_Directory_Separator (Exec (J)) then
781 if J < Exec'Last - 5 then
782 if (To_Lower (Exec (J + 1)) = 'l'
783 and then To_Lower (Exec (J + 2)) = 'i'
784 and then To_Lower (Exec (J + 3)) = 'b')
786 (To_Lower (Exec (J + 1)) = 'b'
787 and then To_Lower (Exec (J + 2)) = 'i'
788 and then To_Lower (Exec (J + 3)) = 'n')
790 return new String'(Exec (Exec'First .. J));
796 return new String'("");
799 -- Start of processing for Executable_Prefix
802 if Exec_Name = null then
803 Exec_Name := new String (1 .. Len_Arg (0));
804 Osint.Fill_Arg (Exec_Name (1)'Address, 0);
807 -- First determine if a path prefix was placed in front of the
810 for J in reverse Exec_Name'Range loop
811 if Is_Directory_Separator (Exec_Name (J)) then
812 return Get_Install_Dir (Exec_Name.all);
816 -- If we come here, the user has typed the executable name with no
819 return Get_Install_Dir
820 (GNAT.OS_Lib.Locate_Exec_On_Path (Exec_Name.all).all);
821 end Executable_Prefix;
827 procedure Exit_Program (Exit_Code : Exit_Code_Type) is
829 -- The program will exit with the following status:
831 -- 0 if the object file has been generated (with or without warnings)
832 -- 1 if recompilation was not needed (smart recompilation)
833 -- 2 if gnat1 has been killed by a signal (detected by GCC)
834 -- 4 for a fatal error
835 -- 5 if there were errors
836 -- 6 if no code has been generated (spec)
838 -- Note that exit code 3 is not used and must not be used as this is
839 -- the code returned by a program aborted via C abort() routine on
840 -- Windows. GCC checks for that case and thinks that the child process
841 -- has been aborted. This code (exit code 3) used to be the code used
842 -- for E_No_Code, but E_No_Code was changed to 6 for this reason.
845 when E_Success => OS_Exit (0);
846 when E_Warnings => OS_Exit (0);
847 when E_No_Compile => OS_Exit (1);
848 when E_Fatal => OS_Exit (4);
849 when E_Errors => OS_Exit (5);
850 when E_No_Code => OS_Exit (6);
851 when E_Abort => OS_Abort;
859 procedure Fail (S1 : String; S2 : String := ""; S3 : String := "") is
861 -- We use Output in case there is a special output set up.
862 -- In this case Set_Standard_Error will have no immediate effect.
865 Osint.Write_Program_Name;
872 Exit_Program (E_Fatal);
879 function File_Hash (F : File_Name_Type) return File_Hash_Num is
881 return File_Hash_Num (Int (F) rem File_Hash_Num'Range_Length);
888 function File_Stamp (Name : File_Name_Type) return Time_Stamp_Type is
890 if Name = No_File then
891 return Empty_Time_Stamp;
894 Get_Name_String (Name);
896 if not Is_Regular_File (Name_Buffer (1 .. Name_Len)) then
897 return Empty_Time_Stamp;
899 Name_Buffer (Name_Len + 1) := ASCII.NUL;
900 return OS_Time_To_GNAT_Time (File_Time_Stamp (Name_Buffer));
910 T : File_Type) return File_Name_Type
916 File_Name : String renames Name_Buffer (1 .. Name_Len);
917 File : File_Name_Type := No_File;
921 -- If we are looking for a config file, look only in the current
922 -- directory, i.e. return input argument unchanged. Also look
923 -- only in the current directory if we are looking for a .dg
924 -- file (happens in -gnatD mode)
927 or else (Debug_Generated_Code
928 and then Name_Len > 3
930 (Name_Buffer (Name_Len - 2 .. Name_Len) = ".dg"
932 (Hostparm.OpenVMS and then
933 Name_Buffer (Name_Len - 2 .. Name_Len) = "_dg")))
937 -- If we are trying to find the current main file just look in the
938 -- directory where the user said it was.
940 elsif Look_In_Primary_Directory_For_Current_Main
941 and then Current_Main = N
943 return Locate_File (N, T, Primary_Directory, File_Name);
945 -- Otherwise do standard search for source file
948 -- Check the mapping of this file name
950 File := Mapped_Path_Name (N);
952 -- If the file name is mapped to a path name, return the
953 -- corresponding path name
955 if File /= No_File then
956 -- For locally removed file, Error_Name is returned; then
957 -- return No_File, indicating the file is not a source.
959 if File = Error_Name then
967 -- First place to look is in the primary directory (i.e. the same
968 -- directory as the source) unless this has been disabled with -I-
970 if Opt.Look_In_Primary_Dir then
971 File := Locate_File (N, T, Primary_Directory, File_Name);
973 if File /= No_File then
978 -- Finally look in directories specified with switches -I/-aI/-aO
981 Last_Dir := Lib_Search_Directories.Last;
983 Last_Dir := Src_Search_Directories.Last;
986 for D in Primary_Directory + 1 .. Last_Dir loop
987 File := Locate_File (N, T, D, File_Name);
989 if File /= No_File then
999 -----------------------
1000 -- Find_Program_Name --
1001 -----------------------
1003 procedure Find_Program_Name is
1004 Command_Name : String (1 .. Len_Arg (0));
1005 Cindex1 : Integer := Command_Name'First;
1006 Cindex2 : Integer := Command_Name'Last;
1009 Fill_Arg (Command_Name'Address, 0);
1011 -- The program name might be specified by a full path name. However,
1012 -- we don't want to print that all out in an error message, so the
1013 -- path might need to be stripped away.
1015 for J in reverse Cindex1 .. Cindex2 loop
1016 if Is_Directory_Separator (Command_Name (J)) then
1022 -- Command_Name(Cindex1 .. Cindex2) is now the equivalent of the
1023 -- POSIX command "basename argv[0]"
1025 -- Strip off any versioning information such as found on VMS.
1026 -- This would take the form of TOOL.exe followed by a ";" or "."
1027 -- and a sequence of one or more numbers.
1029 if Command_Name (Cindex2) in '0' .. '9' then
1030 for J in reverse Cindex1 .. Cindex2 loop
1031 if Command_Name (J) = '.' or Command_Name (J) = ';' then
1036 exit when Command_Name (J) not in '0' .. '9';
1040 -- Strip off any executable extension (usually nothing or .exe)
1041 -- but formally reported by autoconf in the variable EXEEXT
1043 if Cindex2 - Cindex1 >= 4 then
1044 if To_Lower (Command_Name (Cindex2 - 3)) = '.'
1045 and then To_Lower (Command_Name (Cindex2 - 2)) = 'e'
1046 and then To_Lower (Command_Name (Cindex2 - 1)) = 'x'
1047 and then To_Lower (Command_Name (Cindex2)) = 'e'
1049 Cindex2 := Cindex2 - 4;
1053 Name_Len := Cindex2 - Cindex1 + 1;
1054 Name_Buffer (1 .. Name_Len) := Command_Name (Cindex1 .. Cindex2);
1055 end Find_Program_Name;
1057 ------------------------
1058 -- Full_Lib_File_Name --
1059 ------------------------
1061 function Full_Lib_File_Name (N : File_Name_Type) return File_Name_Type is
1063 return Find_File (N, Library);
1064 end Full_Lib_File_Name;
1066 ----------------------------
1067 -- Full_Library_Info_Name --
1068 ----------------------------
1070 function Full_Library_Info_Name return File_Name_Type is
1072 return Current_Full_Lib_Name;
1073 end Full_Library_Info_Name;
1075 ---------------------------
1076 -- Full_Object_File_Name --
1077 ---------------------------
1079 function Full_Object_File_Name return File_Name_Type is
1081 return Current_Full_Obj_Name;
1082 end Full_Object_File_Name;
1084 ----------------------
1085 -- Full_Source_Name --
1086 ----------------------
1088 function Full_Source_Name return File_Name_Type is
1090 return Current_Full_Source_Name;
1091 end Full_Source_Name;
1093 ----------------------
1094 -- Full_Source_Name --
1095 ----------------------
1097 function Full_Source_Name (N : File_Name_Type) return File_Name_Type is
1099 return Smart_Find_File (N, Source);
1100 end Full_Source_Name;
1106 function Get_Directory (Name : File_Name_Type) return File_Name_Type is
1108 Get_Name_String (Name);
1110 for J in reverse 1 .. Name_Len loop
1111 if Is_Directory_Separator (Name_Buffer (J)) then
1117 Name_Len := Hostparm.Normalized_CWD'Length;
1118 Name_Buffer (1 .. Name_Len) := Hostparm.Normalized_CWD;
1122 --------------------------
1123 -- Get_Next_Dir_In_Path --
1124 --------------------------
1126 Search_Path_Pos : Integer;
1127 -- Keeps track of current position in search path. Initialized by the
1128 -- call to Get_Next_Dir_In_Path_Init, updated by Get_Next_Dir_In_Path.
1130 function Get_Next_Dir_In_Path
1131 (Search_Path : String_Access) return String_Access
1133 Lower_Bound : Positive := Search_Path_Pos;
1134 Upper_Bound : Positive;
1138 while Lower_Bound <= Search_Path'Last
1139 and then Search_Path.all (Lower_Bound) = Path_Separator
1141 Lower_Bound := Lower_Bound + 1;
1144 exit when Lower_Bound > Search_Path'Last;
1146 Upper_Bound := Lower_Bound;
1147 while Upper_Bound <= Search_Path'Last
1148 and then Search_Path.all (Upper_Bound) /= Path_Separator
1150 Upper_Bound := Upper_Bound + 1;
1153 Search_Path_Pos := Upper_Bound;
1154 return new String'(Search_Path.all (Lower_Bound .. Upper_Bound - 1));
1158 end Get_Next_Dir_In_Path;
1160 -------------------------------
1161 -- Get_Next_Dir_In_Path_Init --
1162 -------------------------------
1164 procedure Get_Next_Dir_In_Path_Init (Search_Path : String_Access) is
1166 Search_Path_Pos := Search_Path'First;
1167 end Get_Next_Dir_In_Path_Init;
1169 --------------------------------------
1170 -- Get_Primary_Src_Search_Directory --
1171 --------------------------------------
1173 function Get_Primary_Src_Search_Directory return String_Ptr is
1175 return Src_Search_Directories.Table (Primary_Directory);
1176 end Get_Primary_Src_Search_Directory;
1178 ------------------------
1179 -- Get_RTS_Search_Dir --
1180 ------------------------
1182 function Get_RTS_Search_Dir
1183 (Search_Dir : String;
1184 File_Type : Search_File_Type) return String_Ptr
1186 procedure Get_Current_Dir
1187 (Dir : System.Address;
1188 Length : System.Address);
1189 pragma Import (C, Get_Current_Dir, "__gnat_get_current_dir");
1192 pragma Import (C, Max_Path, "__gnat_max_path_len");
1193 -- Maximum length of a path name
1195 Current_Dir : String_Ptr;
1196 Default_Search_Dir : String_Access;
1197 Default_Suffix_Dir : String_Access;
1198 Local_Search_Dir : String_Access;
1199 Norm_Search_Dir : String_Access;
1200 Result_Search_Dir : String_Access;
1201 Search_File : String_Access;
1202 Temp_String : String_Ptr;
1205 -- Add a directory separator at the end of the directory if necessary
1206 -- so that we can directly append a file to the directory
1208 if Search_Dir (Search_Dir'Last) /= Directory_Separator then
1209 Local_Search_Dir := new String'
1210 (Concat (Search_Dir, String'(1 => Directory_Separator)));
1212 Local_Search_Dir := new String'(Search_Dir);
1215 if File_Type = Include then
1216 Search_File := Include_Search_File;
1217 Default_Suffix_Dir := new String'("adainclude");
1219 Search_File := Objects_Search_File;
1220 Default_Suffix_Dir := new String'("adalib");
1223 Norm_Search_Dir := To_Canonical_Path_Spec (Local_Search_Dir.all);
1225 if Is_Absolute_Path (Norm_Search_Dir.all) then
1227 -- We first verify if there is a directory Include_Search_Dir
1228 -- containing default search directories
1231 := Read_Default_Search_Dirs (Norm_Search_Dir,
1234 Default_Search_Dir := new String'
1235 (Concat (Norm_Search_Dir.all, Default_Suffix_Dir.all));
1236 Free (Norm_Search_Dir);
1238 if Result_Search_Dir /= null then
1239 return String_Ptr (Result_Search_Dir);
1240 elsif Is_Directory (Default_Search_Dir.all) then
1241 return String_Ptr (Default_Search_Dir);
1246 -- Search in the current directory
1249 -- Get the current directory
1252 Buffer : String (1 .. Max_Path + 2);
1253 Path_Len : Natural := Max_Path;
1256 Get_Current_Dir (Buffer'Address, Path_Len'Address);
1258 if Buffer (Path_Len) /= Directory_Separator then
1259 Path_Len := Path_Len + 1;
1260 Buffer (Path_Len) := Directory_Separator;
1263 Current_Dir := new String'(Buffer (1 .. Path_Len));
1267 new String'(Concat (Current_Dir.all, Local_Search_Dir.all));
1269 Result_Search_Dir :=
1270 Read_Default_Search_Dirs (Norm_Search_Dir, Search_File, null);
1272 Default_Search_Dir :=
1274 (Concat (Norm_Search_Dir.all, Default_Suffix_Dir.all));
1276 Free (Norm_Search_Dir);
1278 if Result_Search_Dir /= null then
1279 return String_Ptr (Result_Search_Dir);
1281 elsif Is_Directory (Default_Search_Dir.all) then
1282 return String_Ptr (Default_Search_Dir);
1285 -- Search in Search_Dir_Prefix/Search_Dir
1289 (Concat (Update_Path (Search_Dir_Prefix).all,
1290 Local_Search_Dir.all));
1292 Result_Search_Dir :=
1293 Read_Default_Search_Dirs (Norm_Search_Dir, Search_File, null);
1295 Default_Search_Dir :=
1297 (Concat (Norm_Search_Dir.all, Default_Suffix_Dir.all));
1299 Free (Norm_Search_Dir);
1301 if Result_Search_Dir /= null then
1302 return String_Ptr (Result_Search_Dir);
1304 elsif Is_Directory (Default_Search_Dir.all) then
1305 return String_Ptr (Default_Search_Dir);
1308 -- We finally search in Search_Dir_Prefix/rts-Search_Dir
1312 (Concat (Update_Path (Search_Dir_Prefix).all, "rts-"));
1315 new String'(Concat (Temp_String.all, Local_Search_Dir.all));
1317 Result_Search_Dir :=
1318 Read_Default_Search_Dirs (Norm_Search_Dir, Search_File, null);
1320 Default_Search_Dir :=
1322 (Concat (Norm_Search_Dir.all, Default_Suffix_Dir.all));
1323 Free (Norm_Search_Dir);
1325 if Result_Search_Dir /= null then
1326 return String_Ptr (Result_Search_Dir);
1328 elsif Is_Directory (Default_Search_Dir.all) then
1329 return String_Ptr (Default_Search_Dir);
1337 end Get_RTS_Search_Dir;
1339 --------------------------------
1340 -- Include_Dir_Default_Prefix --
1341 --------------------------------
1343 function Include_Dir_Default_Prefix return String is
1344 Include_Dir : String_Access :=
1345 String_Access (Update_Path (Include_Dir_Default_Name));
1348 if Include_Dir = null then
1353 Result : constant String := Include_Dir.all;
1359 end Include_Dir_Default_Prefix;
1365 procedure Initialize is
1367 Number_File_Names := 0;
1368 Current_File_Name_Index := 0;
1370 Src_Search_Directories.Init;
1371 Lib_Search_Directories.Init;
1373 -- Start off by setting all suppress options to False, these will
1374 -- be reset later (turning some on if -gnato is not specified, and
1375 -- turning all of them on if -gnatp is specified).
1377 Suppress_Options := (others => False);
1379 -- Reserve the first slot in the search paths table. This is the
1380 -- directory of the main source file or main library file and is
1381 -- filled in by each call to Next_Main_Source/Next_Main_Lib_File with
1382 -- the directory specified for this main source or library file. This
1383 -- is the directory which is searched first by default. This default
1384 -- search is inhibited by the option -I- for both source and library
1387 Src_Search_Directories.Set_Last (Primary_Directory);
1388 Src_Search_Directories.Table (Primary_Directory) := new String'("");
1390 Lib_Search_Directories.Set_Last (Primary_Directory);
1391 Lib_Search_Directories.Table (Primary_Directory) := new String'("");
1394 ----------------------------
1395 -- Is_Directory_Separator --
1396 ----------------------------
1398 function Is_Directory_Separator (C : Character) return Boolean is
1400 -- In addition to the default directory_separator allow the '/' to
1401 -- act as separator since this is allowed in MS-DOS, Windows 95/NT,
1402 -- and OS2 ports. On VMS, the situation is more complicated because
1403 -- there are two characters to check for.
1406 C = Directory_Separator
1408 or else (Hostparm.OpenVMS
1409 and then (C = ']' or else C = ':'));
1410 end Is_Directory_Separator;
1412 -------------------------
1413 -- Is_Readonly_Library --
1414 -------------------------
1416 function Is_Readonly_Library (File : in File_Name_Type) return Boolean is
1418 Get_Name_String (File);
1420 pragma Assert (Name_Buffer (Name_Len - 3 .. Name_Len) = ".ali");
1422 return not Is_Writable_File (Name_Buffer (1 .. Name_Len));
1423 end Is_Readonly_Library;
1429 function Lib_File_Name
1430 (Source_File : File_Name_Type;
1431 Munit_Index : Nat := 0) return File_Name_Type
1434 Get_Name_String (Source_File);
1436 for J in reverse 2 .. Name_Len loop
1437 if Name_Buffer (J) = '.' then
1443 if Munit_Index /= 0 then
1444 Add_Char_To_Name_Buffer (Multi_Unit_Index_Character);
1445 Add_Nat_To_Name_Buffer (Munit_Index);
1448 Add_Char_To_Name_Buffer ('.');
1449 Add_Str_To_Name_Buffer (ALI_Suffix.all);
1453 ------------------------
1454 -- Library_File_Stamp --
1455 ------------------------
1457 function Library_File_Stamp (N : File_Name_Type) return Time_Stamp_Type is
1459 return File_Stamp (Find_File (N, Library));
1460 end Library_File_Stamp;
1466 function Locate_File
1467 (N : File_Name_Type;
1470 Name : String) return File_Name_Type
1472 Dir_Name : String_Ptr;
1475 -- If Name is already an absolute path, do not look for a directory
1477 if Is_Absolute_Path (Name) then
1480 elsif T = Library then
1481 Dir_Name := Lib_Search_Directories.Table (Dir);
1483 else pragma Assert (T /= Config);
1484 Dir_Name := Src_Search_Directories.Table (Dir);
1488 Full_Name : String (1 .. Dir_Name'Length + Name'Length);
1491 Full_Name (1 .. Dir_Name'Length) := Dir_Name.all;
1492 Full_Name (Dir_Name'Length + 1 .. Full_Name'Length) := Name;
1494 if not Is_Regular_File (Full_Name) then
1498 -- If the file is in the current directory then return N itself
1500 if Dir_Name'Length = 0 then
1503 Name_Len := Full_Name'Length;
1504 Name_Buffer (1 .. Name_Len) := Full_Name;
1511 -------------------------------
1512 -- Matching_Full_Source_Name --
1513 -------------------------------
1515 function Matching_Full_Source_Name
1516 (N : File_Name_Type;
1517 T : Time_Stamp_Type) return File_Name_Type
1520 Get_Name_String (N);
1523 File_Name : constant String := Name_Buffer (1 .. Name_Len);
1524 File : File_Name_Type := No_File;
1528 if Opt.Look_In_Primary_Dir then
1529 File := Locate_File (N, Source, Primary_Directory, File_Name);
1531 if File /= No_File and then T = File_Stamp (N) then
1536 Last_Dir := Src_Search_Directories.Last;
1538 for D in Primary_Directory + 1 .. Last_Dir loop
1539 File := Locate_File (N, Source, D, File_Name);
1541 if File /= No_File and then T = File_Stamp (File) then
1548 end Matching_Full_Source_Name;
1554 function More_Files return Boolean is
1556 return (Current_File_Name_Index < Number_File_Names);
1559 -------------------------------
1560 -- Nb_Dir_In_Obj_Search_Path --
1561 -------------------------------
1563 function Nb_Dir_In_Obj_Search_Path return Natural is
1565 if Opt.Look_In_Primary_Dir then
1566 return Lib_Search_Directories.Last - Primary_Directory + 1;
1568 return Lib_Search_Directories.Last - Primary_Directory;
1570 end Nb_Dir_In_Obj_Search_Path;
1572 -------------------------------
1573 -- Nb_Dir_In_Src_Search_Path --
1574 -------------------------------
1576 function Nb_Dir_In_Src_Search_Path return Natural is
1578 if Opt.Look_In_Primary_Dir then
1579 return Src_Search_Directories.Last - Primary_Directory + 1;
1581 return Src_Search_Directories.Last - Primary_Directory;
1583 end Nb_Dir_In_Src_Search_Path;
1585 --------------------
1586 -- Next_Main_File --
1587 --------------------
1589 function Next_Main_File return File_Name_Type is
1590 File_Name : String_Ptr;
1591 Dir_Name : String_Ptr;
1595 pragma Assert (More_Files);
1597 Current_File_Name_Index := Current_File_Name_Index + 1;
1599 -- Get the file and directory name
1601 File_Name := File_Names (Current_File_Name_Index);
1602 Fptr := File_Name'First;
1604 for J in reverse File_Name'Range loop
1605 if File_Name (J) = Directory_Separator
1606 or else File_Name (J) = '/'
1608 if J = File_Name'Last then
1609 Fail ("File name missing");
1617 -- Save name of directory in which main unit resides for use in
1618 -- locating other units
1620 Dir_Name := new String'(File_Name (File_Name'First .. Fptr - 1));
1622 case Running_Program is
1625 Src_Search_Directories.Table (Primary_Directory) := Dir_Name;
1626 Look_In_Primary_Directory_For_Current_Main := True;
1629 Src_Search_Directories.Table (Primary_Directory) := Dir_Name;
1631 if Fptr > File_Name'First then
1632 Look_In_Primary_Directory_For_Current_Main := True;
1635 when Binder | Gnatls =>
1636 Dir_Name := Normalize_Directory_Name (Dir_Name.all);
1637 Lib_Search_Directories.Table (Primary_Directory) := Dir_Name;
1643 Name_Len := File_Name'Last - Fptr + 1;
1644 Name_Buffer (1 .. Name_Len) := File_Name (Fptr .. File_Name'Last);
1645 Canonical_Case_File_Name (Name_Buffer (1 .. Name_Len));
1646 Current_Main := File_Name_Type (Name_Find);
1648 -- In the gnatmake case, the main file may have not have the
1649 -- extension. Try ".adb" first then ".ads"
1651 if Running_Program = Make then
1653 Orig_Main : constant File_Name_Type := Current_Main;
1656 if Strip_Suffix (Orig_Main) = Orig_Main then
1657 Current_Main := Append_Suffix_To_File_Name (Orig_Main, ".adb");
1659 if Full_Source_Name (Current_Main) = No_File then
1661 Append_Suffix_To_File_Name (Orig_Main, ".ads");
1663 if Full_Source_Name (Current_Main) = No_File then
1664 Current_Main := Orig_Main;
1671 return Current_Main;
1674 ------------------------------
1675 -- Normalize_Directory_Name --
1676 ------------------------------
1678 function Normalize_Directory_Name (Directory : String) return String_Ptr is
1680 function Is_Quoted (Path : String) return Boolean;
1681 pragma Inline (Is_Quoted);
1682 -- Returns true if Path is quoted (either double or single quotes)
1688 function Is_Quoted (Path : String) return Boolean is
1689 First : constant Character := Path (Path'First);
1690 Last : constant Character := Path (Path'Last);
1693 if (First = ''' and then Last = ''')
1695 (First = '"' and then Last = '"')
1703 Result : String_Ptr;
1705 -- Start of processing for Normalize_Directory_Name
1708 if Directory'Length = 0 then
1709 Result := new String'(Hostparm.Normalized_CWD);
1711 elsif Is_Directory_Separator (Directory (Directory'Last)) then
1712 Result := new String'(Directory);
1714 elsif Is_Quoted (Directory) then
1716 -- This is a quoted string, it certainly means that the directory
1717 -- contains some spaces for example. We can safely remove the quotes
1718 -- here as the OS_Lib.Normalize_Arguments will be called before any
1719 -- spawn routines. This ensure that quotes will be added when needed.
1721 Result := new String (1 .. Directory'Length - 1);
1722 Result (1 .. Directory'Length - 1) :=
1723 Directory (Directory'First + 1 .. Directory'Last - 1);
1724 Result (Result'Last) := Directory_Separator;
1727 Result := new String (1 .. Directory'Length + 1);
1728 Result (1 .. Directory'Length) := Directory;
1729 Result (Directory'Length + 1) := Directory_Separator;
1733 end Normalize_Directory_Name;
1735 ---------------------
1736 -- Number_Of_Files --
1737 ---------------------
1739 function Number_Of_Files return Int is
1741 return Number_File_Names;
1742 end Number_Of_Files;
1744 -------------------------------
1745 -- Object_Dir_Default_Prefix --
1746 -------------------------------
1748 function Object_Dir_Default_Prefix return String is
1749 Object_Dir : String_Access :=
1750 String_Access (Update_Path (Object_Dir_Default_Name));
1753 if Object_Dir = null then
1758 Result : constant String := Object_Dir.all;
1764 end Object_Dir_Default_Prefix;
1766 ----------------------
1767 -- Object_File_Name --
1768 ----------------------
1770 function Object_File_Name (N : File_Name_Type) return File_Name_Type is
1776 Get_Name_String (N);
1777 Name_Len := Name_Len - ALI_Suffix'Length - 1;
1779 for J in Object_Suffix'Range loop
1780 Name_Len := Name_Len + 1;
1781 Name_Buffer (Name_Len) := Object_Suffix (J);
1785 end Object_File_Name;
1787 --------------------------
1788 -- OS_Time_To_GNAT_Time --
1789 --------------------------
1791 function OS_Time_To_GNAT_Time (T : OS_Time) return Time_Stamp_Type is
1792 GNAT_Time : Time_Stamp_Type;
1802 GM_Split (T, Y, Mo, D, H, Mn, S);
1808 Minutes => Nat (Mn),
1813 end OS_Time_To_GNAT_Time;
1819 function Program_Name (Nam : String) return String_Access is
1820 Res : String_Access;
1823 -- Get the name of the current program being executed
1827 -- Find the target prefix if any, for the cross compilation case
1828 -- for instance in "alpha-dec-vxworks-gcc" the target prefix is
1829 -- "alpha-dec-vxworks-"
1831 while Name_Len > 0 loop
1833 -- All done if we find the last hyphen
1835 if Name_Buffer (Name_Len) = '-' then
1838 -- If directory separator found, we don't want to look further
1839 -- since in this case, no prefix has been found.
1841 elsif Is_Directory_Separator (Name_Buffer (Name_Len)) then
1846 Name_Len := Name_Len - 1;
1849 -- Create the new program name
1851 Res := new String (1 .. Name_Len + Nam'Length);
1852 Res.all (1 .. Name_Len) := Name_Buffer (1 .. Name_Len);
1853 Res.all (Name_Len + 1 .. Name_Len + Nam'Length) := Nam;
1857 ------------------------------
1858 -- Read_Default_Search_Dirs --
1859 ------------------------------
1861 function Read_Default_Search_Dirs
1862 (Search_Dir_Prefix : String_Access;
1863 Search_File : String_Access;
1864 Search_Dir_Default_Name : String_Access) return String_Access
1866 Prefix_Len : constant Integer := Search_Dir_Prefix.all'Length;
1867 Buffer : String (1 .. Prefix_Len + Search_File.all'Length + 1);
1868 File_FD : File_Descriptor;
1869 S, S1 : String_Access;
1872 Actual_Len : Integer;
1875 Prev_Was_Separator : Boolean;
1876 Nb_Relative_Dir : Integer;
1878 function Is_Relative (S : String; K : Positive) return Boolean;
1879 pragma Inline (Is_Relative);
1880 -- Returns True if a relative directory specification is found
1881 -- in S at position K, False otherwise.
1887 function Is_Relative (S : String; K : Positive) return Boolean is
1889 return not Is_Absolute_Path (S (K .. S'Last));
1892 -- Start of processing for Read_Default_Search_Dirs
1895 -- Construct a C compatible character string buffer
1897 Buffer (1 .. Search_Dir_Prefix.all'Length)
1898 := Search_Dir_Prefix.all;
1899 Buffer (Search_Dir_Prefix.all'Length + 1 .. Buffer'Last - 1)
1901 Buffer (Buffer'Last) := ASCII.NUL;
1903 File_FD := Open_Read (Buffer'Address, Binary);
1904 if File_FD = Invalid_FD then
1905 return Search_Dir_Default_Name;
1908 Len := Integer (File_Length (File_FD));
1910 -- An extra character for a trailing Path_Separator is allocated
1912 S := new String (1 .. Len + 1);
1913 S (Len + 1) := Path_Separator;
1915 -- Read the file. Note that the loop is not necessary since the
1916 -- whole file is read at once except on VMS.
1920 while Actual_Len /= 0 loop
1921 Actual_Len := Read (File_FD, S (Curr)'Address, Len);
1922 Curr := Curr + Actual_Len;
1925 -- Process the file, translating line and file ending
1926 -- control characters to a path separator character.
1928 Prev_Was_Separator := True;
1929 Nb_Relative_Dir := 0;
1930 for J in 1 .. Len loop
1931 if S (J) in ASCII.NUL .. ASCII.US
1934 S (J) := Path_Separator;
1937 if S (J) = Path_Separator then
1938 Prev_Was_Separator := True;
1940 if Prev_Was_Separator and then Is_Relative (S.all, J) then
1941 Nb_Relative_Dir := Nb_Relative_Dir + 1;
1944 Prev_Was_Separator := False;
1948 if Nb_Relative_Dir = 0 then
1952 -- Add the Search_Dir_Prefix to all relative paths
1954 S1 := new String (1 .. S'Length + Nb_Relative_Dir * Prefix_Len);
1956 Prev_Was_Separator := True;
1957 for J in 1 .. Len + 1 loop
1958 if S (J) = Path_Separator then
1959 Prev_Was_Separator := True;
1962 if Prev_Was_Separator and then Is_Relative (S.all, J) then
1963 S1 (J1 .. J1 + Prefix_Len - 1) := Search_Dir_Prefix.all;
1964 J1 := J1 + Prefix_Len;
1967 Prev_Was_Separator := False;
1975 end Read_Default_Search_Dirs;
1977 -----------------------
1978 -- Read_Library_Info --
1979 -----------------------
1981 function Read_Library_Info
1982 (Lib_File : File_Name_Type;
1983 Fatal_Err : Boolean := False) return Text_Buffer_Ptr
1985 Lib_FD : File_Descriptor;
1986 -- The file descriptor for the current library file. A negative value
1987 -- indicates failure to open the specified source file.
1989 Text : Text_Buffer_Ptr;
1990 -- Allocated text buffer
1993 -- For the calls to Close
1996 Current_Full_Lib_Name := Find_File (Lib_File, Library);
1997 Current_Full_Obj_Name := Object_File_Name (Current_Full_Lib_Name);
1999 if Current_Full_Lib_Name = No_File then
2001 Fail ("Cannot find: ", Name_Buffer (1 .. Name_Len));
2003 Current_Full_Obj_Stamp := Empty_Time_Stamp;
2008 Get_Name_String (Current_Full_Lib_Name);
2009 Name_Buffer (Name_Len + 1) := ASCII.NUL;
2011 -- Open the library FD, note that we open in binary mode, because as
2012 -- documented in the spec, the caller is expected to handle either
2013 -- DOS or Unix mode files, and there is no point in wasting time on
2014 -- text translation when it is not required.
2016 Lib_FD := Open_Read (Name_Buffer'Address, Binary);
2018 if Lib_FD = Invalid_FD then
2020 Fail ("Cannot open: ", Name_Buffer (1 .. Name_Len));
2022 Current_Full_Obj_Stamp := Empty_Time_Stamp;
2027 -- Check for object file consistency if requested
2029 if Opt.Check_Object_Consistency then
2030 Current_Full_Lib_Stamp := File_Stamp (Current_Full_Lib_Name);
2031 Current_Full_Obj_Stamp := File_Stamp (Current_Full_Obj_Name);
2033 if Current_Full_Obj_Stamp (1) = ' ' then
2035 -- When the library is readonly, always assume that
2036 -- the object is consistent.
2038 if Is_Readonly_Library (Current_Full_Lib_Name) then
2039 Current_Full_Obj_Stamp := Current_Full_Lib_Stamp;
2041 elsif Fatal_Err then
2042 Get_Name_String (Current_Full_Obj_Name);
2043 Close (Lib_FD, Status);
2044 -- No need to check the status, we fail anyway
2046 Fail ("Cannot find: ", Name_Buffer (1 .. Name_Len));
2049 Current_Full_Obj_Stamp := Empty_Time_Stamp;
2050 Close (Lib_FD, Status);
2052 -- No need to check the status, we return null anyway
2059 -- Read data from the file
2062 Len : constant Integer := Integer (File_Length (Lib_FD));
2063 -- Length of source file text. If it doesn't fit in an integer
2064 -- we're probably stuck anyway (>2 gigs of source seems a lot!)
2066 Actual_Len : Integer := 0;
2068 Lo : constant Text_Ptr := 0;
2069 -- Low bound for allocated text buffer
2071 Hi : Text_Ptr := Text_Ptr (Len);
2072 -- High bound for allocated text buffer. Note length is Len + 1
2073 -- which allows for extra EOF character at the end of the buffer.
2076 -- Allocate text buffer. Note extra character at end for EOF
2078 Text := new Text_Buffer (Lo .. Hi);
2080 -- Some systems (e.g. VMS) have file types that require one
2081 -- read per line, so read until we get the Len bytes or until
2082 -- there are no more characters.
2086 Actual_Len := Read (Lib_FD, Text (Hi)'Address, Len);
2087 Hi := Hi + Text_Ptr (Actual_Len);
2088 exit when Actual_Len = Len or Actual_Len <= 0;
2094 -- Read is complete, close file and we are done
2096 Close (Lib_FD, Status);
2097 -- The status should never be False. But, if it is, what can we do?
2098 -- So, we don't test it.
2102 end Read_Library_Info;
2104 ----------------------
2105 -- Read_Source_File --
2106 ----------------------
2108 procedure Read_Source_File
2109 (N : File_Name_Type;
2111 Hi : out Source_Ptr;
2112 Src : out Source_Buffer_Ptr;
2113 T : File_Type := Source)
2115 Source_File_FD : File_Descriptor;
2116 -- The file descriptor for the current source file. A negative value
2117 -- indicates failure to open the specified source file.
2120 -- Length of file. Assume no more than 2 gigabytes of source!
2122 Actual_Len : Integer;
2125 -- For the call to Close
2128 Current_Full_Source_Name := Find_File (N, T);
2129 Current_Full_Source_Stamp := File_Stamp (Current_Full_Source_Name);
2131 if Current_Full_Source_Name = No_File then
2133 -- If we were trying to access the main file and we could not
2134 -- find it we have an error.
2136 if N = Current_Main then
2137 Get_Name_String (N);
2138 Fail ("Cannot find: ", Name_Buffer (1 .. Name_Len));
2146 Get_Name_String (Current_Full_Source_Name);
2147 Name_Buffer (Name_Len + 1) := ASCII.NUL;
2149 -- Open the source FD, note that we open in binary mode, because as
2150 -- documented in the spec, the caller is expected to handle either
2151 -- DOS or Unix mode files, and there is no point in wasting time on
2152 -- text translation when it is not required.
2154 Source_File_FD := Open_Read (Name_Buffer'Address, Binary);
2156 if Source_File_FD = Invalid_FD then
2162 -- Prepare to read data from the file
2164 Len := Integer (File_Length (Source_File_FD));
2166 -- Set Hi so that length is one more than the physical length,
2167 -- allowing for the extra EOF character at the end of the buffer
2169 Hi := Lo + Source_Ptr (Len);
2171 -- Do the actual read operation
2174 subtype Actual_Source_Buffer is Source_Buffer (Lo .. Hi);
2175 -- Physical buffer allocated
2177 type Actual_Source_Ptr is access Actual_Source_Buffer;
2178 -- This is the pointer type for the physical buffer allocated
2180 Actual_Ptr : constant Actual_Source_Ptr := new Actual_Source_Buffer;
2181 -- And this is the actual physical buffer
2184 -- Allocate source buffer, allowing extra character at end for EOF
2186 -- Some systems (e.g. VMS) have file types that require one
2187 -- read per line, so read until we get the Len bytes or until
2188 -- there are no more characters.
2192 Actual_Len := Read (Source_File_FD, Actual_Ptr (Hi)'Address, Len);
2193 Hi := Hi + Source_Ptr (Actual_Len);
2194 exit when Actual_Len = Len or Actual_Len <= 0;
2197 Actual_Ptr (Hi) := EOF;
2199 -- Now we need to work out the proper virtual origin pointer to
2200 -- return. This is exactly Actual_Ptr (0)'Address, but we have
2201 -- to be careful to suppress checks to compute this address.
2204 pragma Suppress (All_Checks);
2206 pragma Warnings (Off);
2207 -- This use of unchecked conversion is aliasing safe
2209 function To_Source_Buffer_Ptr is new
2210 Unchecked_Conversion (Address, Source_Buffer_Ptr);
2212 pragma Warnings (On);
2215 Src := To_Source_Buffer_Ptr (Actual_Ptr (0)'Address);
2219 -- Read is complete, get time stamp and close file and we are done
2221 Close (Source_File_FD, Status);
2223 -- The status should never be False. But, if it is, what can we do?
2224 -- So, we don't test it.
2226 end Read_Source_File;
2232 function Relocate_Path
2234 Path : String) return String_Ptr
2238 procedure set_std_prefix (S : String; Len : Integer);
2239 pragma Import (C, set_std_prefix);
2242 if Std_Prefix = null then
2243 Std_Prefix := Executable_Prefix;
2245 if Std_Prefix.all /= "" then
2247 -- Remove trailing directory separator when calling set_std_prefix
2249 set_std_prefix (Std_Prefix.all, Std_Prefix'Length - 1);
2253 if Path (Prefix'Range) = Prefix then
2254 if Std_Prefix.all /= "" then
2256 (1 .. Std_Prefix'Length + Path'Last - Prefix'Last);
2257 S (1 .. Std_Prefix'Length) := Std_Prefix.all;
2258 S (Std_Prefix'Length + 1 .. S'Last) :=
2259 Path (Prefix'Last + 1 .. Path'Last);
2264 return new String'(Path);
2271 procedure Set_Program (P : Program_Type) is
2274 Fail ("Set_Program called twice");
2277 Program_Set := True;
2278 Running_Program := P;
2285 function Shared_Lib (Name : String) return String is
2286 Library : String (1 .. Name'Length + Library_Version'Length + 3);
2287 -- 3 = 2 for "-l" + 1 for "-" before lib version
2290 Library (1 .. 2) := "-l";
2291 Library (3 .. 2 + Name'Length) := Name;
2292 Library (3 + Name'Length) := '-';
2293 Library (4 + Name'Length .. Library'Last) := Library_Version;
2295 if Hostparm.OpenVMS then
2296 for K in Library'First + 2 .. Library'Last loop
2297 if Library (K) = '.' or else Library (K) = '-' then
2306 ----------------------
2307 -- Smart_File_Stamp --
2308 ----------------------
2310 function Smart_File_Stamp
2311 (N : File_Name_Type;
2312 T : File_Type) return Time_Stamp_Type
2314 Time_Stamp : Time_Stamp_Type;
2317 if not File_Cache_Enabled then
2318 return File_Stamp (Find_File (N, T));
2321 Time_Stamp := File_Stamp_Hash_Table.Get (N);
2323 if Time_Stamp (1) = ' ' then
2324 Time_Stamp := File_Stamp (Smart_Find_File (N, T));
2325 File_Stamp_Hash_Table.Set (N, Time_Stamp);
2329 end Smart_File_Stamp;
2331 ---------------------
2332 -- Smart_Find_File --
2333 ---------------------
2335 function Smart_Find_File
2336 (N : File_Name_Type;
2337 T : File_Type) return File_Name_Type
2339 Full_File_Name : File_Name_Type;
2342 if not File_Cache_Enabled then
2343 return Find_File (N, T);
2346 Full_File_Name := File_Name_Hash_Table.Get (N);
2348 if Full_File_Name = No_File then
2349 Full_File_Name := Find_File (N, T);
2350 File_Name_Hash_Table.Set (N, Full_File_Name);
2353 return Full_File_Name;
2354 end Smart_Find_File;
2356 ----------------------
2357 -- Source_File_Data --
2358 ----------------------
2360 procedure Source_File_Data (Cache : Boolean) is
2362 File_Cache_Enabled := Cache;
2363 end Source_File_Data;
2365 -----------------------
2366 -- Source_File_Stamp --
2367 -----------------------
2369 function Source_File_Stamp (N : File_Name_Type) return Time_Stamp_Type is
2371 return Smart_File_Stamp (N, Source);
2372 end Source_File_Stamp;
2374 ---------------------
2375 -- Strip_Directory --
2376 ---------------------
2378 function Strip_Directory (Name : File_Name_Type) return File_Name_Type is
2380 Get_Name_String (Name);
2382 for J in reverse 1 .. Name_Len - 1 loop
2384 -- If we find the last directory separator
2386 if Is_Directory_Separator (Name_Buffer (J)) then
2388 -- Return the part of Name that follows this last directory
2391 Name_Buffer (1 .. Name_Len - J) := Name_Buffer (J + 1 .. Name_Len);
2392 Name_Len := Name_Len - J;
2397 -- There were no directory separator, just return Name
2400 end Strip_Directory;
2406 function Strip_Suffix (Name : File_Name_Type) return File_Name_Type is
2408 Get_Name_String (Name);
2410 for J in reverse 2 .. Name_Len loop
2412 -- If we found the last '.', return part of Name that precedes it
2414 if Name_Buffer (J) = '.' then
2423 ---------------------------
2424 -- To_Canonical_Dir_Spec --
2425 ---------------------------
2427 function To_Canonical_Dir_Spec
2429 Prefix_Style : Boolean) return String_Access
2431 function To_Canonical_Dir_Spec
2432 (Host_Dir : Address;
2433 Prefix_Flag : Integer) return Address;
2434 pragma Import (C, To_Canonical_Dir_Spec, "__gnat_to_canonical_dir_spec");
2436 C_Host_Dir : String (1 .. Host_Dir'Length + 1);
2437 Canonical_Dir_Addr : Address;
2438 Canonical_Dir_Len : Integer;
2441 C_Host_Dir (1 .. Host_Dir'Length) := Host_Dir;
2442 C_Host_Dir (C_Host_Dir'Last) := ASCII.NUL;
2444 if Prefix_Style then
2445 Canonical_Dir_Addr := To_Canonical_Dir_Spec (C_Host_Dir'Address, 1);
2447 Canonical_Dir_Addr := To_Canonical_Dir_Spec (C_Host_Dir'Address, 0);
2449 Canonical_Dir_Len := C_String_Length (Canonical_Dir_Addr);
2451 if Canonical_Dir_Len = 0 then
2454 return To_Path_String_Access (Canonical_Dir_Addr, Canonical_Dir_Len);
2459 Fail ("erroneous directory spec: ", Host_Dir);
2461 end To_Canonical_Dir_Spec;
2463 ---------------------------
2464 -- To_Canonical_File_List --
2465 ---------------------------
2467 function To_Canonical_File_List
2468 (Wildcard_Host_File : String;
2469 Only_Dirs : Boolean) return String_Access_List_Access
2471 function To_Canonical_File_List_Init
2472 (Host_File : Address;
2473 Only_Dirs : Integer) return Integer;
2474 pragma Import (C, To_Canonical_File_List_Init,
2475 "__gnat_to_canonical_file_list_init");
2477 function To_Canonical_File_List_Next return Address;
2478 pragma Import (C, To_Canonical_File_List_Next,
2479 "__gnat_to_canonical_file_list_next");
2481 procedure To_Canonical_File_List_Free;
2482 pragma Import (C, To_Canonical_File_List_Free,
2483 "__gnat_to_canonical_file_list_free");
2485 Num_Files : Integer;
2486 C_Wildcard_Host_File : String (1 .. Wildcard_Host_File'Length + 1);
2489 C_Wildcard_Host_File (1 .. Wildcard_Host_File'Length) :=
2491 C_Wildcard_Host_File (C_Wildcard_Host_File'Last) := ASCII.NUL;
2493 -- Do the expansion and say how many there are
2495 Num_Files := To_Canonical_File_List_Init
2496 (C_Wildcard_Host_File'Address, Boolean'Pos (Only_Dirs));
2499 Canonical_File_List : String_Access_List (1 .. Num_Files);
2500 Canonical_File_Addr : Address;
2501 Canonical_File_Len : Integer;
2504 -- Retrieve the expanded directoy names and build the list
2506 for J in 1 .. Num_Files loop
2507 Canonical_File_Addr := To_Canonical_File_List_Next;
2508 Canonical_File_Len := C_String_Length (Canonical_File_Addr);
2509 Canonical_File_List (J) := To_Path_String_Access
2510 (Canonical_File_Addr, Canonical_File_Len);
2513 -- Free up the storage
2515 To_Canonical_File_List_Free;
2517 return new String_Access_List'(Canonical_File_List);
2519 end To_Canonical_File_List;
2521 ----------------------------
2522 -- To_Canonical_File_Spec --
2523 ----------------------------
2525 function To_Canonical_File_Spec
2526 (Host_File : String) return String_Access
2528 function To_Canonical_File_Spec (Host_File : Address) return Address;
2530 (C, To_Canonical_File_Spec, "__gnat_to_canonical_file_spec");
2532 C_Host_File : String (1 .. Host_File'Length + 1);
2533 Canonical_File_Addr : Address;
2534 Canonical_File_Len : Integer;
2537 C_Host_File (1 .. Host_File'Length) := Host_File;
2538 C_Host_File (C_Host_File'Last) := ASCII.NUL;
2540 Canonical_File_Addr := To_Canonical_File_Spec (C_Host_File'Address);
2541 Canonical_File_Len := C_String_Length (Canonical_File_Addr);
2543 if Canonical_File_Len = 0 then
2546 return To_Path_String_Access
2547 (Canonical_File_Addr, Canonical_File_Len);
2552 Fail ("erroneous file spec: ", Host_File);
2554 end To_Canonical_File_Spec;
2556 ----------------------------
2557 -- To_Canonical_Path_Spec --
2558 ----------------------------
2560 function To_Canonical_Path_Spec
2561 (Host_Path : String) return String_Access
2563 function To_Canonical_Path_Spec (Host_Path : Address) return Address;
2565 (C, To_Canonical_Path_Spec, "__gnat_to_canonical_path_spec");
2567 C_Host_Path : String (1 .. Host_Path'Length + 1);
2568 Canonical_Path_Addr : Address;
2569 Canonical_Path_Len : Integer;
2572 C_Host_Path (1 .. Host_Path'Length) := Host_Path;
2573 C_Host_Path (C_Host_Path'Last) := ASCII.NUL;
2575 Canonical_Path_Addr := To_Canonical_Path_Spec (C_Host_Path'Address);
2576 Canonical_Path_Len := C_String_Length (Canonical_Path_Addr);
2578 -- Return a null string (vice a null) for zero length paths, for
2579 -- compatibility with getenv().
2581 return To_Path_String_Access (Canonical_Path_Addr, Canonical_Path_Len);
2585 Fail ("erroneous path spec: ", Host_Path);
2587 end To_Canonical_Path_Spec;
2589 ---------------------------
2590 -- To_Host_Dir_Spec --
2591 ---------------------------
2593 function To_Host_Dir_Spec
2594 (Canonical_Dir : String;
2595 Prefix_Style : Boolean) return String_Access
2597 function To_Host_Dir_Spec
2598 (Canonical_Dir : Address;
2599 Prefix_Flag : Integer) return Address;
2600 pragma Import (C, To_Host_Dir_Spec, "__gnat_to_host_dir_spec");
2602 C_Canonical_Dir : String (1 .. Canonical_Dir'Length + 1);
2603 Host_Dir_Addr : Address;
2604 Host_Dir_Len : Integer;
2607 C_Canonical_Dir (1 .. Canonical_Dir'Length) := Canonical_Dir;
2608 C_Canonical_Dir (C_Canonical_Dir'Last) := ASCII.NUL;
2610 if Prefix_Style then
2611 Host_Dir_Addr := To_Host_Dir_Spec (C_Canonical_Dir'Address, 1);
2613 Host_Dir_Addr := To_Host_Dir_Spec (C_Canonical_Dir'Address, 0);
2615 Host_Dir_Len := C_String_Length (Host_Dir_Addr);
2617 if Host_Dir_Len = 0 then
2620 return To_Path_String_Access (Host_Dir_Addr, Host_Dir_Len);
2622 end To_Host_Dir_Spec;
2624 ----------------------------
2625 -- To_Host_File_Spec --
2626 ----------------------------
2628 function To_Host_File_Spec
2629 (Canonical_File : String) return String_Access
2631 function To_Host_File_Spec (Canonical_File : Address) return Address;
2632 pragma Import (C, To_Host_File_Spec, "__gnat_to_host_file_spec");
2634 C_Canonical_File : String (1 .. Canonical_File'Length + 1);
2635 Host_File_Addr : Address;
2636 Host_File_Len : Integer;
2639 C_Canonical_File (1 .. Canonical_File'Length) := Canonical_File;
2640 C_Canonical_File (C_Canonical_File'Last) := ASCII.NUL;
2642 Host_File_Addr := To_Host_File_Spec (C_Canonical_File'Address);
2643 Host_File_Len := C_String_Length (Host_File_Addr);
2645 if Host_File_Len = 0 then
2648 return To_Path_String_Access
2649 (Host_File_Addr, Host_File_Len);
2651 end To_Host_File_Spec;
2653 ---------------------------
2654 -- To_Path_String_Access --
2655 ---------------------------
2657 function To_Path_String_Access
2658 (Path_Addr : Address;
2659 Path_Len : Integer) return String_Access
2661 subtype Path_String is String (1 .. Path_Len);
2662 type Path_String_Access is access Path_String;
2664 function Address_To_Access is new
2665 Unchecked_Conversion (Source => Address,
2666 Target => Path_String_Access);
2668 Path_Access : constant Path_String_Access :=
2669 Address_To_Access (Path_Addr);
2671 Return_Val : String_Access;
2674 Return_Val := new String (1 .. Path_Len);
2676 for J in 1 .. Path_Len loop
2677 Return_Val (J) := Path_Access (J);
2681 end To_Path_String_Access;
2687 function Update_Path (Path : String_Ptr) return String_Ptr is
2689 function C_Update_Path (Path, Component : Address) return Address;
2690 pragma Import (C, C_Update_Path, "update_path");
2692 function Strlen (Str : Address) return Integer;
2693 pragma Import (C, Strlen, "strlen");
2695 procedure Strncpy (X : Address; Y : Address; Length : Integer);
2696 pragma Import (C, Strncpy, "strncpy");
2698 In_Length : constant Integer := Path'Length;
2699 In_String : String (1 .. In_Length + 1);
2700 Component_Name : aliased String := "GCC" & ASCII.NUL;
2701 Result_Ptr : Address;
2702 Result_Length : Integer;
2703 Out_String : String_Ptr;
2706 In_String (1 .. In_Length) := Path.all;
2707 In_String (In_Length + 1) := ASCII.NUL;
2708 Result_Ptr := C_Update_Path (In_String'Address,
2709 Component_Name'Address);
2710 Result_Length := Strlen (Result_Ptr);
2712 Out_String := new String (1 .. Result_Length);
2713 Strncpy (Out_String.all'Address, Result_Ptr, Result_Length);
2721 procedure Write_Info (Info : String) is
2723 Write_With_Check (Info'Address, Info'Length);
2724 Write_With_Check (EOL'Address, 1);
2727 ------------------------
2728 -- Write_Program_Name --
2729 ------------------------
2731 procedure Write_Program_Name is
2732 Save_Buffer : constant String (1 .. Name_Len) :=
2733 Name_Buffer (1 .. Name_Len);
2738 -- Convert the name to lower case so error messages are the same on
2741 for J in 1 .. Name_Len loop
2742 if Name_Buffer (J) in 'A' .. 'Z' then
2744 Character'Val (Character'Pos (Name_Buffer (J)) + 32);
2748 Write_Str (Name_Buffer (1 .. Name_Len));
2750 -- Restore Name_Buffer which was clobbered by the call to
2751 -- Find_Program_Name
2753 Name_Len := Save_Buffer'Last;
2754 Name_Buffer (1 .. Name_Len) := Save_Buffer;
2755 end Write_Program_Name;
2757 ----------------------
2758 -- Write_With_Check --
2759 ----------------------
2761 procedure Write_With_Check (A : Address; N : Integer) is
2765 if N = Write (Output_FD, A, N) then
2769 Write_Str ("error: disk full writing ");
2770 Write_Name_Decoded (Output_File_Name);
2772 Name_Len := Name_Len + 1;
2773 Name_Buffer (Name_Len) := ASCII.NUL;
2774 Delete_File (Name_Buffer'Address, Ignore);
2775 Exit_Program (E_Fatal);
2777 end Write_With_Check;
2779 ----------------------------
2780 -- Package Initialization --
2781 ----------------------------
2784 Initialization : declare
2786 function Get_Default_Identifier_Character_Set return Character;
2787 pragma Import (C, Get_Default_Identifier_Character_Set,
2788 "__gnat_get_default_identifier_character_set");
2789 -- Function to determine the default identifier character set,
2790 -- which is system dependent. See Opt package spec for a list of
2791 -- the possible character codes and their interpretations.
2793 function Get_Maximum_File_Name_Length return Int;
2794 pragma Import (C, Get_Maximum_File_Name_Length,
2795 "__gnat_get_maximum_file_name_length");
2796 -- Function to get maximum file name length for system
2799 Identifier_Character_Set := Get_Default_Identifier_Character_Set;
2800 Maximum_File_Name_Length := Get_Maximum_File_Name_Length;
2802 -- On VMS, '~' is not allowed in file names. Change the multi unit
2803 -- index character to '$'.
2805 if Hostparm.OpenVMS then
2806 Multi_Unit_Index_Character := '$';
2809 -- Following should be removed by having above function return
2810 -- Integer'Last as indication of no maximum instead of -1 ???
2812 if Maximum_File_Name_Length = -1 then
2813 Maximum_File_Name_Length := Int'Last;
2816 Src_Search_Directories.Set_Last (Primary_Directory);
2817 Src_Search_Directories.Table (Primary_Directory) := new String'("");
2819 Lib_Search_Directories.Set_Last (Primary_Directory);
2820 Lib_Search_Directories.Table (Primary_Directory) := new String'("");