OSDN Git Service

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