OSDN Git Service

gcc/ada/
[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,
647                     char *os_name, int *o_length,
648                     char *encoding, 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)
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)
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 (linux)) && \
891   !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 #define MAX_SAFE_PATH 1000
985   char *tmpdir = getenv ("TMPDIR");
986
987   /* If tmpdir is longer than MAX_SAFE_PATH, revert to default value to avoid
988      a buffer overflow.  */
989   if (tmpdir == NULL || strlen (tmpdir) > MAX_SAFE_PATH)
990     strcpy (tmp_filename, "/tmp/gnat-XXXXXX");
991   else
992     sprintf (tmp_filename, "%s/gnat-XXXXXX", tmpdir);
993
994   close (mkstemp(tmp_filename));
995 #else
996   tmpnam (tmp_filename);
997 #endif
998 }
999
1000 /*  Open directory and returns a DIR pointer.  */
1001
1002 DIR* __gnat_opendir (char *name)
1003 {
1004 #if defined (RTX)
1005   /* Not supported in RTX */
1006
1007   return NULL;
1008
1009 #elif defined (__MINGW32__)
1010   TCHAR wname[GNAT_MAX_PATH_LEN];
1011
1012   S2WSU (wname, name, GNAT_MAX_PATH_LEN);
1013   return (DIR*)_topendir (wname);
1014
1015 #else
1016   return opendir (name);
1017 #endif
1018 }
1019
1020 /* Read the next entry in a directory.  The returned string points somewhere
1021    in the buffer.  */
1022
1023 char *
1024 __gnat_readdir (DIR *dirp, char *buffer, int *len)
1025 {
1026 #if defined (RTX)
1027   /* Not supported in RTX */
1028
1029   return NULL;
1030 #elif defined (__MINGW32__)
1031   struct _tdirent *dirent = _treaddir ((_TDIR*)dirp);
1032
1033   if (dirent != NULL)
1034     {
1035       WS2SU (buffer, dirent->d_name, GNAT_MAX_PATH_LEN);
1036       *len = strlen (buffer);
1037
1038       return buffer;
1039     }
1040   else
1041     return NULL;
1042
1043 #elif defined (HAVE_READDIR_R)
1044   /* If possible, try to use the thread-safe version.  */
1045   if (readdir_r (dirp, buffer) != NULL)
1046     {
1047       *len = strlen (((struct dirent*) buffer)->d_name);
1048       return ((struct dirent*) buffer)->d_name;
1049     }
1050   else
1051     return NULL;
1052
1053 #else
1054   struct dirent *dirent = (struct dirent *) readdir (dirp);
1055
1056   if (dirent != NULL)
1057     {
1058       strcpy (buffer, dirent->d_name);
1059       *len = strlen (buffer);
1060       return buffer;
1061     }
1062   else
1063     return NULL;
1064
1065 #endif
1066 }
1067
1068 /* Close a directory entry.  */
1069
1070 int __gnat_closedir (DIR *dirp)
1071 {
1072 #if defined (RTX)
1073   /* Not supported in RTX */
1074
1075   return 0;
1076
1077 #elif defined (__MINGW32__)
1078   return _tclosedir ((_TDIR*)dirp);
1079
1080 #else
1081   return closedir (dirp);
1082 #endif
1083 }
1084
1085 /* Returns 1 if readdir is thread safe, 0 otherwise.  */
1086
1087 int
1088 __gnat_readdir_is_thread_safe (void)
1089 {
1090 #ifdef HAVE_READDIR_R
1091   return 1;
1092 #else
1093   return 0;
1094 #endif
1095 }
1096
1097 #if defined (_WIN32) && !defined (RTX)
1098 /* Number of seconds between <Jan 1st 1601> and <Jan 1st 1970>.  */
1099 static const unsigned long long w32_epoch_offset = 11644473600ULL;
1100
1101 /* Returns the file modification timestamp using Win32 routines which are
1102    immune against daylight saving time change. It is in fact not possible to
1103    use fstat for this purpose as the DST modify the st_mtime field of the
1104    stat structure.  */
1105
1106 static time_t
1107 win32_filetime (HANDLE h)
1108 {
1109   union
1110   {
1111     FILETIME ft_time;
1112     unsigned long long ull_time;
1113   } t_write;
1114
1115   /* GetFileTime returns FILETIME data which are the number of 100 nanosecs
1116      since <Jan 1st 1601>. This function must return the number of seconds
1117      since <Jan 1st 1970>.  */
1118
1119   if (GetFileTime (h, NULL, NULL, &t_write.ft_time))
1120     return (time_t) (t_write.ull_time / 10000000ULL - w32_epoch_offset);
1121   return (time_t) 0;
1122 }
1123 #endif
1124
1125 /* Return a GNAT time stamp given a file name.  */
1126
1127 OS_Time
1128 __gnat_file_time_name (char *name)
1129 {
1130
1131 #if defined (__EMX__) || defined (MSDOS)
1132   int fd = open (name, O_RDONLY | O_BINARY);
1133   time_t ret = __gnat_file_time_fd (fd);
1134   close (fd);
1135   return (OS_Time)ret;
1136
1137 #elif defined (_WIN32) && !defined (RTX)
1138   time_t ret = -1;
1139   TCHAR wname[GNAT_MAX_PATH_LEN];
1140
1141   S2WSU (wname, name, GNAT_MAX_PATH_LEN);
1142
1143   HANDLE h = CreateFile
1144     (wname, GENERIC_READ, FILE_SHARE_READ, 0,
1145      OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0);
1146
1147   if (h != INVALID_HANDLE_VALUE)
1148     {
1149       ret = win32_filetime (h);
1150       CloseHandle (h);
1151     }
1152   return (OS_Time) ret;
1153 #else
1154   struct stat statbuf;
1155   if (__gnat_stat (name, &statbuf) != 0) {
1156      return (OS_Time)-1;
1157   } else {
1158 #ifdef VMS
1159      /* VMS has file versioning.  */
1160      return (OS_Time)statbuf.st_ctime;
1161 #else
1162      return (OS_Time)statbuf.st_mtime;
1163 #endif
1164   }
1165 #endif
1166 }
1167
1168 /* Return a GNAT time stamp given a file descriptor.  */
1169
1170 OS_Time
1171 __gnat_file_time_fd (int fd)
1172 {
1173   /* The following workaround code is due to the fact that under EMX and
1174      DJGPP fstat attempts to convert time values to GMT rather than keep the
1175      actual OS timestamp of the file. By using the OS2/DOS functions directly
1176      the GNAT timestamp are independent of this behavior, which is desired to
1177      facilitate the distribution of GNAT compiled libraries.  */
1178
1179 #if defined (__EMX__) || defined (MSDOS)
1180 #ifdef __EMX__
1181
1182   FILESTATUS fs;
1183   int ret = DosQueryFileInfo (fd, 1, (unsigned char *) &fs,
1184                                 sizeof (FILESTATUS));
1185
1186   unsigned file_year  = fs.fdateLastWrite.year;
1187   unsigned file_month = fs.fdateLastWrite.month;
1188   unsigned file_day   = fs.fdateLastWrite.day;
1189   unsigned file_hour  = fs.ftimeLastWrite.hours;
1190   unsigned file_min   = fs.ftimeLastWrite.minutes;
1191   unsigned file_tsec  = fs.ftimeLastWrite.twosecs;
1192
1193 #else
1194   struct ftime fs;
1195   int ret = getftime (fd, &fs);
1196
1197   unsigned file_year  = fs.ft_year;
1198   unsigned file_month = fs.ft_month;
1199   unsigned file_day   = fs.ft_day;
1200   unsigned file_hour  = fs.ft_hour;
1201   unsigned file_min   = fs.ft_min;
1202   unsigned file_tsec  = fs.ft_tsec;
1203 #endif
1204
1205   /* Calculate the seconds since epoch from the time components. First count
1206      the whole days passed.  The value for years returned by the DOS and OS2
1207      functions count years from 1980, so to compensate for the UNIX epoch which
1208      begins in 1970 start with 10 years worth of days and add days for each
1209      four year period since then.  */
1210
1211   time_t tot_secs;
1212   int cum_days[12] = {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334};
1213   int days_passed = 3652 + (file_year / 4) * 1461;
1214   int years_since_leap = file_year % 4;
1215
1216   if (years_since_leap == 1)
1217     days_passed += 366;
1218   else if (years_since_leap == 2)
1219     days_passed += 731;
1220   else if (years_since_leap == 3)
1221     days_passed += 1096;
1222
1223   if (file_year > 20)
1224     days_passed -= 1;
1225
1226   days_passed += cum_days[file_month - 1];
1227   if (years_since_leap == 0 && file_year != 20 && file_month > 2)
1228     days_passed++;
1229
1230   days_passed += file_day - 1;
1231
1232   /* OK - have whole days.  Multiply -- then add in other parts.  */
1233
1234   tot_secs  = days_passed * 86400;
1235   tot_secs += file_hour * 3600;
1236   tot_secs += file_min * 60;
1237   tot_secs += file_tsec * 2;
1238   return (OS_Time) tot_secs;
1239
1240 #elif defined (_WIN32) && !defined (RTX)
1241   HANDLE h = (HANDLE) _get_osfhandle (fd);
1242   time_t ret = win32_filetime (h);
1243   return (OS_Time) ret;
1244
1245 #else
1246   struct stat statbuf;
1247
1248   if (fstat (fd, &statbuf) != 0) {
1249      return (OS_Time) -1;
1250   } else {
1251 #ifdef VMS
1252      /* VMS has file versioning.  */
1253      return (OS_Time) statbuf.st_ctime;
1254 #else
1255      return (OS_Time) statbuf.st_mtime;
1256 #endif
1257   }
1258 #endif
1259 }
1260
1261 /* Set the file time stamp.  */
1262
1263 void
1264 __gnat_set_file_time_name (char *name, time_t time_stamp)
1265 {
1266 #if defined (__EMX__) || defined (MSDOS) || defined (__vxworks)
1267
1268 /* Code to implement __gnat_set_file_time_name for these systems.  */
1269
1270 #elif defined (_WIN32) && !defined (RTX)
1271   union
1272   {
1273     FILETIME ft_time;
1274     unsigned long long ull_time;
1275   } t_write;
1276   TCHAR wname[GNAT_MAX_PATH_LEN];
1277
1278   S2WSU (wname, name, GNAT_MAX_PATH_LEN);
1279
1280   HANDLE h  = CreateFile
1281     (wname, GENERIC_WRITE, FILE_SHARE_WRITE, NULL,
1282      OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS,
1283      NULL);
1284   if (h == INVALID_HANDLE_VALUE)
1285     return;
1286   /* Add number of seconds between <Jan 1st 1601> and <Jan 1st 1970> */
1287   t_write.ull_time = ((unsigned long long)time_stamp + w32_epoch_offset);
1288   /*  Convert to 100 nanosecond units  */
1289   t_write.ull_time *= 10000000ULL;
1290
1291   SetFileTime(h, NULL, NULL, &t_write.ft_time);
1292   CloseHandle (h);
1293   return;
1294
1295 #elif defined (VMS)
1296   struct FAB fab;
1297   struct NAM nam;
1298
1299   struct
1300     {
1301       unsigned long long backup, create, expire, revise;
1302       unsigned int uic;
1303       union
1304         {
1305           unsigned short value;
1306           struct
1307             {
1308               unsigned system : 4;
1309               unsigned owner  : 4;
1310               unsigned group  : 4;
1311               unsigned world  : 4;
1312             } bits;
1313         } prot;
1314     } Fat = { 0, 0, 0, 0, 0, { 0 }};
1315
1316   ATRDEF atrlst[]
1317     = {
1318       { ATR$S_CREDATE,  ATR$C_CREDATE,  &Fat.create },
1319       { ATR$S_REVDATE,  ATR$C_REVDATE,  &Fat.revise },
1320       { ATR$S_EXPDATE,  ATR$C_EXPDATE,  &Fat.expire },
1321       { ATR$S_BAKDATE,  ATR$C_BAKDATE,  &Fat.backup },
1322       { ATR$S_FPRO,     ATR$C_FPRO,     &Fat.prot },
1323       { ATR$S_UIC,      ATR$C_UIC,      &Fat.uic },
1324       { 0, 0, 0}
1325     };
1326
1327   FIBDEF fib;
1328   struct dsc$descriptor_fib fibdsc = {sizeof (fib), (void *) &fib};
1329
1330   struct IOSB iosb;
1331
1332   unsigned long long newtime;
1333   unsigned long long revtime;
1334   long status;
1335   short chan;
1336
1337   struct vstring file;
1338   struct dsc$descriptor_s filedsc
1339     = {NAM$C_MAXRSS, DSC$K_DTYPE_T, DSC$K_CLASS_S, (void *) file.string};
1340   struct vstring device;
1341   struct dsc$descriptor_s devicedsc
1342     = {NAM$C_MAXRSS, DSC$K_DTYPE_T, DSC$K_CLASS_S, (void *) device.string};
1343   struct vstring timev;
1344   struct dsc$descriptor_s timedsc
1345     = {NAM$C_MAXRSS, DSC$K_DTYPE_T, DSC$K_CLASS_S, (void *) timev.string};
1346   struct vstring result;
1347   struct dsc$descriptor_s resultdsc
1348     = {NAM$C_MAXRSS, DSC$K_DTYPE_VT, DSC$K_CLASS_VS, (void *) result.string};
1349
1350   /* Convert parameter name (a file spec) to host file form. Note that this
1351      is needed on VMS to prepare for subsequent calls to VMS RMS library
1352      routines. Note that it would not work to call __gnat_to_host_dir_spec
1353      as was done in a previous version, since this fails silently unless
1354      the feature logical DECC$EFS_CHARSET is enabled, in which case a DNF
1355      (directory not found) condition is signalled.  */
1356   tryfile = (char *) __gnat_to_host_file_spec (name);
1357
1358   /* Allocate and initialize a FAB and NAM structures.  */
1359   fab = cc$rms_fab;
1360   nam = cc$rms_nam;
1361
1362   nam.nam$l_esa = file.string;
1363   nam.nam$b_ess = NAM$C_MAXRSS;
1364   nam.nam$l_rsa = result.string;
1365   nam.nam$b_rss = NAM$C_MAXRSS;
1366   fab.fab$l_fna = tryfile;
1367   fab.fab$b_fns = strlen (tryfile);
1368   fab.fab$l_nam = &nam;
1369
1370   /* Validate filespec syntax and device existence.  */
1371   status = SYS$PARSE (&fab, 0, 0);
1372   if ((status & 1) != 1)
1373     LIB$SIGNAL (status);
1374
1375   file.string[nam.nam$b_esl] = 0;
1376
1377   /* Find matching filespec.  */
1378   status = SYS$SEARCH (&fab, 0, 0);
1379   if ((status & 1) != 1)
1380     LIB$SIGNAL (status);
1381
1382   file.string[nam.nam$b_esl] = 0;
1383   result.string[result.length=nam.nam$b_rsl] = 0;
1384
1385   /* Get the device name and assign an IO channel.  */
1386   strncpy (device.string, nam.nam$l_dev, nam.nam$b_dev);
1387   devicedsc.dsc$w_length  = nam.nam$b_dev;
1388   chan = 0;
1389   status = SYS$ASSIGN (&devicedsc, &chan, 0, 0, 0);
1390   if ((status & 1) != 1)
1391     LIB$SIGNAL (status);
1392
1393   /* Initialize the FIB and fill in the directory id field.  */
1394   memset (&fib, 0, sizeof (fib));
1395   fib.fib$w_did[0]  = nam.nam$w_did[0];
1396   fib.fib$w_did[1]  = nam.nam$w_did[1];
1397   fib.fib$w_did[2]  = nam.nam$w_did[2];
1398   fib.fib$l_acctl = 0;
1399   fib.fib$l_wcc = 0;
1400   strcpy (file.string, (strrchr (result.string, ']') + 1));
1401   filedsc.dsc$w_length = strlen (file.string);
1402   result.string[result.length = 0] = 0;
1403
1404   /* Open and close the file to fill in the attributes.  */
1405   status
1406     = SYS$QIOW (0, chan, IO$_ACCESS|IO$M_ACCESS, &iosb, 0, 0,
1407                 &fibdsc, &filedsc, &result.length, &resultdsc, &atrlst, 0);
1408   if ((status & 1) != 1)
1409     LIB$SIGNAL (status);
1410   if ((iosb.status & 1) != 1)
1411     LIB$SIGNAL (iosb.status);
1412
1413   result.string[result.length] = 0;
1414   status = SYS$QIOW (0, chan, IO$_DEACCESS, &iosb, 0, 0, &fibdsc, 0, 0, 0,
1415                      &atrlst, 0);
1416   if ((status & 1) != 1)
1417     LIB$SIGNAL (status);
1418   if ((iosb.status & 1) != 1)
1419     LIB$SIGNAL (iosb.status);
1420
1421   {
1422     time_t t;
1423
1424     /* Set creation time to requested time.  */
1425     unix_time_to_vms (time_stamp, newtime);
1426
1427     t = time ((time_t) 0);
1428
1429     /* Set revision time to now in local time.  */
1430     unix_time_to_vms (t, revtime);
1431   }
1432
1433   /* Reopen the file, modify the times and then close.  */
1434   fib.fib$l_acctl = FIB$M_WRITE;
1435   status
1436     = SYS$QIOW (0, chan, IO$_ACCESS|IO$M_ACCESS, &iosb, 0, 0,
1437                 &fibdsc, &filedsc, &result.length, &resultdsc, &atrlst, 0);
1438   if ((status & 1) != 1)
1439     LIB$SIGNAL (status);
1440   if ((iosb.status & 1) != 1)
1441     LIB$SIGNAL (iosb.status);
1442
1443   Fat.create = newtime;
1444   Fat.revise = revtime;
1445
1446   status = SYS$QIOW (0, chan, IO$_DEACCESS, &iosb, 0, 0,
1447                      &fibdsc, 0, 0, 0, &atrlst, 0);
1448   if ((status & 1) != 1)
1449     LIB$SIGNAL (status);
1450   if ((iosb.status & 1) != 1)
1451     LIB$SIGNAL (iosb.status);
1452
1453   /* Deassign the channel and exit.  */
1454   status = SYS$DASSGN (chan);
1455   if ((status & 1) != 1)
1456     LIB$SIGNAL (status);
1457 #else
1458   struct utimbuf utimbuf;
1459   time_t t;
1460
1461   /* Set modification time to requested time.  */
1462   utimbuf.modtime = time_stamp;
1463
1464   /* Set access time to now in local time.  */
1465   t = time ((time_t) 0);
1466   utimbuf.actime = mktime (localtime (&t));
1467
1468   utime (name, &utimbuf);
1469 #endif
1470 }
1471
1472 #ifdef _WIN32
1473 #include <windows.h>
1474 #endif
1475
1476 /* Get the list of installed standard libraries from the
1477    HKEY_LOCAL_MACHINE\SOFTWARE\Ada Core Technologies\GNAT\Standard Libraries
1478    key.  */
1479
1480 char *
1481 __gnat_get_libraries_from_registry (void)
1482 {
1483   char *result = (char *) "";
1484
1485 #if defined (_WIN32) && ! defined (__vxworks) && ! defined (CROSS_DIRECTORY_STRUCTURE) && ! defined (RTX)
1486
1487   HKEY reg_key;
1488   DWORD name_size, value_size;
1489   char name[256];
1490   char value[256];
1491   DWORD type;
1492   DWORD index;
1493   LONG res;
1494
1495   /* First open the key.  */
1496   res = RegOpenKeyExA (HKEY_LOCAL_MACHINE, "SOFTWARE", 0, KEY_READ, &reg_key);
1497
1498   if (res == ERROR_SUCCESS)
1499     res = RegOpenKeyExA (reg_key, "Ada Core Technologies", 0,
1500                          KEY_READ, &reg_key);
1501
1502   if (res == ERROR_SUCCESS)
1503     res = RegOpenKeyExA (reg_key, "GNAT", 0, KEY_READ, &reg_key);
1504
1505   if (res == ERROR_SUCCESS)
1506     res = RegOpenKeyExA (reg_key, "Standard Libraries", 0, KEY_READ, &reg_key);
1507
1508   /* If the key exists, read out all the values in it and concatenate them
1509      into a path.  */
1510   for (index = 0; res == ERROR_SUCCESS; index++)
1511     {
1512       value_size = name_size = 256;
1513       res = RegEnumValueA (reg_key, index, (TCHAR*)name, &name_size, 0,
1514                            &type, (LPBYTE)value, &value_size);
1515
1516       if (res == ERROR_SUCCESS && type == REG_SZ)
1517         {
1518           char *old_result = result;
1519
1520           result = (char *) xmalloc (strlen (old_result) + value_size + 2);
1521           strcpy (result, old_result);
1522           strcat (result, value);
1523           strcat (result, ";");
1524         }
1525     }
1526
1527   /* Remove the trailing ";".  */
1528   if (result[0] != 0)
1529     result[strlen (result) - 1] = 0;
1530
1531 #endif
1532   return result;
1533 }
1534
1535 int
1536 __gnat_stat (char *name, struct stat *statbuf)
1537 {
1538 #ifdef __MINGW32__
1539   /* Under Windows the directory name for the stat function must not be
1540      terminated by a directory separator except if just after a drive name.  */
1541   TCHAR wname [GNAT_MAX_PATH_LEN + 2];
1542   int name_len;
1543   TCHAR last_char;
1544
1545   S2WSU (wname, name, GNAT_MAX_PATH_LEN + 2);
1546   name_len = _tcslen (wname);
1547
1548   if (name_len > GNAT_MAX_PATH_LEN)
1549     return -1;
1550
1551   last_char = wname[name_len - 1];
1552
1553   while (name_len > 1 && (last_char == _T('\\') || last_char == _T('/')))
1554     {
1555       wname[name_len - 1] = _T('\0');
1556       name_len--;
1557       last_char = wname[name_len - 1];
1558     }
1559
1560   /* Only a drive letter followed by ':', we must add a directory separator
1561      for the stat routine to work properly.  */
1562   if (name_len == 2 && wname[1] == _T(':'))
1563     _tcscat (wname, _T("\\"));
1564
1565   return _tstat (wname, statbuf);
1566
1567 #else
1568   return stat (name, statbuf);
1569 #endif
1570 }
1571
1572 int
1573 __gnat_file_exists (char *name)
1574 {
1575 #if defined (__MINGW32__) && !defined (RTX)
1576   /*  On Windows do not use __gnat_stat() because a bug in Microsoft
1577   _stat() routine. When the system time-zone is set with a negative
1578   offset the _stat() routine fails on specific files like CON:  */
1579   TCHAR wname [GNAT_MAX_PATH_LEN + 2];
1580
1581   S2WSU (wname, name, GNAT_MAX_PATH_LEN + 2);
1582   return GetFileAttributes (wname) != INVALID_FILE_ATTRIBUTES;
1583 #else
1584   struct stat statbuf;
1585
1586   return !__gnat_stat (name, &statbuf);
1587 #endif
1588 }
1589
1590 int
1591 __gnat_is_absolute_path (char *name, int length)
1592 {
1593 #ifdef __vxworks
1594   /* On VxWorks systems, an absolute path can be represented (depending on
1595      the host platform) as either /dir/file, or device:/dir/file, or
1596      device:drive_letter:/dir/file. */
1597
1598   int index;
1599
1600   if (name[0] == '/')
1601     return 1;
1602
1603   for (index = 0; index < length; index++)
1604     {
1605       if (name[index] == ':' &&
1606           ((name[index + 1] == '/') ||
1607            (isalpha (name[index + 1]) && index + 2 <= length &&
1608             name[index + 2] == '/')))
1609         return 1;
1610
1611       else if (name[index] == '/')
1612         return 0;
1613     }
1614   return 0;
1615 #else
1616   return (length != 0) &&
1617      (*name == '/' || *name == DIR_SEPARATOR
1618 #if defined (__EMX__) || defined (MSDOS) || defined (WINNT)
1619       || (length > 1 && isalpha (name[0]) && name[1] == ':')
1620 #endif
1621           );
1622 #endif
1623 }
1624
1625 int
1626 __gnat_is_regular_file (char *name)
1627 {
1628   int ret;
1629   struct stat statbuf;
1630
1631   ret = __gnat_stat (name, &statbuf);
1632   return (!ret && S_ISREG (statbuf.st_mode));
1633 }
1634
1635 int
1636 __gnat_is_directory (char *name)
1637 {
1638   int ret;
1639   struct stat statbuf;
1640
1641   ret = __gnat_stat (name, &statbuf);
1642   return (!ret && S_ISDIR (statbuf.st_mode));
1643 }
1644
1645 int
1646 __gnat_is_readable_file (char *name)
1647 {
1648   int ret;
1649   int mode;
1650   struct stat statbuf;
1651
1652   ret = __gnat_stat (name, &statbuf);
1653   mode = statbuf.st_mode & S_IRUSR;
1654   return (!ret && mode);
1655 }
1656
1657 int
1658 __gnat_is_writable_file (char *name)
1659 {
1660   int ret;
1661   int mode;
1662   struct stat statbuf;
1663
1664   ret = __gnat_stat (name, &statbuf);
1665   mode = statbuf.st_mode & S_IWUSR;
1666   return (!ret && mode);
1667 }
1668
1669 void
1670 __gnat_set_writable (char *name)
1671 {
1672 #if ! defined (__vxworks) && ! defined(__nucleus__)
1673   struct stat statbuf;
1674
1675   if (stat (name, &statbuf) == 0)
1676   {
1677     statbuf.st_mode = statbuf.st_mode | S_IWUSR;
1678     chmod (name, statbuf.st_mode);
1679   }
1680 #endif
1681 }
1682
1683 void
1684 __gnat_set_executable (char *name)
1685 {
1686 #if ! defined (__vxworks) && ! defined(__nucleus__)
1687   struct stat statbuf;
1688
1689   if (stat (name, &statbuf) == 0)
1690   {
1691     statbuf.st_mode = statbuf.st_mode | S_IXUSR;
1692     chmod (name, statbuf.st_mode);
1693   }
1694 #endif
1695 }
1696
1697 void
1698 __gnat_set_readonly (char *name)
1699 {
1700 #if ! defined (__vxworks) && ! defined(__nucleus__)
1701   struct stat statbuf;
1702
1703   if (stat (name, &statbuf) == 0)
1704   {
1705     statbuf.st_mode = statbuf.st_mode & 07577;
1706     chmod (name, statbuf.st_mode);
1707   }
1708 #endif
1709 }
1710
1711 int
1712 __gnat_is_symbolic_link (char *name ATTRIBUTE_UNUSED)
1713 {
1714 #if defined (__vxworks) || defined (__nucleus__)
1715   return 0;
1716
1717 #elif defined (_AIX) || defined (__APPLE__) || defined (__unix__)
1718   int ret;
1719   struct stat statbuf;
1720
1721   ret = lstat (name, &statbuf);
1722   return (!ret && S_ISLNK (statbuf.st_mode));
1723
1724 #else
1725   return 0;
1726 #endif
1727 }
1728
1729 #if defined (sun) && defined (__SVR4)
1730 /* Using fork on Solaris will duplicate all the threads. fork1, which
1731    duplicates only the active thread, must be used instead, or spawning
1732    subprocess from a program with tasking will lead into numerous problems.  */
1733 #define fork fork1
1734 #endif
1735
1736 int
1737 __gnat_portable_spawn (char *args[])
1738 {
1739   int status = 0;
1740   int finished ATTRIBUTE_UNUSED;
1741   int pid ATTRIBUTE_UNUSED;
1742
1743 #if defined (__vxworks) || defined(__nucleus__) || defined(RTX)
1744   return -1;
1745
1746 #elif defined (MSDOS) || defined (_WIN32)
1747   /* args[0] must be quotes as it could contain a full pathname with spaces */
1748   char *args_0 = args[0];
1749   args[0] = (char *)xmalloc (strlen (args_0) + 3);
1750   strcpy (args[0], "\"");
1751   strcat (args[0], args_0);
1752   strcat (args[0], "\"");
1753
1754   status = spawnvp (P_WAIT, args_0, (const char* const*)args);
1755
1756   /* restore previous value */
1757   free (args[0]);
1758   args[0] = (char *)args_0;
1759
1760   if (status < 0)
1761     return -1;
1762   else
1763     return status;
1764
1765 #else
1766
1767 #ifdef __EMX__
1768   pid = spawnvp (P_NOWAIT, args[0], args);
1769   if (pid == -1)
1770     return -1;
1771
1772 #else
1773   pid = fork ();
1774   if (pid < 0)
1775     return -1;
1776
1777   if (pid == 0)
1778     {
1779       /* The child. */
1780       if (execv (args[0], MAYBE_TO_PTR32 (args)) != 0)
1781 #if defined (VMS)
1782         return -1; /* execv is in parent context on VMS.  */
1783 #else
1784         _exit (1);
1785 #endif
1786     }
1787 #endif
1788
1789   /* The parent.  */
1790   finished = waitpid (pid, &status, 0);
1791
1792   if (finished != pid || WIFEXITED (status) == 0)
1793     return -1;
1794
1795   return WEXITSTATUS (status);
1796 #endif
1797
1798   return 0;
1799 }
1800
1801 /* Create a copy of the given file descriptor.
1802    Return -1 if an error occurred.  */
1803
1804 int
1805 __gnat_dup (int oldfd)
1806 {
1807 #if defined (__vxworks) && !defined (__RTP__)
1808   /* Not supported on VxWorks 5.x, but supported on VxWorks 6.0 when using
1809      RTPs. */
1810   return -1;
1811 #else
1812   return dup (oldfd);
1813 #endif
1814 }
1815
1816 /* Make newfd be the copy of oldfd, closing newfd first if necessary.
1817    Return -1 if an error occurred.  */
1818
1819 int
1820 __gnat_dup2 (int oldfd, int newfd)
1821 {
1822 #if defined (__vxworks) && !defined (__RTP__)
1823   /* Not supported on VxWorks 5.x, but supported on VxWorks 6.0 when using
1824      RTPs.  */
1825   return -1;
1826 #else
1827   return dup2 (oldfd, newfd);
1828 #endif
1829 }
1830
1831 /* WIN32 code to implement a wait call that wait for any child process.  */
1832
1833 #if defined (_WIN32) && !defined (RTX)
1834
1835 /* Synchronization code, to be thread safe.  */
1836
1837 static CRITICAL_SECTION plist_cs;
1838
1839 void
1840 __gnat_plist_init (void)
1841 {
1842   InitializeCriticalSection (&plist_cs);
1843 }
1844
1845 static void
1846 plist_enter (void)
1847 {
1848   EnterCriticalSection (&plist_cs);
1849 }
1850
1851 static void
1852 plist_leave (void)
1853 {
1854   LeaveCriticalSection (&plist_cs);
1855 }
1856
1857 typedef struct _process_list
1858 {
1859   HANDLE h;
1860   struct _process_list *next;
1861 } Process_List;
1862
1863 static Process_List *PLIST = NULL;
1864
1865 static int plist_length = 0;
1866
1867 static void
1868 add_handle (HANDLE h)
1869 {
1870   Process_List *pl;
1871
1872   pl = (Process_List *) xmalloc (sizeof (Process_List));
1873
1874   plist_enter();
1875
1876   /* -------------------- critical section -------------------- */
1877   pl->h = h;
1878   pl->next = PLIST;
1879   PLIST = pl;
1880   ++plist_length;
1881   /* -------------------- critical section -------------------- */
1882
1883   plist_leave();
1884 }
1885
1886 static void
1887 remove_handle (HANDLE h)
1888 {
1889   Process_List *pl;
1890   Process_List *prev = NULL;
1891
1892   plist_enter();
1893
1894   /* -------------------- critical section -------------------- */
1895   pl = PLIST;
1896   while (pl)
1897     {
1898       if (pl->h == h)
1899         {
1900           if (pl == PLIST)
1901             PLIST = pl->next;
1902           else
1903             prev->next = pl->next;
1904           free (pl);
1905           break;
1906         }
1907       else
1908         {
1909           prev = pl;
1910           pl = pl->next;
1911         }
1912     }
1913
1914   --plist_length;
1915   /* -------------------- critical section -------------------- */
1916
1917   plist_leave();
1918 }
1919
1920 static int
1921 win32_no_block_spawn (char *command, char *args[])
1922 {
1923   BOOL result;
1924   STARTUPINFO SI;
1925   PROCESS_INFORMATION PI;
1926   SECURITY_ATTRIBUTES SA;
1927   int csize = 1;
1928   char *full_command;
1929   int k;
1930
1931   /* compute the total command line length */
1932   k = 0;
1933   while (args[k])
1934     {
1935       csize += strlen (args[k]) + 1;
1936       k++;
1937     }
1938
1939   full_command = (char *) xmalloc (csize);
1940
1941   /* Startup info. */
1942   SI.cb          = sizeof (STARTUPINFO);
1943   SI.lpReserved  = NULL;
1944   SI.lpReserved2 = NULL;
1945   SI.lpDesktop   = NULL;
1946   SI.cbReserved2 = 0;
1947   SI.lpTitle     = NULL;
1948   SI.dwFlags     = 0;
1949   SI.wShowWindow = SW_HIDE;
1950
1951   /* Security attributes. */
1952   SA.nLength = sizeof (SECURITY_ATTRIBUTES);
1953   SA.bInheritHandle = TRUE;
1954   SA.lpSecurityDescriptor = NULL;
1955
1956   /* Prepare the command string. */
1957   strcpy (full_command, command);
1958   strcat (full_command, " ");
1959
1960   k = 1;
1961   while (args[k])
1962     {
1963       strcat (full_command, args[k]);
1964       strcat (full_command, " ");
1965       k++;
1966     }
1967
1968   {
1969     int wsize = csize * 2;
1970     TCHAR *wcommand = (TCHAR *) xmalloc (wsize);
1971
1972     S2WSU (wcommand, full_command, wsize);
1973
1974     free (full_command);
1975
1976     result = CreateProcess
1977       (NULL, wcommand, &SA, NULL, TRUE,
1978        GetPriorityClass (GetCurrentProcess()), NULL, NULL, &SI, &PI);
1979
1980     free (wcommand);
1981   }
1982
1983   if (result == TRUE)
1984     {
1985       add_handle (PI.hProcess);
1986       CloseHandle (PI.hThread);
1987       return (int) PI.hProcess;
1988     }
1989   else
1990     return -1;
1991 }
1992
1993 static int
1994 win32_wait (int *status)
1995 {
1996   DWORD exitcode;
1997   HANDLE *hl;
1998   HANDLE h;
1999   DWORD res;
2000   int k;
2001   Process_List *pl;
2002
2003   if (plist_length == 0)
2004     {
2005       errno = ECHILD;
2006       return -1;
2007     }
2008
2009   hl = (HANDLE *) xmalloc (sizeof (HANDLE) * plist_length);
2010
2011   k = 0;
2012   plist_enter();
2013
2014   /* -------------------- critical section -------------------- */
2015   pl = PLIST;
2016   while (pl)
2017     {
2018       hl[k++] = pl->h;
2019       pl = pl->next;
2020     }
2021   /* -------------------- critical section -------------------- */
2022
2023   plist_leave();
2024
2025   res = WaitForMultipleObjects (plist_length, hl, FALSE, INFINITE);
2026   h = hl[res - WAIT_OBJECT_0];
2027   free (hl);
2028
2029   remove_handle (h);
2030
2031   GetExitCodeProcess (h, &exitcode);
2032   CloseHandle (h);
2033
2034   *status = (int) exitcode;
2035   return (int) h;
2036 }
2037
2038 #endif
2039
2040 int
2041 __gnat_portable_no_block_spawn (char *args[])
2042 {
2043   int pid = 0;
2044
2045 #if defined (__vxworks) || defined (__nucleus__) || defined (RTX)
2046   return -1;
2047
2048 #elif defined (__EMX__) || defined (MSDOS)
2049
2050   /* ??? For PC machines I (Franco) don't know the system calls to implement
2051      this routine. So I'll fake it as follows. This routine will behave
2052      exactly like the blocking portable_spawn and will systematically return
2053      a pid of 0 unless the spawned task did not complete successfully, in
2054      which case we return a pid of -1.  To synchronize with this the
2055      portable_wait below systematically returns a pid of 0 and reports that
2056      the subprocess terminated successfully. */
2057
2058   if (spawnvp (P_WAIT, args[0], args) != 0)
2059     return -1;
2060
2061 #elif defined (_WIN32)
2062
2063   pid = win32_no_block_spawn (args[0], args);
2064   return pid;
2065
2066 #else
2067   pid = fork ();
2068
2069   if (pid == 0)
2070     {
2071       /* The child.  */
2072       if (execv (args[0], MAYBE_TO_PTR32 (args)) != 0)
2073 #if defined (VMS)
2074         return -1; /* execv is in parent context on VMS. */
2075 #else
2076         _exit (1);
2077 #endif
2078     }
2079
2080 #endif
2081
2082   return pid;
2083 }
2084
2085 int
2086 __gnat_portable_wait (int *process_status)
2087 {
2088   int status = 0;
2089   int pid = 0;
2090
2091 #if defined (__vxworks) || defined (__nucleus__) || defined (RTX)
2092   /* Not sure what to do here, so do same as __EMX__ case, i.e., nothing but
2093      return zero.  */
2094
2095 #elif defined (_WIN32)
2096
2097   pid = win32_wait (&status);
2098
2099 #elif defined (__EMX__) || defined (MSDOS)
2100   /* ??? See corresponding comment in portable_no_block_spawn.  */
2101
2102 #else
2103
2104   pid = waitpid (-1, &status, 0);
2105   status = status & 0xffff;
2106 #endif
2107
2108   *process_status = status;
2109   return pid;
2110 }
2111
2112 void
2113 __gnat_os_exit (int status)
2114 {
2115   exit (status);
2116 }
2117
2118 /* Locate a regular file, give a Path value.  */
2119
2120 char *
2121 __gnat_locate_regular_file (char *file_name, char *path_val)
2122 {
2123   char *ptr;
2124   char *file_path = alloca (strlen (file_name) + 1);
2125   int absolute;
2126
2127   /* Return immediately if file_name is empty */
2128
2129   if (*file_name == '\0')
2130     return 0;
2131
2132   /* Remove quotes around file_name if present */
2133
2134   ptr = file_name;
2135   if (*ptr == '"')
2136     ptr++;
2137
2138   strcpy (file_path, ptr);
2139
2140   ptr = file_path + strlen (file_path) - 1;
2141
2142   if (*ptr == '"')
2143     *ptr = '\0';
2144
2145   /* Handle absolute pathnames.  */
2146
2147   absolute = __gnat_is_absolute_path (file_path, strlen (file_name));
2148
2149   if (absolute)
2150     {
2151      if (__gnat_is_regular_file (file_path))
2152        return xstrdup (file_path);
2153
2154       return 0;
2155     }
2156
2157   /* If file_name include directory separator(s), try it first as
2158      a path name relative to the current directory */
2159   for (ptr = file_name; *ptr && *ptr != '/' && *ptr != DIR_SEPARATOR; ptr++)
2160     ;
2161
2162   if (*ptr != 0)
2163     {
2164       if (__gnat_is_regular_file (file_name))
2165         return xstrdup (file_name);
2166     }
2167
2168   if (path_val == 0)
2169     return 0;
2170
2171   {
2172     /* The result has to be smaller than path_val + file_name.  */
2173     char *file_path = alloca (strlen (path_val) + strlen (file_name) + 2);
2174
2175     for (;;)
2176       {
2177         for (; *path_val == PATH_SEPARATOR; path_val++)
2178           ;
2179
2180       if (*path_val == 0)
2181         return 0;
2182
2183       /* Skip the starting quote */
2184
2185       if (*path_val == '"')
2186         path_val++;
2187
2188       for (ptr = file_path; *path_val && *path_val != PATH_SEPARATOR; )
2189         *ptr++ = *path_val++;
2190
2191       ptr--;
2192
2193       /* Skip the ending quote */
2194
2195       if (*ptr == '"')
2196         ptr--;
2197
2198       if (*ptr != '/' && *ptr != DIR_SEPARATOR)
2199         *++ptr = DIR_SEPARATOR;
2200
2201       strcpy (++ptr, file_name);
2202
2203       if (__gnat_is_regular_file (file_path))
2204         return xstrdup (file_path);
2205       }
2206   }
2207
2208   return 0;
2209 }
2210
2211 /* Locate an executable given a Path argument. This routine is only used by
2212    gnatbl and should not be used otherwise.  Use locate_exec_on_path
2213    instead.  */
2214
2215 char *
2216 __gnat_locate_exec (char *exec_name, char *path_val)
2217 {
2218   char *ptr;
2219   if (!strstr (exec_name, HOST_EXECUTABLE_SUFFIX))
2220     {
2221       char *full_exec_name
2222         = alloca (strlen (exec_name) + strlen (HOST_EXECUTABLE_SUFFIX) + 1);
2223
2224       strcpy (full_exec_name, exec_name);
2225       strcat (full_exec_name, HOST_EXECUTABLE_SUFFIX);
2226       ptr = __gnat_locate_regular_file (full_exec_name, path_val);
2227
2228       if (ptr == 0)
2229          return __gnat_locate_regular_file (exec_name, path_val);
2230       return ptr;
2231     }
2232   else
2233     return __gnat_locate_regular_file (exec_name, path_val);
2234 }
2235
2236 /* Locate an executable using the Systems default PATH.  */
2237
2238 char *
2239 __gnat_locate_exec_on_path (char *exec_name)
2240 {
2241   char *apath_val;
2242
2243 #if defined (_WIN32) && !defined (RTX)
2244   TCHAR *wpath_val = _tgetenv (_T("PATH"));
2245   TCHAR *wapath_val;
2246   /* In Win32 systems we expand the PATH as for XP environment
2247      variables are not automatically expanded. We also prepend the
2248      ".;" to the path to match normal NT path search semantics */
2249
2250   #define EXPAND_BUFFER_SIZE 32767
2251
2252   wapath_val = alloca (EXPAND_BUFFER_SIZE);
2253
2254   wapath_val [0] = '.';
2255   wapath_val [1] = ';';
2256
2257   DWORD res = ExpandEnvironmentStrings
2258     (wpath_val, &wapath_val[2], EXPAND_BUFFER_SIZE - 2);
2259
2260   if (!res) wapath_val [0] = _T('\0');
2261
2262   apath_val = alloca (EXPAND_BUFFER_SIZE);
2263
2264   WS2SU (apath_val, wapath_val, EXPAND_BUFFER_SIZE);
2265   return __gnat_locate_exec (exec_name, apath_val);
2266
2267 #else
2268
2269 #ifdef VMS
2270   char *path_val = "/VAXC$PATH";
2271 #else
2272   char *path_val = getenv ("PATH");
2273 #endif
2274   if (path_val == NULL) return NULL;
2275   apath_val = alloca (strlen (path_val) + 1);
2276   strcpy (apath_val, path_val);
2277   return __gnat_locate_exec (exec_name, apath_val);
2278 #endif
2279 }
2280
2281 #ifdef VMS
2282
2283 /* These functions are used to translate to and from VMS and Unix syntax
2284    file, directory and path specifications.  */
2285
2286 #define MAXPATH  256
2287 #define MAXNAMES 256
2288 #define NEW_CANONICAL_FILELIST_INCREMENT 64
2289
2290 static char new_canonical_dirspec [MAXPATH];
2291 static char new_canonical_filespec [MAXPATH];
2292 static char new_canonical_pathspec [MAXNAMES*MAXPATH];
2293 static unsigned new_canonical_filelist_index;
2294 static unsigned new_canonical_filelist_in_use;
2295 static unsigned new_canonical_filelist_allocated;
2296 static char **new_canonical_filelist;
2297 static char new_host_pathspec [MAXNAMES*MAXPATH];
2298 static char new_host_dirspec [MAXPATH];
2299 static char new_host_filespec [MAXPATH];
2300
2301 /* Routine is called repeatedly by decc$from_vms via
2302    __gnat_to_canonical_file_list_init until it returns 0 or the expansion
2303    runs out. */
2304
2305 static int
2306 wildcard_translate_unix (char *name)
2307 {
2308   char *ver;
2309   char buff [MAXPATH];
2310
2311   strncpy (buff, name, MAXPATH);
2312   buff [MAXPATH - 1] = (char) 0;
2313   ver = strrchr (buff, '.');
2314
2315   /* Chop off the version.  */
2316   if (ver)
2317     *ver = 0;
2318
2319   /* Dynamically extend the allocation by the increment.  */
2320   if (new_canonical_filelist_in_use == new_canonical_filelist_allocated)
2321     {
2322       new_canonical_filelist_allocated += NEW_CANONICAL_FILELIST_INCREMENT;
2323       new_canonical_filelist = (char **) xrealloc
2324         (new_canonical_filelist,
2325          new_canonical_filelist_allocated * sizeof (char *));
2326     }
2327
2328   new_canonical_filelist[new_canonical_filelist_in_use++] = xstrdup (buff);
2329
2330   return 1;
2331 }
2332
2333 /* Translate a wildcard VMS file spec into a list of Unix file specs. First do
2334    full translation and copy the results into a list (_init), then return them
2335    one at a time (_next). If onlydirs set, only expand directory files.  */
2336
2337 int
2338 __gnat_to_canonical_file_list_init (char *filespec, int onlydirs)
2339 {
2340   int len;
2341   char buff [MAXPATH];
2342
2343   len = strlen (filespec);
2344   strncpy (buff, filespec, MAXPATH);
2345
2346   /* Only look for directories */
2347   if (onlydirs && !strstr (&buff [len-5], "*.dir"))
2348     strncat (buff, "*.dir", MAXPATH);
2349
2350   buff [MAXPATH - 1] = (char) 0;
2351
2352   decc$from_vms (buff, wildcard_translate_unix, 1);
2353
2354   /* Remove the .dir extension.  */
2355   if (onlydirs)
2356     {
2357       int i;
2358       char *ext;
2359
2360       for (i = 0; i < new_canonical_filelist_in_use; i++)
2361         {
2362           ext = strstr (new_canonical_filelist[i], ".dir");
2363           if (ext)
2364             *ext = 0;
2365         }
2366     }
2367
2368   return new_canonical_filelist_in_use;
2369 }
2370
2371 /* Return the next filespec in the list.  */
2372
2373 char *
2374 __gnat_to_canonical_file_list_next ()
2375 {
2376   return new_canonical_filelist[new_canonical_filelist_index++];
2377 }
2378
2379 /* Free storage used in the wildcard expansion.  */
2380
2381 void
2382 __gnat_to_canonical_file_list_free ()
2383 {
2384   int i;
2385
2386    for (i = 0; i < new_canonical_filelist_in_use; i++)
2387      free (new_canonical_filelist[i]);
2388
2389   free (new_canonical_filelist);
2390
2391   new_canonical_filelist_in_use = 0;
2392   new_canonical_filelist_allocated = 0;
2393   new_canonical_filelist_index = 0;
2394   new_canonical_filelist = 0;
2395 }
2396
2397 /* The functional equivalent of decc$translate_vms routine.
2398    Designed to produce the same output, but is protected against
2399    malformed paths (original version ACCVIOs in this case) and
2400    does not require VMS-specific DECC RTL */
2401
2402 #define NAM$C_MAXRSS 1024
2403
2404 char *
2405 __gnat_translate_vms (char *src)
2406 {
2407   static char retbuf [NAM$C_MAXRSS+1];
2408   char *srcendpos, *pos1, *pos2, *retpos;
2409   int disp, path_present = 0;
2410
2411   if (!src) return NULL;
2412
2413   srcendpos = strchr (src, '\0');
2414   retpos = retbuf;
2415
2416   /* Look for the node and/or device in front of the path */
2417   pos1 = src;
2418   pos2 = strchr (pos1, ':');
2419
2420   if (pos2 && (pos2 < srcendpos) && (*(pos2 + 1) == ':')) {
2421     /* There is a node name. "node_name::" becomes "node_name!" */
2422     disp = pos2 - pos1;
2423     strncpy (retbuf, pos1, disp);
2424     retpos [disp] = '!';
2425     retpos = retpos + disp + 1;
2426     pos1 = pos2 + 2;
2427     pos2 = strchr (pos1, ':');
2428   }
2429
2430   if (pos2) {
2431     /* There is a device name. "dev_name:" becomes "/dev_name/" */
2432     *(retpos++) = '/';
2433     disp = pos2 - pos1;
2434     strncpy (retpos, pos1, disp);
2435     retpos = retpos + disp;
2436     pos1 = pos2 + 1;
2437     *(retpos++) = '/';
2438   }
2439   else
2440     /* No explicit device; we must look ahead and prepend /sys$disk/ if
2441        the path is absolute */
2442     if ((*pos1 == '[' || *pos1 == '<') && (pos1 < srcendpos)
2443         && !strchr (".-]>", *(pos1 + 1))) {
2444       strncpy (retpos, "/sys$disk/", 10);
2445       retpos += 10;
2446     }
2447
2448   /* Process the path part */
2449   while (*pos1 == '[' || *pos1 == '<') {
2450     path_present++;
2451     pos1++;
2452     if (*pos1 == ']' || *pos1 == '>') {
2453       /* Special case, [] translates to '.' */
2454       *(retpos++) = '.';
2455       pos1++;
2456     }
2457     else {
2458       /* '[000000' means root dir. It can be present in the middle of
2459          the path due to expansion of logical devices, in which case
2460          we skip it */
2461       if (!strncmp (pos1, "000000", 6) && path_present > 1 &&
2462          (*(pos1 + 6) == ']' || *(pos1 + 6) == '>' || *(pos1 + 6) == '.')) {
2463           pos1 += 6;
2464           if (*pos1 == '.') pos1++;
2465         }
2466       else if (*pos1 == '.') {
2467         /* Relative path */
2468         *(retpos++) = '.';
2469       }
2470
2471       /* There is a qualified path */
2472       while (*pos1 && *pos1 != ']' && *pos1 != '>') {
2473         switch (*pos1) {
2474           case '.':
2475             /* '.' is used to separate directories. Replace it with '/' but
2476                only if there isn't already '/' just before */
2477             if (*(retpos - 1) != '/') *(retpos++) = '/';
2478             pos1++;
2479             if (pos1 + 1 < srcendpos && *pos1 == '.' && *(pos1 + 1) == '.') {
2480               /* ellipsis refers to entire subtree; replace with '**' */
2481               *(retpos++) = '*'; *(retpos++) = '*'; *(retpos++) = '/';
2482               pos1 += 2;
2483             }
2484             break;
2485           case '-' :
2486             /* When after '.' '[' '<' is equivalent to Unix ".." but there
2487             may be several in a row */
2488             if (*(pos1 - 1) == '.' || *(pos1 - 1) == '[' ||
2489                 *(pos1 - 1) == '<') {
2490               while (*pos1 == '-') {
2491                 pos1++;
2492                 *(retpos++) = '.'; *(retpos++) = '.'; *(retpos++) = '/';
2493               }
2494               retpos--;
2495               break;
2496             }
2497             /* otherwise fall through to default */
2498           default:
2499             *(retpos++) = *(pos1++);
2500         }
2501       }
2502       pos1++;
2503     }
2504   }
2505
2506   if (pos1 < srcendpos) {
2507     /* Now add the actual file name, until the version suffix if any */
2508     if (path_present) *(retpos++) = '/';
2509     pos2 = strchr (pos1, ';');
2510     disp = pos2? (pos2 - pos1) : (srcendpos - pos1);
2511     strncpy (retpos, pos1, disp);
2512     retpos += disp;
2513     if (pos2 && pos2 < srcendpos) {
2514       /* There is a non-empty version suffix. ";<ver>" becomes ".<ver>" */
2515       *retpos++ = '.';
2516       disp = srcendpos - pos2 - 1;
2517       strncpy (retpos, pos2 + 1, disp);
2518       retpos += disp;
2519     }
2520   }
2521
2522   *retpos = '\0';
2523
2524   return retbuf;
2525
2526 }
2527
2528 /* Translate a VMS syntax directory specification in to Unix syntax.  If
2529    PREFIXFLAG is set, append an underscore "/". If no indicators of VMS syntax
2530    found, return input string. Also translate a dirname that contains no
2531    slashes, in case it's a logical name.  */
2532
2533 char *
2534 __gnat_to_canonical_dir_spec (char *dirspec, int prefixflag)
2535 {
2536   int len;
2537
2538   strcpy (new_canonical_dirspec, "");
2539   if (strlen (dirspec))
2540     {
2541       char *dirspec1;
2542
2543       if (strchr (dirspec, ']') || strchr (dirspec, ':'))
2544         {
2545           strncpy (new_canonical_dirspec,
2546                    __gnat_translate_vms (dirspec),
2547                    MAXPATH);
2548         }
2549       else if (!strchr (dirspec, '/') && (dirspec1 = getenv (dirspec)) != 0)
2550         {
2551           strncpy (new_canonical_dirspec,
2552                   __gnat_translate_vms (dirspec1),
2553                   MAXPATH);
2554         }
2555       else
2556         {
2557           strncpy (new_canonical_dirspec, dirspec, MAXPATH);
2558         }
2559     }
2560
2561   len = strlen (new_canonical_dirspec);
2562   if (prefixflag && new_canonical_dirspec [len-1] != '/')
2563     strncat (new_canonical_dirspec, "/", MAXPATH);
2564
2565   new_canonical_dirspec [MAXPATH - 1] = (char) 0;
2566
2567   return new_canonical_dirspec;
2568
2569 }
2570
2571 /* Translate a VMS syntax file specification into Unix syntax.
2572    If no indicators of VMS syntax found, check if it's an uppercase
2573    alphanumeric_ name and if so try it out as an environment
2574    variable (logical name). If all else fails return the
2575    input string.  */
2576
2577 char *
2578 __gnat_to_canonical_file_spec (char *filespec)
2579 {
2580   char *filespec1;
2581
2582   strncpy (new_canonical_filespec, "", MAXPATH);
2583
2584   if (strchr (filespec, ']') || strchr (filespec, ':'))
2585     {
2586       char *tspec = (char *) __gnat_translate_vms (filespec);
2587
2588       if (tspec != (char *) -1)
2589         strncpy (new_canonical_filespec, tspec, MAXPATH);
2590     }
2591   else if ((strlen (filespec) == strspn (filespec,
2592             "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_"))
2593         && (filespec1 = getenv (filespec)))
2594     {
2595       char *tspec = (char *) __gnat_translate_vms (filespec1);
2596
2597       if (tspec != (char *) -1)
2598         strncpy (new_canonical_filespec, tspec, MAXPATH);
2599     }
2600   else
2601     {
2602       strncpy (new_canonical_filespec, filespec, MAXPATH);
2603     }
2604
2605   new_canonical_filespec [MAXPATH - 1] = (char) 0;
2606
2607   return new_canonical_filespec;
2608 }
2609
2610 /* Translate a VMS syntax path specification into Unix syntax.
2611    If no indicators of VMS syntax found, return input string.  */
2612
2613 char *
2614 __gnat_to_canonical_path_spec (char *pathspec)
2615 {
2616   char *curr, *next, buff [MAXPATH];
2617
2618   if (pathspec == 0)
2619     return pathspec;
2620
2621   /* If there are /'s, assume it's a Unix path spec and return.  */
2622   if (strchr (pathspec, '/'))
2623     return pathspec;
2624
2625   new_canonical_pathspec[0] = 0;
2626   curr = pathspec;
2627
2628   for (;;)
2629     {
2630       next = strchr (curr, ',');
2631       if (next == 0)
2632         next = strchr (curr, 0);
2633
2634       strncpy (buff, curr, next - curr);
2635       buff[next - curr] = 0;
2636
2637       /* Check for wildcards and expand if present.  */
2638       if (strchr (buff, '*') || strchr (buff, '%') || strstr (buff, "..."))
2639         {
2640           int i, dirs;
2641
2642           dirs = __gnat_to_canonical_file_list_init (buff, 1);
2643           for (i = 0; i < dirs; i++)
2644             {
2645               char *next_dir;
2646
2647               next_dir = __gnat_to_canonical_file_list_next ();
2648               strncat (new_canonical_pathspec, next_dir, MAXPATH);
2649
2650               /* Don't append the separator after the last expansion.  */
2651               if (i+1 < dirs)
2652                 strncat (new_canonical_pathspec, ":", MAXPATH);
2653             }
2654
2655           __gnat_to_canonical_file_list_free ();
2656         }
2657       else
2658         strncat (new_canonical_pathspec,
2659                 __gnat_to_canonical_dir_spec (buff, 0), MAXPATH);
2660
2661       if (*next == 0)
2662         break;
2663
2664       strncat (new_canonical_pathspec, ":", MAXPATH);
2665       curr = next + 1;
2666     }
2667
2668   new_canonical_pathspec [MAXPATH - 1] = (char) 0;
2669
2670   return new_canonical_pathspec;
2671 }
2672
2673 static char filename_buff [MAXPATH];
2674
2675 static int
2676 translate_unix (char *name, int type)
2677 {
2678   strncpy (filename_buff, name, MAXPATH);
2679   filename_buff [MAXPATH - 1] = (char) 0;
2680   return 0;
2681 }
2682
2683 /* Translate a Unix syntax path spec into a VMS style (comma separated list of
2684    directories.  */
2685
2686 static char *
2687 to_host_path_spec (char *pathspec)
2688 {
2689   char *curr, *next, buff [MAXPATH];
2690
2691   if (pathspec == 0)
2692     return pathspec;
2693
2694   /* Can't very well test for colons, since that's the Unix separator!  */
2695   if (strchr (pathspec, ']') || strchr (pathspec, ','))
2696     return pathspec;
2697
2698   new_host_pathspec[0] = 0;
2699   curr = pathspec;
2700
2701   for (;;)
2702     {
2703       next = strchr (curr, ':');
2704       if (next == 0)
2705         next = strchr (curr, 0);
2706
2707       strncpy (buff, curr, next - curr);
2708       buff[next - curr] = 0;
2709
2710       strncat (new_host_pathspec, __gnat_to_host_dir_spec (buff, 0), MAXPATH);
2711       if (*next == 0)
2712         break;
2713       strncat (new_host_pathspec, ",", MAXPATH);
2714       curr = next + 1;
2715     }
2716
2717   new_host_pathspec [MAXPATH - 1] = (char) 0;
2718
2719   return new_host_pathspec;
2720 }
2721
2722 /* Translate a Unix syntax directory specification into VMS syntax.  The
2723    PREFIXFLAG has no effect, but is kept for symmetry with
2724    to_canonical_dir_spec.  If indicators of VMS syntax found, return input
2725    string. */
2726
2727 char *
2728 __gnat_to_host_dir_spec (char *dirspec, int prefixflag ATTRIBUTE_UNUSED)
2729 {
2730   int len = strlen (dirspec);
2731
2732   strncpy (new_host_dirspec, dirspec, MAXPATH);
2733   new_host_dirspec [MAXPATH - 1] = (char) 0;
2734
2735   if (strchr (new_host_dirspec, ']') || strchr (new_host_dirspec, ':'))
2736     return new_host_dirspec;
2737
2738   while (len > 1 && new_host_dirspec[len - 1] == '/')
2739     {
2740       new_host_dirspec[len - 1] = 0;
2741       len--;
2742     }
2743
2744   decc$to_vms (new_host_dirspec, translate_unix, 1, 2);
2745   strncpy (new_host_dirspec, filename_buff, MAXPATH);
2746   new_host_dirspec [MAXPATH - 1] = (char) 0;
2747
2748   return new_host_dirspec;
2749 }
2750
2751 /* Translate a Unix syntax file specification into VMS syntax.
2752    If indicators of VMS syntax found, return input string.  */
2753
2754 char *
2755 __gnat_to_host_file_spec (char *filespec)
2756 {
2757   strncpy (new_host_filespec, "", MAXPATH);
2758   if (strchr (filespec, ']') || strchr (filespec, ':'))
2759     {
2760       strncpy (new_host_filespec, filespec, MAXPATH);
2761     }
2762   else
2763     {
2764       decc$to_vms (filespec, translate_unix, 1, 1);
2765       strncpy (new_host_filespec, filename_buff, MAXPATH);
2766     }
2767
2768   new_host_filespec [MAXPATH - 1] = (char) 0;
2769
2770   return new_host_filespec;
2771 }
2772
2773 void
2774 __gnat_adjust_os_resource_limits ()
2775 {
2776   SYS$ADJWSL (131072, 0);
2777 }
2778
2779 #else /* VMS */
2780
2781 /* Dummy functions for Osint import for non-VMS systems.  */
2782
2783 int
2784 __gnat_to_canonical_file_list_init
2785   (char *dirspec ATTRIBUTE_UNUSED, int onlydirs ATTRIBUTE_UNUSED)
2786 {
2787   return 0;
2788 }
2789
2790 char *
2791 __gnat_to_canonical_file_list_next (void)
2792 {
2793   return (char *) "";
2794 }
2795
2796 void
2797 __gnat_to_canonical_file_list_free (void)
2798 {
2799 }
2800
2801 char *
2802 __gnat_to_canonical_dir_spec (char *dirspec, int prefixflag ATTRIBUTE_UNUSED)
2803 {
2804   return dirspec;
2805 }
2806
2807 char *
2808 __gnat_to_canonical_file_spec (char *filespec)
2809 {
2810   return filespec;
2811 }
2812
2813 char *
2814 __gnat_to_canonical_path_spec (char *pathspec)
2815 {
2816   return pathspec;
2817 }
2818
2819 char *
2820 __gnat_to_host_dir_spec (char *dirspec, int prefixflag ATTRIBUTE_UNUSED)
2821 {
2822   return dirspec;
2823 }
2824
2825 char *
2826 __gnat_to_host_file_spec (char *filespec)
2827 {
2828   return filespec;
2829 }
2830
2831 void
2832 __gnat_adjust_os_resource_limits (void)
2833 {
2834 }
2835
2836 #endif
2837
2838 /* For EMX, we cannot include dummy in libgcc, since it is too difficult
2839    to coordinate this with the EMX distribution. Consequently, we put the
2840    definition of dummy which is used for exception handling, here.  */
2841
2842 #if defined (__EMX__)
2843 void __dummy () {}
2844 #endif
2845
2846 #if defined (__mips_vxworks)
2847 int
2848 _flush_cache()
2849 {
2850    CACHE_USER_FLUSH (0, ENTIRE_CACHE);
2851 }
2852 #endif
2853
2854 #if defined (CROSS_DIRECTORY_STRUCTURE)  \
2855   || (! ((defined (sparc) || defined (i386)) && defined (sun) \
2856       && defined (__SVR4)) \
2857       && ! (defined (linux) && (defined (i386) || defined (__x86_64__))) \
2858       && ! (defined (linux) && defined (__ia64__)) \
2859       && ! defined (__FreeBSD__) \
2860       && ! defined (__hpux__) \
2861       && ! defined (__APPLE__) \
2862       && ! defined (_AIX) \
2863       && ! (defined (__alpha__)  && defined (__osf__)) \
2864       && ! defined (VMS) \
2865       && ! defined (__MINGW32__) \
2866       && ! (defined (__mips) && defined (__sgi)))
2867
2868 /* Dummy function to satisfy g-trasym.o. See the preprocessor conditional
2869    just above for a list of native platforms that provide a non-dummy
2870    version of this procedure in libaddr2line.a.  */
2871
2872 void
2873 convert_addresses (const char *file_name ATTRIBUTE_UNUSED,
2874                    void *addrs ATTRIBUTE_UNUSED,
2875                    int n_addr ATTRIBUTE_UNUSED,
2876                    void *buf ATTRIBUTE_UNUSED,
2877                    int *len ATTRIBUTE_UNUSED)
2878 {
2879   *len = 0;
2880 }
2881 #endif
2882
2883 #if defined (_WIN32)
2884 int __gnat_argument_needs_quote = 1;
2885 #else
2886 int __gnat_argument_needs_quote = 0;
2887 #endif
2888
2889 /* This option is used to enable/disable object files handling from the
2890    binder file by the GNAT Project module. For example, this is disabled on
2891    Windows (prior to GCC 3.4) as it is already done by the mdll module.
2892    Stating with GCC 3.4 the shared libraries are not based on mdll
2893    anymore as it uses the GCC's -shared option  */
2894 #if defined (_WIN32) \
2895     && ((__GNUC__ < 3) || ((__GNUC__ == 3) && (__GNUC_MINOR__ < 4)))
2896 int __gnat_prj_add_obj_files = 0;
2897 #else
2898 int __gnat_prj_add_obj_files = 1;
2899 #endif
2900
2901 /* char used as prefix/suffix for environment variables */
2902 #if defined (_WIN32)
2903 char __gnat_environment_char = '%';
2904 #else
2905 char __gnat_environment_char = '$';
2906 #endif
2907
2908 /* This functions copy the file attributes from a source file to a
2909    destination file.
2910
2911    mode = 0  : In this mode copy only the file time stamps (last access and
2912                last modification time stamps).
2913
2914    mode = 1  : In this mode, time stamps and read/write/execute attributes are
2915                copied.
2916
2917    Returns 0 if operation was successful and -1 in case of error. */
2918
2919 int
2920 __gnat_copy_attribs (char *from, char *to, int mode)
2921 {
2922 #if defined (VMS) || defined (__vxworks) || defined (__nucleus__)
2923   return -1;
2924 #else
2925   struct stat fbuf;
2926   struct utimbuf tbuf;
2927
2928   if (stat (from, &fbuf) == -1)
2929     {
2930       return -1;
2931     }
2932
2933   tbuf.actime = fbuf.st_atime;
2934   tbuf.modtime = fbuf.st_mtime;
2935
2936   if (utime (to, &tbuf) == -1)
2937     {
2938       return -1;
2939     }
2940
2941   if (mode == 1)
2942     {
2943       if (chmod (to, fbuf.st_mode) == -1)
2944         {
2945           return -1;
2946         }
2947     }
2948
2949   return 0;
2950 #endif
2951 }
2952
2953 int
2954 __gnat_lseek (int fd, long offset, int whence)
2955 {
2956   return (int) lseek (fd, offset, whence);
2957 }
2958
2959 /* This function returns the major version number of GCC being used.  */
2960 int
2961 get_gcc_version (void)
2962 {
2963 #ifdef IN_RTS
2964   return __GNUC__;
2965 #else
2966   return (int) (version_string[0] - '0');
2967 #endif
2968 }
2969
2970 int
2971 __gnat_set_close_on_exec (int fd ATTRIBUTE_UNUSED,
2972                         int close_on_exec_p ATTRIBUTE_UNUSED)
2973 {
2974 #if defined (F_GETFD) && defined (FD_CLOEXEC) && ! defined (__vxworks)
2975   int flags = fcntl (fd, F_GETFD, 0);
2976   if (flags < 0)
2977     return flags;
2978   if (close_on_exec_p)
2979     flags |= FD_CLOEXEC;
2980   else
2981     flags &= ~FD_CLOEXEC;
2982   return fcntl (fd, F_SETFD, flags | FD_CLOEXEC);
2983 #else
2984   return -1;
2985   /* For the Windows case, we should use SetHandleInformation to remove
2986      the HANDLE_INHERIT property from fd. This is not implemented yet,
2987      but for our purposes (support of GNAT.Expect) this does not matter,
2988      as by default handles are *not* inherited. */
2989 #endif
2990 }
2991
2992 /* Indicates if platforms supports automatic initialization through the
2993    constructor mechanism */
2994 int
2995 __gnat_binder_supports_auto_init ()
2996 {
2997 #ifdef VMS
2998    return 0;
2999 #else
3000    return 1;
3001 #endif
3002 }
3003
3004 /* Indicates that Stand-Alone Libraries are automatically initialized through
3005    the constructor mechanism */
3006 int
3007 __gnat_sals_init_using_constructors ()
3008 {
3009 #if defined (__vxworks) || defined (__Lynx__) || defined (VMS)
3010    return 0;
3011 #else
3012    return 1;
3013 #endif
3014 }
3015
3016 /* In RTX mode, the procedure to get the time (as file time) is different
3017    in RTSS mode and Win32 mode. In order to avoid duplicating an Ada file,
3018    we introduce an intermediate procedure to link against the corresponding
3019    one in each situation. */
3020 #ifdef RTX
3021
3022 void GetTimeAsFileTime(LPFILETIME pTime)
3023 {
3024 #ifdef RTSS
3025   RtGetRtssTimeAsFileTime (pTime); /* RTSS interface */
3026 #else
3027   GetSystemTimeAsFileTime (pTime); /* w32 interface */
3028 #endif
3029 }
3030 #endif
3031
3032 #if defined (linux)
3033 /* pthread affinity support */
3034
3035 #ifdef CPU_SETSIZE
3036 #include <pthread.h>
3037 int
3038 __gnat_pthread_setaffinity_np (pthread_t th,
3039                                size_t cpusetsize,
3040                                const cpu_set_t *cpuset)
3041 {
3042   return pthread_setaffinity_np (th, cpusetsize, cpuset);
3043 }
3044 #else
3045 int
3046 __gnat_pthread_setaffinity_np (pthread_t th,
3047                                size_t cpusetsize,
3048                                const void *cpuset)
3049 {
3050   return 0;
3051 }
3052 #endif
3053 #endif