summaryrefslogtreecommitdiff
path: root/gcc/ada/g-os_lib.adb
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/ada/g-os_lib.adb')
-rw-r--r--gcc/ada/g-os_lib.adb1347
1 files changed, 1347 insertions, 0 deletions
diff --git a/gcc/ada/g-os_lib.adb b/gcc/ada/g-os_lib.adb
new file mode 100644
index 00000000000..ef7968d9b73
--- /dev/null
+++ b/gcc/ada/g-os_lib.adb
@@ -0,0 +1,1347 @@
+------------------------------------------------------------------------------
+-- --
+-- GNAT COMPILER COMPONENTS --
+-- --
+-- G N A T . O S _ L I B --
+-- --
+-- B o d y --
+-- --
+-- $Revision: 1.74 $
+-- --
+-- Copyright (C) 1995-2001 Ada Core Technologies, Inc. --
+-- --
+-- GNAT is free software; you can redistribute it and/or modify it under --
+-- terms of the GNU General Public License as published by the Free Soft- --
+-- ware Foundation; either version 2, or (at your option) any later ver- --
+-- sion. GNAT is distributed in the hope that it will be useful, but WITH- --
+-- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY --
+-- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License --
+-- for more details. You should have received a copy of the GNU General --
+-- Public License distributed with GNAT; see file COPYING. If not, write --
+-- to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, --
+-- MA 02111-1307, USA. --
+-- --
+-- As a special exception, if other files instantiate generics from this --
+-- unit, or you link this unit with other files to produce an executable, --
+-- this unit does not by itself cause the resulting executable to be --
+-- covered by the GNU General Public License. This exception does not --
+-- however invalidate any other reasons why the executable file might be --
+-- covered by the GNU Public License. --
+-- --
+-- GNAT is maintained by Ada Core Technologies Inc (http://www.gnat.com). --
+-- --
+------------------------------------------------------------------------------
+
+with System.Soft_Links;
+with Unchecked_Conversion;
+with System; use System;
+
+package body GNAT.OS_Lib is
+
+ package SSL renames System.Soft_Links;
+
+ -----------------------
+ -- Local Subprograms --
+ -----------------------
+
+ function Args_Length (Args : Argument_List) return Natural;
+ -- Returns total number of characters needed to create a string
+ -- of all Args terminated by ASCII.NUL characters
+
+ function C_String_Length (S : Address) return Integer;
+ -- Returns the length of a C string. Does check for null address
+ -- (returns 0).
+
+ procedure Spawn_Internal
+ (Program_Name : String;
+ Args : Argument_List;
+ Result : out Integer;
+ Pid : out Process_Id;
+ Blocking : Boolean);
+ -- Internal routine to implement the to Spawn (blocking and non blocking)
+ -- routines. If Blocking is set to True then the spawn is blocking
+ -- otherwise it is non blocking. In this latter case the Pid contains
+ -- the process id number. The first three parameters are as in Spawn.
+
+ function To_Path_String_Access
+ (Path_Addr : Address;
+ Path_Len : Integer)
+ return String_Access;
+ -- Converts a C String to an Ada String. We could do this making use of
+ -- Interfaces.C.Strings but we prefer not to import that entire package
+
+ -----------------
+ -- Args_Length --
+ -----------------
+
+ function Args_Length (Args : Argument_List) return Natural is
+ Len : Natural := 0;
+
+ begin
+ for J in Args'Range loop
+ Len := Len + Args (J)'Length + 1; -- One extra for ASCII.NUL
+ end loop;
+
+ return Len;
+ end Args_Length;
+
+ -----------------------------
+ -- Argument_String_To_List --
+ -----------------------------
+
+ function Argument_String_To_List
+ (Arg_String : String)
+ return Argument_List_Access
+ is
+ Max_Args : Integer := Arg_String'Length;
+ New_Argv : Argument_List (1 .. Max_Args);
+ New_Argc : Natural := 0;
+ Idx : Integer;
+
+ begin
+ Idx := Arg_String'First;
+
+ loop
+ declare
+ Quoted : Boolean := False;
+ Backqd : Boolean := False;
+ Old_Idx : Integer;
+
+ begin
+ Old_Idx := Idx;
+
+ loop
+ -- A vanilla space is the end of an argument
+
+ if not Backqd and then not Quoted
+ and then Arg_String (Idx) = ' '
+ then
+ exit;
+
+ -- Start of a quoted string
+
+ elsif not Backqd and then not Quoted
+ and then Arg_String (Idx) = '"'
+ then
+ Quoted := True;
+
+ -- End of a quoted string and end of an argument
+
+ elsif not Backqd and then Quoted
+ and then Arg_String (Idx) = '"'
+ then
+ Idx := Idx + 1;
+ exit;
+
+ -- Following character is backquoted
+
+ elsif Arg_String (Idx) = '\' then
+ Backqd := True;
+
+ -- Turn off backquoting after advancing one character
+
+ elsif Backqd then
+ Backqd := False;
+
+ end if;
+
+ Idx := Idx + 1;
+ exit when Idx > Arg_String'Last;
+ end loop;
+
+ -- Found an argument
+
+ New_Argc := New_Argc + 1;
+ New_Argv (New_Argc) :=
+ new String'(Arg_String (Old_Idx .. Idx - 1));
+
+ -- Skip extraneous spaces
+
+ while Idx <= Arg_String'Last and then Arg_String (Idx) = ' ' loop
+ Idx := Idx + 1;
+ end loop;
+ end;
+
+ exit when Idx > Arg_String'Last;
+ end loop;
+
+ return new Argument_List'(New_Argv (1 .. New_Argc));
+ end Argument_String_To_List;
+
+ ---------------------
+ -- C_String_Length --
+ ---------------------
+
+ function C_String_Length (S : Address) return Integer is
+ function Strlen (S : Address) return Integer;
+ pragma Import (C, Strlen, "strlen");
+
+ begin
+ if S = Null_Address then
+ return 0;
+ else
+ return Strlen (S);
+ end if;
+ end C_String_Length;
+
+ -----------------
+ -- Create_File --
+ -----------------
+
+ function Create_File
+ (Name : C_File_Name;
+ Fmode : Mode)
+ return File_Descriptor
+ is
+ function C_Create_File
+ (Name : C_File_Name;
+ Fmode : Mode)
+ return File_Descriptor;
+ pragma Import (C, C_Create_File, "__gnat_open_create");
+
+ begin
+ return C_Create_File (Name, Fmode);
+ end Create_File;
+
+ function Create_File
+ (Name : String;
+ Fmode : Mode)
+ return File_Descriptor
+ is
+ C_Name : String (1 .. Name'Length + 1);
+
+ begin
+ C_Name (1 .. Name'Length) := Name;
+ C_Name (C_Name'Last) := ASCII.NUL;
+ return Create_File (C_Name (C_Name'First)'Address, Fmode);
+ end Create_File;
+
+ ---------------------
+ -- Create_New_File --
+ ---------------------
+
+ function Create_New_File
+ (Name : C_File_Name;
+ Fmode : Mode)
+ return File_Descriptor
+ is
+ function C_Create_New_File
+ (Name : C_File_Name;
+ Fmode : Mode)
+ return File_Descriptor;
+ pragma Import (C, C_Create_New_File, "__gnat_open_new");
+
+ begin
+ return C_Create_New_File (Name, Fmode);
+ end Create_New_File;
+
+ function Create_New_File
+ (Name : String;
+ Fmode : Mode)
+ return File_Descriptor
+ is
+ C_Name : String (1 .. Name'Length + 1);
+
+ begin
+ C_Name (1 .. Name'Length) := Name;
+ C_Name (C_Name'Last) := ASCII.NUL;
+ return Create_New_File (C_Name (C_Name'First)'Address, Fmode);
+ end Create_New_File;
+
+ ----------------------
+ -- Create_Temp_File --
+ ----------------------
+
+ procedure Create_Temp_File
+ (FD : out File_Descriptor;
+ Name : out Temp_File_Name)
+ is
+ function Open_New_Temp
+ (Name : System.Address;
+ Fmode : Mode)
+ return File_Descriptor;
+ pragma Import (C, Open_New_Temp, "__gnat_open_new_temp");
+
+ begin
+ FD := Open_New_Temp (Name'Address, Binary);
+ end Create_Temp_File;
+
+ -----------------
+ -- Delete_File --
+ -----------------
+
+ procedure Delete_File (Name : Address; Success : out Boolean) is
+ R : Integer;
+
+ function unlink (A : Address) return Integer;
+ pragma Import (C, unlink, "unlink");
+
+ begin
+ R := unlink (Name);
+ Success := (R = 0);
+ end Delete_File;
+
+ procedure Delete_File (Name : String; Success : out Boolean) is
+ C_Name : String (1 .. Name'Length + 1);
+
+ begin
+ C_Name (1 .. Name'Length) := Name;
+ C_Name (C_Name'Last) := ASCII.NUL;
+
+ Delete_File (C_Name'Address, Success);
+ end Delete_File;
+
+ ---------------------
+ -- File_Time_Stamp --
+ ---------------------
+
+ function File_Time_Stamp (FD : File_Descriptor) return OS_Time is
+ function File_Time (FD : File_Descriptor) return OS_Time;
+ pragma Import (C, File_Time, "__gnat_file_time_fd");
+
+ begin
+ return File_Time (FD);
+ end File_Time_Stamp;
+
+ function File_Time_Stamp (Name : C_File_Name) return OS_Time is
+ function File_Time (Name : Address) return OS_Time;
+ pragma Import (C, File_Time, "__gnat_file_time_name");
+
+ begin
+ return File_Time (Name);
+ end File_Time_Stamp;
+
+ function File_Time_Stamp (Name : String) return OS_Time is
+ F_Name : String (1 .. Name'Length + 1);
+
+ begin
+ F_Name (1 .. Name'Length) := Name;
+ F_Name (F_Name'Last) := ASCII.NUL;
+ return File_Time_Stamp (F_Name'Address);
+ end File_Time_Stamp;
+
+ ---------------------------
+ -- Get_Debuggable_Suffix --
+ ---------------------------
+
+ function Get_Debuggable_Suffix return String_Access is
+ procedure Get_Suffix_Ptr (Length, Ptr : Address);
+ pragma Import (C, Get_Suffix_Ptr, "__gnat_get_debuggable_suffix_ptr");
+
+ procedure Strncpy (Astring_Addr, Cstring : Address; N : Integer);
+ pragma Import (C, Strncpy, "strncpy");
+
+ Suffix_Ptr : Address;
+ Suffix_Length : Integer;
+ Result : String_Access;
+
+ begin
+ Get_Suffix_Ptr (Suffix_Length'Address, Suffix_Ptr'Address);
+
+ Result := new String (1 .. Suffix_Length);
+
+ if Suffix_Length > 0 then
+ Strncpy (Result.all'Address, Suffix_Ptr, Suffix_Length);
+ end if;
+
+ return Result;
+ end Get_Debuggable_Suffix;
+
+ ---------------------------
+ -- Get_Executable_Suffix --
+ ---------------------------
+
+ function Get_Executable_Suffix return String_Access is
+ procedure Get_Suffix_Ptr (Length, Ptr : Address);
+ pragma Import (C, Get_Suffix_Ptr, "__gnat_get_executable_suffix_ptr");
+
+ procedure Strncpy (Astring_Addr, Cstring : Address; N : Integer);
+ pragma Import (C, Strncpy, "strncpy");
+
+ Suffix_Ptr : Address;
+ Suffix_Length : Integer;
+ Result : String_Access;
+
+ begin
+ Get_Suffix_Ptr (Suffix_Length'Address, Suffix_Ptr'Address);
+
+ Result := new String (1 .. Suffix_Length);
+
+ if Suffix_Length > 0 then
+ Strncpy (Result.all'Address, Suffix_Ptr, Suffix_Length);
+ end if;
+
+ return Result;
+ end Get_Executable_Suffix;
+
+ -----------------------
+ -- Get_Object_Suffix --
+ -----------------------
+
+ function Get_Object_Suffix return String_Access is
+ procedure Get_Suffix_Ptr (Length, Ptr : Address);
+ pragma Import (C, Get_Suffix_Ptr, "__gnat_get_object_suffix_ptr");
+
+ procedure Strncpy (Astring_Addr, Cstring : Address; N : Integer);
+ pragma Import (C, Strncpy, "strncpy");
+
+ Suffix_Ptr : Address;
+ Suffix_Length : Integer;
+ Result : String_Access;
+
+ begin
+ Get_Suffix_Ptr (Suffix_Length'Address, Suffix_Ptr'Address);
+
+ Result := new String (1 .. Suffix_Length);
+
+ if Suffix_Length > 0 then
+ Strncpy (Result.all'Address, Suffix_Ptr, Suffix_Length);
+ end if;
+
+ return Result;
+ end Get_Object_Suffix;
+
+ ------------
+ -- Getenv --
+ ------------
+
+ function Getenv (Name : String) return String_Access is
+ procedure Get_Env_Value_Ptr (Name, Length, Ptr : Address);
+ pragma Import (C, Get_Env_Value_Ptr, "__gnat_get_env_value_ptr");
+
+ procedure Strncpy (Astring_Addr, Cstring : Address; N : Integer);
+ pragma Import (C, Strncpy, "strncpy");
+
+ Env_Value_Ptr : Address;
+ Env_Value_Length : Integer;
+ F_Name : String (1 .. Name'Length + 1);
+ Result : String_Access;
+
+ begin
+ F_Name (1 .. Name'Length) := Name;
+ F_Name (F_Name'Last) := ASCII.NUL;
+
+ Get_Env_Value_Ptr
+ (F_Name'Address, Env_Value_Length'Address, Env_Value_Ptr'Address);
+
+ Result := new String (1 .. Env_Value_Length);
+
+ if Env_Value_Length > 0 then
+ Strncpy (Result.all'Address, Env_Value_Ptr, Env_Value_Length);
+ end if;
+
+ return Result;
+ end Getenv;
+
+ ------------
+ -- GM_Day --
+ ------------
+
+ function GM_Day (Date : OS_Time) return Day_Type is
+ Y : Year_Type;
+ Mo : Month_Type;
+ D : Day_Type;
+ H : Hour_Type;
+ Mn : Minute_Type;
+ S : Second_Type;
+
+ begin
+ GM_Split (Date, Y, Mo, D, H, Mn, S);
+ return D;
+ end GM_Day;
+
+ -------------
+ -- GM_Hour --
+ -------------
+
+ function GM_Hour (Date : OS_Time) return Hour_Type is
+ Y : Year_Type;
+ Mo : Month_Type;
+ D : Day_Type;
+ H : Hour_Type;
+ Mn : Minute_Type;
+ S : Second_Type;
+
+ begin
+ GM_Split (Date, Y, Mo, D, H, Mn, S);
+ return H;
+ end GM_Hour;
+
+ ---------------
+ -- GM_Minute --
+ ---------------
+
+ function GM_Minute (Date : OS_Time) return Minute_Type is
+ Y : Year_Type;
+ Mo : Month_Type;
+ D : Day_Type;
+ H : Hour_Type;
+ Mn : Minute_Type;
+ S : Second_Type;
+
+ begin
+ GM_Split (Date, Y, Mo, D, H, Mn, S);
+ return Mn;
+ end GM_Minute;
+
+ --------------
+ -- GM_Month --
+ --------------
+
+ function GM_Month (Date : OS_Time) return Month_Type is
+ Y : Year_Type;
+ Mo : Month_Type;
+ D : Day_Type;
+ H : Hour_Type;
+ Mn : Minute_Type;
+ S : Second_Type;
+
+ begin
+ GM_Split (Date, Y, Mo, D, H, Mn, S);
+ return Mo;
+ end GM_Month;
+
+ ---------------
+ -- GM_Second --
+ ---------------
+
+ function GM_Second (Date : OS_Time) return Second_Type is
+ Y : Year_Type;
+ Mo : Month_Type;
+ D : Day_Type;
+ H : Hour_Type;
+ Mn : Minute_Type;
+ S : Second_Type;
+
+ begin
+ GM_Split (Date, Y, Mo, D, H, Mn, S);
+ return S;
+ end GM_Second;
+
+ --------------
+ -- GM_Split --
+ --------------
+
+ procedure GM_Split
+ (Date : OS_Time;
+ Year : out Year_Type;
+ Month : out Month_Type;
+ Day : out Day_Type;
+ Hour : out Hour_Type;
+ Minute : out Minute_Type;
+ Second : out Second_Type)
+ is
+ procedure To_GM_Time
+ (P_Time_T, P_Year, P_Month, P_Day, P_Hours, P_Mins, P_Secs : Address);
+ pragma Import (C, To_GM_Time, "__gnat_to_gm_time");
+
+ T : OS_Time := Date;
+ Y : Integer;
+ Mo : Integer;
+ D : Integer;
+ H : Integer;
+ Mn : Integer;
+ S : Integer;
+
+ begin
+ -- Use the global lock because To_GM_Time is not thread safe.
+
+ Locked_Processing : begin
+ SSL.Lock_Task.all;
+ To_GM_Time
+ (T'Address, Y'Address, Mo'Address, D'Address,
+ H'Address, Mn'Address, S'Address);
+ SSL.Unlock_Task.all;
+
+ exception
+ when others =>
+ SSL.Unlock_Task.all;
+ raise;
+ end Locked_Processing;
+
+ Year := Y + 1900;
+ Month := Mo + 1;
+ Day := D;
+ Hour := H;
+ Minute := Mn;
+ Second := S;
+ end GM_Split;
+
+ -------------
+ -- GM_Year --
+ -------------
+
+ function GM_Year (Date : OS_Time) return Year_Type is
+ Y : Year_Type;
+ Mo : Month_Type;
+ D : Day_Type;
+ H : Hour_Type;
+ Mn : Minute_Type;
+ S : Second_Type;
+
+ begin
+ GM_Split (Date, Y, Mo, D, H, Mn, S);
+ return Y;
+ end GM_Year;
+
+ ----------------------
+ -- Is_Absolute_Path --
+ ----------------------
+
+ function Is_Absolute_Path (Name : String) return Boolean is
+ function Is_Absolute_Path (Name : Address) return Integer;
+ pragma Import (C, Is_Absolute_Path, "__gnat_is_absolute_path");
+
+ F_Name : String (1 .. Name'Length + 1);
+
+ begin
+ F_Name (1 .. Name'Length) := Name;
+ F_Name (F_Name'Last) := ASCII.NUL;
+
+ return Is_Absolute_Path (F_Name'Address) /= 0;
+ end Is_Absolute_Path;
+
+ ------------------
+ -- Is_Directory --
+ ------------------
+
+ function Is_Directory (Name : C_File_Name) return Boolean is
+ function Is_Directory (Name : Address) return Integer;
+ pragma Import (C, Is_Directory, "__gnat_is_directory");
+
+ begin
+ return Is_Directory (Name) /= 0;
+ end Is_Directory;
+
+ function Is_Directory (Name : String) return Boolean is
+ F_Name : String (1 .. Name'Length + 1);
+
+ begin
+ F_Name (1 .. Name'Length) := Name;
+ F_Name (F_Name'Last) := ASCII.NUL;
+ return Is_Directory (F_Name'Address);
+ end Is_Directory;
+
+ ---------------------
+ -- Is_Regular_File --
+ ---------------------
+
+ function Is_Regular_File (Name : C_File_Name) return Boolean is
+ function Is_Regular_File (Name : Address) return Integer;
+ pragma Import (C, Is_Regular_File, "__gnat_is_regular_file");
+
+ begin
+ return Is_Regular_File (Name) /= 0;
+ end Is_Regular_File;
+
+ function Is_Regular_File (Name : String) return Boolean is
+ F_Name : String (1 .. Name'Length + 1);
+
+ begin
+ F_Name (1 .. Name'Length) := Name;
+ F_Name (F_Name'Last) := ASCII.NUL;
+ return Is_Regular_File (F_Name'Address);
+ end Is_Regular_File;
+
+ ----------------------
+ -- Is_Writable_File --
+ ----------------------
+
+ function Is_Writable_File (Name : C_File_Name) return Boolean is
+ function Is_Writable_File (Name : Address) return Integer;
+ pragma Import (C, Is_Writable_File, "__gnat_is_writable_file");
+
+ begin
+ return Is_Writable_File (Name) /= 0;
+ end Is_Writable_File;
+
+ function Is_Writable_File (Name : String) return Boolean is
+ F_Name : String (1 .. Name'Length + 1);
+
+ begin
+ F_Name (1 .. Name'Length) := Name;
+ F_Name (F_Name'Last) := ASCII.NUL;
+ return Is_Writable_File (F_Name'Address);
+ end Is_Writable_File;
+
+ -------------------------
+ -- Locate_Exec_On_Path --
+ -------------------------
+
+ function Locate_Exec_On_Path
+ (Exec_Name : String)
+ return String_Access
+ is
+ function Locate_Exec_On_Path (C_Exec_Name : Address) return Address;
+ pragma Import (C, Locate_Exec_On_Path, "__gnat_locate_exec_on_path");
+
+ procedure Free (Ptr : System.Address);
+ pragma Import (C, Free, "free");
+
+ C_Exec_Name : String (1 .. Exec_Name'Length + 1);
+ Path_Addr : Address;
+ Path_Len : Integer;
+ Result : String_Access;
+
+ begin
+ C_Exec_Name (1 .. Exec_Name'Length) := Exec_Name;
+ C_Exec_Name (C_Exec_Name'Last) := ASCII.NUL;
+
+ Path_Addr := Locate_Exec_On_Path (C_Exec_Name'Address);
+ Path_Len := C_String_Length (Path_Addr);
+
+ if Path_Len = 0 then
+ return null;
+
+ else
+ Result := To_Path_String_Access (Path_Addr, Path_Len);
+ Free (Path_Addr);
+ return Result;
+ end if;
+ end Locate_Exec_On_Path;
+
+ -------------------------
+ -- Locate_Regular_File --
+ -------------------------
+
+ function Locate_Regular_File
+ (File_Name : C_File_Name;
+ Path : C_File_Name)
+ return String_Access
+ is
+ function Locate_Regular_File
+ (C_File_Name, Path_Val : Address) return Address;
+ pragma Import (C, Locate_Regular_File, "__gnat_locate_regular_file");
+
+ procedure Free (Ptr : System.Address);
+ pragma Import (C, Free, "free");
+
+ Path_Addr : Address;
+ Path_Len : Integer;
+ Result : String_Access;
+
+ begin
+ Path_Addr := Locate_Regular_File (File_Name, Path);
+ Path_Len := C_String_Length (Path_Addr);
+
+ if Path_Len = 0 then
+ return null;
+ else
+ Result := To_Path_String_Access (Path_Addr, Path_Len);
+ Free (Path_Addr);
+ return Result;
+ end if;
+ end Locate_Regular_File;
+
+ function Locate_Regular_File
+ (File_Name : String;
+ Path : String)
+ return String_Access
+ is
+ C_File_Name : String (1 .. File_Name'Length + 1);
+ C_Path : String (1 .. Path'Length + 1);
+
+ begin
+ C_File_Name (1 .. File_Name'Length) := File_Name;
+ C_File_Name (C_File_Name'Last) := ASCII.NUL;
+
+ C_Path (1 .. Path'Length) := Path;
+ C_Path (C_Path'Last) := ASCII.NUL;
+
+ return Locate_Regular_File (C_File_Name'Address, C_Path'Address);
+ end Locate_Regular_File;
+
+ ------------------------
+ -- Non_Blocking_Spawn --
+ ------------------------
+
+ function Non_Blocking_Spawn
+ (Program_Name : String;
+ Args : Argument_List)
+ return Process_Id
+ is
+ Junk : Integer;
+ Pid : Process_Id;
+
+ begin
+ Spawn_Internal (Program_Name, Args, Junk, Pid, Blocking => False);
+ return Pid;
+ end Non_Blocking_Spawn;
+
+ ------------------------
+ -- Normalize_Pathname --
+ ------------------------
+
+ function Normalize_Pathname
+ (Name : String;
+ Directory : String := "")
+ return String
+ is
+ Max_Path : Integer;
+ pragma Import (C, Max_Path, "max_path_len");
+ -- Maximum length of a path name
+
+ procedure Get_Current_Dir
+ (Dir : System.Address;
+ Length : System.Address);
+ pragma Import (C, Get_Current_Dir, "__gnat_get_current_dir");
+
+ Path_Buffer : String (1 .. Max_Path + Max_Path + 2);
+ End_Path : Natural := 0;
+ Link_Buffer : String (1 .. Max_Path + 2);
+ Status : Integer;
+ Last : Positive;
+ Start : Natural;
+ Finish : Positive;
+
+ Max_Iterations : constant := 500;
+
+ function Readlink
+ (Path : System.Address;
+ Buf : System.Address;
+ Bufsiz : Integer)
+ return Integer;
+ pragma Import (C, Readlink, "__gnat_readlink");
+
+ function To_Canonical_File_Spec
+ (Host_File : System.Address)
+ return System.Address;
+ pragma Import
+ (C, To_Canonical_File_Spec, "__gnat_to_canonical_file_spec");
+
+ The_Name : String (1 .. Name'Length + 1);
+ Canonical_File_Addr : System.Address;
+ Canonical_File_Len : Integer;
+
+ function Strlen (S : System.Address) return Integer;
+ pragma Import (C, Strlen, "strlen");
+
+ function Get_Directory return String;
+ -- If Directory is not empty, return it, adding a directory separator
+ -- if not already present, otherwise return current working directory
+ -- with terminating directory separator.
+
+ -------------------
+ -- Get_Directory --
+ -------------------
+
+ function Get_Directory return String is
+ begin
+ -- Directory given, add directory separator if needed
+
+ if Directory'Length > 0 then
+ if Directory (Directory'Length) = Directory_Separator then
+ return Directory;
+ else
+ declare
+ Result : String (1 .. Directory'Length + 1);
+
+ begin
+ Result (1 .. Directory'Length) := Directory;
+ Result (Result'Length) := Directory_Separator;
+ return Result;
+ end;
+ end if;
+
+ -- Directory name not given, get current directory
+
+ else
+ declare
+ Buffer : String (1 .. Max_Path + 2);
+ Path_Len : Natural := Max_Path;
+
+ begin
+ Get_Current_Dir (Buffer'Address, Path_Len'Address);
+
+ if Buffer (Path_Len) /= Directory_Separator then
+ Path_Len := Path_Len + 1;
+ Buffer (Path_Len) := Directory_Separator;
+ end if;
+
+ return Buffer (1 .. Path_Len);
+ end;
+ end if;
+ end Get_Directory;
+
+ Reference_Dir : constant String := Get_Directory;
+ -- Current directory name specified
+
+ -- Start of processing for Normalize_Pathname
+
+ begin
+ -- Special case, if name is null, then return null
+
+ if Name'Length = 0 then
+ return "";
+ end if;
+
+ -- First, convert VMS file spec to Unix file spec.
+ -- If Name is not in VMS syntax, then this is equivalent
+ -- to put Name at the begining of Path_Buffer.
+
+ VMS_Conversion : begin
+ The_Name (1 .. Name'Length) := Name;
+ The_Name (The_Name'Last) := ASCII.NUL;
+
+ Canonical_File_Addr := To_Canonical_File_Spec (The_Name'Address);
+ Canonical_File_Len := Strlen (Canonical_File_Addr);
+
+ -- If VMS syntax conversion has failed, return an empty string
+ -- to indicate the failure.
+
+ if Canonical_File_Len = 0 then
+ return "";
+ end if;
+
+ declare
+ subtype Path_String is String (1 .. Canonical_File_Len);
+ type Path_String_Access is access Path_String;
+
+ function Address_To_Access is new
+ Unchecked_Conversion (Source => Address,
+ Target => Path_String_Access);
+
+ Path_Access : Path_String_Access :=
+ Address_To_Access (Canonical_File_Addr);
+
+ begin
+ Path_Buffer (1 .. Canonical_File_Len) := Path_Access.all;
+ End_Path := Canonical_File_Len;
+ Last := 1;
+ end;
+ end VMS_Conversion;
+
+ -- Replace all '/' by Directory Separators (this is for Windows)
+
+ if Directory_Separator /= '/' then
+ for Index in 1 .. End_Path loop
+ if Path_Buffer (Index) = '/' then
+ Path_Buffer (Index) := Directory_Separator;
+ end if;
+ end loop;
+ end if;
+
+ -- Start the conversions
+
+ -- If this is not finished after Max_Iterations, give up and
+ -- return an empty string.
+
+ for J in 1 .. Max_Iterations loop
+
+ -- If we don't have an absolute pathname, prepend
+ -- the directory Reference_Dir.
+
+ if Last = 1
+ and then not Is_Absolute_Path (Path_Buffer (1 .. End_Path))
+ then
+ Path_Buffer
+ (Reference_Dir'Last + 1 .. Reference_Dir'Length + End_Path) :=
+ Path_Buffer (1 .. End_Path);
+ End_Path := Reference_Dir'Length + End_Path;
+ Path_Buffer (1 .. Reference_Dir'Length) := Reference_Dir;
+ Last := Reference_Dir'Length;
+ end if;
+
+ Start := Last + 1;
+ Finish := Last;
+
+ -- If we have traversed the full pathname, return it
+
+ if Start > End_Path then
+ return Path_Buffer (1 .. End_Path);
+ end if;
+
+ -- Remove duplicate directory separators
+
+ while Path_Buffer (Start) = Directory_Separator loop
+ if Start = End_Path then
+ return Path_Buffer (1 .. End_Path - 1);
+
+ else
+ Path_Buffer (Start .. End_Path - 1) :=
+ Path_Buffer (Start + 1 .. End_Path);
+ End_Path := End_Path - 1;
+ end if;
+ end loop;
+
+ -- Find the end of the current field: last character
+ -- or the one preceding the next directory separator.
+
+ while Finish < End_Path
+ and then Path_Buffer (Finish + 1) /= Directory_Separator
+ loop
+ Finish := Finish + 1;
+ end loop;
+
+ -- Remove "." field
+
+ if Start = Finish and then Path_Buffer (Start) = '.' then
+ if Start = End_Path then
+ if Last = 1 then
+ return (1 => Directory_Separator);
+ else
+ return Path_Buffer (1 .. Last - 1);
+ end if;
+
+ else
+ Path_Buffer (Last + 1 .. End_Path - 2) :=
+ Path_Buffer (Last + 3 .. End_Path);
+ End_Path := End_Path - 2;
+ end if;
+
+ -- Remove ".." fields
+
+ elsif Finish = Start + 1
+ and then Path_Buffer (Start .. Finish) = ".."
+ then
+ Start := Last;
+ loop
+ Start := Start - 1;
+ exit when Start < 1 or else
+ Path_Buffer (Start) = Directory_Separator;
+ end loop;
+
+ if Start <= 1 then
+ if Finish = End_Path then
+ return (1 => Directory_Separator);
+
+ else
+ Path_Buffer (1 .. End_Path - Finish) :=
+ Path_Buffer (Finish + 1 .. End_Path);
+ End_Path := End_Path - Finish;
+ Last := 1;
+ end if;
+
+ else
+ if Finish = End_Path then
+ return Path_Buffer (1 .. Start - 1);
+
+ else
+ Path_Buffer (Start + 1 .. Start + End_Path - Finish - 1) :=
+ Path_Buffer (Finish + 2 .. End_Path);
+ End_Path := Start + End_Path - Finish - 1;
+ Last := Start;
+ end if;
+ end if;
+
+ -- Check if current field is a symbolic link
+
+ else
+ declare
+ Saved : Character := Path_Buffer (Finish + 1);
+
+ begin
+ Path_Buffer (Finish + 1) := ASCII.NUL;
+ Status := Readlink (Path_Buffer'Address,
+ Link_Buffer'Address,
+ Link_Buffer'Length);
+ Path_Buffer (Finish + 1) := Saved;
+ end;
+
+ -- Not a symbolic link, move to the next field, if any
+
+ if Status <= 0 then
+ Last := Finish + 1;
+
+ -- Replace symbolic link with its value.
+
+ else
+ if Is_Absolute_Path (Link_Buffer (1 .. Status)) then
+ Path_Buffer (Status + 1 .. End_Path - (Finish - Status)) :=
+ Path_Buffer (Finish + 1 .. End_Path);
+ End_Path := End_Path - (Finish - Status);
+ Path_Buffer (1 .. Status) := Link_Buffer (1 .. Status);
+ Last := 1;
+
+ else
+ Path_Buffer
+ (Last + Status + 1 .. End_Path - Finish + Last + Status) :=
+ Path_Buffer (Finish + 1 .. End_Path);
+ End_Path := End_Path - Finish + Last + Status;
+ Path_Buffer (Last + 1 .. Last + Status) :=
+ Link_Buffer (1 .. Status);
+ end if;
+ end if;
+ end if;
+ end loop;
+
+ -- Too many iterations: give up
+
+ -- This can happen when there is a circularity in the symbolic links:
+ -- A is a symbolic link for B, which itself is a symbolic link, and
+ -- the target of B or of another symbolic link target of B is A.
+ -- In this case, we return an empty string to indicate failure to
+ -- resolve.
+
+ return "";
+ end Normalize_Pathname;
+
+ ---------------
+ -- Open_Read --
+ ---------------
+
+ function Open_Read
+ (Name : C_File_Name;
+ Fmode : Mode)
+ return File_Descriptor
+ is
+ function C_Open_Read
+ (Name : C_File_Name;
+ Fmode : Mode)
+ return File_Descriptor;
+ pragma Import (C, C_Open_Read, "__gnat_open_read");
+
+ begin
+ return C_Open_Read (Name, Fmode);
+ end Open_Read;
+
+ function Open_Read
+ (Name : String;
+ Fmode : Mode)
+ return File_Descriptor
+ is
+ C_Name : String (1 .. Name'Length + 1);
+
+ begin
+ C_Name (1 .. Name'Length) := Name;
+ C_Name (C_Name'Last) := ASCII.NUL;
+ return Open_Read (C_Name (C_Name'First)'Address, Fmode);
+ end Open_Read;
+
+ ---------------------
+ -- Open_Read_Write --
+ ---------------------
+
+ function Open_Read_Write
+ (Name : C_File_Name;
+ Fmode : Mode)
+ return File_Descriptor
+ is
+ function C_Open_Read_Write
+ (Name : C_File_Name;
+ Fmode : Mode)
+ return File_Descriptor;
+ pragma Import (C, C_Open_Read_Write, "__gnat_open_rw");
+
+ begin
+ return C_Open_Read_Write (Name, Fmode);
+ end Open_Read_Write;
+
+ function Open_Read_Write
+ (Name : String;
+ Fmode : Mode)
+ return File_Descriptor
+ is
+ C_Name : String (1 .. Name'Length + 1);
+
+ begin
+ C_Name (1 .. Name'Length) := Name;
+ C_Name (C_Name'Last) := ASCII.NUL;
+ return Open_Read_Write (C_Name (C_Name'First)'Address, Fmode);
+ end Open_Read_Write;
+
+ -----------------
+ -- Rename_File --
+ -----------------
+
+ procedure Rename_File
+ (Old_Name : C_File_Name;
+ New_Name : C_File_Name;
+ Success : out Boolean)
+ is
+ function rename (From, To : Address) return Integer;
+ pragma Import (C, rename, "rename");
+
+ R : Integer;
+
+ begin
+ R := rename (Old_Name, New_Name);
+ Success := (R = 0);
+ end Rename_File;
+
+ procedure Rename_File
+ (Old_Name : String;
+ New_Name : String;
+ Success : out Boolean)
+ is
+ C_Old_Name : String (1 .. Old_Name'Length + 1);
+ C_New_Name : String (1 .. New_Name'Length + 1);
+
+ begin
+ C_Old_Name (1 .. Old_Name'Length) := Old_Name;
+ C_Old_Name (C_Old_Name'Last) := ASCII.NUL;
+
+ C_New_Name (1 .. New_Name'Length) := New_Name;
+ C_New_Name (C_New_Name'Last) := ASCII.NUL;
+
+ Rename_File (C_Old_Name'Address, C_New_Name'Address, Success);
+ end Rename_File;
+
+ ------------
+ -- Setenv --
+ ------------
+
+ procedure Setenv (Name : String; Value : String) is
+ F_Name : String (1 .. Name'Length + 1);
+ F_Value : String (1 .. Value'Length + 1);
+
+ procedure Set_Env_Value (Name, Value : System.Address);
+ pragma Import (C, Set_Env_Value, "__gnat_set_env_value");
+
+ begin
+ F_Name (1 .. Name'Length) := Name;
+ F_Name (F_Name'Last) := ASCII.NUL;
+
+ F_Value (1 .. Value'Length) := Value;
+ F_Value (F_Value'Last) := ASCII.NUL;
+
+ Set_Env_Value (F_Name'Address, F_Value'Address);
+ end Setenv;
+
+ -----------
+ -- Spawn --
+ -----------
+
+ function Spawn
+ (Program_Name : String;
+ Args : Argument_List)
+ return Integer
+ is
+ Junk : Process_Id;
+ Result : Integer;
+
+ begin
+ Spawn_Internal (Program_Name, Args, Result, Junk, Blocking => True);
+ return Result;
+ end Spawn;
+
+ procedure Spawn
+ (Program_Name : String;
+ Args : Argument_List;
+ Success : out Boolean)
+ is
+ begin
+ Success := (Spawn (Program_Name, Args) = 0);
+ end Spawn;
+
+ --------------------
+ -- Spawn_Internal --
+ --------------------
+
+ procedure Spawn_Internal
+ (Program_Name : String;
+ Args : Argument_List;
+ Result : out Integer;
+ Pid : out Process_Id;
+ Blocking : Boolean)
+ is
+ type Chars is array (Positive range <>) of aliased Character;
+ type Char_Ptr is access constant Character;
+
+ Command_Len : constant Positive := Program_Name'Length + 1
+ + Args_Length (Args);
+ Command_Last : Natural := 0;
+ Command : aliased Chars (1 .. Command_Len);
+ -- Command contains all characters of the Program_Name and Args,
+ -- all terminated by ASCII.NUL characters
+
+ Arg_List_Len : constant Positive := Args'Length + 2;
+ Arg_List_Last : Natural := 0;
+ Arg_List : aliased array (1 .. Arg_List_Len) of Char_Ptr;
+ -- List with pointers to NUL-terminated strings of the
+ -- Program_Name and the Args and terminated with a null pointer.
+ -- We rely on the default initialization for the last null pointer.
+
+ procedure Add_To_Command (S : String);
+ -- Add S and a NUL character to Command, updating Last
+
+ function Portable_Spawn (Args : Address) return Integer;
+ pragma Import (C, Portable_Spawn, "__gnat_portable_spawn");
+
+ function Portable_No_Block_Spawn (Args : Address) return Process_Id;
+ pragma Import
+ (C, Portable_No_Block_Spawn, "__gnat_portable_no_block_spawn");
+
+ --------------------
+ -- Add_To_Command --
+ --------------------
+
+ procedure Add_To_Command (S : String) is
+ First : constant Natural := Command_Last + 1;
+
+ begin
+ Command_Last := Command_Last + S'Length;
+ Command (First .. Command_Last) := Chars (S);
+
+ Command_Last := Command_Last + 1;
+ Command (Command_Last) := ASCII.NUL;
+
+ Arg_List_Last := Arg_List_Last + 1;
+ Arg_List (Arg_List_Last) := Command (First)'Access;
+ end Add_To_Command;
+
+ -- Start of processing for Spawn_Internal
+
+ begin
+ Add_To_Command (Program_Name);
+
+ for J in Args'Range loop
+ Add_To_Command (Args (J).all);
+ end loop;
+
+ if Blocking then
+ Pid := Invalid_Pid;
+ Result := Portable_Spawn (Arg_List'Address);
+ else
+ Pid := Portable_No_Block_Spawn (Arg_List'Address);
+ Result := Boolean'Pos (Pid /= Invalid_Pid);
+ end if;
+
+ end Spawn_Internal;
+
+ ---------------------------
+ -- To_Path_String_Access --
+ ---------------------------
+
+ function To_Path_String_Access
+ (Path_Addr : Address;
+ Path_Len : Integer)
+ return String_Access
+ is
+ subtype Path_String is String (1 .. Path_Len);
+ type Path_String_Access is access Path_String;
+
+ function Address_To_Access is new
+ Unchecked_Conversion (Source => Address,
+ Target => Path_String_Access);
+
+ Path_Access : Path_String_Access := Address_To_Access (Path_Addr);
+
+ Return_Val : String_Access;
+
+ begin
+ Return_Val := new String (1 .. Path_Len);
+
+ for J in 1 .. Path_Len loop
+ Return_Val (J) := Path_Access (J);
+ end loop;
+
+ return Return_Val;
+ end To_Path_String_Access;
+
+ ------------------
+ -- Wait_Process --
+ ------------------
+
+ procedure Wait_Process (Pid : out Process_Id; Success : out Boolean) is
+ Status : Integer;
+
+ function Portable_Wait (S : Address) return Process_Id;
+ pragma Import (C, Portable_Wait, "__gnat_portable_wait");
+
+ begin
+ Pid := Portable_Wait (Status'Address);
+ Success := (Status = 0);
+ end Wait_Process;
+
+end GNAT.OS_Lib;