OSDN Git Service

2011-05-25 Kai Tietz <ktietz@redhat.com>
[pf3gnuchains/gcc-fork.git] / gcc / ada / adaint.c
index f5d4d10..bea33f6 100644 (file)
@@ -6,24 +6,23 @@
  *                                                                          *
  *                          C Implementation File                           *
  *                                                                          *
- *          Copyright (C) 1992-2007, Free Software Foundation, Inc.         *
+ *          Copyright (C) 1992-2010, Free Software Foundation, 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- *
+ * ware  Foundation;  either version 3,  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,  51  Franklin  Street,  Fifth  Floor, *
- * Boston, MA 02110-1301, USA.                                              *
+ * or FITNESS FOR A PARTICULAR PURPOSE.                                     *
  *                                                                          *
- * As a  special  exception,  if you  link  this file  with other  files to *
- * produce an executable,  this file does not by itself cause the resulting *
- * executable to be covered by the GNU General Public License. This except- *
- * ion does not  however invalidate  any other reasons  why the  executable *
- * file might be covered by the  GNU Public License.                        *
+ * As a special exception under Section 7 of GPL version 3, you are granted *
+ * additional permissions described in the GCC Runtime Library Exception,   *
+ * version 3.1, as published by the Free Software Foundation.               *
+ *                                                                          *
+ * You should have received a copy of the GNU General Public License and    *
+ * a copy of the GCC Runtime Library Exception along with this program;     *
+ * see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see    *
+ * <http://www.gnu.org/licenses/>.                                          *
  *                                                                          *
  * GNAT was originally developed  by the GNAT team at  New York University. *
  * Extensive contributions were provided by Ada Core Technologies Inc.      *
 
 #endif /* VxWorks */
 
+#if (defined (__mips) && defined (__sgi)) || defined (__APPLE__)
+#include <unistd.h>
+#endif
+
+#if defined (__hpux__)
+#include <sys/param.h>
+#include <sys/pstat.h>
+#endif
+
 #ifdef VMS
 #define _POSIX_EXIT 1
 #define HOST_EXECUTABLE_SUFFIX ".exe"
 
 #if defined (__MINGW32__)
 
+#if defined (RTX)
+#include <windows.h>
+#include <Rtapi.h>
+#else
 #include "mingw32.h"
+
+/* Current code page to use, set in initialize.c.  */
+UINT CurrentCodePage;
+#endif
+
 #include <sys/utime.h>
+
+/* For isalpha-like tests in the compiler, we're expected to resort to
+   safe-ctype.h/ISALPHA.  This isn't available for the runtime library
+   build, so we fallback on ctype.h/isalpha there.  */
+
+#ifdef IN_RTS
 #include <ctype.h>
+#define ISALPHA isalpha
+#endif
 
 #elif defined (__Lynx__)
 
 #include <sys/wait.h>
 #endif
 
-#if defined (__EMX__) || defined (MSDOS) || defined (_WIN32)
+#if defined (_WIN32)
 #elif defined (VMS)
 
 /* Header files and definitions for __gnat_set_file_time_name.  */
@@ -163,17 +188,23 @@ struct vstring
   char string[NAM$C_MAXRSS+1];
 };
 
+#define SYI$_ACTIVECPU_CNT 0x111e
+extern int LIB$GETSYI (int *, unsigned int *);
+
 #else
 #include <utime.h>
 #endif
 
-#if defined (__EMX__) || defined (MSDOS) || defined (_WIN32)
+#if defined (_WIN32)
 #include <process.h>
 #endif
 
 #if defined (_WIN32)
+
 #include <dir.h>
 #include <windows.h>
+#include <accctrl.h>
+#include <aclapi.h>
 #undef DIR_SEPARATOR
 #define DIR_SEPARATOR '\\'
 #endif
@@ -186,14 +217,6 @@ struct vstring
    external file mapped to LF in internal file), but in Unix-like systems,
    no text translation is required, so these flags have no effect.  */
 
-#if defined (__EMX__)
-#include <os2.h>
-#endif
-
-#if defined (MSDOS)
-#include <dos.h>
-#endif
-
 #ifndef O_BINARY
 #define O_BINARY 0
 #endif
@@ -219,9 +242,11 @@ struct vstring
 #endif
 
 /* Check for cross-compilation */
-#ifdef CROSS_DIRECTORY_STRUCTURE
+#if defined (CROSS_COMPILE) || defined (CROSS_DIRECTORY_STRUCTURE)
+#define IS_CROSS 1
 int __gnat_is_cross_compiler = 1;
 #else
+#undef IS_CROSS
 int __gnat_is_cross_compiler = 0;
 #endif
 
@@ -254,9 +279,7 @@ char __gnat_path_separator = PATH_SEPARATOR;
        as well. This is only a temporary work-around for 3.11b.  */
 
 #ifndef GNAT_LIBRARY_TEMPLATE
-#if defined (__EMX__)
-#define GNAT_LIBRARY_TEMPLATE "*.a"
-#elif defined (VMS)
+#if defined (VMS)
 #define GNAT_LIBRARY_TEMPLATE "*.olb"
 #else
 #define GNAT_LIBRARY_TEMPLATE "lib*.a"
@@ -273,10 +296,7 @@ const int __gnat_vmsp = 1;
 const int __gnat_vmsp = 0;
 #endif
 
-#ifdef __EMX__
-#define GNAT_MAX_PATH_LEN MAX_PATH
-
-#elif defined (VMS)
+#if defined (VMS)
 #define GNAT_MAX_PATH_LEN 256 /* PATH_MAX */
 
 #elif defined (__vxworks) || defined (__OPENNT) || defined(__nucleus__)
@@ -303,6 +323,12 @@ const int __gnat_vmsp = 0;
 
 #endif
 
+/* Used for Ada bindings */
+const int __gnat_size_of_file_attributes = sizeof (struct file_attributes);
+
+/* Reset the file attributes as if no system call had been performed */
+void __gnat_stat_to_attr (int fd, char* name, struct file_attributes* attr);
+
 /* The __gnat_max_path_len variable is used to export the maximum
    length of a path name to Ada code. max_path_len is also provided
    for compatibility with older GNAT versions, please do not use
@@ -311,6 +337,10 @@ const int __gnat_vmsp = 0;
 int __gnat_max_path_len = GNAT_MAX_PATH_LEN;
 int max_path_len = GNAT_MAX_PATH_LEN;
 
+/* Control whether we can use ACL on Windows.  */
+
+int __gnat_use_acl = 1;
+
 /* The following macro HAVE_READDIR_R should be defined if the
    system provides the routine readdir_r.  */
 #undef HAVE_READDIR_R
@@ -346,6 +376,26 @@ to_ptr32 (char **ptr64)
 #define MAYBE_TO_PTR32(argv) argv
 #endif
 
+static const char ATTR_UNSET = 127;
+
+void
+__gnat_reset_attributes
+  (struct file_attributes* attr)
+{
+  attr->exists     = ATTR_UNSET;
+
+  attr->writable   = ATTR_UNSET;
+  attr->readable   = ATTR_UNSET;
+  attr->executable = ATTR_UNSET;
+
+  attr->regular    = ATTR_UNSET;
+  attr->symbolic_link = ATTR_UNSET;
+  attr->directory = ATTR_UNSET;
+
+  attr->timestamp = (OS_Time)-2;
+  attr->file_length = -1;
+}
+
 OS_Time
 __gnat_current_time
   (void)
@@ -354,6 +404,30 @@ __gnat_current_time
   return (OS_Time) res;
 }
 
+/* Return the current local time as a string in the ISO 8601 format of
+   "YYYY-MM-DD HH:MM:SS.SS". The returned string is 22 + 1 (NULL) characters
+   long. */
+
+void
+__gnat_current_time_string
+  (char *result)
+{
+  const char *format = "%Y-%m-%d %H:%M:%S";
+  /* Format string necessary to describe the ISO 8601 format */
+
+  const time_t t_val = time (NULL);
+
+  strftime (result, 22, format, localtime (&t_val));
+  /* Convert the local time into a string following the ISO format, copying
+     at most 22 characters into the result string. */
+
+  result [19] = '.';
+  result [20] = '0';
+  result [21] = '0';
+  /* The sub-seconds are manually set to zero since type time_t lacks the
+     precision necessary for nanoseconds. */
+}
+
 void
 __gnat_to_gm_time
   (OS_Time *p_time,
@@ -403,9 +477,8 @@ __gnat_readlink (char *path ATTRIBUTE_UNUSED,
                 char *buf ATTRIBUTE_UNUSED,
                 size_t bufsiz ATTRIBUTE_UNUSED)
 {
-#if defined (MSDOS) || defined (_WIN32) || defined (__EMX__) \
-  || defined (__INTERIX) || defined (VMS) \
-  || defined(__vxworks) || defined (__nucleus__)
+#if defined (_WIN32) || defined (VMS) \
+    || defined(__vxworks) || defined (__nucleus__)
   return -1;
 #else
   return readlink (path, buf, bufsiz);
@@ -420,9 +493,8 @@ int
 __gnat_symlink (char *oldpath ATTRIBUTE_UNUSED,
                char *newpath ATTRIBUTE_UNUSED)
 {
-#if defined (MSDOS) || defined (_WIN32) || defined (__EMX__) \
-  || defined (__INTERIX) || defined (VMS) \
-  || defined(__vxworks) || defined (__nucleus__)
+#if defined (_WIN32) || defined (VMS) \
+    || defined(__vxworks) || defined (__nucleus__)
   return -1;
 #else
   return symlink (oldpath, newpath);
@@ -431,7 +503,8 @@ __gnat_symlink (char *oldpath ATTRIBUTE_UNUSED,
 
 /* Try to lock a file, return 1 if success.  */
 
-#if defined (__vxworks) || defined (__nucleus__) || defined (MSDOS) || defined (_WIN32)
+#if defined (__vxworks) || defined (__nucleus__) \
+  || defined (_WIN32) || defined (VMS)
 
 /* Version that does not use link. */
 
@@ -444,8 +517,8 @@ __gnat_try_lock (char *dir, char *file)
   TCHAR wfile[GNAT_MAX_PATH_LEN];
   TCHAR wdir[GNAT_MAX_PATH_LEN];
 
-  S2WSU (wdir, dir, GNAT_MAX_PATH_LEN);
-  S2WSU (wfile, file, GNAT_MAX_PATH_LEN);
+  S2WSC (wdir, dir, GNAT_MAX_PATH_LEN);
+  S2WSC (wfile, file, GNAT_MAX_PATH_LEN);
 
   _stprintf (wfull_path, _T("%s%c%s"), wdir, _T(DIR_SEPARATOR), wfile);
   fd = _topen (wfull_path, O_CREAT | O_EXCL, 0600);
@@ -463,27 +536,6 @@ __gnat_try_lock (char *dir, char *file)
   return 1;
 }
 
-#elif defined (__EMX__) || defined (VMS)
-
-/* More cases that do not use link; identical code, to solve too long
-   line problem ??? */
-
-int
-__gnat_try_lock (char *dir, char *file)
-{
-  char full_path[256];
-  int fd;
-
-  sprintf (full_path, "%s%c%s", dir, DIR_SEPARATOR, file);
-  fd = open (full_path, O_CREAT | O_EXCL, 0600);
-
-  if (fd < 0)
-    return 0;
-
-  close (fd);
-  return 1;
-}
-
 #else
 
 /* Version using link(), more secure over NFS.  */
@@ -494,7 +546,7 @@ __gnat_try_lock (char *dir, char *file)
 {
   char full_path[256];
   char temp_file[256];
-  struct stat stat_result;
+  GNAT_STRUCT_STAT stat_result;
   int fd;
 
   sprintf (full_path, "%s%c%s", dir, DIR_SEPARATOR, file);
@@ -524,9 +576,7 @@ __gnat_try_lock (char *dir, char *file)
 int
 __gnat_get_maximum_file_name_length (void)
 {
-#if defined (MSDOS)
-  return 8;
-#elif defined (VMS)
+#if defined (VMS)
   if (getenv ("GNAT$EXTENDED_FILE_SPECIFICATIONS"))
     return -1;
   else
@@ -541,21 +591,36 @@ __gnat_get_maximum_file_name_length (void)
 int
 __gnat_get_file_names_case_sensitive (void)
 {
-#if defined (__EMX__) || defined (MSDOS) || defined (VMS) || defined (WINNT)
-  return 0;
+  const char *sensitive = getenv ("GNAT_FILE_NAME_CASE_SENSITIVE");
+
+  if (sensitive != NULL
+      && (sensitive[0] == '0' || sensitive[0] == '1')
+      && sensitive[1] == '\0')
+    return sensitive[0] - '0';
+  else
+#if defined (VMS) || defined (WINNT) || defined (__APPLE__)
+    return 0;
 #else
-  return 1;
+    return 1;
+#endif
+}
+
+/* Return nonzero if environment variables are case sensitive.  */
+
+int
+__gnat_get_env_vars_case_sensitive (void)
+{
+#if defined (VMS) || defined (WINNT)
+ return 0;
+#else
+ return 1;
 #endif
 }
 
 char
 __gnat_get_default_identifier_character_set (void)
 {
-#if defined (__EMX__) || defined (MSDOS)
-  return 'p';
-#else
   return '1';
-#endif
 }
 
 /* Return the current working directory.  */
@@ -568,7 +633,7 @@ __gnat_get_current_dir (char *dir, int *length)
 
   _tgetcwd (wdir, *length);
 
-  WS2SU (dir, wdir, GNAT_MAX_PATH_LEN);
+  WS2SC (dir, wdir, GNAT_MAX_PATH_LEN);
 
 #elif defined (VMS)
    /* Force Unix style, which is what GNAT uses internally.  */
@@ -622,12 +687,7 @@ __gnat_get_executable_suffix_ptr (int *len, const char **value)
 void
 __gnat_get_debuggable_suffix_ptr (int *len, const char **value)
 {
-#ifndef MSDOS
   *value = HOST_EXECUTABLE_SUFFIX;
-#else
-  /* On DOS, the extensionless COFF file is what gdb likes.  */
-  *value = "";
-#endif
 
   if (*value == 0)
     *len = 0;
@@ -640,12 +700,13 @@ __gnat_get_debuggable_suffix_ptr (int *len, const char **value)
 /* Returns the OS filename and corresponding encoding.  */
 
 void
-__gnat_os_filename (char *filename, char *w_filename,
+__gnat_os_filename (char *filename ATTRIBUTE_UNUSED,
+                   char *w_filename ATTRIBUTE_UNUSED,
                    char *os_name, int *o_length,
-                   char *encoding, int *e_length)
+                   char *encoding ATTRIBUTE_UNUSED, int *e_length)
 {
-#if defined (_WIN32) && ! defined (__vxworks) && ! defined (CROSS_DIRECTORY_STRUCTURE)
-  WS2SU (os_name, (TCHAR *)w_filename, o_length);
+#if defined (_WIN32) && ! defined (__vxworks) && ! defined (IS_CROSS)
+  WS2SC (os_name, (TCHAR *)w_filename, (DWORD)*o_length);
   *o_length = strlen (os_name);
   strcpy (encoding, "encoding=utf8");
   *e_length = strlen (encoding);
@@ -656,16 +717,90 @@ __gnat_os_filename (char *filename, char *w_filename,
 #endif
 }
 
+/* Delete a file.  */
+
+int
+__gnat_unlink (char *path)
+{
+#if defined (__MINGW32__) && ! defined (__vxworks) && ! defined (IS_CROSS)
+  {
+    TCHAR wpath[GNAT_MAX_PATH_LEN];
+
+    S2WSC (wpath, path, GNAT_MAX_PATH_LEN);
+    return _tunlink (wpath);
+  }
+#else
+  return unlink (path);
+#endif
+}
+
+/* Rename a file.  */
+
+int
+__gnat_rename (char *from, char *to)
+{
+#if defined (__MINGW32__) && ! defined (__vxworks) && ! defined (IS_CROSS)
+  {
+    TCHAR wfrom[GNAT_MAX_PATH_LEN], wto[GNAT_MAX_PATH_LEN];
+
+    S2WSC (wfrom, from, GNAT_MAX_PATH_LEN);
+    S2WSC (wto, to, GNAT_MAX_PATH_LEN);
+    return _trename (wfrom, wto);
+  }
+#else
+  return rename (from, to);
+#endif
+}
+
+/* Changing directory.  */
+
+int
+__gnat_chdir (char *path)
+{
+#if defined (__MINGW32__) && ! defined (__vxworks) && ! defined (IS_CROSS)
+  {
+    TCHAR wpath[GNAT_MAX_PATH_LEN];
+
+    S2WSC (wpath, path, GNAT_MAX_PATH_LEN);
+    return _tchdir (wpath);
+  }
+#else
+  return chdir (path);
+#endif
+}
+
+/* Removing a directory.  */
+
+int
+__gnat_rmdir (char *path)
+{
+#if defined (__MINGW32__) && ! defined (__vxworks) && ! defined (IS_CROSS)
+  {
+    TCHAR wpath[GNAT_MAX_PATH_LEN];
+
+    S2WSC (wpath, path, GNAT_MAX_PATH_LEN);
+    return _trmdir (wpath);
+  }
+#elif defined (VTHREADS)
+  /* rmdir not available */
+  return -1;
+#else
+  return rmdir (path);
+#endif
+}
+
 FILE *
-__gnat_fopen (char *path, char *mode, int encoding)
+__gnat_fopen (char *path, char *mode, int encoding ATTRIBUTE_UNUSED)
 {
-#if defined (_WIN32) && ! defined (__vxworks) && ! defined (CROSS_DIRECTORY_STRUCTURE)
+#if defined (_WIN32) && ! defined (__vxworks) && ! defined (IS_CROSS)
   TCHAR wpath[GNAT_MAX_PATH_LEN];
   TCHAR wmode[10];
 
   S2WS (wmode, mode, 10);
 
-  if (encoding == Encoding_UTF8)
+  if (encoding == Encoding_Unspecified)
+    S2WSC (wpath, path, GNAT_MAX_PATH_LEN);
+  else if (encoding == Encoding_UTF8)
     S2WSU (wpath, path, GNAT_MAX_PATH_LEN);
   else
     S2WS (wpath, path, GNAT_MAX_PATH_LEN);
@@ -674,20 +809,25 @@ __gnat_fopen (char *path, char *mode, int encoding)
 #elif defined (VMS)
   return decc$fopen (path, mode);
 #else
-  return fopen (path, mode);
+  return GNAT_FOPEN (path, mode);
 #endif
 }
 
 FILE *
-__gnat_freopen (char *path, char *mode, FILE *stream, int encoding)
+__gnat_freopen (char *path,
+               char *mode,
+               FILE *stream,
+               int encoding ATTRIBUTE_UNUSED)
 {
-#if defined (_WIN32) && ! defined (__vxworks) && ! defined (CROSS_DIRECTORY_STRUCTURE)
+#if defined (_WIN32) && ! defined (__vxworks) && ! defined (IS_CROSS)
   TCHAR wpath[GNAT_MAX_PATH_LEN];
   TCHAR wmode[10];
 
   S2WS (wmode, mode, 10);
 
-  if (encoding == Encoding_UTF8)
+  if (encoding == Encoding_Unspecified)
+    S2WSC (wpath, path, GNAT_MAX_PATH_LEN);
+  else if (encoding == Encoding_UTF8)
     S2WSU (wpath, path, GNAT_MAX_PATH_LEN);
   else
     S2WS (wpath, path, GNAT_MAX_PATH_LEN);
@@ -719,7 +859,7 @@ __gnat_open_read (char *path, int fmode)
  {
    TCHAR wpath[GNAT_MAX_PATH_LEN];
 
-   S2WSU (wpath, path, GNAT_MAX_PATH_LEN);
+   S2WSC (wpath, path, GNAT_MAX_PATH_LEN);
    fd = _topen (wpath, O_RDONLY | o_fmode, 0444);
  }
 #else
@@ -729,7 +869,7 @@ __gnat_open_read (char *path, int fmode)
   return fd < 0 ? -1 : fd;
 }
 
-#if defined (__EMX__) || defined (__MINGW32__)
+#if defined (__MINGW32__)
 #define PERM (S_IREAD | S_IWRITE)
 #elif defined (VMS)
 /* Excerpt from DECC C RTL Reference Manual:
@@ -760,7 +900,7 @@ __gnat_open_rw (char *path, int fmode)
   {
     TCHAR wpath[GNAT_MAX_PATH_LEN];
 
-    S2WSU (wpath, path, GNAT_MAX_PATH_LEN);
+    S2WSC (wpath, path, GNAT_MAX_PATH_LEN);
     fd = _topen (wpath, O_RDWR | o_fmode, PERM);
   }
 #else
@@ -786,7 +926,7 @@ __gnat_open_create (char *path, int fmode)
   {
     TCHAR wpath[GNAT_MAX_PATH_LEN];
 
-    S2WSU (wpath, path, GNAT_MAX_PATH_LEN);
+    S2WSC (wpath, path, GNAT_MAX_PATH_LEN);
     fd = _topen (wpath, O_WRONLY | O_CREAT | O_TRUNC | o_fmode, PERM);
   }
 #else
@@ -808,7 +948,7 @@ __gnat_create_output_file (char *path)
   {
     TCHAR wpath[GNAT_MAX_PATH_LEN];
 
-    S2WSU (wpath, path, GNAT_MAX_PATH_LEN);
+    S2WSC (wpath, path, GNAT_MAX_PATH_LEN);
     fd = _topen (wpath, O_WRONLY | O_CREAT | O_TRUNC | O_TEXT, PERM);
   }
 #else
@@ -819,6 +959,28 @@ __gnat_create_output_file (char *path)
 }
 
 int
+__gnat_create_output_file_new (char *path)
+{
+  int fd;
+#if defined (VMS)
+  fd = open (path, O_WRONLY | O_CREAT | O_TRUNC | O_TEXT | O_EXCL, PERM,
+             "rfm=stmlf", "ctx=rec", "rat=none", "rop=nlk",
+             "shr=del,get,put,upd");
+#elif defined (__MINGW32__)
+  {
+    TCHAR wpath[GNAT_MAX_PATH_LEN];
+
+    S2WSC (wpath, path, GNAT_MAX_PATH_LEN);
+    fd = _topen (wpath, O_WRONLY | O_CREAT | O_TRUNC | O_TEXT | O_EXCL, PERM);
+  }
+#else
+  fd = open (path, O_WRONLY | O_CREAT | O_TRUNC | O_TEXT | O_EXCL, PERM);
+#endif
+
+  return fd < 0 ? -1 : fd;
+}
+
+int
 __gnat_open_append (char *path, int fmode)
 {
   int fd;
@@ -834,7 +996,7 @@ __gnat_open_append (char *path, int fmode)
   {
     TCHAR wpath[GNAT_MAX_PATH_LEN];
 
-    S2WSU (wpath, path, GNAT_MAX_PATH_LEN);
+    S2WSC (wpath, path, GNAT_MAX_PATH_LEN);
     fd = _topen (wpath, O_WRONLY | O_CREAT | O_APPEND | o_fmode, PERM);
   }
 #else
@@ -862,7 +1024,7 @@ __gnat_open_new (char *path, int fmode)
   {
     TCHAR wpath[GNAT_MAX_PATH_LEN];
 
-    S2WSU (wpath, path, GNAT_MAX_PATH_LEN);
+    S2WSC (wpath, path, GNAT_MAX_PATH_LEN);
     fd = _topen (wpath, O_WRONLY | O_CREAT | O_EXCL | o_fmode, PERM);
   }
 #else
@@ -884,7 +1046,8 @@ __gnat_open_new_temp (char *path, int fmode)
 
   strcpy (path, "GNAT-XXXXXX");
 
-#if (defined (__FreeBSD__) || defined (linux)) && !defined (__vxworks)
+#if (defined (__FreeBSD__) || defined (__NetBSD__) || defined (__OpenBSD__) \
+  || defined (linux) || defined(__GLIBC__)) && !defined (__vxworks)
   return mkstemp (path);
 #elif defined (__Lynx__)
   mktemp (path);
@@ -909,34 +1072,82 @@ __gnat_open_new_temp (char *path, int fmode)
   return fd < 0 ? -1 : fd;
 }
 
-/* Return the number of bytes in the specified file.  */
+/****************************************************************
+ ** Perform a call to GNAT_STAT or GNAT_FSTAT, and extract as much information
+ ** as possible from it, storing the result in a cache for later reuse
+ ****************************************************************/
 
-long
-__gnat_file_length (int fd)
+void
+__gnat_stat_to_attr (int fd, char* name, struct file_attributes* attr)
 {
+  GNAT_STRUCT_STAT statbuf;
   int ret;
-  struct stat statbuf;
 
-  ret = fstat (fd, &statbuf);
-  if (ret || !S_ISREG (statbuf.st_mode))
-    return 0;
+  if (fd != -1)
+    ret = GNAT_FSTAT (fd, &statbuf);
+  else
+    ret = __gnat_stat (name, &statbuf);
+
+  attr->regular   = (!ret && S_ISREG (statbuf.st_mode));
+  attr->directory = (!ret && S_ISDIR (statbuf.st_mode));
 
-  return (statbuf.st_size);
+  if (!attr->regular)
+    attr->file_length = 0;
+  else
+    /* st_size may be 32 bits, or 64 bits which is converted to long. We
+       don't return a useful value for files larger than 2 gigabytes in
+       either case. */
+    attr->file_length = statbuf.st_size;  /* all systems */
+
+  attr->exists = !ret;
+
+#if !defined (_WIN32) || defined (RTX)
+  /* on Windows requires extra system call, see __gnat_is_readable_file_attr */
+  attr->readable   = (!ret && (statbuf.st_mode & S_IRUSR));
+  attr->writable   = (!ret && (statbuf.st_mode & S_IWUSR));
+  attr->executable = (!ret && (statbuf.st_mode & S_IXUSR));
+#endif
+
+  if (ret != 0) {
+     attr->timestamp = (OS_Time)-1;
+  } else {
+#ifdef VMS
+     /* VMS has file versioning.  */
+     attr->timestamp = (OS_Time)statbuf.st_ctime;
+#else
+     attr->timestamp = (OS_Time)statbuf.st_mtime;
+#endif
+  }
 }
 
-/* Return the number of bytes in the specified named file.  */
+/****************************************************************
+ ** Return the number of bytes in the specified file
+ ****************************************************************/
 
 long
-__gnat_named_file_length (char *name)
+__gnat_file_length_attr (int fd, char* name, struct file_attributes* attr)
 {
-  int ret;
-  struct stat statbuf;
+  if (attr->file_length == -1) {
+    __gnat_stat_to_attr (fd, name, attr);
+  }
 
-  ret = __gnat_stat (name, &statbuf);
-  if (ret || !S_ISREG (statbuf.st_mode))
-    return 0;
+  return attr->file_length;
+}
+
+long
+__gnat_file_length (int fd)
+{
+  struct file_attributes attr;
+  __gnat_reset_attributes (&attr);
+  return __gnat_file_length_attr (fd, NULL, &attr);
+}
 
-  return (statbuf.st_size);
+long
+__gnat_named_file_length (char *name)
+{
+  struct file_attributes attr;
+  __gnat_reset_attributes (&attr);
+  return __gnat_file_length_attr (-1, name, &attr);
 }
 
 /* Create a temporary filename and put it in string pointed to by
@@ -945,7 +1156,15 @@ __gnat_named_file_length (char *name)
 void
 __gnat_tmp_name (char *tmp_filename)
 {
-#ifdef __MINGW32__
+#ifdef RTX
+  /* Variable used to create a series of unique names */
+  static int counter = 0;
+
+  /* RTX in RTSS mode does not support tempnam nor tmpnam so we emulate it */
+  strcpy (tmp_filename, "c:\\WINDOWS\\Temp\\gnat-");
+  sprintf (&tmp_filename[strlen (tmp_filename)], "%d\0", counter++);
+
+#elif defined (__MINGW32__)
   {
     char *pname;
 
@@ -976,7 +1195,8 @@ __gnat_tmp_name (char *tmp_filename)
     free (pname);
   }
 
-#elif defined (linux) || defined (__FreeBSD__)
+#elif defined (linux) || defined (__FreeBSD__) || defined (__NetBSD__) \
+  || defined (__OpenBSD__) || defined(__GLIBC__)
 #define MAX_SAFE_PATH 1000
   char *tmpdir = getenv ("TMPDIR");
 
@@ -997,10 +1217,15 @@ __gnat_tmp_name (char *tmp_filename)
 
 DIR* __gnat_opendir (char *name)
 {
-#ifdef __MINGW32__
+#if defined (RTX)
+  /* Not supported in RTX */
+
+  return NULL;
+
+#elif defined (__MINGW32__)
   TCHAR wname[GNAT_MAX_PATH_LEN];
 
-  S2WSU (wname, name, GNAT_MAX_PATH_LEN);
+  S2WSC (wname, name, GNAT_MAX_PATH_LEN);
   return (DIR*)_topendir (wname);
 
 #else
@@ -1014,12 +1239,17 @@ DIR* __gnat_opendir (char *name)
 char *
 __gnat_readdir (DIR *dirp, char *buffer, int *len)
 {
-#if defined (__MINGW32__)
+#if defined (RTX)
+  /* Not supported in RTX */
+
+  return NULL;
+
+#elif defined (__MINGW32__)
   struct _tdirent *dirent = _treaddir ((_TDIR*)dirp);
 
   if (dirent != NULL)
     {
-      WS2SU (buffer, dirent->d_name, GNAT_MAX_PATH_LEN);
+      WS2SC (buffer, dirent->d_name, GNAT_MAX_PATH_LEN);
       *len = strlen (buffer);
 
       return buffer;
@@ -1056,7 +1286,12 @@ __gnat_readdir (DIR *dirp, char *buffer, int *len)
 
 int __gnat_closedir (DIR *dirp)
 {
-#ifdef __MINGW32__
+#if defined (RTX)
+  /* Not supported in RTX */
+
+  return 0;
+
+#elif defined (__MINGW32__)
   return _tclosedir ((_TDIR*)dirp);
 
 #else
@@ -1076,7 +1311,7 @@ __gnat_readdir_is_thread_safe (void)
 #endif
 }
 
-#ifdef _WIN32
+#if defined (_WIN32) && !defined (RTX)
 /* Number of seconds between <Jan 1st 1601> and <Jan 1st 1970>.  */
 static const unsigned long long w32_epoch_offset = 11644473600ULL;
 
@@ -1102,142 +1337,78 @@ win32_filetime (HANDLE h)
     return (time_t) (t_write.ull_time / 10000000ULL - w32_epoch_offset);
   return (time_t) 0;
 }
+
+/* As above but starting from a FILETIME.  */
+static void
+f2t (const FILETIME *ft, time_t *t)
+{
+  union
+  {
+    FILETIME ft_time;
+    unsigned long long ull_time;
+  } t_write;
+
+  t_write.ft_time = *ft;
+  *t = (time_t) (t_write.ull_time / 10000000ULL - w32_epoch_offset);
+}
 #endif
 
 /* Return a GNAT time stamp given a file name.  */
 
 OS_Time
-__gnat_file_time_name (char *name)
+__gnat_file_time_name_attr (char* name, struct file_attributes* attr)
 {
+   if (attr->timestamp == (OS_Time)-2) {
+#if defined (_WIN32) && !defined (RTX)
+      BOOL res;
+      WIN32_FILE_ATTRIBUTE_DATA fad;
+      time_t ret = -1;
+      TCHAR wname[GNAT_MAX_PATH_LEN];
+      S2WSC (wname, name, GNAT_MAX_PATH_LEN);
 
-#if defined (__EMX__) || defined (MSDOS)
-  int fd = open (name, O_RDONLY | O_BINARY);
-  time_t ret = __gnat_file_time_fd (fd);
-  close (fd);
-  return (OS_Time)ret;
-
-#elif defined (_WIN32)
-  time_t ret = -1;
-  TCHAR wname[GNAT_MAX_PATH_LEN];
-
-  S2WSU (wname, name, GNAT_MAX_PATH_LEN);
-
-  HANDLE h = CreateFile
-    (wname, GENERIC_READ, FILE_SHARE_READ, 0,
-     OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0);
-
-  if (h != INVALID_HANDLE_VALUE)
-    {
-      ret = win32_filetime (h);
-      CloseHandle (h);
-    }
-  return (OS_Time) ret;
+      if (res = GetFileAttributesEx (wname, GetFileExInfoStandard, &fad))
+       f2t (&fad.ftLastWriteTime, &ret);
+      attr->timestamp = (OS_Time) ret;
 #else
-  struct stat statbuf;
-  if (__gnat_stat (name, &statbuf) != 0) {
-     return (OS_Time)-1;
-  } else {
-#ifdef VMS
-     /* VMS has file versioning.  */
-     return (OS_Time)statbuf.st_ctime;
-#else
-     return (OS_Time)statbuf.st_mtime;
+      __gnat_stat_to_attr (-1, name, attr);
 #endif
   }
-#endif
+  return attr->timestamp;
 }
 
-/* Return a GNAT time stamp given a file descriptor.  */
-
 OS_Time
-__gnat_file_time_fd (int fd)
+__gnat_file_time_name (char *name)
 {
-  /* The following workaround code is due to the fact that under EMX and
-     DJGPP fstat attempts to convert time values to GMT rather than keep the
-     actual OS timestamp of the file. By using the OS2/DOS functions directly
-     the GNAT timestamp are independent of this behavior, which is desired to
-     facilitate the distribution of GNAT compiled libraries.  */
-
-#if defined (__EMX__) || defined (MSDOS)
-#ifdef __EMX__
+   struct file_attributes attr;
+   __gnat_reset_attributes (&attr);
+   return __gnat_file_time_name_attr (name, &attr);
+}
 
-  FILESTATUS fs;
-  int ret = DosQueryFileInfo (fd, 1, (unsigned char *) &fs,
-                                sizeof (FILESTATUS));
+/* Return a GNAT time stamp given a file descriptor.  */
 
-  unsigned file_year  = fs.fdateLastWrite.year;
-  unsigned file_month = fs.fdateLastWrite.month;
-  unsigned file_day   = fs.fdateLastWrite.day;
-  unsigned file_hour  = fs.ftimeLastWrite.hours;
-  unsigned file_min   = fs.ftimeLastWrite.minutes;
-  unsigned file_tsec  = fs.ftimeLastWrite.twosecs;
+OS_Time
+__gnat_file_time_fd_attr (int fd, struct file_attributes* attr)
+{
+   if (attr->timestamp == (OS_Time)-2) {
+#if defined (_WIN32) && !defined (RTX)
+     HANDLE h = (HANDLE) _get_osfhandle (fd);
+     time_t ret = win32_filetime (h);
+     attr->timestamp = (OS_Time) ret;
 
 #else
-  struct ftime fs;
-  int ret = getftime (fd, &fs);
-
-  unsigned file_year  = fs.ft_year;
-  unsigned file_month = fs.ft_month;
-  unsigned file_day   = fs.ft_day;
-  unsigned file_hour  = fs.ft_hour;
-  unsigned file_min   = fs.ft_min;
-  unsigned file_tsec  = fs.ft_tsec;
+     __gnat_stat_to_attr (fd, NULL, attr);
 #endif
+   }
 
-  /* Calculate the seconds since epoch from the time components. First count
-     the whole days passed.  The value for years returned by the DOS and OS2
-     functions count years from 1980, so to compensate for the UNIX epoch which
-     begins in 1970 start with 10 years worth of days and add days for each
-     four year period since then.  */
-
-  time_t tot_secs;
-  int cum_days[12] = {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334};
-  int days_passed = 3652 + (file_year / 4) * 1461;
-  int years_since_leap = file_year % 4;
-
-  if (years_since_leap == 1)
-    days_passed += 366;
-  else if (years_since_leap == 2)
-    days_passed += 731;
-  else if (years_since_leap == 3)
-    days_passed += 1096;
-
-  if (file_year > 20)
-    days_passed -= 1;
-
-  days_passed += cum_days[file_month - 1];
-  if (years_since_leap == 0 && file_year != 20 && file_month > 2)
-    days_passed++;
-
-  days_passed += file_day - 1;
-
-  /* OK - have whole days.  Multiply -- then add in other parts.  */
-
-  tot_secs  = days_passed * 86400;
-  tot_secs += file_hour * 3600;
-  tot_secs += file_min * 60;
-  tot_secs += file_tsec * 2;
-  return (OS_Time) tot_secs;
-
-#elif defined (_WIN32)
-  HANDLE h = (HANDLE) _get_osfhandle (fd);
-  time_t ret = win32_filetime (h);
-  return (OS_Time) ret;
-
-#else
-  struct stat statbuf;
+   return attr->timestamp;
+}
 
-  if (fstat (fd, &statbuf) != 0) {
-     return (OS_Time) -1;
-  } else {
-#ifdef VMS
-     /* VMS has file versioning.  */
-     return (OS_Time) statbuf.st_ctime;
-#else
-     return (OS_Time) statbuf.st_mtime;
-#endif
-  }
-#endif
+OS_Time
+__gnat_file_time_fd (int fd)
+{
+   struct file_attributes attr;
+   __gnat_reset_attributes (&attr);
+   return __gnat_file_time_fd_attr (fd, &attr);
 }
 
 /* Set the file time stamp.  */
@@ -1245,11 +1416,11 @@ __gnat_file_time_fd (int fd)
 void
 __gnat_set_file_time_name (char *name, time_t time_stamp)
 {
-#if defined (__EMX__) || defined (MSDOS) || defined (__vxworks)
+#if defined (__vxworks)
 
 /* Code to implement __gnat_set_file_time_name for these systems.  */
 
-#elif defined (_WIN32)
+#elif defined (_WIN32) && !defined (RTX)
   union
   {
     FILETIME ft_time;
@@ -1257,7 +1428,7 @@ __gnat_set_file_time_name (char *name, time_t time_stamp)
   } t_write;
   TCHAR wname[GNAT_MAX_PATH_LEN];
 
-  S2WSU (wname, name, GNAT_MAX_PATH_LEN);
+  S2WSC (wname, name, GNAT_MAX_PATH_LEN);
 
   HANDLE h  = CreateFile
     (wname, GENERIC_WRITE, FILE_SHARE_WRITE, NULL,
@@ -1451,10 +1622,6 @@ __gnat_set_file_time_name (char *name, time_t time_stamp)
 #endif
 }
 
-#ifdef _WIN32
-#include <windows.h>
-#endif
-
 /* Get the list of installed standard libraries from the
    HKEY_LOCAL_MACHINE\SOFTWARE\Ada Core Technologies\GNAT\Standard Libraries
    key.  */
@@ -1462,9 +1629,12 @@ __gnat_set_file_time_name (char *name, time_t time_stamp)
 char *
 __gnat_get_libraries_from_registry (void)
 {
-  char *result = (char *) "";
+  char *result = (char *) xmalloc (1);
 
-#if defined (_WIN32) && ! defined (__vxworks) && ! defined (CROSS_DIRECTORY_STRUCTURE)
+  result[0] = '\0';
+
+#if defined (_WIN32) && ! defined (__vxworks) && ! defined (IS_CROSS) \
+  && ! defined (RTX)
 
   HKEY reg_key;
   DWORD name_size, value_size;
@@ -1492,7 +1662,7 @@ __gnat_get_libraries_from_registry (void)
   for (index = 0; res == ERROR_SUCCESS; index++)
     {
       value_size = name_size = 256;
-      res = RegEnumValueA (reg_key, index, (TCHAR*)name, &name_size, 0,
+      res = RegEnumValueA (reg_key, index, name, &name_size, 0,
                            &type, (LPBYTE)value, &value_size);
 
       if (res == ERROR_SUCCESS && type == REG_SZ)
@@ -1503,6 +1673,7 @@ __gnat_get_libraries_from_registry (void)
           strcpy (result, old_result);
           strcat (result, value);
           strcat (result, ";");
+          free (old_result);
         }
     }
 
@@ -1515,197 +1686,601 @@ __gnat_get_libraries_from_registry (void)
 }
 
 int
-__gnat_stat (char *name, struct stat *statbuf)
+__gnat_stat (char *name, GNAT_STRUCT_STAT *statbuf)
 {
 #ifdef __MINGW32__
-  /* Under Windows the directory name for the stat function must not be
-     terminated by a directory separator except if just after a drive name.  */
+  WIN32_FILE_ATTRIBUTE_DATA fad;
   TCHAR wname [GNAT_MAX_PATH_LEN + 2];
   int name_len;
-  TCHAR last_char;
+  BOOL res;
 
-  S2WSU (wname, name, GNAT_MAX_PATH_LEN + 2);
+  S2WSC (wname, name, GNAT_MAX_PATH_LEN + 2);
   name_len = _tcslen (wname);
 
   if (name_len > GNAT_MAX_PATH_LEN)
     return -1;
 
-  last_char = wname[name_len - 1];
-
-  while (name_len > 1 && (last_char == _T('\\') || last_char == _T('/')))
-    {
-      wname[name_len - 1] = _T('\0');
-      name_len--;
-      last_char = wname[name_len - 1];
+  ZeroMemory (statbuf, sizeof(GNAT_STRUCT_STAT));
+
+  res = GetFileAttributesEx (wname, GetFileExInfoStandard, &fad);
+
+  if (res == FALSE)
+    switch (GetLastError()) {
+      case ERROR_ACCESS_DENIED:
+      case ERROR_SHARING_VIOLATION:
+      case ERROR_LOCK_VIOLATION:
+      case ERROR_SHARING_BUFFER_EXCEEDED:
+       return EACCES;
+      case ERROR_BUFFER_OVERFLOW:
+       return ENAMETOOLONG;
+      case ERROR_NOT_ENOUGH_MEMORY:
+       return ENOMEM;
+      default:
+       return ENOENT;
     }
 
-  /* Only a drive letter followed by ':', we must add a directory separator
-     for the stat routine to work properly.  */
-  if (name_len == 2 && wname[1] == _T(':'))
-    _tcscat (wname, _T("\\"));
+  f2t (&fad.ftCreationTime, &statbuf->st_ctime);
+  f2t (&fad.ftLastWriteTime, &statbuf->st_mtime);
+  f2t (&fad.ftLastAccessTime, &statbuf->st_atime);
 
-  return _tstat (wname, statbuf);
+  statbuf->st_size = (off_t)fad.nFileSizeLow;
+
+  /* We do not have the S_IEXEC attribute, but this is not used on GNAT.  */
+  statbuf->st_mode = S_IREAD;
+
+  if (fad.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
+    statbuf->st_mode |= S_IFDIR;
+  else
+    statbuf->st_mode |= S_IFREG;
+
+  if (!(fad.dwFileAttributes & FILE_ATTRIBUTE_READONLY))
+    statbuf->st_mode |= S_IWRITE;
+
+  return 0;
 
 #else
-  return stat (name, statbuf);
+  return GNAT_STAT (name, statbuf);
 #endif
 }
 
+/*************************************************************************
+ ** Check whether a file exists
+ *************************************************************************/
+
+int
+__gnat_file_exists_attr (char* name, struct file_attributes* attr)
+{
+   if (attr->exists == ATTR_UNSET) {
+      __gnat_stat_to_attr (-1, name, attr);
+   }
+
+   return attr->exists;
+}
+
 int
 __gnat_file_exists (char *name)
 {
-#ifdef __MINGW32__
-  /*  On Windows do not use __gnat_stat() because a bug in Microsoft
-  _stat() routine. When the system time-zone is set with a negative
-  offset the _stat() routine fails on specific files like CON:  */
-  TCHAR wname [GNAT_MAX_PATH_LEN + 2];
+   struct file_attributes attr;
+   __gnat_reset_attributes (&attr);
+   return __gnat_file_exists_attr (name, &attr);
+}
+
+/**********************************************************************
+ ** Whether name is an absolute path
+ **********************************************************************/
+
+int
+__gnat_is_absolute_path (char *name, int length)
+{
+#ifdef __vxworks
+  /* On VxWorks systems, an absolute path can be represented (depending on
+     the host platform) as either /dir/file, or device:/dir/file, or
+     device:drive_letter:/dir/file. */
+
+  int index;
+
+  if (name[0] == '/')
+    return 1;
+
+  for (index = 0; index < length; index++)
+    {
+      if (name[index] == ':' &&
+          ((name[index + 1] == '/') ||
+           (isalpha (name[index + 1]) && index + 2 <= length &&
+            name[index + 2] == '/')))
+        return 1;
 
-  S2WSU (wname, name, GNAT_MAX_PATH_LEN + 2);
-  return GetFileAttributes (wname) != INVALID_FILE_ATTRIBUTES;
+      else if (name[index] == '/')
+        return 0;
+    }
+  return 0;
 #else
-  struct stat statbuf;
+  return (length != 0) &&
+     (*name == '/' || *name == DIR_SEPARATOR
+#if defined (WINNT)
+      || (length > 1 && ISALPHA (name[0]) && name[1] == ':')
+#endif
+         );
+#endif
+}
+
+int
+__gnat_is_regular_file_attr (char* name, struct file_attributes* attr)
+{
+   if (attr->regular == ATTR_UNSET) {
+      __gnat_stat_to_attr (-1, name, attr);
+   }
+
+   return attr->regular;
+}
+
+int
+__gnat_is_regular_file (char *name)
+{
+   struct file_attributes attr;
+   __gnat_reset_attributes (&attr);
+   return __gnat_is_regular_file_attr (name, &attr);
+}
+
+int
+__gnat_is_directory_attr (char* name, struct file_attributes* attr)
+{
+   if (attr->directory == ATTR_UNSET) {
+      __gnat_stat_to_attr (-1, name, attr);
+   }
+
+   return attr->directory;
+}
+
+int
+__gnat_is_directory (char *name)
+{
+   struct file_attributes attr;
+   __gnat_reset_attributes (&attr);
+   return __gnat_is_directory_attr (name, &attr);
+}
+
+#if defined (_WIN32) && !defined (RTX)
+
+/* Returns the same constant as GetDriveType but takes a pathname as
+   argument. */
+
+static UINT
+GetDriveTypeFromPath (TCHAR *wfullpath)
+{
+  TCHAR wdrv[MAX_PATH];
+  TCHAR wpath[MAX_PATH];
+  TCHAR wfilename[MAX_PATH];
+  TCHAR wext[MAX_PATH];
+
+  _tsplitpath (wfullpath, wdrv, wpath, wfilename, wext);
+
+  if (_tcslen (wdrv) != 0)
+    {
+      /* we have a drive specified. */
+      _tcscat (wdrv, _T("\\"));
+      return GetDriveType (wdrv);
+    }
+  else
+    {
+      /* No drive specified. */
+
+      /* Is this a relative path, if so get current drive type. */
+      if (wpath[0] != _T('\\') ||
+         (_tcslen (wpath) > 2 && wpath[0] == _T('\\') && wpath[1] != _T('\\')))
+       return GetDriveType (NULL);
+
+      UINT result = GetDriveType (wpath);
+
+      /* Cannot guess the drive type, is this \\.\ ? */
+
+      if (result == DRIVE_NO_ROOT_DIR &&
+        _tcslen (wpath) >= 4 && wpath[0] == _T('\\') && wpath[1] == _T('\\')
+         && wpath[2] == _T('.') && wpath[3] == _T('\\'))
+       {
+         if (_tcslen (wpath) == 4)
+           _tcscat (wpath, wfilename);
+
+         LPTSTR p = &wpath[4];
+         LPTSTR b = _tcschr (p, _T('\\'));
+
+         if (b != NULL)
+           { /* logical drive \\.\c\dir\file */
+             *b++ = _T(':');
+             *b++ = _T('\\');
+             *b = _T('\0');
+           }
+         else
+           _tcscat (p, _T(":\\"));
+
+         return GetDriveType (p);
+       }
+
+      return result;
+    }
+}
+
+/*  This MingW section contains code to work with ACL. */
+static int
+__gnat_check_OWNER_ACL
+(TCHAR *wname,
+ DWORD CheckAccessDesired,
+ GENERIC_MAPPING CheckGenericMapping)
+{
+  DWORD dwAccessDesired, dwAccessAllowed;
+  PRIVILEGE_SET PrivilegeSet;
+  DWORD dwPrivSetSize = sizeof (PRIVILEGE_SET);
+  BOOL fAccessGranted = FALSE;
+  HANDLE hToken = NULL;
+  DWORD nLength = 0;
+  SECURITY_DESCRIPTOR* pSD = NULL;
+
+  GetFileSecurity
+    (wname, OWNER_SECURITY_INFORMATION |
+     GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION,
+     NULL, 0, &nLength);
+
+  if ((pSD = (PSECURITY_DESCRIPTOR) HeapAlloc
+       (GetProcessHeap (), HEAP_ZERO_MEMORY, nLength)) == NULL)
+    return 0;
+
+  /* Obtain the security descriptor. */
+
+  if (!GetFileSecurity
+      (wname, OWNER_SECURITY_INFORMATION |
+       GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION,
+       pSD, nLength, &nLength))
+    goto error;
+
+  if (!ImpersonateSelf (SecurityImpersonation))
+    goto error;
+
+  if (!OpenThreadToken
+      (GetCurrentThread(), TOKEN_DUPLICATE | TOKEN_QUERY, FALSE, &hToken))
+    goto error;
+
+  /*  Undoes the effect of ImpersonateSelf. */
+
+  RevertToSelf ();
+
+  /*  We want to test for write permissions. */
+
+  dwAccessDesired = CheckAccessDesired;
+
+  MapGenericMask (&dwAccessDesired, &CheckGenericMapping);
+
+  if (!AccessCheck
+      (pSD ,                 /* security descriptor to check */
+       hToken,               /* impersonation token */
+       dwAccessDesired,      /* requested access rights */
+       &CheckGenericMapping, /* pointer to GENERIC_MAPPING */
+       &PrivilegeSet,        /* receives privileges used in check */
+       &dwPrivSetSize,       /* size of PrivilegeSet buffer */
+       &dwAccessAllowed,     /* receives mask of allowed access rights */
+       &fAccessGranted))
+    goto error;
+
+  CloseHandle (hToken);
+  HeapFree (GetProcessHeap (), 0, pSD);
+  return fAccessGranted;
+
+ error:
+  if (hToken)
+    CloseHandle (hToken);
+  HeapFree (GetProcessHeap (), 0, pSD);
+  return 0;
+}
+
+static void
+__gnat_set_OWNER_ACL
+(TCHAR *wname,
+ DWORD AccessMode,
+ DWORD AccessPermissions)
+{
+  PACL pOldDACL = NULL;
+  PACL pNewDACL = NULL;
+  PSECURITY_DESCRIPTOR pSD = NULL;
+  EXPLICIT_ACCESS ea;
+  TCHAR username [100];
+  DWORD unsize = 100;
+
+  /*  Get current user, he will act as the owner */
+
+  if (!GetUserName (username, &unsize))
+    return;
+
+  if (GetNamedSecurityInfo
+      (wname,
+       SE_FILE_OBJECT,
+       DACL_SECURITY_INFORMATION,
+       NULL, NULL, &pOldDACL, NULL, &pSD) != ERROR_SUCCESS)
+    return;
+
+  BuildExplicitAccessWithName
+    (&ea, username, AccessPermissions, AccessMode, NO_INHERITANCE);
 
-  return !__gnat_stat (name, &statbuf);
+  if (AccessMode == SET_ACCESS)
+    {
+      /*  SET_ACCESS, we want to set an explicte set of permissions, do not
+         merge with current DACL.  */
+      if (SetEntriesInAcl (1, &ea, NULL, &pNewDACL) != ERROR_SUCCESS)
+       return;
+    }
+  else
+    if (SetEntriesInAcl (1, &ea, pOldDACL, &pNewDACL) != ERROR_SUCCESS)
+      return;
+
+  if (SetNamedSecurityInfo
+      (wname, SE_FILE_OBJECT,
+       DACL_SECURITY_INFORMATION, NULL, NULL, pNewDACL, NULL) != ERROR_SUCCESS)
+    return;
+
+  LocalFree (pSD);
+  LocalFree (pNewDACL);
+}
+
+/* Check if it is possible to use ACL for wname, the file must not be on a
+   network drive. */
+
+static int
+__gnat_can_use_acl (TCHAR *wname)
+{
+  return __gnat_use_acl && GetDriveTypeFromPath (wname) != DRIVE_REMOTE;
+}
+
+#endif /* defined (_WIN32) && !defined (RTX) */
+
+int
+__gnat_is_readable_file_attr (char* name, struct file_attributes* attr)
+{
+   if (attr->readable == ATTR_UNSET) {
+#if defined (_WIN32) && !defined (RTX)
+     TCHAR wname [GNAT_MAX_PATH_LEN + 2];
+     GENERIC_MAPPING GenericMapping;
+
+     S2WSC (wname, name, GNAT_MAX_PATH_LEN + 2);
+
+     if (__gnat_can_use_acl (wname))
+     {
+        ZeroMemory (&GenericMapping, sizeof (GENERIC_MAPPING));
+        GenericMapping.GenericRead = GENERIC_READ;
+       attr->readable =
+         __gnat_check_OWNER_ACL (wname, FILE_READ_DATA, GenericMapping);
+     }
+     else
+        attr->readable = GetFileAttributes (wname) != INVALID_FILE_ATTRIBUTES;
+#else
+     __gnat_stat_to_attr (-1, name, attr);
 #endif
+   }
+
+   return attr->readable;
+}
+
+int
+__gnat_is_readable_file (char *name)
+{
+   struct file_attributes attr;
+   __gnat_reset_attributes (&attr);
+   return __gnat_is_readable_file_attr (name, &attr);
 }
 
 int
-__gnat_is_absolute_path (char *name, int length)
+__gnat_is_writable_file_attr (char* name, struct file_attributes* attr)
 {
-#ifdef __vxworks
-  /* On VxWorks systems, an absolute path can be represented (depending on
-     the host platform) as either /dir/file, or device:/dir/file, or
-     device:drive_letter:/dir/file. */
+   if (attr->writable == ATTR_UNSET) {
+#if defined (_WIN32) && !defined (RTX)
+     TCHAR wname [GNAT_MAX_PATH_LEN + 2];
+     GENERIC_MAPPING GenericMapping;
 
-  int index;
+     S2WSC (wname, name, GNAT_MAX_PATH_LEN + 2);
 
-  if (name[0] == '/')
-    return 1;
+     if (__gnat_can_use_acl (wname))
+       {
+         ZeroMemory (&GenericMapping, sizeof (GENERIC_MAPPING));
+         GenericMapping.GenericWrite = GENERIC_WRITE;
 
-  for (index = 0; index < length; index++)
-    {
-      if (name[index] == ':' &&
-          ((name[index + 1] == '/') ||
-           (isalpha (name[index + 1]) && index + 2 <= length &&
-            name[index + 2] == '/')))
-        return 1;
+         attr->writable = __gnat_check_OWNER_ACL
+            (wname, FILE_WRITE_DATA | FILE_APPEND_DATA, GenericMapping)
+            && !(GetFileAttributes (wname) & FILE_ATTRIBUTE_READONLY);
+       }
+     else
+       attr->writable = !(GetFileAttributes (wname) & FILE_ATTRIBUTE_READONLY);
 
-      else if (name[index] == '/')
-        return 0;
-    }
-  return 0;
 #else
-  return (length != 0) &&
-     (*name == '/' || *name == DIR_SEPARATOR
-#if defined (__EMX__) || defined (MSDOS) || defined (WINNT)
-      || (length > 1 && isalpha (name[0]) && name[1] == ':')
-#endif
-         );
+     __gnat_stat_to_attr (-1, name, attr);
 #endif
+   }
+
+   return attr->writable;
 }
 
 int
-__gnat_is_regular_file (char *name)
+__gnat_is_writable_file (char *name)
 {
-  int ret;
-  struct stat statbuf;
-
-  ret = __gnat_stat (name, &statbuf);
-  return (!ret && S_ISREG (statbuf.st_mode));
+   struct file_attributes attr;
+   __gnat_reset_attributes (&attr);
+   return __gnat_is_writable_file_attr (name, &attr);
 }
 
 int
-__gnat_is_directory (char *name)
+__gnat_is_executable_file_attr (char* name, struct file_attributes* attr)
 {
-  int ret;
-  struct stat statbuf;
+   if (attr->executable == ATTR_UNSET) {
+#if defined (_WIN32) && !defined (RTX)
+     TCHAR wname [GNAT_MAX_PATH_LEN + 2];
+     GENERIC_MAPPING GenericMapping;
 
-  ret = __gnat_stat (name, &statbuf);
-  return (!ret && S_ISDIR (statbuf.st_mode));
+     S2WSC (wname, name, GNAT_MAX_PATH_LEN + 2);
+
+     if (__gnat_can_use_acl (wname))
+       {
+         ZeroMemory (&GenericMapping, sizeof (GENERIC_MAPPING));
+         GenericMapping.GenericExecute = GENERIC_EXECUTE;
+
+         attr->executable =
+           __gnat_check_OWNER_ACL (wname, FILE_EXECUTE, GenericMapping);
+       }
+     else
+       attr->executable = GetFileAttributes (wname) != INVALID_FILE_ATTRIBUTES
+         && _tcsstr (wname, _T(".exe")) - wname == (int) (_tcslen (wname) - 4);
+#else
+     __gnat_stat_to_attr (-1, name, attr);
+#endif
+   }
+
+   return attr->executable;
 }
 
 int
-__gnat_is_readable_file (char *name)
+__gnat_is_executable_file (char *name)
 {
-  int ret;
-  int mode;
-  struct stat statbuf;
+   struct file_attributes attr;
+   __gnat_reset_attributes (&attr);
+   return __gnat_is_executable_file_attr (name, &attr);
+}
+
+void
+__gnat_set_writable (char *name)
+{
+#if defined (_WIN32) && !defined (RTX)
+  TCHAR wname [GNAT_MAX_PATH_LEN + 2];
+
+  S2WSC (wname, name, GNAT_MAX_PATH_LEN + 2);
+
+  if (__gnat_can_use_acl (wname))
+    __gnat_set_OWNER_ACL (wname, GRANT_ACCESS, FILE_GENERIC_WRITE);
+
+  SetFileAttributes
+    (wname, GetFileAttributes (wname) & ~FILE_ATTRIBUTE_READONLY);
+#elif ! defined (__vxworks) && ! defined(__nucleus__)
+  GNAT_STRUCT_STAT statbuf;
 
-  ret = __gnat_stat (name, &statbuf);
-  mode = statbuf.st_mode & S_IRUSR;
-  return (!ret && mode);
+  if (GNAT_STAT (name, &statbuf) == 0)
+    {
+      statbuf.st_mode = statbuf.st_mode | S_IWUSR;
+      chmod (name, statbuf.st_mode);
+    }
+#endif
 }
 
-int
-__gnat_is_writable_file (char *name)
+void
+__gnat_set_executable (char *name)
 {
-  int ret;
-  int mode;
-  struct stat statbuf;
+#if defined (_WIN32) && !defined (RTX)
+  TCHAR wname [GNAT_MAX_PATH_LEN + 2];
+
+  S2WSC (wname, name, GNAT_MAX_PATH_LEN + 2);
+
+  if (__gnat_can_use_acl (wname))
+    __gnat_set_OWNER_ACL (wname, GRANT_ACCESS, FILE_GENERIC_EXECUTE);
+
+#elif ! defined (__vxworks) && ! defined(__nucleus__)
+  GNAT_STRUCT_STAT statbuf;
 
-  ret = __gnat_stat (name, &statbuf);
-  mode = statbuf.st_mode & S_IWUSR;
-  return (!ret && mode);
+  if (GNAT_STAT (name, &statbuf) == 0)
+    {
+      statbuf.st_mode = statbuf.st_mode | S_IXUSR;
+      chmod (name, statbuf.st_mode);
+    }
+#endif
 }
 
 void
-__gnat_set_writable (char *name)
+__gnat_set_non_writable (char *name)
 {
-#if ! defined (__vxworks) && ! defined(__nucleus__)
-  struct stat statbuf;
+#if defined (_WIN32) && !defined (RTX)
+  TCHAR wname [GNAT_MAX_PATH_LEN + 2];
 
-  if (stat (name, &statbuf) == 0)
-  {
-    statbuf.st_mode = statbuf.st_mode | S_IWUSR;
-    chmod (name, statbuf.st_mode);
-  }
+  S2WSC (wname, name, GNAT_MAX_PATH_LEN + 2);
+
+  if (__gnat_can_use_acl (wname))
+    __gnat_set_OWNER_ACL
+      (wname, DENY_ACCESS,
+       FILE_WRITE_DATA | FILE_APPEND_DATA |
+       FILE_WRITE_EA | FILE_WRITE_ATTRIBUTES);
+
+  SetFileAttributes
+    (wname, GetFileAttributes (wname) | FILE_ATTRIBUTE_READONLY);
+#elif ! defined (__vxworks) && ! defined(__nucleus__)
+  GNAT_STRUCT_STAT statbuf;
+
+  if (GNAT_STAT (name, &statbuf) == 0)
+    {
+      statbuf.st_mode = statbuf.st_mode & 07577;
+      chmod (name, statbuf.st_mode);
+    }
 #endif
 }
 
 void
-__gnat_set_executable (char *name)
+__gnat_set_readable (char *name)
 {
-#if ! defined (__vxworks) && ! defined(__nucleus__)
-  struct stat statbuf;
+#if defined (_WIN32) && !defined (RTX)
+  TCHAR wname [GNAT_MAX_PATH_LEN + 2];
 
-  if (stat (name, &statbuf) == 0)
-  {
-    statbuf.st_mode = statbuf.st_mode | S_IXUSR;
-    chmod (name, statbuf.st_mode);
-  }
+  S2WSC (wname, name, GNAT_MAX_PATH_LEN + 2);
+
+  if (__gnat_can_use_acl (wname))
+    __gnat_set_OWNER_ACL (wname, GRANT_ACCESS, FILE_GENERIC_READ);
+
+#elif ! defined (__vxworks) && ! defined(__nucleus__)
+  GNAT_STRUCT_STAT statbuf;
+
+  if (GNAT_STAT (name, &statbuf) == 0)
+    {
+      chmod (name, statbuf.st_mode | S_IREAD);
+    }
 #endif
 }
 
 void
-__gnat_set_readonly (char *name)
+__gnat_set_non_readable (char *name)
 {
-#if ! defined (__vxworks) && ! defined(__nucleus__)
-  struct stat statbuf;
+#if defined (_WIN32) && !defined (RTX)
+  TCHAR wname [GNAT_MAX_PATH_LEN + 2];
 
-  if (stat (name, &statbuf) == 0)
-  {
-    statbuf.st_mode = statbuf.st_mode & 07577;
-    chmod (name, statbuf.st_mode);
-  }
+  S2WSC (wname, name, GNAT_MAX_PATH_LEN + 2);
+
+  if (__gnat_can_use_acl (wname))
+    __gnat_set_OWNER_ACL (wname, DENY_ACCESS, FILE_GENERIC_READ);
+
+#elif ! defined (__vxworks) && ! defined(__nucleus__)
+  GNAT_STRUCT_STAT statbuf;
+
+  if (GNAT_STAT (name, &statbuf) == 0)
+    {
+      chmod (name, statbuf.st_mode & (~S_IREAD));
+    }
 #endif
 }
 
 int
-__gnat_is_symbolic_link (char *name ATTRIBUTE_UNUSED)
+__gnat_is_symbolic_link_attr (char* name, struct file_attributes* attr)
 {
+   if (attr->symbolic_link == ATTR_UNSET) {
 #if defined (__vxworks) || defined (__nucleus__)
-  return 0;
+      attr->symbolic_link = 0;
 
 #elif defined (_AIX) || defined (__APPLE__) || defined (__unix__)
-  int ret;
-  struct stat statbuf;
-
-  ret = lstat (name, &statbuf);
-  return (!ret && S_ISLNK (statbuf.st_mode));
-
+      int ret;
+      GNAT_STRUCT_STAT statbuf;
+      ret = GNAT_LSTAT (name, &statbuf);
+      attr->symbolic_link = (!ret && S_ISLNK (statbuf.st_mode));
 #else
-  return 0;
+      attr->symbolic_link = 0;
 #endif
+   }
+   return attr->symbolic_link;
+}
+
+int
+__gnat_is_symbolic_link (char *name ATTRIBUTE_UNUSED)
+{
+   struct file_attributes attr;
+   __gnat_reset_attributes (&attr);
+   return __gnat_is_symbolic_link_attr (name, &attr);
+
 }
 
 #if defined (sun) && defined (__SVR4)
@@ -1722,7 +2297,10 @@ __gnat_portable_spawn (char *args[])
   int finished ATTRIBUTE_UNUSED;
   int pid ATTRIBUTE_UNUSED;
 
-#if defined (MSDOS) || defined (_WIN32)
+#if defined (__vxworks) || defined(__nucleus__) || defined(RTX)
+  return -1;
+
+#elif defined (_WIN32)
   /* args[0] must be quotes as it could contain a full pathname with spaces */
   char *args_0 = args[0];
   args[0] = (char *)xmalloc (strlen (args_0) + 3);
@@ -1741,16 +2319,8 @@ __gnat_portable_spawn (char *args[])
   else
     return status;
 
-#elif defined (__vxworks) || defined(__nucleus__)
-  return -1;
 #else
 
-#ifdef __EMX__
-  pid = spawnvp (P_NOWAIT, args[0], args);
-  if (pid == -1)
-    return -1;
-
-#else
   pid = fork ();
   if (pid < 0)
     return -1;
@@ -1765,7 +2335,6 @@ __gnat_portable_spawn (char *args[])
        _exit (1);
 #endif
     }
-#endif
 
   /* The parent.  */
   finished = waitpid (pid, &status, 0);
@@ -1809,97 +2378,121 @@ __gnat_dup2 (int oldfd, int newfd)
 #endif
 }
 
+int
+__gnat_number_of_cpus (void)
+{
+  int cores = 1;
+
+#if defined (linux) || defined (sun) || defined (AIX) \
+    || (defined (__alpha__)  && defined (_osf_)) || defined (__APPLE__)
+  cores = (int) sysconf (_SC_NPROCESSORS_ONLN);
+
+#elif (defined (__mips) && defined (__sgi))
+  cores = (int) sysconf (_SC_NPROC_ONLN);
+
+#elif defined (__hpux__)
+  struct pst_dynamic psd;
+  if (pstat_getdynamic (&psd, sizeof (psd), 1, 0) != -1)
+    cores = (int) psd.psd_proc_cnt;
+
+#elif defined (_WIN32)
+  SYSTEM_INFO sysinfo;
+  GetSystemInfo (&sysinfo);
+  cores = (int) sysinfo.dwNumberOfProcessors;
+
+#elif defined (VMS)
+  int code = SYI$_ACTIVECPU_CNT;
+  unsigned int res;
+  int status;
+
+  status = LIB$GETSYI (&code, &res);
+  if ((status & 1) != 0)
+    cores = res;
+#endif
+
+  return cores;
+}
+
 /* WIN32 code to implement a wait call that wait for any child process.  */
 
-#ifdef _WIN32
+#if defined (_WIN32) && !defined (RTX)
 
 /* Synchronization code, to be thread safe.  */
 
-static CRITICAL_SECTION plist_cs;
+#ifdef CERT
 
-void
-__gnat_plist_init (void)
-{
-  InitializeCriticalSection (&plist_cs);
-}
+/* For the Cert run times on native Windows we use dummy functions
+   for locking and unlocking tasks since we do not support multiple
+   threads on this configuration (Cert run time on native Windows). */
 
-static void
-plist_enter (void)
-{
-  EnterCriticalSection (&plist_cs);
-}
+void dummy (void) {}
 
-static void
-plist_leave (void)
-{
-  LeaveCriticalSection (&plist_cs);
-}
+void (*Lock_Task) ()   = &dummy;
+void (*Unlock_Task) () = &dummy;
 
-typedef struct _process_list
-{
-  HANDLE h;
-  struct _process_list *next;
-} Process_List;
+#else
 
-static Process_List *PLIST = NULL;
+#define Lock_Task system__soft_links__lock_task
+extern void (*Lock_Task) (void);
 
-static int plist_length = 0;
+#define Unlock_Task system__soft_links__unlock_task
+extern void (*Unlock_Task) (void);
+
+#endif
+
+static HANDLE *HANDLES_LIST = NULL;
+static int *PID_LIST = NULL, plist_length = 0, plist_max_length = 0;
 
 static void
-add_handle (HANDLE h)
+add_handle (HANDLE h, int pid)
 {
-  Process_List *pl;
 
-  pl = (Process_List *) xmalloc (sizeof (Process_List));
+  /* -------------------- critical section -------------------- */
+  (*Lock_Task) ();
 
-  plist_enter();
+  if (plist_length == plist_max_length)
+    {
+      plist_max_length += 1000;
+      HANDLES_LIST =
+        xrealloc (HANDLES_LIST, sizeof (HANDLE) * plist_max_length);
+      PID_LIST =
+        xrealloc (PID_LIST, sizeof (int) * plist_max_length);
+    }
 
-  /* -------------------- critical section -------------------- */
-  pl->h = h;
-  pl->next = PLIST;
-  PLIST = pl;
+  HANDLES_LIST[plist_length] = h;
+  PID_LIST[plist_length] = pid;
   ++plist_length;
-  /* -------------------- critical section -------------------- */
 
-  plist_leave();
+  (*Unlock_Task) ();
+  /* -------------------- critical section -------------------- */
 }
 
-static void
-remove_handle (HANDLE h)
+void
+__gnat_win32_remove_handle (HANDLE h, int pid)
 {
-  Process_List *pl;
-  Process_List *prev = NULL;
-
-  plist_enter();
+  int j;
 
   /* -------------------- critical section -------------------- */
-  pl = PLIST;
-  while (pl)
+  (*Lock_Task) ();
+
+  for (j = 0; j < plist_length; j++)
     {
-      if (pl->h == h)
+      if ((HANDLES_LIST[j] == h) || (PID_LIST[j] == pid))
         {
-          if (pl == PLIST)
-           PLIST = pl->next;
-          else
-           prev->next = pl->next;
-          free (pl);
+          CloseHandle (h);
+          --plist_length;
+          HANDLES_LIST[j] = HANDLES_LIST[plist_length];
+          PID_LIST[j] = PID_LIST[plist_length];
           break;
         }
-      else
-        {
-          prev = pl;
-          pl = pl->next;
-        }
     }
 
-  --plist_length;
+  (*Unlock_Task) ();
   /* -------------------- critical section -------------------- */
-
-  plist_leave();
 }
 
-static int
-win32_no_block_spawn (char *command, char *args[])
+static void
+win32_no_block_spawn (char *command, char *args[], HANDLE *h, int *pid)
 {
   BOOL result;
   STARTUPINFO SI;
@@ -1950,7 +2543,7 @@ win32_no_block_spawn (char *command, char *args[])
     int wsize = csize * 2;
     TCHAR *wcommand = (TCHAR *) xmalloc (wsize);
 
-    S2WSU (wcommand, full_command, wsize);
+    S2WSC (wcommand, full_command, wsize);
 
     free (full_command);
 
@@ -1963,23 +2556,26 @@ win32_no_block_spawn (char *command, char *args[])
 
   if (result == TRUE)
     {
-      add_handle (PI.hProcess);
       CloseHandle (PI.hThread);
-      return (int) PI.hProcess;
+      *h = PI.hProcess;
+      *pid = PI.dwProcessId;
     }
   else
-    return -1;
+    {
+      *h = NULL;
+      *pid = 0;
+    }
 }
 
 static int
 win32_wait (int *status)
 {
-  DWORD exitcode;
+  DWORD exitcode, pid;
   HANDLE *hl;
   HANDLE h;
   DWORD res;
   int k;
-  Process_List *pl;
+  int hl_len;
 
   if (plist_length == 0)
     {
@@ -1987,33 +2583,31 @@ win32_wait (int *status)
       return -1;
     }
 
-  hl = (HANDLE *) xmalloc (sizeof (HANDLE) * plist_length);
-
   k = 0;
-  plist_enter();
 
   /* -------------------- critical section -------------------- */
-  pl = PLIST;
-  while (pl)
-    {
-      hl[k++] = pl->h;
-      pl = pl->next;
-    }
-  /* -------------------- critical section -------------------- */
+  (*Lock_Task) ();
 
-  plist_leave();
+  hl_len = plist_length;
 
-  res = WaitForMultipleObjects (plist_length, hl, FALSE, INFINITE);
-  h = hl[res - WAIT_OBJECT_0];
-  free (hl);
+  hl = (HANDLE *) xmalloc (sizeof (HANDLE) * hl_len);
 
-  remove_handle (h);
+  memmove (hl, HANDLES_LIST, sizeof (HANDLE) * hl_len);
+
+  (*Unlock_Task) ();
+  /* -------------------- critical section -------------------- */
+
+  res = WaitForMultipleObjects (hl_len, hl, FALSE, INFINITE);
+  h = hl[res - WAIT_OBJECT_0];
 
   GetExitCodeProcess (h, &exitcode);
-  CloseHandle (h);
+  pid = PID_LIST [res - WAIT_OBJECT_0];
+  __gnat_win32_remove_handle (h, -1);
+
+  free (hl);
 
   *status = (int) exitcode;
-  return (int) h;
+  return (int) pid;
 }
 
 #endif
@@ -2021,31 +2615,27 @@ win32_wait (int *status)
 int
 __gnat_portable_no_block_spawn (char *args[])
 {
-  int pid = 0;
 
-#if defined (__EMX__) || defined (MSDOS)
-
-  /* ??? For PC machines I (Franco) don't know the system calls to implement
-     this routine. So I'll fake it as follows. This routine will behave
-     exactly like the blocking portable_spawn and will systematically return
-     a pid of 0 unless the spawned task did not complete successfully, in
-     which case we return a pid of -1.  To synchronize with this the
-     portable_wait below systematically returns a pid of 0 and reports that
-     the subprocess terminated successfully. */
-
-  if (spawnvp (P_WAIT, args[0], args) != 0)
-    return -1;
+#if defined (__vxworks) || defined (__nucleus__) || defined (RTX)
+  return -1;
 
 #elif defined (_WIN32)
 
-  pid = win32_no_block_spawn (args[0], args);
-  return pid;
+  HANDLE h = NULL;
+  int pid;
 
-#elif defined (__vxworks) || defined (__nucleus__)
-  return -1;
+  win32_no_block_spawn (args[0], args, &h, &pid);
+  if (h != NULL)
+    {
+      add_handle (h, pid);
+      return pid;
+    }
+  else
+    return -1;
 
 #else
-  pid = fork ();
+
+  int pid = fork ();
 
   if (pid == 0)
     {
@@ -2058,9 +2648,9 @@ __gnat_portable_no_block_spawn (char *args[])
 #endif
     }
 
-#endif
-
   return pid;
+
+  #endif
 }
 
 int
@@ -2069,16 +2659,13 @@ __gnat_portable_wait (int *process_status)
   int status = 0;
   int pid = 0;
 
-#if defined (_WIN32)
+#if defined (__vxworks) || defined (__nucleus__) || defined (RTX)
+  /* Not sure what to do here, so do nothing but return zero.  */
 
-  pid = win32_wait (&status);
+#elif defined (_WIN32)
 
-#elif defined (__EMX__) || defined (MSDOS)
-  /* ??? See corresponding comment in portable_no_block_spawn.  */
+  pid = win32_wait (&status);
 
-#elif defined (__vxworks) || defined (__nucleus__)
-  /* Not sure what to do here, so do same as __EMX__ case, i.e., nothing but
-     return zero.  */
 #else
 
   pid = waitpid (-1, &status, 0);
@@ -2101,7 +2688,7 @@ char *
 __gnat_locate_regular_file (char *file_name, char *path_val)
 {
   char *ptr;
-  char *file_path = alloca (strlen (file_name) + 1);
+  char *file_path = (char *) alloca (strlen (file_name) + 1);
   int absolute;
 
   /* Return immediately if file_name is empty */
@@ -2150,16 +2737,11 @@ __gnat_locate_regular_file (char *file_name, char *path_val)
 
   {
     /* The result has to be smaller than path_val + file_name.  */
-    char *file_path = alloca (strlen (path_val) + strlen (file_name) + 2);
+    char *file_path =
+      (char *) alloca (strlen (path_val) + strlen (file_name) + 2);
 
     for (;;)
       {
-        for (; *path_val == PATH_SEPARATOR; path_val++)
-          ;
-
-      if (*path_val == 0)
-        return 0;
-
       /* Skip the starting quote */
 
       if (*path_val == '"')
@@ -2168,7 +2750,14 @@ __gnat_locate_regular_file (char *file_name, char *path_val)
       for (ptr = file_path; *path_val && *path_val != PATH_SEPARATOR; )
        *ptr++ = *path_val++;
 
-      ptr--;
+      /* If directory is empty, it is the current directory*/
+
+      if (ptr == file_path)
+        {
+         *ptr = '.';
+        }
+      else
+        ptr--;
 
       /* Skip the ending quote */
 
@@ -2182,6 +2771,13 @@ __gnat_locate_regular_file (char *file_name, char *path_val)
 
       if (__gnat_is_regular_file (file_path))
         return xstrdup (file_path);
+
+      if (*path_val == 0)
+        return 0;
+
+      /* Skip path separator */
+
+      path_val++;
       }
   }
 
@@ -2198,8 +2794,9 @@ __gnat_locate_exec (char *exec_name, char *path_val)
   char *ptr;
   if (!strstr (exec_name, HOST_EXECUTABLE_SUFFIX))
     {
-      char *full_exec_name
-        = alloca (strlen (exec_name) + strlen (HOST_EXECUTABLE_SUFFIX) + 1);
+      char *full_exec_name =
+        (char *) alloca
+         (strlen (exec_name) + strlen (HOST_EXECUTABLE_SUFFIX) + 1);
 
       strcpy (full_exec_name, exec_name);
       strcat (full_exec_name, HOST_EXECUTABLE_SUFFIX);
@@ -2220,7 +2817,7 @@ __gnat_locate_exec_on_path (char *exec_name)
 {
   char *apath_val;
 
-#ifdef _WIN32
+#if defined (_WIN32) && !defined (RTX)
   TCHAR *wpath_val = _tgetenv (_T("PATH"));
   TCHAR *wapath_val;
   /* In Win32 systems we expand the PATH as for XP environment
@@ -2241,7 +2838,7 @@ __gnat_locate_exec_on_path (char *exec_name)
 
   apath_val = alloca (EXPAND_BUFFER_SIZE);
 
-  WS2SU (apath_val, wapath_val, EXPAND_BUFFER_SIZE);
+  WS2SC (apath_val, wapath_val, EXPAND_BUFFER_SIZE);
   return __gnat_locate_exec (exec_name, apath_val);
 
 #else
@@ -2252,7 +2849,7 @@ __gnat_locate_exec_on_path (char *exec_name)
   char *path_val = getenv ("PATH");
 #endif
   if (path_val == NULL) return NULL;
-  apath_val = alloca (strlen (path_val) + 1);
+  apath_val = (char *) alloca (strlen (path_val) + 1);
   strcpy (apath_val, path_val);
   return __gnat_locate_exec (exec_name, apath_val);
 #endif
@@ -2770,7 +3367,8 @@ __gnat_to_canonical_file_list_init
 char *
 __gnat_to_canonical_file_list_next (void)
 {
-  return (char *) "";
+  static char empty[] = "";
+  return empty;
 }
 
 void
@@ -2815,14 +3413,6 @@ __gnat_adjust_os_resource_limits (void)
 
 #endif
 
-/* For EMX, we cannot include dummy in libgcc, since it is too difficult
-   to coordinate this with the EMX distribution. Consequently, we put the
-   definition of dummy which is used for exception handling, here.  */
-
-#if defined (__EMX__)
-void __dummy () {}
-#endif
-
 #if defined (__mips_vxworks)
 int
 _flush_cache()
@@ -2831,12 +3421,14 @@ _flush_cache()
 }
 #endif
 
-#if defined (CROSS_DIRECTORY_STRUCTURE)  \
+#if defined (IS_CROSS)  \
   || (! ((defined (sparc) || defined (i386)) && defined (sun) \
       && defined (__SVR4)) \
       && ! (defined (linux) && (defined (i386) || defined (__x86_64__))) \
       && ! (defined (linux) && defined (__ia64__)) \
+      && ! (defined (linux) && defined (powerpc)) \
       && ! defined (__FreeBSD__) \
+      && ! defined (__Lynx__) \
       && ! defined (__hpux__) \
       && ! defined (__APPLE__) \
       && ! defined (_AIX) \
@@ -2901,11 +3493,68 @@ __gnat_copy_attribs (char *from, char *to, int mode)
 {
 #if defined (VMS) || defined (__vxworks) || defined (__nucleus__)
   return -1;
+
+#elif defined (_WIN32) && !defined (RTX)
+  TCHAR wfrom [GNAT_MAX_PATH_LEN + 2];
+  TCHAR wto [GNAT_MAX_PATH_LEN + 2];
+  BOOL res;
+  FILETIME fct, flat, flwt;
+  HANDLE hfrom, hto;
+
+  S2WSC (wfrom, from, GNAT_MAX_PATH_LEN + 2);
+  S2WSC (wto, to, GNAT_MAX_PATH_LEN + 2);
+
+  /* retrieve from times */
+
+  hfrom = CreateFile
+    (wfrom, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
+
+  if (hfrom == INVALID_HANDLE_VALUE)
+    return -1;
+
+  res = GetFileTime (hfrom, &fct, &flat, &flwt);
+
+  CloseHandle (hfrom);
+
+  if (res == 0)
+    return -1;
+
+  /* retrieve from times */
+
+  hto = CreateFile
+    (wto, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
+
+  if (hto == INVALID_HANDLE_VALUE)
+    return -1;
+
+  res = SetFileTime (hto, NULL, &flat, &flwt);
+
+  CloseHandle (hto);
+
+  if (res == 0)
+    return -1;
+
+  /* Set file attributes in full mode. */
+
+  if (mode == 1)
+    {
+      DWORD attribs = GetFileAttributes (wfrom);
+
+      if (attribs == INVALID_FILE_ATTRIBUTES)
+       return -1;
+
+      res = SetFileAttributes (wto, attribs);
+      if (res == 0)
+       return -1;
+    }
+
+  return 0;
+
 #else
-  struct stat fbuf;
+  GNAT_STRUCT_STAT fbuf;
   struct utimbuf tbuf;
 
-  if (stat (from, &fbuf) == -1)
+  if (GNAT_STAT (from, &fbuf) == -1)
     {
       return -1;
     }
@@ -2949,7 +3598,7 @@ get_gcc_version (void)
 
 int
 __gnat_set_close_on_exec (int fd ATTRIBUTE_UNUSED,
-                        int close_on_exec_p ATTRIBUTE_UNUSED)
+                          int close_on_exec_p ATTRIBUTE_UNUSED)
 {
 #if defined (F_GETFD) && defined (FD_CLOEXEC) && ! defined (__vxworks)
   int flags = fcntl (fd, F_GETFD, 0);
@@ -2960,19 +3609,24 @@ __gnat_set_close_on_exec (int fd ATTRIBUTE_UNUSED,
   else
     flags &= ~FD_CLOEXEC;
   return fcntl (fd, F_SETFD, flags | FD_CLOEXEC);
+#elif defined(_WIN32)
+  HANDLE h = (HANDLE) _get_osfhandle (fd);
+  if (h == (HANDLE) -1)
+    return -1;
+  if (close_on_exec_p)
+    return ! SetHandleInformation (h, HANDLE_FLAG_INHERIT, 0);
+  return ! SetHandleInformation (h, HANDLE_FLAG_INHERIT,
+    HANDLE_FLAG_INHERIT);
 #else
+  /* TODO: Unimplemented. */
   return -1;
-  /* For the Windows case, we should use SetHandleInformation to remove
-     the HANDLE_INHERIT property from fd. This is not implemented yet,
-     but for our purposes (support of GNAT.Expect) this does not matter,
-     as by default handles are *not* inherited. */
 #endif
 }
 
 /* Indicates if platforms supports automatic initialization through the
    constructor mechanism */
 int
-__gnat_binder_supports_auto_init ()
+__gnat_binder_supports_auto_init (void)
 {
 #ifdef VMS
    return 0;
@@ -2984,7 +3638,7 @@ __gnat_binder_supports_auto_init ()
 /* Indicates that Stand-Alone Libraries are automatically initialized through
    the constructor mechanism */
 int
-__gnat_sals_init_using_constructors ()
+__gnat_sals_init_using_constructors (void)
 {
 #if defined (__vxworks) || defined (__Lynx__) || defined (VMS)
    return 0;
@@ -2992,3 +3646,43 @@ __gnat_sals_init_using_constructors ()
    return 1;
 #endif
 }
+
+#ifdef RTX
+
+/* In RTX mode, the procedure to get the time (as file time) is different
+   in RTSS mode and Win32 mode. In order to avoid duplicating an Ada file,
+   we introduce an intermediate procedure to link against the corresponding
+   one in each situation. */
+
+extern void GetTimeAsFileTime(LPFILETIME pTime);
+
+void GetTimeAsFileTime(LPFILETIME pTime)
+{
+#ifdef RTSS
+  RtGetRtssTimeAsFileTime (pTime); /* RTSS interface */
+#else
+  GetSystemTimeAsFileTime (pTime); /* w32 interface */
+#endif
+}
+
+#ifdef RTSS
+/* Add symbol that is required to link. It would otherwise be taken from
+   libgcc.a and it would try to use the gcc constructors that are not
+   supported by Microsoft linker. */
+
+extern void __main (void);
+
+void __main (void) {}
+#endif
+#endif
+
+#if defined (linux)
+/* There is no function in the glibc to retrieve the LWP of the current
+   thread. We need to do a system call in order to retrieve this
+   information. */
+#include <sys/syscall.h>
+void *__gnat_lwp_self (void)
+{
+   return (void *) syscall (__NR_gettid);
+}
+#endif