OSDN Git Service

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