OSDN Git Service

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