OSDN Git Service

* gcc-interface/decl.c (gnat_to_gnu_entity) <E_Class_Wide_Type>: Fix
[pf3gnuchains/gcc-fork.git] / gcc / ada / adaint.c
1 /****************************************************************************
2  *                                                                          *
3  *                         GNAT COMPILER COMPONENTS                         *
4  *                                                                          *
5  *                               A D A I N T                                *
6  *                                                                          *
7  *                          C Implementation File                           *
8  *                                                                          *
9  *          Copyright (C) 1992-2009, Free Software Foundation, Inc.         *
10  *                                                                          *
11  * GNAT is free software;  you can  redistribute it  and/or modify it under *
12  * terms of the  GNU General Public License as published  by the Free Soft- *
13  * ware  Foundation;  either version 3,  or (at your option) any later ver- *
14  * sion.  GNAT is distributed in the hope that it will be useful, but WITH- *
15  * OUT ANY WARRANTY;  without even the  implied warranty of MERCHANTABILITY *
16  * or FITNESS FOR A PARTICULAR PURPOSE.                                     *
17  *                                                                          *
18  * As a special exception under Section 7 of GPL version 3, you are granted *
19  * additional permissions described in the GCC Runtime Library Exception,   *
20  * version 3.1, as published by the Free Software Foundation.               *
21  *                                                                          *
22  * You should have received a copy of the GNU General Public License and    *
23  * a copy of the GCC Runtime Library Exception along with this program;     *
24  * see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see    *
25  * <http://www.gnu.org/licenses/>.                                          *
26  *                                                                          *
27  * GNAT was originally developed  by the GNAT team at  New York University. *
28  * Extensive contributions were provided by Ada Core Technologies Inc.      *
29  *                                                                          *
30  ****************************************************************************/
31
32 /* This file contains those routines named by Import pragmas in
33    packages in the GNAT hierarchy (especially GNAT.OS_Lib) and in
34    package Osint.  Many of the subprograms in OS_Lib import standard
35    library calls directly. This file contains all other routines.  */
36
37 #ifdef __vxworks
38
39 /* No need to redefine exit here.  */
40 #undef exit
41
42 /* We want to use the POSIX variants of include files.  */
43 #define POSIX
44 #include "vxWorks.h"
45
46 #if defined (__mips_vxworks)
47 #include "cacheLib.h"
48 #endif /* __mips_vxworks */
49
50 #endif /* VxWorks */
51
52 #ifdef VMS
53 #define _POSIX_EXIT 1
54 #define HOST_EXECUTABLE_SUFFIX ".exe"
55 #define HOST_OBJECT_SUFFIX ".obj"
56 #endif
57
58 #ifdef IN_RTS
59 #include "tconfig.h"
60 #include "tsystem.h"
61
62 #include <sys/stat.h>
63 #include <fcntl.h>
64 #include <time.h>
65 #ifdef VMS
66 #include <unixio.h>
67 #endif
68
69 /* We don't have libiberty, so use malloc.  */
70 #define xmalloc(S) malloc (S)
71 #define xrealloc(V,S) realloc (V,S)
72 #else
73 #include "config.h"
74 #include "system.h"
75 #include "version.h"
76 #endif
77
78 #if defined (__MINGW32__)
79
80 #if defined (RTX)
81 #include <windows.h>
82 #include <Rtapi.h>
83 #else
84 #include "mingw32.h"
85
86 /* Current code page to use, set in initialize.c.  */
87 UINT CurrentCodePage;
88 #endif
89
90 #include <sys/utime.h>
91
92 /* For isalpha-like tests in the compiler, we're expected to resort to
93    safe-ctype.h/ISALPHA.  This isn't available for the runtime library
94    build, so we fallback on ctype.h/isalpha there.  */
95
96 #ifdef IN_RTS
97 #include <ctype.h>
98 #define ISALPHA isalpha
99 #endif
100
101 #elif defined (__Lynx__)
102
103 /* Lynx utime.h only defines the entities of interest to us if
104    defined (VMOS_DEV), so ... */
105 #define VMOS_DEV
106 #include <utime.h>
107 #undef VMOS_DEV
108
109 #elif !defined (VMS)
110 #include <utime.h>
111 #endif
112
113 /* wait.h processing */
114 #ifdef __MINGW32__
115 #if OLD_MINGW
116 #include <sys/wait.h>
117 #endif
118 #elif defined (__vxworks) && defined (__RTP__)
119 #include <wait.h>
120 #elif defined (__Lynx__)
121 /* ??? We really need wait.h and it includes resource.h on Lynx.  GCC
122    has a resource.h header as well, included instead of the lynx
123    version in our setup, causing lots of errors.  We don't really need
124    the lynx contents of this file, so just workaround the issue by
125    preventing the inclusion of the GCC header from doing anything.  */
126 #define GCC_RESOURCE_H
127 #include <sys/wait.h>
128 #elif defined (__nucleus__)
129 /* No wait() or waitpid() calls available */
130 #else
131 /* Default case */
132 #include <sys/wait.h>
133 #endif
134
135 #if defined (__EMX__) || defined (MSDOS) || defined (_WIN32)
136 #elif defined (VMS)
137
138 /* Header files and definitions for __gnat_set_file_time_name.  */
139
140 #define __NEW_STARLET 1
141 #include <vms/rms.h>
142 #include <vms/atrdef.h>
143 #include <vms/fibdef.h>
144 #include <vms/stsdef.h>
145 #include <vms/iodef.h>
146 #include <errno.h>
147 #include <vms/descrip.h>
148 #include <string.h>
149 #include <unixlib.h>
150
151 /* Use native 64-bit arithmetic.  */
152 #define unix_time_to_vms(X,Y) \
153   { unsigned long long reftime, tmptime = (X); \
154     $DESCRIPTOR (unixtime,"1-JAN-1970 0:00:00.00"); \
155     SYS$BINTIM (&unixtime, &reftime); \
156     Y = tmptime * 10000000 + reftime; }
157
158 /* descrip.h doesn't have everything ... */
159 typedef struct fibdef* __fibdef_ptr32 __attribute__ (( mode (SI) ));
160 struct dsc$descriptor_fib
161 {
162   unsigned int fib$l_len;
163   __fibdef_ptr32 fib$l_addr;
164 };
165
166 /* I/O Status Block.  */
167 struct IOSB
168 {
169   unsigned short status, count;
170   unsigned int devdep;
171 };
172
173 static char *tryfile;
174
175 /* Variable length string.  */
176 struct vstring
177 {
178   short length;
179   char string[NAM$C_MAXRSS+1];
180 };
181
182 #else
183 #include <utime.h>
184 #endif
185
186 #if defined (__EMX__) || defined (MSDOS) || defined (_WIN32)
187 #include <process.h>
188 #endif
189
190 #if defined (_WIN32)
191
192 #include <dir.h>
193 #include <windows.h>
194 #include <accctrl.h>
195 #include <aclapi.h>
196 #undef DIR_SEPARATOR
197 #define DIR_SEPARATOR '\\'
198 #endif
199
200 #include "adaint.h"
201
202 /* Define symbols O_BINARY and O_TEXT as harmless zeroes if they are not
203    defined in the current system. On DOS-like systems these flags control
204    whether the file is opened/created in text-translation mode (CR/LF in
205    external file mapped to LF in internal file), but in Unix-like systems,
206    no text translation is required, so these flags have no effect.  */
207
208 #if defined (__EMX__)
209 #include <os2.h>
210 #endif
211
212 #if defined (MSDOS)
213 #include <dos.h>
214 #endif
215
216 #ifndef O_BINARY
217 #define O_BINARY 0
218 #endif
219
220 #ifndef O_TEXT
221 #define O_TEXT 0
222 #endif
223
224 #ifndef HOST_EXECUTABLE_SUFFIX
225 #define HOST_EXECUTABLE_SUFFIX ""
226 #endif
227
228 #ifndef HOST_OBJECT_SUFFIX
229 #define HOST_OBJECT_SUFFIX ".o"
230 #endif
231
232 #ifndef PATH_SEPARATOR
233 #define PATH_SEPARATOR ':'
234 #endif
235
236 #ifndef DIR_SEPARATOR
237 #define DIR_SEPARATOR '/'
238 #endif
239
240 /* Check for cross-compilation */
241 #if defined (CROSS_COMPILE) || defined (CROSS_DIRECTORY_STRUCTURE)
242 #define IS_CROSS 1
243 int __gnat_is_cross_compiler = 1;
244 #else
245 #undef IS_CROSS
246 int __gnat_is_cross_compiler = 0;
247 #endif
248
249 char __gnat_dir_separator = DIR_SEPARATOR;
250
251 char __gnat_path_separator = PATH_SEPARATOR;
252
253 /* The GNAT_LIBRARY_TEMPLATE contains a list of expressions that define
254    the base filenames that libraries specified with -lsomelib options
255    may have. This is used by GNATMAKE to check whether an executable
256    is up-to-date or not. The syntax is
257
258      library_template ::= { pattern ; } pattern NUL
259      pattern          ::= [ prefix ] * [ postfix ]
260
261    These should only specify names of static libraries as it makes
262    no sense to determine at link time if dynamic-link libraries are
263    up to date or not. Any libraries that are not found are supposed
264    to be up-to-date:
265
266      * if they are needed but not present, the link
267        will fail,
268
269      * otherwise they are libraries in the system paths and so
270        they are considered part of the system and not checked
271        for that reason.
272
273    ??? This should be part of a GNAT host-specific compiler
274        file instead of being included in all user applications
275        as well. This is only a temporary work-around for 3.11b.  */
276
277 #ifndef GNAT_LIBRARY_TEMPLATE
278 #if defined (__EMX__)
279 #define GNAT_LIBRARY_TEMPLATE "*.a"
280 #elif defined (VMS)
281 #define GNAT_LIBRARY_TEMPLATE "*.olb"
282 #else
283 #define GNAT_LIBRARY_TEMPLATE "lib*.a"
284 #endif
285 #endif
286
287 const char *__gnat_library_template = GNAT_LIBRARY_TEMPLATE;
288
289 /* This variable is used in hostparm.ads to say whether the host is a VMS
290    system.  */
291 #ifdef VMS
292 const int __gnat_vmsp = 1;
293 #else
294 const int __gnat_vmsp = 0;
295 #endif
296
297 #ifdef __EMX__
298 #define GNAT_MAX_PATH_LEN MAX_PATH
299
300 #elif defined (VMS)
301 #define GNAT_MAX_PATH_LEN 256 /* PATH_MAX */
302
303 #elif defined (__vxworks) || defined (__OPENNT) || defined(__nucleus__)
304 #define GNAT_MAX_PATH_LEN PATH_MAX
305
306 #else
307
308 #if defined (__MINGW32__)
309 #include "mingw32.h"
310
311 #if OLD_MINGW
312 #include <sys/param.h>
313 #endif
314
315 #else
316 #include <sys/param.h>
317 #endif
318
319 #ifdef MAXPATHLEN
320 #define GNAT_MAX_PATH_LEN MAXPATHLEN
321 #else
322 #define GNAT_MAX_PATH_LEN 256
323 #endif
324
325 #endif
326
327 /* Used for Ada bindings */
328 const int __gnat_size_of_file_attributes = sizeof (struct file_attributes);
329
330 /* Reset the file attributes as if no system call had been performed */
331 void __gnat_stat_to_attr (int fd, char* name, struct file_attributes* attr);
332
333 /* The __gnat_max_path_len variable is used to export the maximum
334    length of a path name to Ada code. max_path_len is also provided
335    for compatibility with older GNAT versions, please do not use
336    it. */
337
338 int __gnat_max_path_len = GNAT_MAX_PATH_LEN;
339 int max_path_len = GNAT_MAX_PATH_LEN;
340
341 /* Control whether we can use ACL on Windows.  */
342
343 int __gnat_use_acl = 1;
344
345 /* The following macro HAVE_READDIR_R should be defined if the
346    system provides the routine readdir_r.  */
347 #undef HAVE_READDIR_R
348 \f
349 #if defined(VMS) && defined (__LONG_POINTERS)
350
351 /* Return a 32 bit pointer to an array of 32 bit pointers
352    given a 64 bit pointer to an array of 64 bit pointers */
353
354 typedef __char_ptr32 *__char_ptr_char_ptr32 __attribute__ ((mode (SI)));
355
356 static __char_ptr_char_ptr32
357 to_ptr32 (char **ptr64)
358 {
359   int argc;
360   __char_ptr_char_ptr32 short_argv;
361
362   for (argc=0; ptr64[argc]; argc++);
363
364   /* Reallocate argv with 32 bit pointers. */
365   short_argv = (__char_ptr_char_ptr32) decc$malloc
366     (sizeof (__char_ptr32) * (argc + 1));
367
368   for (argc=0; ptr64[argc]; argc++)
369     short_argv[argc] = (__char_ptr32) decc$strdup (ptr64[argc]);
370
371   short_argv[argc] = (__char_ptr32) 0;
372   return short_argv;
373
374 }
375 #define MAYBE_TO_PTR32(argv) to_ptr32 (argv)
376 #else
377 #define MAYBE_TO_PTR32(argv) argv
378 #endif
379
380 const char ATTR_UNSET = 127;
381
382 void
383 __gnat_reset_attributes
384   (struct file_attributes* attr)
385 {
386   attr->exists     = ATTR_UNSET;
387
388   attr->writable   = ATTR_UNSET;
389   attr->readable   = ATTR_UNSET;
390   attr->executable = ATTR_UNSET;
391
392   attr->regular    = ATTR_UNSET;
393   attr->symbolic_link = ATTR_UNSET;
394   attr->directory = ATTR_UNSET;
395
396   attr->timestamp = (OS_Time)-2;
397   attr->file_length = -1;
398 }
399
400 OS_Time
401 __gnat_current_time
402   (void)
403 {
404   time_t res = time (NULL);
405   return (OS_Time) res;
406 }
407
408 /* Return the current local time as a string in the ISO 8601 format of
409    "YYYY-MM-DD HH:MM:SS.SS". The returned string is 22 + 1 (NULL) characters
410    long. */
411
412 void
413 __gnat_current_time_string
414   (char *result)
415 {
416   const char *format = "%Y-%m-%d %H:%M:%S";
417   /* Format string necessary to describe the ISO 8601 format */
418
419   const time_t t_val = time (NULL);
420
421   strftime (result, 22, format, localtime (&t_val));
422   /* Convert the local time into a string following the ISO format, copying
423      at most 22 characters into the result string. */
424
425   result [19] = '.';
426   result [20] = '0';
427   result [21] = '0';
428   /* The sub-seconds are manually set to zero since type time_t lacks the
429      precision necessary for nanoseconds. */
430 }
431
432 void
433 __gnat_to_gm_time
434   (OS_Time *p_time,
435    int *p_year,
436    int *p_month,
437    int *p_day,
438    int *p_hours,
439    int *p_mins,
440    int *p_secs)
441 {
442   struct tm *res;
443   time_t time = (time_t) *p_time;
444
445 #ifdef _WIN32
446   /* On Windows systems, the time is sometimes rounded up to the nearest
447      even second, so if the number of seconds is odd, increment it.  */
448   if (time & 1)
449     time++;
450 #endif
451
452 #ifdef VMS
453   res = localtime (&time);
454 #else
455   res = gmtime (&time);
456 #endif
457
458   if (res)
459     {
460       *p_year = res->tm_year;
461       *p_month = res->tm_mon;
462       *p_day = res->tm_mday;
463       *p_hours = res->tm_hour;
464       *p_mins = res->tm_min;
465       *p_secs = res->tm_sec;
466     }
467   else
468     *p_year = *p_month = *p_day = *p_hours = *p_mins = *p_secs = 0;
469 }
470
471 /* Place the contents of the symbolic link named PATH in the buffer BUF,
472    which has size BUFSIZ.  If PATH is a symbolic link, then return the number
473    of characters of its content in BUF.  Otherwise, return -1.
474    For systems not supporting symbolic links, always return -1.  */
475
476 int
477 __gnat_readlink (char *path ATTRIBUTE_UNUSED,
478                  char *buf ATTRIBUTE_UNUSED,
479                  size_t bufsiz ATTRIBUTE_UNUSED)
480 {
481 #if defined (MSDOS) || defined (_WIN32) || defined (__EMX__) \
482   || defined (VMS) || defined(__vxworks) || defined (__nucleus__)
483   return -1;
484 #else
485   return readlink (path, buf, bufsiz);
486 #endif
487 }
488
489 /* Creates a symbolic link named NEWPATH which contains the string OLDPATH.
490    If NEWPATH exists it will NOT be overwritten.
491    For systems not supporting symbolic links, always return -1.  */
492
493 int
494 __gnat_symlink (char *oldpath ATTRIBUTE_UNUSED,
495                 char *newpath ATTRIBUTE_UNUSED)
496 {
497 #if defined (MSDOS) || defined (_WIN32) || defined (__EMX__) \
498   || defined (VMS) || defined(__vxworks) || defined (__nucleus__)
499   return -1;
500 #else
501   return symlink (oldpath, newpath);
502 #endif
503 }
504
505 /* Try to lock a file, return 1 if success.  */
506
507 #if defined (__vxworks) || defined (__nucleus__) || defined (MSDOS) \
508   || defined (_WIN32) || defined (__EMX__) || defined (VMS)
509
510 /* Version that does not use link. */
511
512 int
513 __gnat_try_lock (char *dir, char *file)
514 {
515   int fd;
516 #ifdef __MINGW32__
517   TCHAR wfull_path[GNAT_MAX_PATH_LEN];
518   TCHAR wfile[GNAT_MAX_PATH_LEN];
519   TCHAR wdir[GNAT_MAX_PATH_LEN];
520
521   S2WSC (wdir, dir, GNAT_MAX_PATH_LEN);
522   S2WSC (wfile, file, GNAT_MAX_PATH_LEN);
523
524   _stprintf (wfull_path, _T("%s%c%s"), wdir, _T(DIR_SEPARATOR), wfile);
525   fd = _topen (wfull_path, O_CREAT | O_EXCL, 0600);
526 #else
527   char full_path[256];
528
529   sprintf (full_path, "%s%c%s", dir, DIR_SEPARATOR, file);
530   fd = open (full_path, O_CREAT | O_EXCL, 0600);
531 #endif
532
533   if (fd < 0)
534     return 0;
535
536   close (fd);
537   return 1;
538 }
539
540 #else
541
542 /* Version using link(), more secure over NFS.  */
543 /* See TN 6913-016 for discussion ??? */
544
545 int
546 __gnat_try_lock (char *dir, char *file)
547 {
548   char full_path[256];
549   char temp_file[256];
550   GNAT_STRUCT_STAT stat_result;
551   int fd;
552
553   sprintf (full_path, "%s%c%s", dir, DIR_SEPARATOR, file);
554   sprintf (temp_file, "%s%cTMP-%ld-%ld",
555            dir, DIR_SEPARATOR, (long)getpid(), (long)getppid ());
556
557   /* Create the temporary file and write the process number.  */
558   fd = open (temp_file, O_CREAT | O_WRONLY, 0600);
559   if (fd < 0)
560     return 0;
561
562   close (fd);
563
564   /* Link it with the new file.  */
565   link (temp_file, full_path);
566
567   /* Count the references on the old one. If we have a count of two, then
568      the link did succeed. Remove the temporary file before returning.  */
569   __gnat_stat (temp_file, &stat_result);
570   unlink (temp_file);
571   return stat_result.st_nlink == 2;
572 }
573 #endif
574
575 /* Return the maximum file name length.  */
576
577 int
578 __gnat_get_maximum_file_name_length (void)
579 {
580 #if defined (MSDOS)
581   return 8;
582 #elif defined (VMS)
583   if (getenv ("GNAT$EXTENDED_FILE_SPECIFICATIONS"))
584     return -1;
585   else
586     return 39;
587 #else
588   return -1;
589 #endif
590 }
591
592 /* Return nonzero if file names are case sensitive.  */
593
594 int
595 __gnat_get_file_names_case_sensitive (void)
596 {
597 #if defined (__EMX__) || defined (MSDOS) || defined (VMS) || defined (WINNT)
598   return 0;
599 #else
600   return 1;
601 #endif
602 }
603
604 char
605 __gnat_get_default_identifier_character_set (void)
606 {
607 #if defined (__EMX__) || defined (MSDOS)
608   return 'p';
609 #else
610   return '1';
611 #endif
612 }
613
614 /* Return the current working directory.  */
615
616 void
617 __gnat_get_current_dir (char *dir, int *length)
618 {
619 #if defined (__MINGW32__)
620   TCHAR wdir[GNAT_MAX_PATH_LEN];
621
622   _tgetcwd (wdir, *length);
623
624   WS2SC (dir, wdir, GNAT_MAX_PATH_LEN);
625
626 #elif defined (VMS)
627    /* Force Unix style, which is what GNAT uses internally.  */
628    getcwd (dir, *length, 0);
629 #else
630    getcwd (dir, *length);
631 #endif
632
633    *length = strlen (dir);
634
635    if (dir [*length - 1] != DIR_SEPARATOR)
636      {
637        dir [*length] = DIR_SEPARATOR;
638        ++(*length);
639      }
640    dir[*length] = '\0';
641 }
642
643 /* Return the suffix for object files.  */
644
645 void
646 __gnat_get_object_suffix_ptr (int *len, const char **value)
647 {
648   *value = HOST_OBJECT_SUFFIX;
649
650   if (*value == 0)
651     *len = 0;
652   else
653     *len = strlen (*value);
654
655   return;
656 }
657
658 /* Return the suffix for executable files.  */
659
660 void
661 __gnat_get_executable_suffix_ptr (int *len, const char **value)
662 {
663   *value = HOST_EXECUTABLE_SUFFIX;
664   if (!*value)
665     *len = 0;
666   else
667     *len = strlen (*value);
668
669   return;
670 }
671
672 /* Return the suffix for debuggable files. Usually this is the same as the
673    executable extension.  */
674
675 void
676 __gnat_get_debuggable_suffix_ptr (int *len, const char **value)
677 {
678 #ifndef MSDOS
679   *value = HOST_EXECUTABLE_SUFFIX;
680 #else
681   /* On DOS, the extensionless COFF file is what gdb likes.  */
682   *value = "";
683 #endif
684
685   if (*value == 0)
686     *len = 0;
687   else
688     *len = strlen (*value);
689
690   return;
691 }
692
693 /* Returns the OS filename and corresponding encoding.  */
694
695 void
696 __gnat_os_filename (char *filename ATTRIBUTE_UNUSED,
697                     char *w_filename ATTRIBUTE_UNUSED,
698                     char *os_name, int *o_length,
699                     char *encoding ATTRIBUTE_UNUSED, int *e_length)
700 {
701 #if defined (_WIN32) && ! defined (__vxworks) && ! defined (IS_CROSS)
702   WS2SC (os_name, (TCHAR *)w_filename, (DWORD)*o_length);
703   *o_length = strlen (os_name);
704   strcpy (encoding, "encoding=utf8");
705   *e_length = strlen (encoding);
706 #else
707   strcpy (os_name, filename);
708   *o_length = strlen (filename);
709   *e_length = 0;
710 #endif
711 }
712
713 /* Delete a file.  */
714
715 int
716 __gnat_unlink (char *path)
717 {
718 #if defined (__MINGW32__) && ! defined (__vxworks) && ! defined (IS_CROSS)
719   {
720     TCHAR wpath[GNAT_MAX_PATH_LEN];
721
722     S2WSC (wpath, path, GNAT_MAX_PATH_LEN);
723     return _tunlink (wpath);
724   }
725 #else
726   return unlink (path);
727 #endif
728 }
729
730 /* Rename a file.  */
731
732 int
733 __gnat_rename (char *from, char *to)
734 {
735 #if defined (__MINGW32__) && ! defined (__vxworks) && ! defined (IS_CROSS)
736   {
737     TCHAR wfrom[GNAT_MAX_PATH_LEN], wto[GNAT_MAX_PATH_LEN];
738
739     S2WSC (wfrom, from, GNAT_MAX_PATH_LEN);
740     S2WSC (wto, to, GNAT_MAX_PATH_LEN);
741     return _trename (wfrom, wto);
742   }
743 #else
744   return rename (from, to);
745 #endif
746 }
747
748 /* Changing directory.  */
749
750 int
751 __gnat_chdir (char *path)
752 {
753 #if defined (__MINGW32__) && ! defined (__vxworks) && ! defined (IS_CROSS)
754   {
755     TCHAR wpath[GNAT_MAX_PATH_LEN];
756
757     S2WSC (wpath, path, GNAT_MAX_PATH_LEN);
758     return _tchdir (wpath);
759   }
760 #else
761   return chdir (path);
762 #endif
763 }
764
765 /* Removing a directory.  */
766
767 int
768 __gnat_rmdir (char *path)
769 {
770 #if defined (__MINGW32__) && ! defined (__vxworks) && ! defined (IS_CROSS)
771   {
772     TCHAR wpath[GNAT_MAX_PATH_LEN];
773
774     S2WSC (wpath, path, GNAT_MAX_PATH_LEN);
775     return _trmdir (wpath);
776   }
777 #elif defined (VTHREADS)
778   /* rmdir not available */
779   return -1;
780 #else
781   return rmdir (path);
782 #endif
783 }
784
785 FILE *
786 __gnat_fopen (char *path, char *mode, int encoding ATTRIBUTE_UNUSED)
787 {
788 #if defined (_WIN32) && ! defined (__vxworks) && ! defined (IS_CROSS)
789   TCHAR wpath[GNAT_MAX_PATH_LEN];
790   TCHAR wmode[10];
791
792   S2WS (wmode, mode, 10);
793
794   if (encoding == Encoding_Unspecified)
795     S2WSC (wpath, path, GNAT_MAX_PATH_LEN);
796   else if (encoding == Encoding_UTF8)
797     S2WSU (wpath, path, GNAT_MAX_PATH_LEN);
798   else
799     S2WS (wpath, path, GNAT_MAX_PATH_LEN);
800
801   return _tfopen (wpath, wmode);
802 #elif defined (VMS)
803   return decc$fopen (path, mode);
804 #else
805   return GNAT_FOPEN (path, mode);
806 #endif
807 }
808
809 FILE *
810 __gnat_freopen (char *path, char *mode, FILE *stream, int encoding ATTRIBUTE_UNUSED)
811 {
812 #if defined (_WIN32) && ! defined (__vxworks) && ! defined (IS_CROSS)
813   TCHAR wpath[GNAT_MAX_PATH_LEN];
814   TCHAR wmode[10];
815
816   S2WS (wmode, mode, 10);
817
818   if (encoding == Encoding_Unspecified)
819     S2WSC (wpath, path, GNAT_MAX_PATH_LEN);
820   else if (encoding == Encoding_UTF8)
821     S2WSU (wpath, path, GNAT_MAX_PATH_LEN);
822   else
823     S2WS (wpath, path, GNAT_MAX_PATH_LEN);
824
825   return _tfreopen (wpath, wmode, stream);
826 #elif defined (VMS)
827   return decc$freopen (path, mode, stream);
828 #else
829   return freopen (path, mode, stream);
830 #endif
831 }
832
833 int
834 __gnat_open_read (char *path, int fmode)
835 {
836   int fd;
837   int o_fmode = O_BINARY;
838
839   if (fmode)
840     o_fmode = O_TEXT;
841
842 #if defined (VMS)
843   /* Optional arguments mbc,deq,fop increase read performance.  */
844   fd = open (path, O_RDONLY | o_fmode, 0444,
845              "mbc=16", "deq=64", "fop=tef");
846 #elif defined (__vxworks)
847   fd = open (path, O_RDONLY | o_fmode, 0444);
848 #elif defined (__MINGW32__)
849  {
850    TCHAR wpath[GNAT_MAX_PATH_LEN];
851
852    S2WSC (wpath, path, GNAT_MAX_PATH_LEN);
853    fd = _topen (wpath, O_RDONLY | o_fmode, 0444);
854  }
855 #else
856   fd = open (path, O_RDONLY | o_fmode);
857 #endif
858
859   return fd < 0 ? -1 : fd;
860 }
861
862 #if defined (__EMX__) || defined (__MINGW32__)
863 #define PERM (S_IREAD | S_IWRITE)
864 #elif defined (VMS)
865 /* Excerpt from DECC C RTL Reference Manual:
866    To create files with OpenVMS RMS default protections using the UNIX
867    system-call functions umask, mkdir, creat, and open, call mkdir, creat,
868    and open with a file-protection mode argument of 0777 in a program
869    that never specifically calls umask. These default protections include
870    correctly establishing protections based on ACLs, previous versions of
871    files, and so on. */
872 #define PERM 0777
873 #else
874 #define PERM (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH)
875 #endif
876
877 int
878 __gnat_open_rw (char *path, int fmode)
879 {
880   int fd;
881   int o_fmode = O_BINARY;
882
883   if (fmode)
884     o_fmode = O_TEXT;
885
886 #if defined (VMS)
887   fd = open (path, O_RDWR | o_fmode, PERM,
888              "mbc=16", "deq=64", "fop=tef");
889 #elif defined (__MINGW32__)
890   {
891     TCHAR wpath[GNAT_MAX_PATH_LEN];
892
893     S2WSC (wpath, path, GNAT_MAX_PATH_LEN);
894     fd = _topen (wpath, O_RDWR | o_fmode, PERM);
895   }
896 #else
897   fd = open (path, O_RDWR | o_fmode, PERM);
898 #endif
899
900   return fd < 0 ? -1 : fd;
901 }
902
903 int
904 __gnat_open_create (char *path, int fmode)
905 {
906   int fd;
907   int o_fmode = O_BINARY;
908
909   if (fmode)
910     o_fmode = O_TEXT;
911
912 #if defined (VMS)
913   fd = open (path, O_WRONLY | O_CREAT | O_TRUNC | o_fmode, PERM,
914              "mbc=16", "deq=64", "fop=tef");
915 #elif defined (__MINGW32__)
916   {
917     TCHAR wpath[GNAT_MAX_PATH_LEN];
918
919     S2WSC (wpath, path, GNAT_MAX_PATH_LEN);
920     fd = _topen (wpath, O_WRONLY | O_CREAT | O_TRUNC | o_fmode, PERM);
921   }
922 #else
923   fd = open (path, O_WRONLY | O_CREAT | O_TRUNC | o_fmode, PERM);
924 #endif
925
926   return fd < 0 ? -1 : fd;
927 }
928
929 int
930 __gnat_create_output_file (char *path)
931 {
932   int fd;
933 #if defined (VMS)
934   fd = open (path, O_WRONLY | O_CREAT | O_TRUNC | O_TEXT, PERM,
935              "rfm=stmlf", "ctx=rec", "rat=none", "rop=nlk",
936              "shr=del,get,put,upd");
937 #elif defined (__MINGW32__)
938   {
939     TCHAR wpath[GNAT_MAX_PATH_LEN];
940
941     S2WSC (wpath, path, GNAT_MAX_PATH_LEN);
942     fd = _topen (wpath, O_WRONLY | O_CREAT | O_TRUNC | O_TEXT, PERM);
943   }
944 #else
945   fd = open (path, O_WRONLY | O_CREAT | O_TRUNC | O_TEXT, PERM);
946 #endif
947
948   return fd < 0 ? -1 : fd;
949 }
950
951 int
952 __gnat_create_output_file_new (char *path)
953 {
954   int fd;
955 #if defined (VMS)
956   fd = open (path, O_WRONLY | O_CREAT | O_TRUNC | O_TEXT | O_EXCL, PERM,
957              "rfm=stmlf", "ctx=rec", "rat=none", "rop=nlk",
958              "shr=del,get,put,upd");
959 #elif defined (__MINGW32__)
960   {
961     TCHAR wpath[GNAT_MAX_PATH_LEN];
962
963     S2WSC (wpath, path, GNAT_MAX_PATH_LEN);
964     fd = _topen (wpath, O_WRONLY | O_CREAT | O_TRUNC | O_TEXT | O_EXCL, PERM);
965   }
966 #else
967   fd = open (path, O_WRONLY | O_CREAT | O_TRUNC | O_TEXT | O_EXCL, PERM);
968 #endif
969
970   return fd < 0 ? -1 : fd;
971 }
972
973 int
974 __gnat_open_append (char *path, int fmode)
975 {
976   int fd;
977   int o_fmode = O_BINARY;
978
979   if (fmode)
980     o_fmode = O_TEXT;
981
982 #if defined (VMS)
983   fd = open (path, O_WRONLY | O_CREAT | O_APPEND | o_fmode, PERM,
984              "mbc=16", "deq=64", "fop=tef");
985 #elif defined (__MINGW32__)
986   {
987     TCHAR wpath[GNAT_MAX_PATH_LEN];
988
989     S2WSC (wpath, path, GNAT_MAX_PATH_LEN);
990     fd = _topen (wpath, O_WRONLY | O_CREAT | O_APPEND | o_fmode, PERM);
991   }
992 #else
993   fd = open (path, O_WRONLY | O_CREAT | O_APPEND | o_fmode, PERM);
994 #endif
995
996   return fd < 0 ? -1 : fd;
997 }
998
999 /*  Open a new file.  Return error (-1) if the file already exists.  */
1000
1001 int
1002 __gnat_open_new (char *path, int fmode)
1003 {
1004   int fd;
1005   int o_fmode = O_BINARY;
1006
1007   if (fmode)
1008     o_fmode = O_TEXT;
1009
1010 #if defined (VMS)
1011   fd = open (path, O_WRONLY | O_CREAT | O_EXCL | o_fmode, PERM,
1012              "mbc=16", "deq=64", "fop=tef");
1013 #elif defined (__MINGW32__)
1014   {
1015     TCHAR wpath[GNAT_MAX_PATH_LEN];
1016
1017     S2WSC (wpath, path, GNAT_MAX_PATH_LEN);
1018     fd = _topen (wpath, O_WRONLY | O_CREAT | O_EXCL | o_fmode, PERM);
1019   }
1020 #else
1021   fd = open (path, O_WRONLY | O_CREAT | O_EXCL | o_fmode, PERM);
1022 #endif
1023
1024   return fd < 0 ? -1 : fd;
1025 }
1026
1027 /* Open a new temp file.  Return error (-1) if the file already exists.
1028    Special options for VMS allow the file to be shared between parent and child
1029    processes, however they really slow down output.  Used in gnatchop.  */
1030
1031 int
1032 __gnat_open_new_temp (char *path, int fmode)
1033 {
1034   int fd;
1035   int o_fmode = O_BINARY;
1036
1037   strcpy (path, "GNAT-XXXXXX");
1038
1039 #if (defined (__FreeBSD__) || defined (__NetBSD__) || defined (__OpenBSD__) \
1040   || defined (linux) || defined(__GLIBC__)) && !defined (__vxworks)
1041   return mkstemp (path);
1042 #elif defined (__Lynx__)
1043   mktemp (path);
1044 #elif defined (__nucleus__)
1045   return -1;
1046 #else
1047   if (mktemp (path) == NULL)
1048     return -1;
1049 #endif
1050
1051   if (fmode)
1052     o_fmode = O_TEXT;
1053
1054 #if defined (VMS)
1055   fd = open (path, O_WRONLY | O_CREAT | O_EXCL | o_fmode, PERM,
1056              "rfm=stmlf", "ctx=rec", "rat=none", "shr=del,get,put,upd",
1057              "mbc=16", "deq=64", "fop=tef");
1058 #else
1059   fd = open (path, O_WRONLY | O_CREAT | O_EXCL | o_fmode, PERM);
1060 #endif
1061
1062   return fd < 0 ? -1 : fd;
1063 }
1064
1065 /****************************************************************
1066  ** Perform a call to GNAT_STAT or GNAT_FSTAT, and extract as much information
1067  ** as possible from it, storing the result in a cache for later reuse
1068  ****************************************************************/
1069
1070 void
1071 __gnat_stat_to_attr (int fd, char* name, struct file_attributes* attr)
1072 {
1073   GNAT_STRUCT_STAT statbuf;
1074   int ret;
1075
1076   if (fd != -1)
1077     ret = GNAT_FSTAT (fd, &statbuf);
1078   else
1079     ret = __gnat_stat (name, &statbuf);
1080
1081   attr->regular   = (!ret && S_ISREG (statbuf.st_mode));
1082   attr->directory = (!ret && S_ISDIR (statbuf.st_mode));
1083
1084   if (!attr->regular)
1085     attr->file_length = 0;
1086   else
1087     /* st_size may be 32 bits, or 64 bits which is converted to long. We
1088        don't return a useful value for files larger than 2 gigabytes in
1089        either case. */
1090     attr->file_length = statbuf.st_size;  /* all systems */
1091
1092 #ifndef __MINGW32__
1093   /* on Windows requires extra system call, see comment in __gnat_file_exists_attr */
1094   attr->exists = !ret;
1095 #endif
1096
1097 #if !defined (_WIN32) || defined (RTX)
1098   /* on Windows requires extra system call, see __gnat_is_readable_file_attr */
1099   attr->readable   = (!ret && (statbuf.st_mode & S_IRUSR));
1100   attr->writable   = (!ret && (statbuf.st_mode & S_IWUSR));
1101   attr->executable = (!ret && (statbuf.st_mode & S_IXUSR));
1102 #endif
1103
1104 #if !defined (__EMX__) && !defined (MSDOS) && (!defined (_WIN32) || defined (RTX))
1105   /* on Windows requires extra system call, see __gnat_file_time_name_attr */
1106   if (ret != 0) {
1107      attr->timestamp = (OS_Time)-1;
1108   } else {
1109 #ifdef VMS
1110      /* VMS has file versioning.  */
1111      attr->timestamp = (OS_Time)statbuf.st_ctime;
1112 #else
1113      attr->timestamp = (OS_Time)statbuf.st_mtime;
1114 #endif
1115   }
1116 #endif
1117
1118 }
1119
1120 /****************************************************************
1121  ** Return the number of bytes in the specified file
1122  ****************************************************************/
1123
1124 long
1125 __gnat_file_length_attr (int fd, char* name, struct file_attributes* attr)
1126 {
1127   if (attr->file_length == -1) {
1128     __gnat_stat_to_attr (fd, name, attr);
1129   }
1130
1131   return attr->file_length;
1132 }
1133
1134 long
1135 __gnat_file_length (int fd)
1136 {
1137   struct file_attributes attr;
1138   __gnat_reset_attributes (&attr);
1139   return __gnat_file_length_attr (fd, NULL, &attr);
1140 }
1141
1142 long
1143 __gnat_named_file_length (char *name)
1144 {
1145   struct file_attributes attr;
1146   __gnat_reset_attributes (&attr);
1147   return __gnat_file_length_attr (-1, name, &attr);
1148 }
1149
1150 /* Create a temporary filename and put it in string pointed to by
1151    TMP_FILENAME.  */
1152
1153 void
1154 __gnat_tmp_name (char *tmp_filename)
1155 {
1156 #ifdef RTX
1157   /* Variable used to create a series of unique names */
1158   static int counter = 0;
1159
1160   /* RTX in RTSS mode does not support tempnam nor tmpnam so we emulate it */
1161   strcpy (tmp_filename, "c:\\WINDOWS\\Temp\\gnat-");
1162   sprintf (&tmp_filename[strlen (tmp_filename)], "%d\0", counter++);
1163
1164 #elif defined (__MINGW32__)
1165   {
1166     char *pname;
1167
1168     /* tempnam tries to create a temporary file in directory pointed to by
1169        TMP environment variable, in c:\temp if TMP is not set, and in
1170        directory specified by P_tmpdir in stdio.h if c:\temp does not
1171        exist. The filename will be created with the prefix "gnat-".  */
1172
1173     pname = (char *) tempnam ("c:\\temp", "gnat-");
1174
1175     /* if pname is NULL, the file was not created properly, the disk is full
1176        or there is no more free temporary files */
1177
1178     if (pname == NULL)
1179       *tmp_filename = '\0';
1180
1181     /* If pname start with a back slash and not path information it means that
1182        the filename is valid for the current working directory.  */
1183
1184     else if (pname[0] == '\\')
1185       {
1186         strcpy (tmp_filename, ".\\");
1187         strcat (tmp_filename, pname+1);
1188       }
1189     else
1190       strcpy (tmp_filename, pname);
1191
1192     free (pname);
1193   }
1194
1195 #elif defined (linux) || defined (__FreeBSD__) || defined (__NetBSD__) \
1196   || defined (__OpenBSD__) || defined(__GLIBC__)
1197 #define MAX_SAFE_PATH 1000
1198   char *tmpdir = getenv ("TMPDIR");
1199
1200   /* If tmpdir is longer than MAX_SAFE_PATH, revert to default value to avoid
1201      a buffer overflow.  */
1202   if (tmpdir == NULL || strlen (tmpdir) > MAX_SAFE_PATH)
1203     strcpy (tmp_filename, "/tmp/gnat-XXXXXX");
1204   else
1205     sprintf (tmp_filename, "%s/gnat-XXXXXX", tmpdir);
1206
1207   close (mkstemp(tmp_filename));
1208 #else
1209   tmpnam (tmp_filename);
1210 #endif
1211 }
1212
1213 /*  Open directory and returns a DIR pointer.  */
1214
1215 DIR* __gnat_opendir (char *name)
1216 {
1217 #if defined (RTX)
1218   /* Not supported in RTX */
1219
1220   return NULL;
1221
1222 #elif defined (__MINGW32__)
1223   TCHAR wname[GNAT_MAX_PATH_LEN];
1224
1225   S2WSC (wname, name, GNAT_MAX_PATH_LEN);
1226   return (DIR*)_topendir (wname);
1227
1228 #else
1229   return opendir (name);
1230 #endif
1231 }
1232
1233 /* Read the next entry in a directory.  The returned string points somewhere
1234    in the buffer.  */
1235
1236 char *
1237 __gnat_readdir (DIR *dirp, char *buffer, int *len)
1238 {
1239 #if defined (RTX)
1240   /* Not supported in RTX */
1241
1242   return NULL;
1243
1244 #elif defined (__MINGW32__)
1245   struct _tdirent *dirent = _treaddir ((_TDIR*)dirp);
1246
1247   if (dirent != NULL)
1248     {
1249       WS2SC (buffer, dirent->d_name, GNAT_MAX_PATH_LEN);
1250       *len = strlen (buffer);
1251
1252       return buffer;
1253     }
1254   else
1255     return NULL;
1256
1257 #elif defined (HAVE_READDIR_R)
1258   /* If possible, try to use the thread-safe version.  */
1259   if (readdir_r (dirp, buffer) != NULL)
1260     {
1261       *len = strlen (((struct dirent*) buffer)->d_name);
1262       return ((struct dirent*) buffer)->d_name;
1263     }
1264   else
1265     return NULL;
1266
1267 #else
1268   struct dirent *dirent = (struct dirent *) readdir (dirp);
1269
1270   if (dirent != NULL)
1271     {
1272       strcpy (buffer, dirent->d_name);
1273       *len = strlen (buffer);
1274       return buffer;
1275     }
1276   else
1277     return NULL;
1278
1279 #endif
1280 }
1281
1282 /* Close a directory entry.  */
1283
1284 int __gnat_closedir (DIR *dirp)
1285 {
1286 #if defined (RTX)
1287   /* Not supported in RTX */
1288
1289   return 0;
1290
1291 #elif defined (__MINGW32__)
1292   return _tclosedir ((_TDIR*)dirp);
1293
1294 #else
1295   return closedir (dirp);
1296 #endif
1297 }
1298
1299 /* Returns 1 if readdir is thread safe, 0 otherwise.  */
1300
1301 int
1302 __gnat_readdir_is_thread_safe (void)
1303 {
1304 #ifdef HAVE_READDIR_R
1305   return 1;
1306 #else
1307   return 0;
1308 #endif
1309 }
1310
1311 #if defined (_WIN32) && !defined (RTX)
1312 /* Number of seconds between <Jan 1st 1601> and <Jan 1st 1970>.  */
1313 static const unsigned long long w32_epoch_offset = 11644473600ULL;
1314
1315 /* Returns the file modification timestamp using Win32 routines which are
1316    immune against daylight saving time change. It is in fact not possible to
1317    use fstat for this purpose as the DST modify the st_mtime field of the
1318    stat structure.  */
1319
1320 static time_t
1321 win32_filetime (HANDLE h)
1322 {
1323   union
1324   {
1325     FILETIME ft_time;
1326     unsigned long long ull_time;
1327   } t_write;
1328
1329   /* GetFileTime returns FILETIME data which are the number of 100 nanosecs
1330      since <Jan 1st 1601>. This function must return the number of seconds
1331      since <Jan 1st 1970>.  */
1332
1333   if (GetFileTime (h, NULL, NULL, &t_write.ft_time))
1334     return (time_t) (t_write.ull_time / 10000000ULL - w32_epoch_offset);
1335   return (time_t) 0;
1336 }
1337 #endif
1338
1339 /* Return a GNAT time stamp given a file name.  */
1340
1341 OS_Time
1342 __gnat_file_time_name_attr (char* name, struct file_attributes* attr)
1343 {
1344    if (attr->timestamp == (OS_Time)-2) {
1345 #if defined (__EMX__) || defined (MSDOS)
1346       int fd = open (name, O_RDONLY | O_BINARY);
1347       time_t ret = __gnat_file_time_fd (fd);
1348       close (fd);
1349       attr->timestamp = (OS_Time)ret;
1350
1351 #elif defined (_WIN32) && !defined (RTX)
1352       time_t ret = -1;
1353       TCHAR wname[GNAT_MAX_PATH_LEN];
1354       S2WSC (wname, name, GNAT_MAX_PATH_LEN);
1355
1356       HANDLE h = CreateFile
1357         (wname, GENERIC_READ, FILE_SHARE_READ, 0,
1358          OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0);
1359
1360       if (h != INVALID_HANDLE_VALUE) {
1361          ret = win32_filetime (h);
1362          CloseHandle (h);
1363       }
1364       attr->timestamp = (OS_Time) ret;
1365 #else
1366       __gnat_stat_to_attr (-1, name, attr);
1367 #endif
1368   }
1369   return attr->timestamp;
1370 }
1371
1372 OS_Time
1373 __gnat_file_time_name (char *name)
1374 {
1375    struct file_attributes attr;
1376    __gnat_reset_attributes (&attr);
1377    return __gnat_file_time_name_attr (name, &attr);
1378 }
1379
1380 /* Return a GNAT time stamp given a file descriptor.  */
1381
1382 OS_Time
1383 __gnat_file_time_fd_attr (int fd, struct file_attributes* attr)
1384 {
1385    if (attr->timestamp == (OS_Time)-2) {
1386      /* The following workaround code is due to the fact that under EMX and
1387         DJGPP fstat attempts to convert time values to GMT rather than keep the
1388         actual OS timestamp of the file. By using the OS2/DOS functions directly
1389         the GNAT timestamp are independent of this behavior, which is desired to
1390         facilitate the distribution of GNAT compiled libraries.  */
1391
1392 #if defined (__EMX__) || defined (MSDOS)
1393 #ifdef __EMX__
1394
1395      FILESTATUS fs;
1396      int ret = DosQueryFileInfo (fd, 1, (unsigned char *) &fs,
1397                                    sizeof (FILESTATUS));
1398
1399      unsigned file_year  = fs.fdateLastWrite.year;
1400      unsigned file_month = fs.fdateLastWrite.month;
1401      unsigned file_day   = fs.fdateLastWrite.day;
1402      unsigned file_hour  = fs.ftimeLastWrite.hours;
1403      unsigned file_min   = fs.ftimeLastWrite.minutes;
1404      unsigned file_tsec  = fs.ftimeLastWrite.twosecs;
1405
1406 #else
1407      struct ftime fs;
1408      int ret = getftime (fd, &fs);
1409
1410      unsigned file_year  = fs.ft_year;
1411      unsigned file_month = fs.ft_month;
1412      unsigned file_day   = fs.ft_day;
1413      unsigned file_hour  = fs.ft_hour;
1414      unsigned file_min   = fs.ft_min;
1415      unsigned file_tsec  = fs.ft_tsec;
1416 #endif
1417
1418      /* Calculate the seconds since epoch from the time components. First count
1419         the whole days passed.  The value for years returned by the DOS and OS2
1420         functions count years from 1980, so to compensate for the UNIX epoch which
1421         begins in 1970 start with 10 years worth of days and add days for each
1422         four year period since then.  */
1423
1424      time_t tot_secs;
1425      int cum_days[12] = {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334};
1426      int days_passed = 3652 + (file_year / 4) * 1461;
1427      int years_since_leap = file_year % 4;
1428
1429      if (years_since_leap == 1)
1430        days_passed += 366;
1431      else if (years_since_leap == 2)
1432        days_passed += 731;
1433      else if (years_since_leap == 3)
1434        days_passed += 1096;
1435
1436      if (file_year > 20)
1437        days_passed -= 1;
1438
1439      days_passed += cum_days[file_month - 1];
1440      if (years_since_leap == 0 && file_year != 20 && file_month > 2)
1441        days_passed++;
1442
1443      days_passed += file_day - 1;
1444
1445      /* OK - have whole days.  Multiply -- then add in other parts.  */
1446
1447      tot_secs  = days_passed * 86400;
1448      tot_secs += file_hour * 3600;
1449      tot_secs += file_min * 60;
1450      tot_secs += file_tsec * 2;
1451      attr->timestamp = (OS_Time) tot_secs;
1452
1453 #elif defined (_WIN32) && !defined (RTX)
1454      HANDLE h = (HANDLE) _get_osfhandle (fd);
1455      time_t ret = win32_filetime (h);
1456      attr->timestamp = (OS_Time) ret;
1457
1458 #else
1459      __gnat_stat_to_attr (fd, NULL, attr);
1460 #endif
1461    }
1462
1463    return attr->timestamp;
1464 }
1465
1466 OS_Time
1467 __gnat_file_time_fd (int fd)
1468 {
1469    struct file_attributes attr;
1470    __gnat_reset_attributes (&attr);
1471    return __gnat_file_time_fd_attr (fd, &attr);
1472 }
1473
1474 /* Set the file time stamp.  */
1475
1476 void
1477 __gnat_set_file_time_name (char *name, time_t time_stamp)
1478 {
1479 #if defined (__EMX__) || defined (MSDOS) || defined (__vxworks)
1480
1481 /* Code to implement __gnat_set_file_time_name for these systems.  */
1482
1483 #elif defined (_WIN32) && !defined (RTX)
1484   union
1485   {
1486     FILETIME ft_time;
1487     unsigned long long ull_time;
1488   } t_write;
1489   TCHAR wname[GNAT_MAX_PATH_LEN];
1490
1491   S2WSC (wname, name, GNAT_MAX_PATH_LEN);
1492
1493   HANDLE h  = CreateFile
1494     (wname, GENERIC_WRITE, FILE_SHARE_WRITE, NULL,
1495      OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS,
1496      NULL);
1497   if (h == INVALID_HANDLE_VALUE)
1498     return;
1499   /* Add number of seconds between <Jan 1st 1601> and <Jan 1st 1970> */
1500   t_write.ull_time = ((unsigned long long)time_stamp + w32_epoch_offset);
1501   /*  Convert to 100 nanosecond units  */
1502   t_write.ull_time *= 10000000ULL;
1503
1504   SetFileTime(h, NULL, NULL, &t_write.ft_time);
1505   CloseHandle (h);
1506   return;
1507
1508 #elif defined (VMS)
1509   struct FAB fab;
1510   struct NAM nam;
1511
1512   struct
1513     {
1514       unsigned long long backup, create, expire, revise;
1515       unsigned int uic;
1516       union
1517         {
1518           unsigned short value;
1519           struct
1520             {
1521               unsigned system : 4;
1522               unsigned owner  : 4;
1523               unsigned group  : 4;
1524               unsigned world  : 4;
1525             } bits;
1526         } prot;
1527     } Fat = { 0, 0, 0, 0, 0, { 0 }};
1528
1529   ATRDEF atrlst[]
1530     = {
1531       { ATR$S_CREDATE,  ATR$C_CREDATE,  &Fat.create },
1532       { ATR$S_REVDATE,  ATR$C_REVDATE,  &Fat.revise },
1533       { ATR$S_EXPDATE,  ATR$C_EXPDATE,  &Fat.expire },
1534       { ATR$S_BAKDATE,  ATR$C_BAKDATE,  &Fat.backup },
1535       { ATR$S_FPRO,     ATR$C_FPRO,     &Fat.prot },
1536       { ATR$S_UIC,      ATR$C_UIC,      &Fat.uic },
1537       { 0, 0, 0}
1538     };
1539
1540   FIBDEF fib;
1541   struct dsc$descriptor_fib fibdsc = {sizeof (fib), (void *) &fib};
1542
1543   struct IOSB iosb;
1544
1545   unsigned long long newtime;
1546   unsigned long long revtime;
1547   long status;
1548   short chan;
1549
1550   struct vstring file;
1551   struct dsc$descriptor_s filedsc
1552     = {NAM$C_MAXRSS, DSC$K_DTYPE_T, DSC$K_CLASS_S, (void *) file.string};
1553   struct vstring device;
1554   struct dsc$descriptor_s devicedsc
1555     = {NAM$C_MAXRSS, DSC$K_DTYPE_T, DSC$K_CLASS_S, (void *) device.string};
1556   struct vstring timev;
1557   struct dsc$descriptor_s timedsc
1558     = {NAM$C_MAXRSS, DSC$K_DTYPE_T, DSC$K_CLASS_S, (void *) timev.string};
1559   struct vstring result;
1560   struct dsc$descriptor_s resultdsc
1561     = {NAM$C_MAXRSS, DSC$K_DTYPE_VT, DSC$K_CLASS_VS, (void *) result.string};
1562
1563   /* Convert parameter name (a file spec) to host file form. Note that this
1564      is needed on VMS to prepare for subsequent calls to VMS RMS library
1565      routines. Note that it would not work to call __gnat_to_host_dir_spec
1566      as was done in a previous version, since this fails silently unless
1567      the feature logical DECC$EFS_CHARSET is enabled, in which case a DNF
1568      (directory not found) condition is signalled.  */
1569   tryfile = (char *) __gnat_to_host_file_spec (name);
1570
1571   /* Allocate and initialize a FAB and NAM structures.  */
1572   fab = cc$rms_fab;
1573   nam = cc$rms_nam;
1574
1575   nam.nam$l_esa = file.string;
1576   nam.nam$b_ess = NAM$C_MAXRSS;
1577   nam.nam$l_rsa = result.string;
1578   nam.nam$b_rss = NAM$C_MAXRSS;
1579   fab.fab$l_fna = tryfile;
1580   fab.fab$b_fns = strlen (tryfile);
1581   fab.fab$l_nam = &nam;
1582
1583   /* Validate filespec syntax and device existence.  */
1584   status = SYS$PARSE (&fab, 0, 0);
1585   if ((status & 1) != 1)
1586     LIB$SIGNAL (status);
1587
1588   file.string[nam.nam$b_esl] = 0;
1589
1590   /* Find matching filespec.  */
1591   status = SYS$SEARCH (&fab, 0, 0);
1592   if ((status & 1) != 1)
1593     LIB$SIGNAL (status);
1594
1595   file.string[nam.nam$b_esl] = 0;
1596   result.string[result.length=nam.nam$b_rsl] = 0;
1597
1598   /* Get the device name and assign an IO channel.  */
1599   strncpy (device.string, nam.nam$l_dev, nam.nam$b_dev);
1600   devicedsc.dsc$w_length  = nam.nam$b_dev;
1601   chan = 0;
1602   status = SYS$ASSIGN (&devicedsc, &chan, 0, 0, 0);
1603   if ((status & 1) != 1)
1604     LIB$SIGNAL (status);
1605
1606   /* Initialize the FIB and fill in the directory id field.  */
1607   memset (&fib, 0, sizeof (fib));
1608   fib.fib$w_did[0]  = nam.nam$w_did[0];
1609   fib.fib$w_did[1]  = nam.nam$w_did[1];
1610   fib.fib$w_did[2]  = nam.nam$w_did[2];
1611   fib.fib$l_acctl = 0;
1612   fib.fib$l_wcc = 0;
1613   strcpy (file.string, (strrchr (result.string, ']') + 1));
1614   filedsc.dsc$w_length = strlen (file.string);
1615   result.string[result.length = 0] = 0;
1616
1617   /* Open and close the file to fill in the attributes.  */
1618   status
1619     = SYS$QIOW (0, chan, IO$_ACCESS|IO$M_ACCESS, &iosb, 0, 0,
1620                 &fibdsc, &filedsc, &result.length, &resultdsc, &atrlst, 0);
1621   if ((status & 1) != 1)
1622     LIB$SIGNAL (status);
1623   if ((iosb.status & 1) != 1)
1624     LIB$SIGNAL (iosb.status);
1625
1626   result.string[result.length] = 0;
1627   status = SYS$QIOW (0, chan, IO$_DEACCESS, &iosb, 0, 0, &fibdsc, 0, 0, 0,
1628                      &atrlst, 0);
1629   if ((status & 1) != 1)
1630     LIB$SIGNAL (status);
1631   if ((iosb.status & 1) != 1)
1632     LIB$SIGNAL (iosb.status);
1633
1634   {
1635     time_t t;
1636
1637     /* Set creation time to requested time.  */
1638     unix_time_to_vms (time_stamp, newtime);
1639
1640     t = time ((time_t) 0);
1641
1642     /* Set revision time to now in local time.  */
1643     unix_time_to_vms (t, revtime);
1644   }
1645
1646   /* Reopen the file, modify the times and then close.  */
1647   fib.fib$l_acctl = FIB$M_WRITE;
1648   status
1649     = SYS$QIOW (0, chan, IO$_ACCESS|IO$M_ACCESS, &iosb, 0, 0,
1650                 &fibdsc, &filedsc, &result.length, &resultdsc, &atrlst, 0);
1651   if ((status & 1) != 1)
1652     LIB$SIGNAL (status);
1653   if ((iosb.status & 1) != 1)
1654     LIB$SIGNAL (iosb.status);
1655
1656   Fat.create = newtime;
1657   Fat.revise = revtime;
1658
1659   status = SYS$QIOW (0, chan, IO$_DEACCESS, &iosb, 0, 0,
1660                      &fibdsc, 0, 0, 0, &atrlst, 0);
1661   if ((status & 1) != 1)
1662     LIB$SIGNAL (status);
1663   if ((iosb.status & 1) != 1)
1664     LIB$SIGNAL (iosb.status);
1665
1666   /* Deassign the channel and exit.  */
1667   status = SYS$DASSGN (chan);
1668   if ((status & 1) != 1)
1669     LIB$SIGNAL (status);
1670 #else
1671   struct utimbuf utimbuf;
1672   time_t t;
1673
1674   /* Set modification time to requested time.  */
1675   utimbuf.modtime = time_stamp;
1676
1677   /* Set access time to now in local time.  */
1678   t = time ((time_t) 0);
1679   utimbuf.actime = mktime (localtime (&t));
1680
1681   utime (name, &utimbuf);
1682 #endif
1683 }
1684
1685 /* Get the list of installed standard libraries from the
1686    HKEY_LOCAL_MACHINE\SOFTWARE\Ada Core Technologies\GNAT\Standard Libraries
1687    key.  */
1688
1689 char *
1690 __gnat_get_libraries_from_registry (void)
1691 {
1692   char *result = (char *) xmalloc (1);
1693
1694   result[0] = '\0';
1695
1696 #if defined (_WIN32) && ! defined (__vxworks) && ! defined (IS_CROSS) \
1697   && ! defined (RTX)
1698
1699   HKEY reg_key;
1700   DWORD name_size, value_size;
1701   char name[256];
1702   char value[256];
1703   DWORD type;
1704   DWORD index;
1705   LONG res;
1706
1707   /* First open the key.  */
1708   res = RegOpenKeyExA (HKEY_LOCAL_MACHINE, "SOFTWARE", 0, KEY_READ, &reg_key);
1709
1710   if (res == ERROR_SUCCESS)
1711     res = RegOpenKeyExA (reg_key, "Ada Core Technologies", 0,
1712                          KEY_READ, &reg_key);
1713
1714   if (res == ERROR_SUCCESS)
1715     res = RegOpenKeyExA (reg_key, "GNAT", 0, KEY_READ, &reg_key);
1716
1717   if (res == ERROR_SUCCESS)
1718     res = RegOpenKeyExA (reg_key, "Standard Libraries", 0, KEY_READ, &reg_key);
1719
1720   /* If the key exists, read out all the values in it and concatenate them
1721      into a path.  */
1722   for (index = 0; res == ERROR_SUCCESS; index++)
1723     {
1724       value_size = name_size = 256;
1725       res = RegEnumValueA (reg_key, index, name, &name_size, 0,
1726                            &type, (LPBYTE)value, &value_size);
1727
1728       if (res == ERROR_SUCCESS && type == REG_SZ)
1729         {
1730           char *old_result = result;
1731
1732           result = (char *) xmalloc (strlen (old_result) + value_size + 2);
1733           strcpy (result, old_result);
1734           strcat (result, value);
1735           strcat (result, ";");
1736           free (old_result);
1737         }
1738     }
1739
1740   /* Remove the trailing ";".  */
1741   if (result[0] != 0)
1742     result[strlen (result) - 1] = 0;
1743
1744 #endif
1745   return result;
1746 }
1747
1748 int
1749 __gnat_stat (char *name, GNAT_STRUCT_STAT *statbuf)
1750 {
1751 #ifdef __MINGW32__
1752   /* Under Windows the directory name for the stat function must not be
1753      terminated by a directory separator except if just after a drive name
1754      or with UNC path without directory (only the name of the shared
1755      resource), for example: \\computer\share\  */
1756
1757   TCHAR wname [GNAT_MAX_PATH_LEN + 2];
1758   int name_len, k;
1759   TCHAR last_char;
1760   int dirsep_count = 0;
1761
1762   S2WSC (wname, name, GNAT_MAX_PATH_LEN + 2);
1763   name_len = _tcslen (wname);
1764
1765   if (name_len > GNAT_MAX_PATH_LEN)
1766     return -1;
1767
1768   last_char = wname[name_len - 1];
1769
1770   while (name_len > 1 && (last_char == _T('\\') || last_char == _T('/')))
1771     {
1772       wname[name_len - 1] = _T('\0');
1773       name_len--;
1774       last_char = wname[name_len - 1];
1775     }
1776
1777   /* Count back-slashes.  */
1778
1779   for (k=0; k<name_len; k++)
1780     if (wname[k] == _T('\\') || wname[k] == _T('/'))
1781       dirsep_count++;
1782
1783   /* Only a drive letter followed by ':', we must add a directory separator
1784      for the stat routine to work properly.  */
1785   if ((name_len == 2 && wname[1] == _T(':'))
1786       || (name_len > 3 && wname[0] == _T('\\') && wname[1] == _T('\\')
1787           && dirsep_count == 3))
1788     _tcscat (wname, _T("\\"));
1789
1790   return _tstat (wname, (struct _stat *)statbuf);
1791
1792 #else
1793   return GNAT_STAT (name, statbuf);
1794 #endif
1795 }
1796
1797 /*************************************************************************
1798  ** Check whether a file exists
1799  *************************************************************************/
1800
1801 int
1802 __gnat_file_exists_attr (char* name, struct file_attributes* attr)
1803 {
1804    if (attr->exists == ATTR_UNSET) {
1805 #ifdef __MINGW32__
1806       /*  On Windows do not use __gnat_stat() because of a bug in Microsoft
1807          _stat() routine. When the system time-zone is set with a negative
1808          offset the _stat() routine fails on specific files like CON:  */
1809       TCHAR wname [GNAT_MAX_PATH_LEN + 2];
1810       S2WSC (wname, name, GNAT_MAX_PATH_LEN + 2);
1811       attr->exists = GetFileAttributes (wname) != INVALID_FILE_ATTRIBUTES;
1812 #else
1813       __gnat_stat_to_attr (-1, name, attr);
1814 #endif
1815    }
1816
1817    return attr->exists;
1818 }
1819
1820 int
1821 __gnat_file_exists (char *name)
1822 {
1823    struct file_attributes attr;
1824    __gnat_reset_attributes (&attr);
1825    return __gnat_file_exists_attr (name, &attr);
1826 }
1827
1828 /**********************************************************************
1829  ** Whether name is an absolute path
1830  **********************************************************************/
1831
1832 int
1833 __gnat_is_absolute_path (char *name, int length)
1834 {
1835 #ifdef __vxworks
1836   /* On VxWorks systems, an absolute path can be represented (depending on
1837      the host platform) as either /dir/file, or device:/dir/file, or
1838      device:drive_letter:/dir/file. */
1839
1840   int index;
1841
1842   if (name[0] == '/')
1843     return 1;
1844
1845   for (index = 0; index < length; index++)
1846     {
1847       if (name[index] == ':' &&
1848           ((name[index + 1] == '/') ||
1849            (isalpha (name[index + 1]) && index + 2 <= length &&
1850             name[index + 2] == '/')))
1851         return 1;
1852
1853       else if (name[index] == '/')
1854         return 0;
1855     }
1856   return 0;
1857 #else
1858   return (length != 0) &&
1859      (*name == '/' || *name == DIR_SEPARATOR
1860 #if defined (__EMX__) || defined (MSDOS) || defined (WINNT)
1861       || (length > 1 && ISALPHA (name[0]) && name[1] == ':')
1862 #endif
1863           );
1864 #endif
1865 }
1866
1867 int
1868 __gnat_is_regular_file_attr (char* name, struct file_attributes* attr)
1869 {
1870    if (attr->regular == ATTR_UNSET) {
1871       __gnat_stat_to_attr (-1, name, attr);
1872    }
1873
1874    return attr->regular;
1875 }
1876
1877 int
1878 __gnat_is_regular_file (char *name)
1879 {
1880    struct file_attributes attr;
1881    __gnat_reset_attributes (&attr);
1882    return __gnat_is_regular_file_attr (name, &attr);
1883 }
1884
1885 int
1886 __gnat_is_directory_attr (char* name, struct file_attributes* attr)
1887 {
1888    if (attr->directory == ATTR_UNSET) {
1889       __gnat_stat_to_attr (-1, name, attr);
1890    }
1891
1892    return attr->directory;
1893 }
1894
1895 int
1896 __gnat_is_directory (char *name)
1897 {
1898    struct file_attributes attr;
1899    __gnat_reset_attributes (&attr);
1900    return __gnat_is_directory_attr (name, &attr);
1901 }
1902
1903 #if defined (_WIN32) && !defined (RTX)
1904
1905 /* Returns the same constant as GetDriveType but takes a pathname as
1906    argument. */
1907
1908 static UINT
1909 GetDriveTypeFromPath (TCHAR *wfullpath)
1910 {
1911   TCHAR wdrv[MAX_PATH];
1912   TCHAR wpath[MAX_PATH];
1913   TCHAR wfilename[MAX_PATH];
1914   TCHAR wext[MAX_PATH];
1915
1916   _tsplitpath (wfullpath, wdrv, wpath, wfilename, wext);
1917
1918   if (_tcslen (wdrv) != 0)
1919     {
1920       /* we have a drive specified. */
1921       _tcscat (wdrv, _T("\\"));
1922       return GetDriveType (wdrv);
1923     }
1924   else
1925     {
1926       /* No drive specified. */
1927
1928       /* Is this a relative path, if so get current drive type. */
1929       if (wpath[0] != _T('\\') ||
1930           (_tcslen (wpath) > 2 && wpath[0] == _T('\\') && wpath[1] != _T('\\')))
1931         return GetDriveType (NULL);
1932
1933       UINT result = GetDriveType (wpath);
1934
1935       /* Cannot guess the drive type, is this \\.\ ? */
1936
1937       if (result == DRIVE_NO_ROOT_DIR &&
1938          _tcslen (wpath) >= 4 && wpath[0] == _T('\\') && wpath[1] == _T('\\')
1939           && wpath[2] == _T('.') && wpath[3] == _T('\\'))
1940         {
1941           if (_tcslen (wpath) == 4)
1942             _tcscat (wpath, wfilename);
1943
1944           LPTSTR p = &wpath[4];
1945           LPTSTR b = _tcschr (p, _T('\\'));
1946
1947           if (b != NULL)
1948             { /* logical drive \\.\c\dir\file */
1949               *b++ = _T(':');
1950               *b++ = _T('\\');
1951               *b = _T('\0');
1952             }
1953           else
1954             _tcscat (p, _T(":\\"));
1955
1956           return GetDriveType (p);
1957         }
1958
1959       return result;
1960     }
1961 }
1962
1963 /*  This MingW section contains code to work with ACL. */
1964 static int
1965 __gnat_check_OWNER_ACL
1966 (TCHAR *wname,
1967  DWORD CheckAccessDesired,
1968  GENERIC_MAPPING CheckGenericMapping)
1969 {
1970   DWORD dwAccessDesired, dwAccessAllowed;
1971   PRIVILEGE_SET PrivilegeSet;
1972   DWORD dwPrivSetSize = sizeof (PRIVILEGE_SET);
1973   BOOL fAccessGranted = FALSE;
1974   HANDLE hToken = NULL;
1975   DWORD nLength = 0;
1976   SECURITY_DESCRIPTOR* pSD = NULL;
1977
1978   GetFileSecurity
1979     (wname, OWNER_SECURITY_INFORMATION |
1980      GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION,
1981      NULL, 0, &nLength);
1982
1983   if ((pSD = (PSECURITY_DESCRIPTOR) HeapAlloc
1984        (GetProcessHeap (), HEAP_ZERO_MEMORY, nLength)) == NULL)
1985     return 0;
1986
1987   /* Obtain the security descriptor. */
1988
1989   if (!GetFileSecurity
1990       (wname, OWNER_SECURITY_INFORMATION |
1991        GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION,
1992        pSD, nLength, &nLength))
1993     goto error;
1994
1995   if (!ImpersonateSelf (SecurityImpersonation))
1996     goto error;
1997
1998   if (!OpenThreadToken
1999       (GetCurrentThread(), TOKEN_DUPLICATE | TOKEN_QUERY, FALSE, &hToken))
2000     goto error;
2001
2002   /*  Undoes the effect of ImpersonateSelf. */
2003
2004   RevertToSelf ();
2005
2006   /*  We want to test for write permissions. */
2007
2008   dwAccessDesired = CheckAccessDesired;
2009
2010   MapGenericMask (&dwAccessDesired, &CheckGenericMapping);
2011
2012   if (!AccessCheck
2013       (pSD ,                 /* security descriptor to check */
2014        hToken,               /* impersonation token */
2015        dwAccessDesired,      /* requested access rights */
2016        &CheckGenericMapping, /* pointer to GENERIC_MAPPING */
2017        &PrivilegeSet,        /* receives privileges used in check */
2018        &dwPrivSetSize,       /* size of PrivilegeSet buffer */
2019        &dwAccessAllowed,     /* receives mask of allowed access rights */
2020        &fAccessGranted))
2021     goto error;
2022
2023   CloseHandle (hToken);
2024   HeapFree (GetProcessHeap (), 0, pSD);
2025   return fAccessGranted;
2026
2027  error:
2028   if (hToken)
2029     CloseHandle (hToken);
2030   HeapFree (GetProcessHeap (), 0, pSD);
2031   return 0;
2032 }
2033
2034 static void
2035 __gnat_set_OWNER_ACL
2036 (TCHAR *wname,
2037  DWORD AccessMode,
2038  DWORD AccessPermissions)
2039 {
2040   PACL pOldDACL = NULL;
2041   PACL pNewDACL = NULL;
2042   PSECURITY_DESCRIPTOR pSD = NULL;
2043   EXPLICIT_ACCESS ea;
2044   TCHAR username [100];
2045   DWORD unsize = 100;
2046
2047   /*  Get current user, he will act as the owner */
2048
2049   if (!GetUserName (username, &unsize))
2050     return;
2051
2052   if (GetNamedSecurityInfo
2053       (wname,
2054        SE_FILE_OBJECT,
2055        DACL_SECURITY_INFORMATION,
2056        NULL, NULL, &pOldDACL, NULL, &pSD) != ERROR_SUCCESS)
2057     return;
2058
2059   BuildExplicitAccessWithName
2060     (&ea, username, AccessPermissions, AccessMode, NO_INHERITANCE);
2061
2062   if (AccessMode == SET_ACCESS)
2063     {
2064       /*  SET_ACCESS, we want to set an explicte set of permissions, do not
2065           merge with current DACL.  */
2066       if (SetEntriesInAcl (1, &ea, NULL, &pNewDACL) != ERROR_SUCCESS)
2067         return;
2068     }
2069   else
2070     if (SetEntriesInAcl (1, &ea, pOldDACL, &pNewDACL) != ERROR_SUCCESS)
2071       return;
2072
2073   if (SetNamedSecurityInfo
2074       (wname, SE_FILE_OBJECT,
2075        DACL_SECURITY_INFORMATION, NULL, NULL, pNewDACL, NULL) != ERROR_SUCCESS)
2076     return;
2077
2078   LocalFree (pSD);
2079   LocalFree (pNewDACL);
2080 }
2081
2082 /* Check if it is possible to use ACL for wname, the file must not be on a
2083    network drive. */
2084
2085 static int
2086 __gnat_can_use_acl (TCHAR *wname)
2087 {
2088   return __gnat_use_acl && GetDriveTypeFromPath (wname) != DRIVE_REMOTE;
2089 }
2090
2091 #endif /* defined (_WIN32) && !defined (RTX) */
2092
2093 int
2094 __gnat_is_readable_file_attr (char* name, struct file_attributes* attr)
2095 {
2096    if (attr->readable == ATTR_UNSET) {
2097 #if defined (_WIN32) && !defined (RTX)
2098      TCHAR wname [GNAT_MAX_PATH_LEN + 2];
2099      GENERIC_MAPPING GenericMapping;
2100
2101      S2WSC (wname, name, GNAT_MAX_PATH_LEN + 2);
2102
2103      if (__gnat_can_use_acl (wname))
2104      {
2105         ZeroMemory (&GenericMapping, sizeof (GENERIC_MAPPING));
2106         GenericMapping.GenericRead = GENERIC_READ;
2107         attr->readable = __gnat_check_OWNER_ACL (wname, FILE_READ_DATA, GenericMapping);
2108      }
2109      else
2110         attr->readable = GetFileAttributes (wname) != INVALID_FILE_ATTRIBUTES;
2111 #else
2112      __gnat_stat_to_attr (-1, name, attr);
2113 #endif
2114    }
2115
2116    return attr->readable;
2117 }
2118
2119 int
2120 __gnat_is_readable_file (char *name)
2121 {
2122    struct file_attributes attr;
2123    __gnat_reset_attributes (&attr);
2124    return __gnat_is_readable_file_attr (name, &attr);
2125 }
2126
2127 int
2128 __gnat_is_writable_file_attr (char* name, struct file_attributes* attr)
2129 {
2130    if (attr->writable == ATTR_UNSET) {
2131 #if defined (_WIN32) && !defined (RTX)
2132      TCHAR wname [GNAT_MAX_PATH_LEN + 2];
2133      GENERIC_MAPPING GenericMapping;
2134
2135      S2WSC (wname, name, GNAT_MAX_PATH_LEN + 2);
2136
2137      if (__gnat_can_use_acl (wname))
2138        {
2139          ZeroMemory (&GenericMapping, sizeof (GENERIC_MAPPING));
2140          GenericMapping.GenericWrite = GENERIC_WRITE;
2141
2142          attr->writable = __gnat_check_OWNER_ACL
2143              (wname, FILE_WRITE_DATA | FILE_APPEND_DATA, GenericMapping)
2144              && !(GetFileAttributes (wname) & FILE_ATTRIBUTE_READONLY);
2145        }
2146      else
2147        attr->writable = !(GetFileAttributes (wname) & FILE_ATTRIBUTE_READONLY);
2148
2149 #else
2150      __gnat_stat_to_attr (-1, name, attr);
2151 #endif
2152    }
2153
2154    return attr->writable;
2155 }
2156
2157 int
2158 __gnat_is_writable_file (char *name)
2159 {
2160    struct file_attributes attr;
2161    __gnat_reset_attributes (&attr);
2162    return __gnat_is_writable_file_attr (name, &attr);
2163 }
2164
2165 int
2166 __gnat_is_executable_file_attr (char* name, struct file_attributes* attr)
2167 {
2168    if (attr->executable == ATTR_UNSET) {
2169 #if defined (_WIN32) && !defined (RTX)
2170      TCHAR wname [GNAT_MAX_PATH_LEN + 2];
2171      GENERIC_MAPPING GenericMapping;
2172
2173      S2WSC (wname, name, GNAT_MAX_PATH_LEN + 2);
2174
2175      if (__gnat_can_use_acl (wname))
2176        {
2177          ZeroMemory (&GenericMapping, sizeof (GENERIC_MAPPING));
2178          GenericMapping.GenericExecute = GENERIC_EXECUTE;
2179
2180          attr->executable = __gnat_check_OWNER_ACL (wname, FILE_EXECUTE, GenericMapping);
2181        }
2182      else
2183        attr->executable = GetFileAttributes (wname) != INVALID_FILE_ATTRIBUTES
2184          && _tcsstr (wname, _T(".exe")) - wname == (int) (_tcslen (wname) - 4);
2185 #else
2186      __gnat_stat_to_attr (-1, name, attr);
2187 #endif
2188    }
2189
2190    return attr->executable;
2191 }
2192
2193 int
2194 __gnat_is_executable_file (char *name)
2195 {
2196    struct file_attributes attr;
2197    __gnat_reset_attributes (&attr);
2198    return __gnat_is_executable_file_attr (name, &attr);
2199 }
2200
2201 void
2202 __gnat_set_writable (char *name)
2203 {
2204 #if defined (_WIN32) && !defined (RTX)
2205   TCHAR wname [GNAT_MAX_PATH_LEN + 2];
2206
2207   S2WSC (wname, name, GNAT_MAX_PATH_LEN + 2);
2208
2209   if (__gnat_can_use_acl (wname))
2210     __gnat_set_OWNER_ACL (wname, GRANT_ACCESS, FILE_GENERIC_WRITE);
2211
2212   SetFileAttributes
2213     (wname, GetFileAttributes (wname) & ~FILE_ATTRIBUTE_READONLY);
2214 #elif ! defined (__vxworks) && ! defined(__nucleus__)
2215   GNAT_STRUCT_STAT statbuf;
2216
2217   if (GNAT_STAT (name, &statbuf) == 0)
2218     {
2219       statbuf.st_mode = statbuf.st_mode | S_IWUSR;
2220       chmod (name, statbuf.st_mode);
2221     }
2222 #endif
2223 }
2224
2225 void
2226 __gnat_set_executable (char *name)
2227 {
2228 #if defined (_WIN32) && !defined (RTX)
2229   TCHAR wname [GNAT_MAX_PATH_LEN + 2];
2230
2231   S2WSC (wname, name, GNAT_MAX_PATH_LEN + 2);
2232
2233   if (__gnat_can_use_acl (wname))
2234     __gnat_set_OWNER_ACL (wname, GRANT_ACCESS, FILE_GENERIC_EXECUTE);
2235
2236 #elif ! defined (__vxworks) && ! defined(__nucleus__)
2237   GNAT_STRUCT_STAT statbuf;
2238
2239   if (GNAT_STAT (name, &statbuf) == 0)
2240     {
2241       statbuf.st_mode = statbuf.st_mode | S_IXUSR;
2242       chmod (name, statbuf.st_mode);
2243     }
2244 #endif
2245 }
2246
2247 void
2248 __gnat_set_non_writable (char *name)
2249 {
2250 #if defined (_WIN32) && !defined (RTX)
2251   TCHAR wname [GNAT_MAX_PATH_LEN + 2];
2252
2253   S2WSC (wname, name, GNAT_MAX_PATH_LEN + 2);
2254
2255   if (__gnat_can_use_acl (wname))
2256     __gnat_set_OWNER_ACL
2257       (wname, DENY_ACCESS,
2258        FILE_WRITE_DATA | FILE_APPEND_DATA |
2259        FILE_WRITE_EA | FILE_WRITE_ATTRIBUTES);
2260
2261   SetFileAttributes
2262     (wname, GetFileAttributes (wname) | FILE_ATTRIBUTE_READONLY);
2263 #elif ! defined (__vxworks) && ! defined(__nucleus__)
2264   GNAT_STRUCT_STAT statbuf;
2265
2266   if (GNAT_STAT (name, &statbuf) == 0)
2267     {
2268       statbuf.st_mode = statbuf.st_mode & 07577;
2269       chmod (name, statbuf.st_mode);
2270     }
2271 #endif
2272 }
2273
2274 void
2275 __gnat_set_readable (char *name)
2276 {
2277 #if defined (_WIN32) && !defined (RTX)
2278   TCHAR wname [GNAT_MAX_PATH_LEN + 2];
2279
2280   S2WSC (wname, name, GNAT_MAX_PATH_LEN + 2);
2281
2282   if (__gnat_can_use_acl (wname))
2283     __gnat_set_OWNER_ACL (wname, GRANT_ACCESS, FILE_GENERIC_READ);
2284
2285 #elif ! defined (__vxworks) && ! defined(__nucleus__)
2286   GNAT_STRUCT_STAT statbuf;
2287
2288   if (GNAT_STAT (name, &statbuf) == 0)
2289     {
2290       chmod (name, statbuf.st_mode | S_IREAD);
2291     }
2292 #endif
2293 }
2294
2295 void
2296 __gnat_set_non_readable (char *name)
2297 {
2298 #if defined (_WIN32) && !defined (RTX)
2299   TCHAR wname [GNAT_MAX_PATH_LEN + 2];
2300
2301   S2WSC (wname, name, GNAT_MAX_PATH_LEN + 2);
2302
2303   if (__gnat_can_use_acl (wname))
2304     __gnat_set_OWNER_ACL (wname, DENY_ACCESS, FILE_GENERIC_READ);
2305
2306 #elif ! defined (__vxworks) && ! defined(__nucleus__)
2307   GNAT_STRUCT_STAT statbuf;
2308
2309   if (GNAT_STAT (name, &statbuf) == 0)
2310     {
2311       chmod (name, statbuf.st_mode & (~S_IREAD));
2312     }
2313 #endif
2314 }
2315
2316 int
2317 __gnat_is_symbolic_link_attr (char* name, struct file_attributes* attr)
2318 {
2319    if (attr->symbolic_link == ATTR_UNSET) {
2320 #if defined (__vxworks) || defined (__nucleus__)
2321       attr->symbolic_link = 0;
2322
2323 #elif defined (_AIX) || defined (__APPLE__) || defined (__unix__)
2324       int ret;
2325       GNAT_STRUCT_STAT statbuf;
2326       ret = GNAT_LSTAT (name, &statbuf);
2327       attr->symbolic_link = (!ret && S_ISLNK (statbuf.st_mode));
2328 #else
2329       attr->symbolic_link = 0;
2330 #endif
2331    }
2332    return attr->symbolic_link;
2333 }
2334
2335 int
2336 __gnat_is_symbolic_link (char *name ATTRIBUTE_UNUSED)
2337 {
2338    struct file_attributes attr;
2339    __gnat_reset_attributes (&attr);
2340    return __gnat_is_symbolic_link_attr (name, &attr);
2341
2342 }
2343
2344 #if defined (sun) && defined (__SVR4)
2345 /* Using fork on Solaris will duplicate all the threads. fork1, which
2346    duplicates only the active thread, must be used instead, or spawning
2347    subprocess from a program with tasking will lead into numerous problems.  */
2348 #define fork fork1
2349 #endif
2350
2351 int
2352 __gnat_portable_spawn (char *args[])
2353 {
2354   int status = 0;
2355   int finished ATTRIBUTE_UNUSED;
2356   int pid ATTRIBUTE_UNUSED;
2357
2358 #if defined (__vxworks) || defined(__nucleus__) || defined(RTX)
2359   return -1;
2360
2361 #elif defined (MSDOS) || defined (_WIN32)
2362   /* args[0] must be quotes as it could contain a full pathname with spaces */
2363   char *args_0 = args[0];
2364   args[0] = (char *)xmalloc (strlen (args_0) + 3);
2365   strcpy (args[0], "\"");
2366   strcat (args[0], args_0);
2367   strcat (args[0], "\"");
2368
2369   status = spawnvp (P_WAIT, args_0, (const char* const*)args);
2370
2371   /* restore previous value */
2372   free (args[0]);
2373   args[0] = (char *)args_0;
2374
2375   if (status < 0)
2376     return -1;
2377   else
2378     return status;
2379
2380 #else
2381
2382 #ifdef __EMX__
2383   pid = spawnvp (P_NOWAIT, args[0], args);
2384   if (pid == -1)
2385     return -1;
2386
2387 #else
2388   pid = fork ();
2389   if (pid < 0)
2390     return -1;
2391
2392   if (pid == 0)
2393     {
2394       /* The child. */
2395       if (execv (args[0], MAYBE_TO_PTR32 (args)) != 0)
2396 #if defined (VMS)
2397         return -1; /* execv is in parent context on VMS.  */
2398 #else
2399         _exit (1);
2400 #endif
2401     }
2402 #endif
2403
2404   /* The parent.  */
2405   finished = waitpid (pid, &status, 0);
2406
2407   if (finished != pid || WIFEXITED (status) == 0)
2408     return -1;
2409
2410   return WEXITSTATUS (status);
2411 #endif
2412
2413   return 0;
2414 }
2415
2416 /* Create a copy of the given file descriptor.
2417    Return -1 if an error occurred.  */
2418
2419 int
2420 __gnat_dup (int oldfd)
2421 {
2422 #if defined (__vxworks) && !defined (__RTP__)
2423   /* Not supported on VxWorks 5.x, but supported on VxWorks 6.0 when using
2424      RTPs. */
2425   return -1;
2426 #else
2427   return dup (oldfd);
2428 #endif
2429 }
2430
2431 /* Make newfd be the copy of oldfd, closing newfd first if necessary.
2432    Return -1 if an error occurred.  */
2433
2434 int
2435 __gnat_dup2 (int oldfd, int newfd)
2436 {
2437 #if defined (__vxworks) && !defined (__RTP__)
2438   /* Not supported on VxWorks 5.x, but supported on VxWorks 6.0 when using
2439      RTPs.  */
2440   return -1;
2441 #else
2442   return dup2 (oldfd, newfd);
2443 #endif
2444 }
2445
2446 /* WIN32 code to implement a wait call that wait for any child process.  */
2447
2448 #if defined (_WIN32) && !defined (RTX)
2449
2450 /* Synchronization code, to be thread safe.  */
2451
2452 #ifdef CERT
2453
2454 /* For the Cert run times on native Windows we use dummy functions
2455    for locking and unlocking tasks since we do not support multiple
2456    threads on this configuration (Cert run time on native Windows). */
2457
2458 void dummy (void) {}
2459
2460 void (*Lock_Task) ()   = &dummy;
2461 void (*Unlock_Task) () = &dummy;
2462
2463 #else
2464
2465 #define Lock_Task system__soft_links__lock_task
2466 extern void (*Lock_Task) (void);
2467
2468 #define Unlock_Task system__soft_links__unlock_task
2469 extern void (*Unlock_Task) (void);
2470
2471 #endif
2472
2473 static HANDLE *HANDLES_LIST = NULL;
2474 static int *PID_LIST = NULL, plist_length = 0, plist_max_length = 0;
2475
2476 static void
2477 add_handle (HANDLE h)
2478 {
2479
2480   /* -------------------- critical section -------------------- */
2481   (*Lock_Task) ();
2482
2483   if (plist_length == plist_max_length)
2484     {
2485       plist_max_length += 1000;
2486       HANDLES_LIST =
2487         xrealloc (HANDLES_LIST, sizeof (HANDLE) * plist_max_length);
2488       PID_LIST =
2489         xrealloc (PID_LIST, sizeof (int) * plist_max_length);
2490     }
2491
2492   HANDLES_LIST[plist_length] = h;
2493   PID_LIST[plist_length] = GetProcessId (h);
2494   ++plist_length;
2495
2496   (*Unlock_Task) ();
2497   /* -------------------- critical section -------------------- */
2498 }
2499
2500 void
2501 __gnat_win32_remove_handle (HANDLE h, int pid)
2502 {
2503   int j;
2504
2505   /* -------------------- critical section -------------------- */
2506   (*Lock_Task) ();
2507
2508   for (j = 0; j < plist_length; j++)
2509     {
2510       if ((HANDLES_LIST[j] == h) || (PID_LIST[j] == pid))
2511         {
2512           CloseHandle (h);
2513           --plist_length;
2514           HANDLES_LIST[j] = HANDLES_LIST[plist_length];
2515           PID_LIST[j] = PID_LIST[plist_length];
2516           break;
2517         }
2518     }
2519
2520   (*Unlock_Task) ();
2521   /* -------------------- critical section -------------------- */
2522 }
2523
2524 static HANDLE
2525 win32_no_block_spawn (char *command, char *args[])
2526 {
2527   BOOL result;
2528   STARTUPINFO SI;
2529   PROCESS_INFORMATION PI;
2530   SECURITY_ATTRIBUTES SA;
2531   int csize = 1;
2532   char *full_command;
2533   int k;
2534
2535   /* compute the total command line length */
2536   k = 0;
2537   while (args[k])
2538     {
2539       csize += strlen (args[k]) + 1;
2540       k++;
2541     }
2542
2543   full_command = (char *) xmalloc (csize);
2544
2545   /* Startup info. */
2546   SI.cb          = sizeof (STARTUPINFO);
2547   SI.lpReserved  = NULL;
2548   SI.lpReserved2 = NULL;
2549   SI.lpDesktop   = NULL;
2550   SI.cbReserved2 = 0;
2551   SI.lpTitle     = NULL;
2552   SI.dwFlags     = 0;
2553   SI.wShowWindow = SW_HIDE;
2554
2555   /* Security attributes. */
2556   SA.nLength = sizeof (SECURITY_ATTRIBUTES);
2557   SA.bInheritHandle = TRUE;
2558   SA.lpSecurityDescriptor = NULL;
2559
2560   /* Prepare the command string. */
2561   strcpy (full_command, command);
2562   strcat (full_command, " ");
2563
2564   k = 1;
2565   while (args[k])
2566     {
2567       strcat (full_command, args[k]);
2568       strcat (full_command, " ");
2569       k++;
2570     }
2571
2572   {
2573     int wsize = csize * 2;
2574     TCHAR *wcommand = (TCHAR *) xmalloc (wsize);
2575
2576     S2WSC (wcommand, full_command, wsize);
2577
2578     free (full_command);
2579
2580     result = CreateProcess
2581       (NULL, wcommand, &SA, NULL, TRUE,
2582        GetPriorityClass (GetCurrentProcess()), NULL, NULL, &SI, &PI);
2583
2584     free (wcommand);
2585   }
2586
2587   if (result == TRUE)
2588     {
2589       CloseHandle (PI.hThread);
2590       return PI.hProcess;
2591     }
2592   else
2593     return NULL;
2594 }
2595
2596 static int
2597 win32_wait (int *status)
2598 {
2599   DWORD exitcode, pid;
2600   HANDLE *hl;
2601   HANDLE h;
2602   DWORD res;
2603   int k;
2604   int hl_len;
2605
2606   if (plist_length == 0)
2607     {
2608       errno = ECHILD;
2609       return -1;
2610     }
2611
2612   k = 0;
2613
2614   /* -------------------- critical section -------------------- */
2615   (*Lock_Task) ();
2616
2617   hl_len = plist_length;
2618
2619   hl = (HANDLE *) xmalloc (sizeof (HANDLE) * hl_len);
2620
2621   memmove (hl, HANDLES_LIST, sizeof (HANDLE) * hl_len);
2622
2623   (*Unlock_Task) ();
2624   /* -------------------- critical section -------------------- */
2625
2626   res = WaitForMultipleObjects (hl_len, hl, FALSE, INFINITE);
2627   h = hl[res - WAIT_OBJECT_0];
2628
2629   GetExitCodeProcess (h, &exitcode);
2630   pid = GetProcessId (h);
2631   __gnat_win32_remove_handle (h, -1);
2632
2633   free (hl);
2634
2635   *status = (int) exitcode;
2636   return (int) pid;
2637 }
2638
2639 #endif
2640
2641 int
2642 __gnat_portable_no_block_spawn (char *args[])
2643 {
2644
2645 #if defined (__vxworks) || defined (__nucleus__) || defined (RTX)
2646   return -1;
2647
2648 #elif defined (__EMX__) || defined (MSDOS)
2649
2650   /* ??? For PC machines I (Franco) don't know the system calls to implement
2651      this routine. So I'll fake it as follows. This routine will behave
2652      exactly like the blocking portable_spawn and will systematically return
2653      a pid of 0 unless the spawned task did not complete successfully, in
2654      which case we return a pid of -1.  To synchronize with this the
2655      portable_wait below systematically returns a pid of 0 and reports that
2656      the subprocess terminated successfully. */
2657
2658   if (spawnvp (P_WAIT, args[0], args) != 0)
2659     return -1;
2660
2661 #elif defined (_WIN32)
2662
2663   HANDLE h = NULL;
2664
2665   h = win32_no_block_spawn (args[0], args);
2666   if (h != NULL)
2667     {
2668       add_handle (h);
2669       return GetProcessId (h);
2670     }
2671   else
2672     return -1;
2673
2674 #else
2675
2676   int pid = fork ();
2677
2678   if (pid == 0)
2679     {
2680       /* The child.  */
2681       if (execv (args[0], MAYBE_TO_PTR32 (args)) != 0)
2682 #if defined (VMS)
2683         return -1; /* execv is in parent context on VMS. */
2684 #else
2685         _exit (1);
2686 #endif
2687     }
2688
2689   return pid;
2690
2691   #endif
2692 }
2693
2694 int
2695 __gnat_portable_wait (int *process_status)
2696 {
2697   int status = 0;
2698   int pid = 0;
2699
2700 #if defined (__vxworks) || defined (__nucleus__) || defined (RTX)
2701   /* Not sure what to do here, so do same as __EMX__ case, i.e., nothing but
2702      return zero.  */
2703
2704 #elif defined (_WIN32)
2705
2706   pid = win32_wait (&status);
2707
2708 #elif defined (__EMX__) || defined (MSDOS)
2709   /* ??? See corresponding comment in portable_no_block_spawn.  */
2710
2711 #else
2712
2713   pid = waitpid (-1, &status, 0);
2714   status = status & 0xffff;
2715 #endif
2716
2717   *process_status = status;
2718   return pid;
2719 }
2720
2721 void
2722 __gnat_os_exit (int status)
2723 {
2724   exit (status);
2725 }
2726
2727 /* Locate a regular file, give a Path value.  */
2728
2729 char *
2730 __gnat_locate_regular_file (char *file_name, char *path_val)
2731 {
2732   char *ptr;
2733   char *file_path = (char *) alloca (strlen (file_name) + 1);
2734   int absolute;
2735
2736   /* Return immediately if file_name is empty */
2737
2738   if (*file_name == '\0')
2739     return 0;
2740
2741   /* Remove quotes around file_name if present */
2742
2743   ptr = file_name;
2744   if (*ptr == '"')
2745     ptr++;
2746
2747   strcpy (file_path, ptr);
2748
2749   ptr = file_path + strlen (file_path) - 1;
2750
2751   if (*ptr == '"')
2752     *ptr = '\0';
2753
2754   /* Handle absolute pathnames.  */
2755
2756   absolute = __gnat_is_absolute_path (file_path, strlen (file_name));
2757
2758   if (absolute)
2759     {
2760      if (__gnat_is_regular_file (file_path))
2761        return xstrdup (file_path);
2762
2763       return 0;
2764     }
2765
2766   /* If file_name include directory separator(s), try it first as
2767      a path name relative to the current directory */
2768   for (ptr = file_name; *ptr && *ptr != '/' && *ptr != DIR_SEPARATOR; ptr++)
2769     ;
2770
2771   if (*ptr != 0)
2772     {
2773       if (__gnat_is_regular_file (file_name))
2774         return xstrdup (file_name);
2775     }
2776
2777   if (path_val == 0)
2778     return 0;
2779
2780   {
2781     /* The result has to be smaller than path_val + file_name.  */
2782     char *file_path = (char *) alloca (strlen (path_val) + strlen (file_name) + 2);
2783
2784     for (;;)
2785       {
2786         for (; *path_val == PATH_SEPARATOR; path_val++)
2787           ;
2788
2789       if (*path_val == 0)
2790         return 0;
2791
2792       /* Skip the starting quote */
2793
2794       if (*path_val == '"')
2795         path_val++;
2796
2797       for (ptr = file_path; *path_val && *path_val != PATH_SEPARATOR; )
2798         *ptr++ = *path_val++;
2799
2800       ptr--;
2801
2802       /* Skip the ending quote */
2803
2804       if (*ptr == '"')
2805         ptr--;
2806
2807       if (*ptr != '/' && *ptr != DIR_SEPARATOR)
2808         *++ptr = DIR_SEPARATOR;
2809
2810       strcpy (++ptr, file_name);
2811
2812       if (__gnat_is_regular_file (file_path))
2813         return xstrdup (file_path);
2814       }
2815   }
2816
2817   return 0;
2818 }
2819
2820 /* Locate an executable given a Path argument. This routine is only used by
2821    gnatbl and should not be used otherwise.  Use locate_exec_on_path
2822    instead.  */
2823
2824 char *
2825 __gnat_locate_exec (char *exec_name, char *path_val)
2826 {
2827   char *ptr;
2828   if (!strstr (exec_name, HOST_EXECUTABLE_SUFFIX))
2829     {
2830       char *full_exec_name
2831         = (char *) alloca (strlen (exec_name) + strlen (HOST_EXECUTABLE_SUFFIX) + 1);
2832
2833       strcpy (full_exec_name, exec_name);
2834       strcat (full_exec_name, HOST_EXECUTABLE_SUFFIX);
2835       ptr = __gnat_locate_regular_file (full_exec_name, path_val);
2836
2837       if (ptr == 0)
2838          return __gnat_locate_regular_file (exec_name, path_val);
2839       return ptr;
2840     }
2841   else
2842     return __gnat_locate_regular_file (exec_name, path_val);
2843 }
2844
2845 /* Locate an executable using the Systems default PATH.  */
2846
2847 char *
2848 __gnat_locate_exec_on_path (char *exec_name)
2849 {
2850   char *apath_val;
2851
2852 #if defined (_WIN32) && !defined (RTX)
2853   TCHAR *wpath_val = _tgetenv (_T("PATH"));
2854   TCHAR *wapath_val;
2855   /* In Win32 systems we expand the PATH as for XP environment
2856      variables are not automatically expanded. We also prepend the
2857      ".;" to the path to match normal NT path search semantics */
2858
2859   #define EXPAND_BUFFER_SIZE 32767
2860
2861   wapath_val = alloca (EXPAND_BUFFER_SIZE);
2862
2863   wapath_val [0] = '.';
2864   wapath_val [1] = ';';
2865
2866   DWORD res = ExpandEnvironmentStrings
2867     (wpath_val, &wapath_val[2], EXPAND_BUFFER_SIZE - 2);
2868
2869   if (!res) wapath_val [0] = _T('\0');
2870
2871   apath_val = alloca (EXPAND_BUFFER_SIZE);
2872
2873   WS2SC (apath_val, wapath_val, EXPAND_BUFFER_SIZE);
2874   return __gnat_locate_exec (exec_name, apath_val);
2875
2876 #else
2877
2878 #ifdef VMS
2879   char *path_val = "/VAXC$PATH";
2880 #else
2881   char *path_val = getenv ("PATH");
2882 #endif
2883   if (path_val == NULL) return NULL;
2884   apath_val = (char *) alloca (strlen (path_val) + 1);
2885   strcpy (apath_val, path_val);
2886   return __gnat_locate_exec (exec_name, apath_val);
2887 #endif
2888 }
2889
2890 #ifdef VMS
2891
2892 /* These functions are used to translate to and from VMS and Unix syntax
2893    file, directory and path specifications.  */
2894
2895 #define MAXPATH  256
2896 #define MAXNAMES 256
2897 #define NEW_CANONICAL_FILELIST_INCREMENT 64
2898
2899 static char new_canonical_dirspec [MAXPATH];
2900 static char new_canonical_filespec [MAXPATH];
2901 static char new_canonical_pathspec [MAXNAMES*MAXPATH];
2902 static unsigned new_canonical_filelist_index;
2903 static unsigned new_canonical_filelist_in_use;
2904 static unsigned new_canonical_filelist_allocated;
2905 static char **new_canonical_filelist;
2906 static char new_host_pathspec [MAXNAMES*MAXPATH];
2907 static char new_host_dirspec [MAXPATH];
2908 static char new_host_filespec [MAXPATH];
2909
2910 /* Routine is called repeatedly by decc$from_vms via
2911    __gnat_to_canonical_file_list_init until it returns 0 or the expansion
2912    runs out. */
2913
2914 static int
2915 wildcard_translate_unix (char *name)
2916 {
2917   char *ver;
2918   char buff [MAXPATH];
2919
2920   strncpy (buff, name, MAXPATH);
2921   buff [MAXPATH - 1] = (char) 0;
2922   ver = strrchr (buff, '.');
2923
2924   /* Chop off the version.  */
2925   if (ver)
2926     *ver = 0;
2927
2928   /* Dynamically extend the allocation by the increment.  */
2929   if (new_canonical_filelist_in_use == new_canonical_filelist_allocated)
2930     {
2931       new_canonical_filelist_allocated += NEW_CANONICAL_FILELIST_INCREMENT;
2932       new_canonical_filelist = (char **) xrealloc
2933         (new_canonical_filelist,
2934          new_canonical_filelist_allocated * sizeof (char *));
2935     }
2936
2937   new_canonical_filelist[new_canonical_filelist_in_use++] = xstrdup (buff);
2938
2939   return 1;
2940 }
2941
2942 /* Translate a wildcard VMS file spec into a list of Unix file specs. First do
2943    full translation and copy the results into a list (_init), then return them
2944    one at a time (_next). If onlydirs set, only expand directory files.  */
2945
2946 int
2947 __gnat_to_canonical_file_list_init (char *filespec, int onlydirs)
2948 {
2949   int len;
2950   char buff [MAXPATH];
2951
2952   len = strlen (filespec);
2953   strncpy (buff, filespec, MAXPATH);
2954
2955   /* Only look for directories */
2956   if (onlydirs && !strstr (&buff [len-5], "*.dir"))
2957     strncat (buff, "*.dir", MAXPATH);
2958
2959   buff [MAXPATH - 1] = (char) 0;
2960
2961   decc$from_vms (buff, wildcard_translate_unix, 1);
2962
2963   /* Remove the .dir extension.  */
2964   if (onlydirs)
2965     {
2966       int i;
2967       char *ext;
2968
2969       for (i = 0; i < new_canonical_filelist_in_use; i++)
2970         {
2971           ext = strstr (new_canonical_filelist[i], ".dir");
2972           if (ext)
2973             *ext = 0;
2974         }
2975     }
2976
2977   return new_canonical_filelist_in_use;
2978 }
2979
2980 /* Return the next filespec in the list.  */
2981
2982 char *
2983 __gnat_to_canonical_file_list_next ()
2984 {
2985   return new_canonical_filelist[new_canonical_filelist_index++];
2986 }
2987
2988 /* Free storage used in the wildcard expansion.  */
2989
2990 void
2991 __gnat_to_canonical_file_list_free ()
2992 {
2993   int i;
2994
2995    for (i = 0; i < new_canonical_filelist_in_use; i++)
2996      free (new_canonical_filelist[i]);
2997
2998   free (new_canonical_filelist);
2999
3000   new_canonical_filelist_in_use = 0;
3001   new_canonical_filelist_allocated = 0;
3002   new_canonical_filelist_index = 0;
3003   new_canonical_filelist = 0;
3004 }
3005
3006 /* The functional equivalent of decc$translate_vms routine.
3007    Designed to produce the same output, but is protected against
3008    malformed paths (original version ACCVIOs in this case) and
3009    does not require VMS-specific DECC RTL */
3010
3011 #define NAM$C_MAXRSS 1024
3012
3013 char *
3014 __gnat_translate_vms (char *src)
3015 {
3016   static char retbuf [NAM$C_MAXRSS+1];
3017   char *srcendpos, *pos1, *pos2, *retpos;
3018   int disp, path_present = 0;
3019
3020   if (!src) return NULL;
3021
3022   srcendpos = strchr (src, '\0');
3023   retpos = retbuf;
3024
3025   /* Look for the node and/or device in front of the path */
3026   pos1 = src;
3027   pos2 = strchr (pos1, ':');
3028
3029   if (pos2 && (pos2 < srcendpos) && (*(pos2 + 1) == ':')) {
3030     /* There is a node name. "node_name::" becomes "node_name!" */
3031     disp = pos2 - pos1;
3032     strncpy (retbuf, pos1, disp);
3033     retpos [disp] = '!';
3034     retpos = retpos + disp + 1;
3035     pos1 = pos2 + 2;
3036     pos2 = strchr (pos1, ':');
3037   }
3038
3039   if (pos2) {
3040     /* There is a device name. "dev_name:" becomes "/dev_name/" */
3041     *(retpos++) = '/';
3042     disp = pos2 - pos1;
3043     strncpy (retpos, pos1, disp);
3044     retpos = retpos + disp;
3045     pos1 = pos2 + 1;
3046     *(retpos++) = '/';
3047   }
3048   else
3049     /* No explicit device; we must look ahead and prepend /sys$disk/ if
3050        the path is absolute */
3051     if ((*pos1 == '[' || *pos1 == '<') && (pos1 < srcendpos)
3052         && !strchr (".-]>", *(pos1 + 1))) {
3053       strncpy (retpos, "/sys$disk/", 10);
3054       retpos += 10;
3055     }
3056
3057   /* Process the path part */
3058   while (*pos1 == '[' || *pos1 == '<') {
3059     path_present++;
3060     pos1++;
3061     if (*pos1 == ']' || *pos1 == '>') {
3062       /* Special case, [] translates to '.' */
3063       *(retpos++) = '.';
3064       pos1++;
3065     }
3066     else {
3067       /* '[000000' means root dir. It can be present in the middle of
3068          the path due to expansion of logical devices, in which case
3069          we skip it */
3070       if (!strncmp (pos1, "000000", 6) && path_present > 1 &&
3071          (*(pos1 + 6) == ']' || *(pos1 + 6) == '>' || *(pos1 + 6) == '.')) {
3072           pos1 += 6;
3073           if (*pos1 == '.') pos1++;
3074         }
3075       else if (*pos1 == '.') {
3076         /* Relative path */
3077         *(retpos++) = '.';
3078       }
3079
3080       /* There is a qualified path */
3081       while (*pos1 && *pos1 != ']' && *pos1 != '>') {
3082         switch (*pos1) {
3083           case '.':
3084             /* '.' is used to separate directories. Replace it with '/' but
3085                only if there isn't already '/' just before */
3086             if (*(retpos - 1) != '/') *(retpos++) = '/';
3087             pos1++;
3088             if (pos1 + 1 < srcendpos && *pos1 == '.' && *(pos1 + 1) == '.') {
3089               /* ellipsis refers to entire subtree; replace with '**' */
3090               *(retpos++) = '*'; *(retpos++) = '*'; *(retpos++) = '/';
3091               pos1 += 2;
3092             }
3093             break;
3094           case '-' :
3095             /* When after '.' '[' '<' is equivalent to Unix ".." but there
3096             may be several in a row */
3097             if (*(pos1 - 1) == '.' || *(pos1 - 1) == '[' ||
3098                 *(pos1 - 1) == '<') {
3099               while (*pos1 == '-') {
3100                 pos1++;
3101                 *(retpos++) = '.'; *(retpos++) = '.'; *(retpos++) = '/';
3102               }
3103               retpos--;
3104               break;
3105             }
3106             /* otherwise fall through to default */
3107           default:
3108             *(retpos++) = *(pos1++);
3109         }
3110       }
3111       pos1++;
3112     }
3113   }
3114
3115   if (pos1 < srcendpos) {
3116     /* Now add the actual file name, until the version suffix if any */
3117     if (path_present) *(retpos++) = '/';
3118     pos2 = strchr (pos1, ';');
3119     disp = pos2? (pos2 - pos1) : (srcendpos - pos1);
3120     strncpy (retpos, pos1, disp);
3121     retpos += disp;
3122     if (pos2 && pos2 < srcendpos) {
3123       /* There is a non-empty version suffix. ";<ver>" becomes ".<ver>" */
3124       *retpos++ = '.';
3125       disp = srcendpos - pos2 - 1;
3126       strncpy (retpos, pos2 + 1, disp);
3127       retpos += disp;
3128     }
3129   }
3130
3131   *retpos = '\0';
3132
3133   return retbuf;
3134
3135 }
3136
3137 /* Translate a VMS syntax directory specification in to Unix syntax.  If
3138    PREFIXFLAG is set, append an underscore "/". If no indicators of VMS syntax
3139    found, return input string. Also translate a dirname that contains no
3140    slashes, in case it's a logical name.  */
3141
3142 char *
3143 __gnat_to_canonical_dir_spec (char *dirspec, int prefixflag)
3144 {
3145   int len;
3146
3147   strcpy (new_canonical_dirspec, "");
3148   if (strlen (dirspec))
3149     {
3150       char *dirspec1;
3151
3152       if (strchr (dirspec, ']') || strchr (dirspec, ':'))
3153         {
3154           strncpy (new_canonical_dirspec,
3155                    __gnat_translate_vms (dirspec),
3156                    MAXPATH);
3157         }
3158       else if (!strchr (dirspec, '/') && (dirspec1 = getenv (dirspec)) != 0)
3159         {
3160           strncpy (new_canonical_dirspec,
3161                   __gnat_translate_vms (dirspec1),
3162                   MAXPATH);
3163         }
3164       else
3165         {
3166           strncpy (new_canonical_dirspec, dirspec, MAXPATH);
3167         }
3168     }
3169
3170   len = strlen (new_canonical_dirspec);
3171   if (prefixflag && new_canonical_dirspec [len-1] != '/')
3172     strncat (new_canonical_dirspec, "/", MAXPATH);
3173
3174   new_canonical_dirspec [MAXPATH - 1] = (char) 0;
3175
3176   return new_canonical_dirspec;
3177
3178 }
3179
3180 /* Translate a VMS syntax file specification into Unix syntax.
3181    If no indicators of VMS syntax found, check if it's an uppercase
3182    alphanumeric_ name and if so try it out as an environment
3183    variable (logical name). If all else fails return the
3184    input string.  */
3185
3186 char *
3187 __gnat_to_canonical_file_spec (char *filespec)
3188 {
3189   char *filespec1;
3190
3191   strncpy (new_canonical_filespec, "", MAXPATH);
3192
3193   if (strchr (filespec, ']') || strchr (filespec, ':'))
3194     {
3195       char *tspec = (char *) __gnat_translate_vms (filespec);
3196
3197       if (tspec != (char *) -1)
3198         strncpy (new_canonical_filespec, tspec, MAXPATH);
3199     }
3200   else if ((strlen (filespec) == strspn (filespec,
3201             "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_"))
3202         && (filespec1 = getenv (filespec)))
3203     {
3204       char *tspec = (char *) __gnat_translate_vms (filespec1);
3205
3206       if (tspec != (char *) -1)
3207         strncpy (new_canonical_filespec, tspec, MAXPATH);
3208     }
3209   else
3210     {
3211       strncpy (new_canonical_filespec, filespec, MAXPATH);
3212     }
3213
3214   new_canonical_filespec [MAXPATH - 1] = (char) 0;
3215
3216   return new_canonical_filespec;
3217 }
3218
3219 /* Translate a VMS syntax path specification into Unix syntax.
3220    If no indicators of VMS syntax found, return input string.  */
3221
3222 char *
3223 __gnat_to_canonical_path_spec (char *pathspec)
3224 {
3225   char *curr, *next, buff [MAXPATH];
3226
3227   if (pathspec == 0)
3228     return pathspec;
3229
3230   /* If there are /'s, assume it's a Unix path spec and return.  */
3231   if (strchr (pathspec, '/'))
3232     return pathspec;
3233
3234   new_canonical_pathspec[0] = 0;
3235   curr = pathspec;
3236
3237   for (;;)
3238     {
3239       next = strchr (curr, ',');
3240       if (next == 0)
3241         next = strchr (curr, 0);
3242
3243       strncpy (buff, curr, next - curr);
3244       buff[next - curr] = 0;
3245
3246       /* Check for wildcards and expand if present.  */
3247       if (strchr (buff, '*') || strchr (buff, '%') || strstr (buff, "..."))
3248         {
3249           int i, dirs;
3250
3251           dirs = __gnat_to_canonical_file_list_init (buff, 1);
3252           for (i = 0; i < dirs; i++)
3253             {
3254               char *next_dir;
3255
3256               next_dir = __gnat_to_canonical_file_list_next ();
3257               strncat (new_canonical_pathspec, next_dir, MAXPATH);
3258
3259               /* Don't append the separator after the last expansion.  */
3260               if (i+1 < dirs)
3261                 strncat (new_canonical_pathspec, ":", MAXPATH);
3262             }
3263
3264           __gnat_to_canonical_file_list_free ();
3265         }
3266       else
3267         strncat (new_canonical_pathspec,
3268                 __gnat_to_canonical_dir_spec (buff, 0), MAXPATH);
3269
3270       if (*next == 0)
3271         break;
3272
3273       strncat (new_canonical_pathspec, ":", MAXPATH);
3274       curr = next + 1;
3275     }
3276
3277   new_canonical_pathspec [MAXPATH - 1] = (char) 0;
3278
3279   return new_canonical_pathspec;
3280 }
3281
3282 static char filename_buff [MAXPATH];
3283
3284 static int
3285 translate_unix (char *name, int type)
3286 {
3287   strncpy (filename_buff, name, MAXPATH);
3288   filename_buff [MAXPATH - 1] = (char) 0;
3289   return 0;
3290 }
3291
3292 /* Translate a Unix syntax path spec into a VMS style (comma separated list of
3293    directories.  */
3294
3295 static char *
3296 to_host_path_spec (char *pathspec)
3297 {
3298   char *curr, *next, buff [MAXPATH];
3299
3300   if (pathspec == 0)
3301     return pathspec;
3302
3303   /* Can't very well test for colons, since that's the Unix separator!  */
3304   if (strchr (pathspec, ']') || strchr (pathspec, ','))
3305     return pathspec;
3306
3307   new_host_pathspec[0] = 0;
3308   curr = pathspec;
3309
3310   for (;;)
3311     {
3312       next = strchr (curr, ':');
3313       if (next == 0)
3314         next = strchr (curr, 0);
3315
3316       strncpy (buff, curr, next - curr);
3317       buff[next - curr] = 0;
3318
3319       strncat (new_host_pathspec, __gnat_to_host_dir_spec (buff, 0), MAXPATH);
3320       if (*next == 0)
3321         break;
3322       strncat (new_host_pathspec, ",", MAXPATH);
3323       curr = next + 1;
3324     }
3325
3326   new_host_pathspec [MAXPATH - 1] = (char) 0;
3327
3328   return new_host_pathspec;
3329 }
3330
3331 /* Translate a Unix syntax directory specification into VMS syntax.  The
3332    PREFIXFLAG has no effect, but is kept for symmetry with
3333    to_canonical_dir_spec.  If indicators of VMS syntax found, return input
3334    string. */
3335
3336 char *
3337 __gnat_to_host_dir_spec (char *dirspec, int prefixflag ATTRIBUTE_UNUSED)
3338 {
3339   int len = strlen (dirspec);
3340
3341   strncpy (new_host_dirspec, dirspec, MAXPATH);
3342   new_host_dirspec [MAXPATH - 1] = (char) 0;
3343
3344   if (strchr (new_host_dirspec, ']') || strchr (new_host_dirspec, ':'))
3345     return new_host_dirspec;
3346
3347   while (len > 1 && new_host_dirspec[len - 1] == '/')
3348     {
3349       new_host_dirspec[len - 1] = 0;
3350       len--;
3351     }
3352
3353   decc$to_vms (new_host_dirspec, translate_unix, 1, 2);
3354   strncpy (new_host_dirspec, filename_buff, MAXPATH);
3355   new_host_dirspec [MAXPATH - 1] = (char) 0;
3356
3357   return new_host_dirspec;
3358 }
3359
3360 /* Translate a Unix syntax file specification into VMS syntax.
3361    If indicators of VMS syntax found, return input string.  */
3362
3363 char *
3364 __gnat_to_host_file_spec (char *filespec)
3365 {
3366   strncpy (new_host_filespec, "", MAXPATH);
3367   if (strchr (filespec, ']') || strchr (filespec, ':'))
3368     {
3369       strncpy (new_host_filespec, filespec, MAXPATH);
3370     }
3371   else
3372     {
3373       decc$to_vms (filespec, translate_unix, 1, 1);
3374       strncpy (new_host_filespec, filename_buff, MAXPATH);
3375     }
3376
3377   new_host_filespec [MAXPATH - 1] = (char) 0;
3378
3379   return new_host_filespec;
3380 }
3381
3382 void
3383 __gnat_adjust_os_resource_limits ()
3384 {
3385   SYS$ADJWSL (131072, 0);
3386 }
3387
3388 #else /* VMS */
3389
3390 /* Dummy functions for Osint import for non-VMS systems.  */
3391
3392 int
3393 __gnat_to_canonical_file_list_init
3394   (char *dirspec ATTRIBUTE_UNUSED, int onlydirs ATTRIBUTE_UNUSED)
3395 {
3396   return 0;
3397 }
3398
3399 char *
3400 __gnat_to_canonical_file_list_next (void)
3401 {
3402   static char *empty = "";
3403   return empty;
3404 }
3405
3406 void
3407 __gnat_to_canonical_file_list_free (void)
3408 {
3409 }
3410
3411 char *
3412 __gnat_to_canonical_dir_spec (char *dirspec, int prefixflag ATTRIBUTE_UNUSED)
3413 {
3414   return dirspec;
3415 }
3416
3417 char *
3418 __gnat_to_canonical_file_spec (char *filespec)
3419 {
3420   return filespec;
3421 }
3422
3423 char *
3424 __gnat_to_canonical_path_spec (char *pathspec)
3425 {
3426   return pathspec;
3427 }
3428
3429 char *
3430 __gnat_to_host_dir_spec (char *dirspec, int prefixflag ATTRIBUTE_UNUSED)
3431 {
3432   return dirspec;
3433 }
3434
3435 char *
3436 __gnat_to_host_file_spec (char *filespec)
3437 {
3438   return filespec;
3439 }
3440
3441 void
3442 __gnat_adjust_os_resource_limits (void)
3443 {
3444 }
3445
3446 #endif
3447
3448 /* For EMX, we cannot include dummy in libgcc, since it is too difficult
3449    to coordinate this with the EMX distribution. Consequently, we put the
3450    definition of dummy which is used for exception handling, here.  */
3451
3452 #if defined (__EMX__)
3453 void __dummy () {}
3454 #endif
3455
3456 #if defined (__mips_vxworks)
3457 int
3458 _flush_cache()
3459 {
3460    CACHE_USER_FLUSH (0, ENTIRE_CACHE);
3461 }
3462 #endif
3463
3464 #if defined (IS_CROSS)  \
3465   || (! ((defined (sparc) || defined (i386)) && defined (sun) \
3466       && defined (__SVR4)) \
3467       && ! (defined (linux) && (defined (i386) || defined (__x86_64__))) \
3468       && ! (defined (linux) && defined (__ia64__)) \
3469       && ! (defined (linux) && defined (powerpc)) \
3470       && ! defined (__FreeBSD__) \
3471       && ! defined (__Lynx__) \
3472       && ! defined (__hpux__) \
3473       && ! defined (__APPLE__) \
3474       && ! defined (_AIX) \
3475       && ! (defined (__alpha__)  && defined (__osf__)) \
3476       && ! defined (VMS) \
3477       && ! defined (__MINGW32__) \
3478       && ! (defined (__mips) && defined (__sgi)))
3479
3480 /* Dummy function to satisfy g-trasym.o. See the preprocessor conditional
3481    just above for a list of native platforms that provide a non-dummy
3482    version of this procedure in libaddr2line.a.  */
3483
3484 void
3485 convert_addresses (const char *file_name ATTRIBUTE_UNUSED,
3486                    void *addrs ATTRIBUTE_UNUSED,
3487                    int n_addr ATTRIBUTE_UNUSED,
3488                    void *buf ATTRIBUTE_UNUSED,
3489                    int *len ATTRIBUTE_UNUSED)
3490 {
3491   *len = 0;
3492 }
3493 #endif
3494
3495 #if defined (_WIN32)
3496 int __gnat_argument_needs_quote = 1;
3497 #else
3498 int __gnat_argument_needs_quote = 0;
3499 #endif
3500
3501 /* This option is used to enable/disable object files handling from the
3502    binder file by the GNAT Project module. For example, this is disabled on
3503    Windows (prior to GCC 3.4) as it is already done by the mdll module.
3504    Stating with GCC 3.4 the shared libraries are not based on mdll
3505    anymore as it uses the GCC's -shared option  */
3506 #if defined (_WIN32) \
3507     && ((__GNUC__ < 3) || ((__GNUC__ == 3) && (__GNUC_MINOR__ < 4)))
3508 int __gnat_prj_add_obj_files = 0;
3509 #else
3510 int __gnat_prj_add_obj_files = 1;
3511 #endif
3512
3513 /* char used as prefix/suffix for environment variables */
3514 #if defined (_WIN32)
3515 char __gnat_environment_char = '%';
3516 #else
3517 char __gnat_environment_char = '$';
3518 #endif
3519
3520 /* This functions copy the file attributes from a source file to a
3521    destination file.
3522
3523    mode = 0  : In this mode copy only the file time stamps (last access and
3524                last modification time stamps).
3525
3526    mode = 1  : In this mode, time stamps and read/write/execute attributes are
3527                copied.
3528
3529    Returns 0 if operation was successful and -1 in case of error. */
3530
3531 int
3532 __gnat_copy_attribs (char *from, char *to, int mode)
3533 {
3534 #if defined (VMS) || defined (__vxworks) || defined (__nucleus__)
3535   return -1;
3536
3537 #elif defined (_WIN32) && !defined (RTX)
3538   TCHAR wfrom [GNAT_MAX_PATH_LEN + 2];
3539   TCHAR wto [GNAT_MAX_PATH_LEN + 2];
3540   BOOL res;
3541   FILETIME fct, flat, flwt;
3542   HANDLE hfrom, hto;
3543
3544   S2WSC (wfrom, from, GNAT_MAX_PATH_LEN + 2);
3545   S2WSC (wto, to, GNAT_MAX_PATH_LEN + 2);
3546
3547   /* retrieve from times */
3548
3549   hfrom = CreateFile
3550     (wfrom, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
3551
3552   if (hfrom == INVALID_HANDLE_VALUE)
3553     return -1;
3554
3555   res = GetFileTime (hfrom, &fct, &flat, &flwt);
3556
3557   CloseHandle (hfrom);
3558
3559   if (res == 0)
3560     return -1;
3561
3562   /* retrieve from times */
3563
3564   hto = CreateFile
3565     (wto, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
3566
3567   if (hto == INVALID_HANDLE_VALUE)
3568     return -1;
3569
3570   res = SetFileTime (hto, NULL, &flat, &flwt);
3571
3572   CloseHandle (hto);
3573
3574   if (res == 0)
3575     return -1;
3576
3577   /* Set file attributes in full mode. */
3578
3579   if (mode == 1)
3580     {
3581       DWORD attribs = GetFileAttributes (wfrom);
3582
3583       if (attribs == INVALID_FILE_ATTRIBUTES)
3584         return -1;
3585
3586       res = SetFileAttributes (wto, attribs);
3587       if (res == 0)
3588         return -1;
3589     }
3590
3591   return 0;
3592
3593 #else
3594   GNAT_STRUCT_STAT fbuf;
3595   struct utimbuf tbuf;
3596
3597   if (GNAT_STAT (from, &fbuf) == -1)
3598     {
3599       return -1;
3600     }
3601
3602   tbuf.actime = fbuf.st_atime;
3603   tbuf.modtime = fbuf.st_mtime;
3604
3605   if (utime (to, &tbuf) == -1)
3606     {
3607       return -1;
3608     }
3609
3610   if (mode == 1)
3611     {
3612       if (chmod (to, fbuf.st_mode) == -1)
3613         {
3614           return -1;
3615         }
3616     }
3617
3618   return 0;
3619 #endif
3620 }
3621
3622 int
3623 __gnat_lseek (int fd, long offset, int whence)
3624 {
3625   return (int) lseek (fd, offset, whence);
3626 }
3627
3628 /* This function returns the major version number of GCC being used.  */
3629 int
3630 get_gcc_version (void)
3631 {
3632 #ifdef IN_RTS
3633   return __GNUC__;
3634 #else
3635   return (int) (version_string[0] - '0');
3636 #endif
3637 }
3638
3639 int
3640 __gnat_set_close_on_exec (int fd ATTRIBUTE_UNUSED,
3641                           int close_on_exec_p ATTRIBUTE_UNUSED)
3642 {
3643 #if defined (F_GETFD) && defined (FD_CLOEXEC) && ! defined (__vxworks)
3644   int flags = fcntl (fd, F_GETFD, 0);
3645   if (flags < 0)
3646     return flags;
3647   if (close_on_exec_p)
3648     flags |= FD_CLOEXEC;
3649   else
3650     flags &= ~FD_CLOEXEC;
3651   return fcntl (fd, F_SETFD, flags | FD_CLOEXEC);
3652 #elif defined(_WIN32)
3653   HANDLE h = (HANDLE) _get_osfhandle (fd);
3654   if (h == (HANDLE) -1)
3655     return -1;
3656   if (close_on_exec_p)
3657     return ! SetHandleInformation (h, HANDLE_FLAG_INHERIT, 0);
3658   return ! SetHandleInformation (h, HANDLE_FLAG_INHERIT,
3659     HANDLE_FLAG_INHERIT);
3660 #else
3661   /* TODO: Unimplemented. */
3662   return -1;
3663 #endif
3664 }
3665
3666 /* Indicates if platforms supports automatic initialization through the
3667    constructor mechanism */
3668 int
3669 __gnat_binder_supports_auto_init (void)
3670 {
3671 #ifdef VMS
3672    return 0;
3673 #else
3674    return 1;
3675 #endif
3676 }
3677
3678 /* Indicates that Stand-Alone Libraries are automatically initialized through
3679    the constructor mechanism */
3680 int
3681 __gnat_sals_init_using_constructors (void)
3682 {
3683 #if defined (__vxworks) || defined (__Lynx__) || defined (VMS)
3684    return 0;
3685 #else
3686    return 1;
3687 #endif
3688 }
3689
3690 #ifdef RTX
3691
3692 /* In RTX mode, the procedure to get the time (as file time) is different
3693    in RTSS mode and Win32 mode. In order to avoid duplicating an Ada file,
3694    we introduce an intermediate procedure to link against the corresponding
3695    one in each situation. */
3696
3697 extern void GetTimeAsFileTime(LPFILETIME pTime);
3698
3699 void GetTimeAsFileTime(LPFILETIME pTime)
3700 {
3701 #ifdef RTSS
3702   RtGetRtssTimeAsFileTime (pTime); /* RTSS interface */
3703 #else
3704   GetSystemTimeAsFileTime (pTime); /* w32 interface */
3705 #endif
3706 }
3707
3708 #ifdef RTSS
3709 /* Add symbol that is required to link. It would otherwise be taken from
3710    libgcc.a and it would try to use the gcc constructors that are not
3711    supported by Microsoft linker. */
3712
3713 extern void __main (void);
3714
3715 void __main (void) {}
3716 #endif
3717 #endif
3718
3719 #if defined (linux) || defined(__GLIBC__)
3720 /* pthread affinity support */
3721
3722 int __gnat_pthread_setaffinity_np (pthread_t th,
3723                                    size_t cpusetsize,
3724                                    const void *cpuset);
3725
3726 #ifdef CPU_SETSIZE
3727 #include <pthread.h>
3728 int
3729 __gnat_pthread_setaffinity_np (pthread_t th,
3730                                size_t cpusetsize,
3731                                const cpu_set_t *cpuset)
3732 {
3733   return pthread_setaffinity_np (th, cpusetsize, cpuset);
3734 }
3735 #else
3736 int
3737 __gnat_pthread_setaffinity_np (pthread_t th ATTRIBUTE_UNUSED,
3738                                size_t cpusetsize ATTRIBUTE_UNUSED,
3739                                const void *cpuset ATTRIBUTE_UNUSED)
3740 {
3741   return 0;
3742 }
3743 #endif
3744 #endif
3745
3746 #if defined (linux)
3747 /* There is no function in the glibc to retrieve the LWP of the current
3748    thread. We need to do a system call in order to retrieve this
3749    information. */
3750 #include <sys/syscall.h>
3751 void *__gnat_lwp_self (void)
3752 {
3753    return (void *) syscall (__NR_gettid);
3754 }
3755 #endif