OSDN Git Service

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