OSDN Git Service

2003-12-03 Thomas Quinot <quinot@act-europe.fr>
[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-2003, Free Software Foundation, Inc.         *
10  *                                                                          *
11  * GNAT is free software;  you can  redistribute it  and/or modify it under *
12  * terms of the  GNU General Public License as published  by the Free Soft- *
13  * ware  Foundation;  either version 2,  or (at your option) any later ver- *
14  * sion.  GNAT is distributed in the hope that it will be useful, but WITH- *
15  * OUT ANY WARRANTY;  without even the  implied warranty of MERCHANTABILITY *
16  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License *
17  * for  more details.  You should have  received  a copy of the GNU General *
18  * Public License  distributed with GNAT;  see file COPYING.  If not, write *
19  * to  the Free Software Foundation,  59 Temple Place - Suite 330,  Boston, *
20  * MA 02111-1307, USA.                                                      *
21  *                                                                          *
22  * As a  special  exception,  if you  link  this file  with other  files to *
23  * produce an executable,  this file does not by itself cause the resulting *
24  * executable to be covered by the GNU General Public License. This except- *
25  * ion does not  however invalidate  any other reasons  why the  executable *
26  * file might be covered by the  GNU Public License.                        *
27  *                                                                          *
28  * GNAT was originally developed  by the GNAT team at  New York University. *
29  * Extensive contributions were provided by Ada Core Technologies Inc.      *
30  *                                                                          *
31  ****************************************************************************/
32
33 /* This file contains those routines named by Import pragmas in
34    packages in the GNAT hierarchy (especially GNAT.OS_Lib) and in
35    package Osint.  Many of the subprograms in OS_Lib import standard
36    library calls directly. This file contains all other routines.  */
37
38 #ifdef __vxworks
39
40 /* No need to redefine exit here.  */
41 #undef exit
42
43 /* We want to use the POSIX variants of include files.  */
44 #define POSIX
45 #include "vxWorks.h"
46
47 #if defined (__mips_vxworks)
48 #include "cacheLib.h"
49 #endif /* __mips_vxworks */
50
51 #endif /* VxWorks */
52
53 #ifdef VMS
54 #define _POSIX_EXIT 1
55 #endif
56
57 #ifdef IN_RTS
58 #include "tconfig.h"
59 #include "tsystem.h"
60
61 #include <sys/stat.h>
62 #include <fcntl.h>
63 #include <time.h>
64 #ifdef VMS
65 #include <unixio.h>
66 #endif
67
68 /* We don't have libiberty, so use malloc.  */
69 #define xmalloc(S) malloc (S)
70 #define xrealloc(V,S) realloc (V,S)
71 #else
72 #include "config.h"
73 #include "system.h"
74 #endif
75
76 #ifdef __MINGW32__
77 #include "mingw32.h"
78 #include <sys/utime.h>
79 #include <ctype.h>
80 #else
81 #ifndef VMS
82 #include <utime.h>
83 #endif
84 #endif
85
86 #ifdef __MINGW32__
87 #if OLD_MINGW
88 #include <sys/wait.h>
89 #endif
90 #else
91 #include <sys/wait.h>
92 #endif
93
94 #if defined (__EMX__) || defined (MSDOS) || defined (_WIN32)
95 #elif defined (VMS)
96
97 /* Header files and definitions for __gnat_set_file_time_name.  */
98
99 #include <rms.h>
100 #include <atrdef.h>
101 #include <fibdef.h>
102 #include <stsdef.h>
103 #include <iodef.h>
104 #include <errno.h>
105 #include <descrip.h>
106 #include <string.h>
107 #include <unixlib.h>
108
109 /* Use native 64-bit arithmetic.  */
110 #define unix_time_to_vms(X,Y) \
111   { unsigned long long reftime, tmptime = (X); \
112     $DESCRIPTOR (unixtime,"1-JAN-1970 0:00:00.00"); \
113     SYS$BINTIM (&unixtime, &reftime); \
114     Y = tmptime * 10000000 + reftime; }
115
116 /* descrip.h doesn't have everything ... */
117 struct dsc$descriptor_fib
118 {
119   unsigned long fib$l_len;
120   struct fibdef *fib$l_addr;
121 };
122
123 /* I/O Status Block.  */
124 struct IOSB
125 {
126   unsigned short status, count;
127   unsigned long devdep;
128 };
129
130 static char *tryfile;
131
132 /* Variable length string.  */
133 struct vstring
134 {
135   short length;
136   char string[NAM$C_MAXRSS+1];
137 };
138
139 #else
140 #include <utime.h>
141 #endif
142
143 #if defined (__EMX__) || defined (MSDOS) || defined (_WIN32)
144 #include <process.h>
145 #endif
146
147 #if defined (_WIN32)
148 #include <dir.h>
149 #include <windows.h>
150 #endif
151
152 #include "adaint.h"
153
154 /* Define symbols O_BINARY and O_TEXT as harmless zeroes if they are not
155    defined in the current system. On DOS-like systems these flags control
156    whether the file is opened/created in text-translation mode (CR/LF in
157    external file mapped to LF in internal file), but in Unix-like systems,
158    no text translation is required, so these flags have no effect.  */
159
160 #if defined (__EMX__)
161 #include <os2.h>
162 #endif
163
164 #if defined (MSDOS)
165 #include <dos.h>
166 #endif
167
168 #ifndef O_BINARY
169 #define O_BINARY 0
170 #endif
171
172 #ifndef O_TEXT
173 #define O_TEXT 0
174 #endif
175
176 #ifndef HOST_EXECUTABLE_SUFFIX
177 #define HOST_EXECUTABLE_SUFFIX ""
178 #endif
179
180 #ifndef HOST_OBJECT_SUFFIX
181 #define HOST_OBJECT_SUFFIX ".o"
182 #endif
183
184 #ifndef PATH_SEPARATOR
185 #define PATH_SEPARATOR ':'
186 #endif
187
188 #ifndef DIR_SEPARATOR
189 #define DIR_SEPARATOR '/'
190 #endif
191
192 char __gnat_dir_separator = DIR_SEPARATOR;
193
194 char __gnat_path_separator = PATH_SEPARATOR;
195
196 /* The GNAT_LIBRARY_TEMPLATE contains a list of expressions that define
197    the base filenames that libraries specified with -lsomelib options
198    may have. This is used by GNATMAKE to check whether an executable
199    is up-to-date or not. The syntax is
200
201      library_template ::= { pattern ; } pattern NUL
202      pattern          ::= [ prefix ] * [ postfix ]
203
204    These should only specify names of static libraries as it makes
205    no sense to determine at link time if dynamic-link libraries are
206    up to date or not. Any libraries that are not found are supposed
207    to be up-to-date:
208
209      * if they are needed but not present, the link
210        will fail,
211
212      * otherwise they are libraries in the system paths and so
213        they are considered part of the system and not checked
214        for that reason.
215
216    ??? This should be part of a GNAT host-specific compiler
217        file instead of being included in all user applications
218        as well. This is only a temporary work-around for 3.11b.  */
219
220 #ifndef GNAT_LIBRARY_TEMPLATE
221 #if defined (__EMX__)
222 #define GNAT_LIBRARY_TEMPLATE "*.a"
223 #elif defined (VMS)
224 #define GNAT_LIBRARY_TEMPLATE "*.olb"
225 #else
226 #define GNAT_LIBRARY_TEMPLATE "lib*.a"
227 #endif
228 #endif
229
230 const char *__gnat_library_template = GNAT_LIBRARY_TEMPLATE;
231
232 /* This variable is used in hostparm.ads to say whether the host is a VMS
233    system.  */
234 #ifdef VMS
235 const int __gnat_vmsp = 1;
236 #else
237 const int __gnat_vmsp = 0;
238 #endif
239
240 #ifdef __EMX__
241 #define GNAT_MAX_PATH_LEN MAX_PATH
242
243 #elif defined (VMS)
244 #define GNAT_MAX_PATH_LEN 256 /* PATH_MAX */
245
246 #elif defined (__vxworks) || defined (__OPENNT)
247 #define GNAT_MAX_PATH_LEN PATH_MAX
248
249 #else
250
251 #if defined (__MINGW32__)
252 #include "mingw32.h"
253
254 #if OLD_MINGW
255 #include <sys/param.h>
256 #endif
257
258 #else
259 #include <sys/param.h>
260 #endif
261
262 #define GNAT_MAX_PATH_LEN MAXPATHLEN
263
264 #endif
265
266 /* The __gnat_max_path_len variable is used to export the maximum
267    length of a path name to Ada code. max_path_len is also provided
268    for compatibility with older GNAT versions, please do not use
269    it. */
270
271 int __gnat_max_path_len = GNAT_MAX_PATH_LEN;
272 int max_path_len = GNAT_MAX_PATH_LEN;
273
274 /* The following macro HAVE_READDIR_R should be defined if the
275    system provides the routine readdir_r.  */
276 #undef HAVE_READDIR_R
277 \f
278 void
279 __gnat_to_gm_time
280   (OS_Time *p_time,
281    int *p_year,
282    int *p_month,
283    int *p_day,
284    int *p_hours,
285    int *p_mins,
286    int *p_secs)
287 {
288   struct tm *res;
289   time_t time = (time_t) *p_time;
290
291 #ifdef _WIN32
292   /* On Windows systems, the time is sometimes rounded up to the nearest
293      even second, so if the number of seconds is odd, increment it.  */
294   if (time & 1)
295     time++;
296 #endif
297
298 #ifdef VMS
299   res = localtime (&time);
300 #else
301   res = gmtime (&time);
302 #endif
303
304   if (res)
305     {
306       *p_year = res->tm_year;
307       *p_month = res->tm_mon;
308       *p_day = res->tm_mday;
309       *p_hours = res->tm_hour;
310       *p_mins = res->tm_min;
311       *p_secs = res->tm_sec;
312     }
313   else
314     *p_year = *p_month = *p_day = *p_hours = *p_mins = *p_secs = 0;
315 }
316
317 /* Place the contents of the symbolic link named PATH in the buffer BUF,
318    which has size BUFSIZ.  If PATH is a symbolic link, then return the number
319    of characters of its content in BUF.  Otherwise, return -1.  For Windows,
320    OS/2 and vxworks, always return -1.  */
321
322 int
323 __gnat_readlink (char *path ATTRIBUTE_UNUSED,
324                  char *buf ATTRIBUTE_UNUSED,
325                  size_t bufsiz ATTRIBUTE_UNUSED)
326 {
327 #if defined (MSDOS) || defined (_WIN32) || defined (__EMX__)
328   return -1;
329 #elif defined (__INTERIX) || defined (VMS)
330   return -1;
331 #elif defined (__vxworks)
332   return -1;
333 #else
334   return readlink (path, buf, bufsiz);
335 #endif
336 }
337
338 /* Creates a symbolic link named NEWPATH which contains the string OLDPATH.  If
339    NEWPATH exists it will NOT be overwritten.  For Windows, OS/2, VxWorks,
340    Interix and VMS, always return -1. */
341
342 int
343 __gnat_symlink (char *oldpath ATTRIBUTE_UNUSED,
344                 char *newpath ATTRIBUTE_UNUSED)
345 {
346 #if defined (MSDOS) || defined (_WIN32) || defined (__EMX__)
347   return -1;
348 #elif defined (__INTERIX) || defined (VMS)
349   return -1;
350 #elif defined (__vxworks)
351   return -1;
352 #else
353   return symlink (oldpath, newpath);
354 #endif
355 }
356
357 /* Try to lock a file, return 1 if success.  */
358
359 #if defined (__vxworks) || defined (MSDOS) || defined (_WIN32)
360
361 /* Version that does not use link. */
362
363 int
364 __gnat_try_lock (char *dir, char *file)
365 {
366   char full_path[256];
367   int fd;
368
369   sprintf (full_path, "%s%c%s", dir, DIR_SEPARATOR, file);
370   fd = open (full_path, O_CREAT | O_EXCL, 0600);
371   if (fd < 0)
372     return 0;
373
374   close (fd);
375   return 1;
376 }
377
378 #elif defined (__EMX__) || defined (VMS)
379
380 /* More cases that do not use link; identical code, to solve too long
381    line problem ??? */
382
383 int
384 __gnat_try_lock (char *dir, char *file)
385 {
386   char full_path[256];
387   int fd;
388
389   sprintf (full_path, "%s%c%s", dir, DIR_SEPARATOR, file);
390   fd = open (full_path, O_CREAT | O_EXCL, 0600);
391   if (fd < 0)
392     return 0;
393
394   close (fd);
395   return 1;
396 }
397
398 #else
399
400 /* Version using link(), more secure over NFS.  */
401 /* See TN 6913-016 for discussion ??? */
402
403 int
404 __gnat_try_lock (char *dir, char *file)
405 {
406   char full_path[256];
407   char temp_file[256];
408   struct stat stat_result;
409   int fd;
410
411   sprintf (full_path, "%s%c%s", dir, DIR_SEPARATOR, file);
412   sprintf (temp_file, "%s-%ld-%ld", dir, (long) getpid(), (long) getppid ());
413
414   /* Create the temporary file and write the process number.  */
415   fd = open (temp_file, O_CREAT | O_WRONLY, 0600);
416   if (fd < 0)
417     return 0;
418
419   close (fd);
420
421   /* Link it with the new file.  */
422   link (temp_file, full_path);
423
424   /* Count the references on the old one. If we have a count of two, then
425      the link did succeed. Remove the temporary file before returning.  */
426   __gnat_stat (temp_file, &stat_result);
427   unlink (temp_file);
428   return stat_result.st_nlink == 2;
429 }
430 #endif
431
432 /* Return the maximum file name length.  */
433
434 int
435 __gnat_get_maximum_file_name_length (void)
436 {
437 #if defined (MSDOS)
438   return 8;
439 #elif defined (VMS)
440   if (getenv ("GNAT$EXTENDED_FILE_SPECIFICATIONS"))
441     return -1;
442   else
443     return 39;
444 #else
445   return -1;
446 #endif
447 }
448
449 /* Return nonzero if file names are case sensitive.  */
450
451 int
452 __gnat_get_file_names_case_sensitive (void)
453 {
454 #if defined (__EMX__) || defined (MSDOS) || defined (VMS) || defined (WINNT)
455   return 0;
456 #else
457   return 1;
458 #endif
459 }
460
461 char
462 __gnat_get_default_identifier_character_set (void)
463 {
464 #if defined (__EMX__) || defined (MSDOS)
465   return 'p';
466 #else
467   return '1';
468 #endif
469 }
470
471 /* Return the current working directory.  */
472
473 void
474 __gnat_get_current_dir (char *dir, int *length)
475 {
476 #ifdef VMS
477    /* Force Unix style, which is what GNAT uses internally.  */
478    getcwd (dir, *length, 0);
479 #else
480    getcwd (dir, *length);
481 #endif
482
483    *length = strlen (dir);
484
485    if (dir [*length - 1] != DIR_SEPARATOR)
486      {
487        dir [*length] = DIR_SEPARATOR;
488        ++(*length);
489      }
490    dir[*length] = '\0';
491 }
492
493 /* Return the suffix for object files.  */
494
495 void
496 __gnat_get_object_suffix_ptr (int *len, const char **value)
497 {
498   *value = HOST_OBJECT_SUFFIX;
499
500   if (*value == 0)
501     *len = 0;
502   else
503     *len = strlen (*value);
504
505   return;
506 }
507
508 /* Return the suffix for executable files.  */
509
510 void
511 __gnat_get_executable_suffix_ptr (int *len, const char **value)
512 {
513   *value = HOST_EXECUTABLE_SUFFIX;
514   if (!*value)
515     *len = 0;
516   else
517     *len = strlen (*value);
518
519   return;
520 }
521
522 /* Return the suffix for debuggable files. Usually this is the same as the
523    executable extension.  */
524
525 void
526 __gnat_get_debuggable_suffix_ptr (int *len, const char **value)
527 {
528 #ifndef MSDOS
529   *value = HOST_EXECUTABLE_SUFFIX;
530 #else
531   /* On DOS, the extensionless COFF file is what gdb likes.  */
532   *value = "";
533 #endif
534
535   if (*value == 0)
536     *len = 0;
537   else
538     *len = strlen (*value);
539
540   return;
541 }
542
543 int
544 __gnat_open_read (char *path, int fmode)
545 {
546   int fd;
547   int o_fmode = O_BINARY;
548
549   if (fmode)
550     o_fmode = O_TEXT;
551
552 #if defined (VMS)
553   /* Optional arguments mbc,deq,fop increase read performance.  */
554   fd = open (path, O_RDONLY | o_fmode, 0444,
555              "mbc=16", "deq=64", "fop=tef");
556 #elif defined (__vxworks)
557   fd = open (path, O_RDONLY | o_fmode, 0444);
558 #else
559   fd = open (path, O_RDONLY | o_fmode);
560 #endif
561
562   return fd < 0 ? -1 : fd;
563 }
564
565 #if defined (__EMX__) || defined (__MINGW32__)
566 #define PERM (S_IREAD | S_IWRITE)
567 #elif defined (VMS)
568 /* Excerpt from DECC C RTL Reference Manual:
569    To create files with OpenVMS RMS default protections using the UNIX
570    system-call functions umask, mkdir, creat, and open, call mkdir, creat,
571    and open with a file-protection mode argument of 0777 in a program
572    that never specifically calls umask. These default protections include
573    correctly establishing protections based on ACLs, previous versions of
574    files, and so on. */
575 #define PERM 0777
576 #else
577 #define PERM (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH)
578 #endif
579
580 int
581 __gnat_open_rw (char *path, int fmode)
582 {
583   int fd;
584   int o_fmode = O_BINARY;
585
586   if (fmode)
587     o_fmode = O_TEXT;
588
589 #if defined (VMS)
590   fd = open (path, O_RDWR | o_fmode, PERM,
591              "mbc=16", "deq=64", "fop=tef");
592 #else
593   fd = open (path, O_RDWR | o_fmode, PERM);
594 #endif
595
596   return fd < 0 ? -1 : fd;
597 }
598
599 int
600 __gnat_open_create (char *path, int fmode)
601 {
602   int fd;
603   int o_fmode = O_BINARY;
604
605   if (fmode)
606     o_fmode = O_TEXT;
607
608 #if defined (VMS)
609   fd = open (path, O_WRONLY | O_CREAT | O_TRUNC | o_fmode, PERM,
610              "mbc=16", "deq=64", "fop=tef");
611 #else
612   fd = open (path, O_WRONLY | O_CREAT | O_TRUNC | o_fmode, PERM);
613 #endif
614
615   return fd < 0 ? -1 : fd;
616 }
617
618 int
619 __gnat_open_append (char *path, int fmode)
620 {
621   int fd;
622   int o_fmode = O_BINARY;
623
624   if (fmode)
625     o_fmode = O_TEXT;
626
627 #if defined (VMS)
628   fd = open (path, O_WRONLY | O_CREAT | O_APPEND | o_fmode, PERM,
629              "mbc=16", "deq=64", "fop=tef");
630 #else
631   fd = open (path, O_WRONLY | O_CREAT | O_APPEND | o_fmode, PERM);
632 #endif
633
634   return fd < 0 ? -1 : fd;
635 }
636
637 /*  Open a new file.  Return error (-1) if the file already exists.  */
638
639 int
640 __gnat_open_new (char *path, int fmode)
641 {
642   int fd;
643   int o_fmode = O_BINARY;
644
645   if (fmode)
646     o_fmode = O_TEXT;
647
648 #if defined (VMS)
649   fd = open (path, O_WRONLY | O_CREAT | O_EXCL | o_fmode, PERM,
650              "mbc=16", "deq=64", "fop=tef");
651 #else
652   fd = open (path, O_WRONLY | O_CREAT | O_EXCL | o_fmode, PERM);
653 #endif
654
655   return fd < 0 ? -1 : fd;
656 }
657
658 /* Open a new temp file.  Return error (-1) if the file already exists.
659    Special options for VMS allow the file to be shared between parent and child
660    processes, however they really slow down output.  Used in gnatchop.  */
661
662 int
663 __gnat_open_new_temp (char *path, int fmode)
664 {
665   int fd;
666   int o_fmode = O_BINARY;
667
668   strcpy (path, "GNAT-XXXXXX");
669
670 #if (defined (__FreeBSD__) || defined (linux)) && !defined (__vxworks)
671   return mkstemp (path);
672 #elif defined (__Lynx__)
673   mktemp (path);
674 #else
675   if (mktemp (path) == NULL)
676     return -1;
677 #endif
678
679   if (fmode)
680     o_fmode = O_TEXT;
681
682 #if defined (VMS)
683   fd = open (path, O_WRONLY | O_CREAT | O_EXCL | o_fmode, PERM,
684              "rfm=stmlf", "ctx=rec", "rat=none", "shr=del,get,put,upd",
685              "mbc=16", "deq=64", "fop=tef");
686 #else
687   fd = open (path, O_WRONLY | O_CREAT | O_EXCL | o_fmode, PERM);
688 #endif
689
690   return fd < 0 ? -1 : fd;
691 }
692
693 /* Return the number of bytes in the specified file.  */
694
695 long
696 __gnat_file_length (int fd)
697 {
698   int ret;
699   struct stat statbuf;
700
701   ret = fstat (fd, &statbuf);
702   if (ret || !S_ISREG (statbuf.st_mode))
703     return 0;
704
705   return (statbuf.st_size);
706 }
707
708 /* Create a temporary filename and put it in string pointed to by
709    TMP_FILENAME.  */
710
711 void
712 __gnat_tmp_name (char *tmp_filename)
713 {
714 #ifdef __MINGW32__
715   {
716     char *pname;
717
718     /* tempnam tries to create a temporary file in directory pointed to by
719        TMP environment variable, in c:\temp if TMP is not set, and in
720        directory specified by P_tmpdir in stdio.h if c:\temp does not
721        exist. The filename will be created with the prefix "gnat-".  */
722
723     pname = (char *) tempnam ("c:\\temp", "gnat-");
724
725     /* if pname is NULL, the file was not created properly, the disk is full
726        or there is no more free temporary files */
727
728     if (pname == NULL)
729       *tmp_filename = '\0';
730
731     /* If pname start with a back slash and not path information it means that
732        the filename is valid for the current working directory.  */
733
734     else if (pname[0] == '\\')
735       {
736         strcpy (tmp_filename, ".\\");
737         strcat (tmp_filename, pname+1);
738       }
739     else
740       strcpy (tmp_filename, pname);
741
742     free (pname);
743   }
744
745 #elif defined (linux) || defined (__FreeBSD__)
746 #define MAX_SAFE_PATH 1000
747   char *tmpdir = getenv ("TMPDIR");
748
749   /* If tmpdir is longer than MAX_SAFE_PATH, revert to default value to avoid
750      a buffer overflow.  */
751   if (tmpdir == NULL || strlen (tmpdir) > MAX_SAFE_PATH)
752     strcpy (tmp_filename, "/tmp/gnat-XXXXXX");
753   else
754     sprintf (tmp_filename, "%s/gnat-XXXXXX", tmpdir);
755
756   close (mkstemp(tmp_filename));
757 #else
758   tmpnam (tmp_filename);
759 #endif
760 }
761
762 /* Read the next entry in a directory.  The returned string points somewhere
763    in the buffer.  */
764
765 char *
766 __gnat_readdir (DIR *dirp, char *buffer)
767 {
768   /* If possible, try to use the thread-safe version.  */
769 #ifdef HAVE_READDIR_R
770   if (readdir_r (dirp, buffer) != NULL)
771     return ((struct dirent*) buffer)->d_name;
772   else
773     return NULL;
774
775 #else
776   struct dirent *dirent = readdir (dirp);
777
778   if (dirent != NULL)
779     {
780       strcpy (buffer, dirent->d_name);
781       return buffer;
782     }
783   else
784     return NULL;
785
786 #endif
787 }
788
789 /* Returns 1 if readdir is thread safe, 0 otherwise.  */
790
791 int
792 __gnat_readdir_is_thread_safe (void)
793 {
794 #ifdef HAVE_READDIR_R
795   return 1;
796 #else
797   return 0;
798 #endif
799 }
800
801 #ifdef _WIN32
802 /* Number of seconds between <Jan 1st 1601> and <Jan 1st 1970>.  */
803 static const unsigned long long w32_epoch_offset = 11644473600ULL;
804
805 /* Returns the file modification timestamp using Win32 routines which are
806    immune against daylight saving time change. It is in fact not possible to
807    use fstat for this purpose as the DST modify the st_mtime field of the
808    stat structure.  */
809
810 static time_t
811 win32_filetime (HANDLE h)
812 {
813   union
814   {
815     FILETIME ft_time;
816     unsigned long long ull_time;
817   } t_write;
818
819   /* GetFileTime returns FILETIME data which are the number of 100 nanosecs
820      since <Jan 1st 1601>. This function must return the number of seconds
821      since <Jan 1st 1970>.  */
822
823   if (GetFileTime (h, NULL, NULL, &t_write.ft_time))
824     return (time_t) (t_write.ull_time / 10000000ULL
825                      - w32_epoch_offset);
826   return (time_t) 0;
827 }
828 #endif
829
830 /* Return a GNAT time stamp given a file name.  */
831
832 time_t
833 __gnat_file_time_name (char *name)
834 {
835
836 #if defined (__EMX__) || defined (MSDOS)
837   int fd = open (name, O_RDONLY | O_BINARY);
838   time_t ret = __gnat_file_time_fd (fd);
839   close (fd);
840   return ret;
841
842 #elif defined (_WIN32)
843   time_t ret = 0;
844   HANDLE h = CreateFile (name, GENERIC_READ, FILE_SHARE_READ, 0,
845                          OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0);
846
847   if (h != INVALID_HANDLE_VALUE)
848     {
849       ret = win32_filetime (h);
850       CloseHandle (h);
851     }
852   return ret;
853 #else
854   struct stat statbuf;
855   (void) __gnat_stat (name, &statbuf);
856 #ifdef VMS
857   /* VMS has file versioning.  */
858   return statbuf.st_ctime;
859 #else
860   return statbuf.st_mtime;
861 #endif
862 #endif
863 }
864
865 /* Return a GNAT time stamp given a file descriptor.  */
866
867 time_t
868 __gnat_file_time_fd (int fd)
869 {
870   /* The following workaround code is due to the fact that under EMX and
871      DJGPP fstat attempts to convert time values to GMT rather than keep the
872      actual OS timestamp of the file. By using the OS2/DOS functions directly
873      the GNAT timestamp are independent of this behavior, which is desired to
874      facilitate the distribution of GNAT compiled libraries.  */
875
876 #if defined (__EMX__) || defined (MSDOS)
877 #ifdef __EMX__
878
879   FILESTATUS fs;
880   int ret = DosQueryFileInfo (fd, 1, (unsigned char *) &fs,
881                                 sizeof (FILESTATUS));
882
883   unsigned file_year  = fs.fdateLastWrite.year;
884   unsigned file_month = fs.fdateLastWrite.month;
885   unsigned file_day   = fs.fdateLastWrite.day;
886   unsigned file_hour  = fs.ftimeLastWrite.hours;
887   unsigned file_min   = fs.ftimeLastWrite.minutes;
888   unsigned file_tsec  = fs.ftimeLastWrite.twosecs;
889
890 #else
891   struct ftime fs;
892   int ret = getftime (fd, &fs);
893
894   unsigned file_year  = fs.ft_year;
895   unsigned file_month = fs.ft_month;
896   unsigned file_day   = fs.ft_day;
897   unsigned file_hour  = fs.ft_hour;
898   unsigned file_min   = fs.ft_min;
899   unsigned file_tsec  = fs.ft_tsec;
900 #endif
901
902   /* Calculate the seconds since epoch from the time components. First count
903      the whole days passed.  The value for years returned by the DOS and OS2
904      functions count years from 1980, so to compensate for the UNIX epoch which
905      begins in 1970 start with 10 years worth of days and add days for each
906      four year period since then.  */
907
908   time_t tot_secs;
909   int cum_days[12] = {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334};
910   int days_passed = 3652 + (file_year / 4) * 1461;
911   int years_since_leap = file_year % 4;
912
913   if (years_since_leap == 1)
914     days_passed += 366;
915   else if (years_since_leap == 2)
916     days_passed += 731;
917   else if (years_since_leap == 3)
918     days_passed += 1096;
919
920   if (file_year > 20)
921     days_passed -= 1;
922
923   days_passed += cum_days[file_month - 1];
924   if (years_since_leap == 0 && file_year != 20 && file_month > 2)
925     days_passed++;
926
927   days_passed += file_day - 1;
928
929   /* OK - have whole days.  Multiply -- then add in other parts.  */
930
931   tot_secs  = days_passed * 86400;
932   tot_secs += file_hour * 3600;
933   tot_secs += file_min * 60;
934   tot_secs += file_tsec * 2;
935   return tot_secs;
936
937 #elif defined (_WIN32)
938   HANDLE h = (HANDLE) _get_osfhandle (fd);
939   time_t ret = win32_filetime (h);
940   return ret;
941
942 #else
943   struct stat statbuf;
944
945   (void) fstat (fd, &statbuf);
946
947 #ifdef VMS
948   /* VMS has file versioning.  */
949   return statbuf.st_ctime;
950 #else
951   return statbuf.st_mtime;
952 #endif
953 #endif
954 }
955
956 /* Set the file time stamp.  */
957
958 void
959 __gnat_set_file_time_name (char *name, time_t time_stamp)
960 {
961 #if defined (__EMX__) || defined (MSDOS) || defined (__vxworks)
962
963 /* Code to implement __gnat_set_file_time_name for these systems.  */
964
965 #elif defined (_WIN32)
966   union
967   {
968     FILETIME ft_time;
969     unsigned long long ull_time;
970   } t_write;
971
972   HANDLE h  = CreateFile (name, GENERIC_WRITE, FILE_SHARE_WRITE, NULL,
973                           OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS,
974                           NULL);
975   if (h == INVALID_HANDLE_VALUE)
976     return;
977   /* Add number of seconds between <Jan 1st 1601> and <Jan 1st 1970> */
978   t_write.ull_time = ((unsigned long long)time_stamp + w32_epoch_offset);
979   /*  Convert to 100 nanosecond units  */
980   t_write.ull_time *= 10000000ULL;
981
982   SetFileTime(h, NULL, NULL, &t_write.ft_time);
983   CloseHandle (h);
984   return;
985
986 #elif defined (VMS)
987   struct FAB fab;
988   struct NAM nam;
989
990   struct
991     {
992       unsigned long long backup, create, expire, revise;
993       unsigned long uic;
994       union
995         {
996           unsigned short value;
997           struct
998             {
999               unsigned system : 4;
1000               unsigned owner  : 4;
1001               unsigned group  : 4;
1002               unsigned world  : 4;
1003             } bits;
1004         } prot;
1005     } Fat = { 0, 0, 0, 0, 0, { 0 }};
1006
1007   ATRDEF atrlst[]
1008     = {
1009       { ATR$S_CREDATE,  ATR$C_CREDATE,  &Fat.create },
1010       { ATR$S_REVDATE,  ATR$C_REVDATE,  &Fat.revise },
1011       { ATR$S_EXPDATE,  ATR$C_EXPDATE,  &Fat.expire },
1012       { ATR$S_BAKDATE,  ATR$C_BAKDATE,  &Fat.backup },
1013       { ATR$S_FPRO,     ATR$C_FPRO,     &Fat.prot },
1014       { ATR$S_UIC,      ATR$C_UIC,      &Fat.uic },
1015       { 0, 0, 0}
1016     };
1017
1018   FIBDEF fib;
1019   struct dsc$descriptor_fib fibdsc = {sizeof (fib), (void *) &fib};
1020
1021   struct IOSB iosb;
1022
1023   unsigned long long newtime;
1024   unsigned long long revtime;
1025   long status;
1026   short chan;
1027
1028   struct vstring file;
1029   struct dsc$descriptor_s filedsc
1030     = {NAM$C_MAXRSS, DSC$K_DTYPE_T, DSC$K_CLASS_S, (void *) file.string};
1031   struct vstring device;
1032   struct dsc$descriptor_s devicedsc
1033     = {NAM$C_MAXRSS, DSC$K_DTYPE_T, DSC$K_CLASS_S, (void *) device.string};
1034   struct vstring timev;
1035   struct dsc$descriptor_s timedsc
1036     = {NAM$C_MAXRSS, DSC$K_DTYPE_T, DSC$K_CLASS_S, (void *) timev.string};
1037   struct vstring result;
1038   struct dsc$descriptor_s resultdsc
1039     = {NAM$C_MAXRSS, DSC$K_DTYPE_VT, DSC$K_CLASS_VS, (void *) result.string};
1040
1041   tryfile = (char *) __gnat_to_host_dir_spec (name, 0);
1042
1043   /* Allocate and initialize a FAB and NAM structures.  */
1044   fab = cc$rms_fab;
1045   nam = cc$rms_nam;
1046
1047   nam.nam$l_esa = file.string;
1048   nam.nam$b_ess = NAM$C_MAXRSS;
1049   nam.nam$l_rsa = result.string;
1050   nam.nam$b_rss = NAM$C_MAXRSS;
1051   fab.fab$l_fna = tryfile;
1052   fab.fab$b_fns = strlen (tryfile);
1053   fab.fab$l_nam = &nam;
1054
1055   /* Validate filespec syntax and device existence.  */
1056   status = SYS$PARSE (&fab, 0, 0);
1057   if ((status & 1) != 1)
1058     LIB$SIGNAL (status);
1059
1060   file.string[nam.nam$b_esl] = 0;
1061
1062   /* Find matching filespec.  */
1063   status = SYS$SEARCH (&fab, 0, 0);
1064   if ((status & 1) != 1)
1065     LIB$SIGNAL (status);
1066
1067   file.string[nam.nam$b_esl] = 0;
1068   result.string[result.length=nam.nam$b_rsl] = 0;
1069
1070   /* Get the device name and assign an IO channel.  */
1071   strncpy (device.string, nam.nam$l_dev, nam.nam$b_dev);
1072   devicedsc.dsc$w_length  = nam.nam$b_dev;
1073   chan = 0;
1074   status = SYS$ASSIGN (&devicedsc, &chan, 0, 0, 0);
1075   if ((status & 1) != 1)
1076     LIB$SIGNAL (status);
1077
1078   /* Initialize the FIB and fill in the directory id field.  */
1079   memset (&fib, 0, sizeof (fib));
1080   fib.fib$w_did[0]  = nam.nam$w_did[0];
1081   fib.fib$w_did[1]  = nam.nam$w_did[1];
1082   fib.fib$w_did[2]  = nam.nam$w_did[2];
1083   fib.fib$l_acctl = 0;
1084   fib.fib$l_wcc = 0;
1085   strcpy (file.string, (strrchr (result.string, ']') + 1));
1086   filedsc.dsc$w_length = strlen (file.string);
1087   result.string[result.length = 0] = 0;
1088
1089   /* Open and close the file to fill in the attributes.  */
1090   status
1091     = SYS$QIOW (0, chan, IO$_ACCESS|IO$M_ACCESS, &iosb, 0, 0,
1092                 &fibdsc, &filedsc, &result.length, &resultdsc, &atrlst, 0);
1093   if ((status & 1) != 1)
1094     LIB$SIGNAL (status);
1095   if ((iosb.status & 1) != 1)
1096     LIB$SIGNAL (iosb.status);
1097
1098   result.string[result.length] = 0;
1099   status = SYS$QIOW (0, chan, IO$_DEACCESS, &iosb, 0, 0, &fibdsc, 0, 0, 0,
1100                      &atrlst, 0);
1101   if ((status & 1) != 1)
1102     LIB$SIGNAL (status);
1103   if ((iosb.status & 1) != 1)
1104     LIB$SIGNAL (iosb.status);
1105
1106   {
1107     time_t t;
1108
1109     /* Set creation time to requested time.  */
1110     unix_time_to_vms (time_stamp, newtime);
1111
1112     t = time ((time_t) 0);
1113
1114     /* Set revision time to now in local time.  */
1115     unix_time_to_vms (t, revtime);
1116   }
1117
1118   /* Reopen the file, modify the times and then close.  */
1119   fib.fib$l_acctl = FIB$M_WRITE;
1120   status
1121     = SYS$QIOW (0, chan, IO$_ACCESS|IO$M_ACCESS, &iosb, 0, 0,
1122                 &fibdsc, &filedsc, &result.length, &resultdsc, &atrlst, 0);
1123   if ((status & 1) != 1)
1124     LIB$SIGNAL (status);
1125   if ((iosb.status & 1) != 1)
1126     LIB$SIGNAL (iosb.status);
1127
1128   Fat.create = newtime;
1129   Fat.revise = revtime;
1130
1131   status = SYS$QIOW (0, chan, IO$_DEACCESS, &iosb, 0, 0,
1132                      &fibdsc, 0, 0, 0, &atrlst, 0);
1133   if ((status & 1) != 1)
1134     LIB$SIGNAL (status);
1135   if ((iosb.status & 1) != 1)
1136     LIB$SIGNAL (iosb.status);
1137
1138   /* Deassign the channel and exit.  */
1139   status = SYS$DASSGN (chan);
1140   if ((status & 1) != 1)
1141     LIB$SIGNAL (status);
1142 #else
1143   struct utimbuf utimbuf;
1144   time_t t;
1145
1146   /* Set modification time to requested time.  */
1147   utimbuf.modtime = time_stamp;
1148
1149   /* Set access time to now in local time.  */
1150   t = time ((time_t) 0);
1151   utimbuf.actime = mktime (localtime (&t));
1152
1153   utime (name, &utimbuf);
1154 #endif
1155 }
1156
1157 void
1158 __gnat_get_env_value_ptr (char *name, int *len, char **value)
1159 {
1160   *value = getenv (name);
1161   if (!*value)
1162     *len = 0;
1163   else
1164     *len = strlen (*value);
1165
1166   return;
1167 }
1168
1169 /* VMS specific declarations for set_env_value.  */
1170
1171 #ifdef VMS
1172
1173 static char *to_host_path_spec (char *);
1174
1175 struct descriptor_s
1176 {
1177   unsigned short len, mbz;
1178   char *adr;
1179 };
1180
1181 typedef struct _ile3
1182 {
1183   unsigned short len, code;
1184   char *adr;
1185   unsigned short *retlen_adr;
1186 } ile_s;
1187
1188 #endif
1189
1190 void
1191 __gnat_set_env_value (char *name, char *value)
1192 {
1193 #ifdef MSDOS
1194
1195 #elif defined (VMS)
1196   struct descriptor_s name_desc;
1197   /* Put in JOB table for now, so that the project stuff at least works.  */
1198   struct descriptor_s table_desc = {7, 0, "LNM$JOB"};
1199   char *host_pathspec = value;
1200   char *copy_pathspec;
1201   int num_dirs_in_pathspec = 1;
1202   char *ptr;
1203   long status;
1204
1205   name_desc.len = strlen (name);
1206   name_desc.mbz = 0;
1207   name_desc.adr = name;
1208
1209   if (*host_pathspec == 0)
1210     /* deassign */
1211     {
1212       status = LIB$DELETE_LOGICAL (&name_desc, &table_desc);
1213       /* no need to check status; if the logical name is not
1214          defined, that's fine. */
1215       return;
1216     }
1217
1218   ptr = host_pathspec;
1219   while (*ptr++)
1220     if (*ptr == ',')
1221       num_dirs_in_pathspec++;
1222
1223   {
1224     int i, status;
1225     ile_s *ile_array = alloca (sizeof (ile_s) * (num_dirs_in_pathspec + 1));
1226     char *copy_pathspec = alloca (strlen (host_pathspec) + 1);
1227     char *curr, *next;
1228
1229     strcpy (copy_pathspec, host_pathspec);
1230     curr = copy_pathspec;
1231     for (i = 0; i < num_dirs_in_pathspec; i++)
1232       {
1233         next = strchr (curr, ',');
1234         if (next == 0)
1235           next = strchr (curr, 0);
1236
1237         *next = 0;
1238         ile_array[i].len = strlen (curr);
1239
1240         /* Code 2 from lnmdef.h means its a string.  */
1241         ile_array[i].code = 2;
1242         ile_array[i].adr = curr;
1243
1244         /* retlen_adr is ignored.  */
1245         ile_array[i].retlen_adr = 0;
1246         curr = next + 1;
1247       }
1248
1249     /* Terminating item must be zero.  */
1250     ile_array[i].len = 0;
1251     ile_array[i].code = 0;
1252     ile_array[i].adr = 0;
1253     ile_array[i].retlen_adr = 0;
1254
1255     status = LIB$SET_LOGICAL (&name_desc, 0, &table_desc, 0, ile_array);
1256     if ((status & 1) != 1)
1257       LIB$SIGNAL (status);
1258   }
1259
1260 #else
1261   int size = strlen (name) + strlen (value) + 2;
1262   char *expression;
1263
1264   expression = (char *) xmalloc (size * sizeof (char));
1265
1266   sprintf (expression, "%s=%s", name, value);
1267   putenv (expression);
1268 #endif
1269 }
1270
1271 #ifdef _WIN32
1272 #include <windows.h>
1273 #endif
1274
1275 /* Get the list of installed standard libraries from the
1276    HKEY_LOCAL_MACHINE\SOFTWARE\Ada Core Technologies\GNAT\Standard Libraries
1277    key.  */
1278
1279 char *
1280 __gnat_get_libraries_from_registry (void)
1281 {
1282   char *result = (char *) "";
1283
1284 #if defined (_WIN32) && ! defined (__vxworks) && ! defined (CROSS_COMPILE)
1285
1286   HKEY reg_key;
1287   DWORD name_size, value_size;
1288   char name[256];
1289   char value[256];
1290   DWORD type;
1291   DWORD index;
1292   LONG res;
1293
1294   /* First open the key.  */
1295   res = RegOpenKeyExA (HKEY_LOCAL_MACHINE, "SOFTWARE", 0, KEY_READ, &reg_key);
1296
1297   if (res == ERROR_SUCCESS)
1298     res = RegOpenKeyExA (reg_key, "Ada Core Technologies", 0,
1299                          KEY_READ, &reg_key);
1300
1301   if (res == ERROR_SUCCESS)
1302     res = RegOpenKeyExA (reg_key, "GNAT", 0, KEY_READ, &reg_key);
1303
1304   if (res == ERROR_SUCCESS)
1305     res = RegOpenKeyExA (reg_key, "Standard Libraries", 0, KEY_READ, &reg_key);
1306
1307   /* If the key exists, read out all the values in it and concatenate them
1308      into a path.  */
1309   for (index = 0; res == ERROR_SUCCESS; index++)
1310     {
1311       value_size = name_size = 256;
1312       res = RegEnumValue (reg_key, index, name, &name_size, 0,
1313                           &type, value, &value_size);
1314
1315       if (res == ERROR_SUCCESS && type == REG_SZ)
1316         {
1317           char *old_result = result;
1318
1319           result = (char *) xmalloc (strlen (old_result) + value_size + 2);
1320           strcpy (result, old_result);
1321           strcat (result, value);
1322           strcat (result, ";");
1323         }
1324     }
1325
1326   /* Remove the trailing ";".  */
1327   if (result[0] != 0)
1328     result[strlen (result) - 1] = 0;
1329
1330 #endif
1331   return result;
1332 }
1333
1334 int
1335 __gnat_stat (char *name, struct stat *statbuf)
1336 {
1337 #ifdef _WIN32
1338   /* Under Windows the directory name for the stat function must not be
1339      terminated by a directory separator except if just after a drive name.  */
1340   int name_len  = strlen (name);
1341   char last_char = name[name_len - 1];
1342   char win32_name[GNAT_MAX_PATH_LEN + 2];
1343
1344   if (name_len > GNAT_MAX_PATH_LEN)
1345     return -1;
1346
1347   strcpy (win32_name, name);
1348
1349   while (name_len > 1 && (last_char == '\\' || last_char == '/'))
1350     {
1351       win32_name[name_len - 1] = '\0';
1352       name_len--;
1353       last_char = win32_name[name_len - 1];
1354     }
1355
1356   if (name_len == 2 && win32_name[1] == ':')
1357     strcat (win32_name, "\\");
1358
1359   return stat (win32_name, statbuf);
1360
1361 #else
1362   return stat (name, statbuf);
1363 #endif
1364 }
1365
1366 int
1367 __gnat_file_exists (char *name)
1368 {
1369   struct stat statbuf;
1370
1371   return !__gnat_stat (name, &statbuf);
1372 }
1373
1374 int
1375 __gnat_is_absolute_path (char *name)
1376 {
1377   return (*name == '/' || *name == DIR_SEPARATOR
1378 #if defined (__EMX__) || defined (MSDOS) || defined (WINNT)
1379       || (strlen (name) > 1 && isalpha (name[0]) && name[1] == ':')
1380 #endif
1381           );
1382 }
1383
1384 int
1385 __gnat_is_regular_file (char *name)
1386 {
1387   int ret;
1388   struct stat statbuf;
1389
1390   ret = __gnat_stat (name, &statbuf);
1391   return (!ret && S_ISREG (statbuf.st_mode));
1392 }
1393
1394 int
1395 __gnat_is_directory (char *name)
1396 {
1397   int ret;
1398   struct stat statbuf;
1399
1400   ret = __gnat_stat (name, &statbuf);
1401   return (!ret && S_ISDIR (statbuf.st_mode));
1402 }
1403
1404 int
1405 __gnat_is_readable_file (char *name)
1406 {
1407   int ret;
1408   int mode;
1409   struct stat statbuf;
1410
1411   ret = __gnat_stat (name, &statbuf);
1412   mode = statbuf.st_mode & S_IRUSR;
1413   return (!ret && mode);
1414 }
1415
1416 int
1417 __gnat_is_writable_file (char *name)
1418 {
1419   int ret;
1420   int mode;
1421   struct stat statbuf;
1422
1423   ret = __gnat_stat (name, &statbuf);
1424   mode = statbuf.st_mode & S_IWUSR;
1425   return (!ret && mode);
1426 }
1427
1428 void
1429 __gnat_set_writable (char *name)
1430 {
1431 #ifndef __vxworks
1432   struct stat statbuf;
1433
1434   if (stat (name, &statbuf) == 0)
1435   {
1436     statbuf.st_mode = statbuf.st_mode | S_IWUSR;
1437     chmod (name, statbuf.st_mode);
1438   }
1439 #endif
1440 }
1441
1442 void
1443 __gnat_set_readonly (char *name)
1444 {
1445 #ifndef __vxworks
1446   struct stat statbuf;
1447
1448   if (stat (name, &statbuf) == 0)
1449   {
1450     statbuf.st_mode = statbuf.st_mode & 07577;
1451     chmod (name, statbuf.st_mode);
1452   }
1453 #endif
1454 }
1455
1456 int
1457 __gnat_is_symbolic_link (char *name ATTRIBUTE_UNUSED)
1458 {
1459 #if defined (__vxworks)
1460   return 0;
1461
1462 #elif defined (_AIX) || defined (unix)
1463   int ret;
1464   struct stat statbuf;
1465
1466   ret = lstat (name, &statbuf);
1467   return (!ret && S_ISLNK (statbuf.st_mode));
1468
1469 #else
1470   return 0;
1471 #endif
1472 }
1473
1474 #ifdef VMS
1475 /* Defined in VMS header files. */
1476 #if defined (__ALPHA)
1477 #define fork() (decc$$alloc_vfork_blocks() >= 0 ? \
1478                 LIB$GET_CURRENT_INVO_CONTEXT (decc$$get_vfork_jmpbuf()) : -1)
1479 #elif defined (__IA64)
1480 #define fork() (decc$$alloc_vfork_blocks() >= 0 ? \
1481                 LIB$I64_GET_CURR_INVO_CONTEXT(decc$$get_vfork_jmpbuf()) : -1)
1482 #endif
1483 #endif
1484
1485 #if defined (sun) && defined (__SVR4)
1486 /* Using fork on Solaris will duplicate all the threads. fork1, which
1487    duplicates only the active thread, must be used instead, or spawning
1488    subprocess from a program with tasking will lead into numerous problems.  */
1489 #define fork fork1
1490 #endif
1491
1492 int
1493 __gnat_portable_spawn (char *args[])
1494 {
1495   int status = 0;
1496   int finished ATTRIBUTE_UNUSED;
1497   int pid ATTRIBUTE_UNUSED;
1498
1499 #if defined (MSDOS) || defined (_WIN32)
1500   status = spawnvp (P_WAIT, args[0],(const char* const*)args);
1501   if (status < 0)
1502     return -1;
1503   else
1504     return status;
1505
1506 #elif defined (__vxworks)
1507   return -1;
1508 #else
1509
1510 #ifdef __EMX__
1511   pid = spawnvp (P_NOWAIT, args[0], args);
1512   if (pid == -1)
1513     return -1;
1514
1515 #else
1516   pid = fork ();
1517   if (pid < 0)
1518     return -1;
1519
1520   if (pid == 0)
1521     {
1522       /* The child. */
1523       if (execv (args[0], args) != 0)
1524 #if defined (VMS)
1525         return -1; /* execv is in parent context on VMS.  */
1526 #else
1527         _exit (1);
1528 #endif
1529     }
1530 #endif
1531
1532   /* The parent.  */
1533   finished = waitpid (pid, &status, 0);
1534
1535   if (finished != pid || WIFEXITED (status) == 0)
1536     return -1;
1537
1538   return WEXITSTATUS (status);
1539 #endif
1540
1541   return 0;
1542 }
1543
1544 /* WIN32 code to implement a wait call that wait for any child process.  */
1545
1546 #ifdef _WIN32
1547
1548 /* Synchronization code, to be thread safe.  */
1549
1550 static CRITICAL_SECTION plist_cs;
1551
1552 void
1553 __gnat_plist_init (void)
1554 {
1555   InitializeCriticalSection (&plist_cs);
1556 }
1557
1558 static void
1559 plist_enter (void)
1560 {
1561   EnterCriticalSection (&plist_cs);
1562 }
1563
1564 static void
1565 plist_leave (void)
1566 {
1567   LeaveCriticalSection (&plist_cs);
1568 }
1569
1570 typedef struct _process_list
1571 {
1572   HANDLE h;
1573   struct _process_list *next;
1574 } Process_List;
1575
1576 static Process_List *PLIST = NULL;
1577
1578 static int plist_length = 0;
1579
1580 static void
1581 add_handle (HANDLE h)
1582 {
1583   Process_List *pl;
1584
1585   pl = (Process_List *) xmalloc (sizeof (Process_List));
1586
1587   plist_enter();
1588
1589   /* -------------------- critical section -------------------- */
1590   pl->h = h;
1591   pl->next = PLIST;
1592   PLIST = pl;
1593   ++plist_length;
1594   /* -------------------- critical section -------------------- */
1595
1596   plist_leave();
1597 }
1598
1599 static void
1600 remove_handle (HANDLE h)
1601 {
1602   Process_List *pl;
1603   Process_List *prev = NULL;
1604
1605   plist_enter();
1606
1607   /* -------------------- critical section -------------------- */
1608   pl = PLIST;
1609   while (pl)
1610     {
1611       if (pl->h == h)
1612         {
1613           if (pl == PLIST)
1614             PLIST = pl->next;
1615           else
1616             prev->next = pl->next;
1617           free (pl);
1618           break;
1619         }
1620       else
1621         {
1622           prev = pl;
1623           pl = pl->next;
1624         }
1625     }
1626
1627   --plist_length;
1628   /* -------------------- critical section -------------------- */
1629
1630   plist_leave();
1631 }
1632
1633 static int
1634 win32_no_block_spawn (char *command, char *args[])
1635 {
1636   BOOL result;
1637   STARTUPINFO SI;
1638   PROCESS_INFORMATION PI;
1639   SECURITY_ATTRIBUTES SA;
1640   int csize = 1;
1641   char *full_command;
1642   int k;
1643
1644   /* compute the total command line length */
1645   k = 0;
1646   while (args[k])
1647     {
1648       csize += strlen (args[k]) + 1;
1649       k++;
1650     }
1651
1652   full_command = (char *) xmalloc (csize);
1653
1654   /* Startup info. */
1655   SI.cb          = sizeof (STARTUPINFO);
1656   SI.lpReserved  = NULL;
1657   SI.lpReserved2 = NULL;
1658   SI.lpDesktop   = NULL;
1659   SI.cbReserved2 = 0;
1660   SI.lpTitle     = NULL;
1661   SI.dwFlags     = 0;
1662   SI.wShowWindow = SW_HIDE;
1663
1664   /* Security attributes. */
1665   SA.nLength = sizeof (SECURITY_ATTRIBUTES);
1666   SA.bInheritHandle = TRUE;
1667   SA.lpSecurityDescriptor = NULL;
1668
1669   /* Prepare the command string. */
1670   strcpy (full_command, command);
1671   strcat (full_command, " ");
1672
1673   k = 1;
1674   while (args[k])
1675     {
1676       strcat (full_command, args[k]);
1677       strcat (full_command, " ");
1678       k++;
1679     }
1680
1681   result = CreateProcess (NULL, (char *) full_command, &SA, NULL, TRUE,
1682                           NORMAL_PRIORITY_CLASS, NULL, NULL, &SI, &PI);
1683
1684   free (full_command);
1685
1686   if (result == TRUE)
1687     {
1688       add_handle (PI.hProcess);
1689       CloseHandle (PI.hThread);
1690       return (int) PI.hProcess;
1691     }
1692   else
1693     return -1;
1694 }
1695
1696 static int
1697 win32_wait (int *status)
1698 {
1699   DWORD exitcode;
1700   HANDLE *hl;
1701   HANDLE h;
1702   DWORD res;
1703   int k;
1704   Process_List *pl;
1705
1706   if (plist_length == 0)
1707     {
1708       errno = ECHILD;
1709       return -1;
1710     }
1711
1712   hl = (HANDLE *) xmalloc (sizeof (HANDLE) * plist_length);
1713
1714   k = 0;
1715   plist_enter();
1716
1717   /* -------------------- critical section -------------------- */
1718   pl = PLIST;
1719   while (pl)
1720     {
1721       hl[k++] = pl->h;
1722       pl = pl->next;
1723     }
1724   /* -------------------- critical section -------------------- */
1725
1726   plist_leave();
1727
1728   res = WaitForMultipleObjects (plist_length, hl, FALSE, INFINITE);
1729   h = hl[res - WAIT_OBJECT_0];
1730   free (hl);
1731
1732   remove_handle (h);
1733
1734   GetExitCodeProcess (h, &exitcode);
1735   CloseHandle (h);
1736
1737   *status = (int) exitcode;
1738   return (int) h;
1739 }
1740
1741 #endif
1742
1743 int
1744 __gnat_portable_no_block_spawn (char *args[])
1745 {
1746   int pid = 0;
1747
1748 #if defined (__EMX__) || defined (MSDOS)
1749
1750   /* ??? For PC machines I (Franco) don't know the system calls to implement
1751      this routine. So I'll fake it as follows. This routine will behave
1752      exactly like the blocking portable_spawn and will systematically return
1753      a pid of 0 unless the spawned task did not complete successfully, in
1754      which case we return a pid of -1.  To synchronize with this the
1755      portable_wait below systematically returns a pid of 0 and reports that
1756      the subprocess terminated successfully. */
1757
1758   if (spawnvp (P_WAIT, args[0], args) != 0)
1759     return -1;
1760
1761 #elif defined (_WIN32)
1762
1763   pid = win32_no_block_spawn (args[0], args);
1764   return pid;
1765
1766 #elif defined (__vxworks)
1767   return -1;
1768
1769 #else
1770   pid = fork ();
1771
1772   if (pid == 0)
1773     {
1774       /* The child.  */
1775       if (execv (args[0], args) != 0)
1776 #if defined (VMS)
1777         return -1; /* execv is in parent context on VMS. */
1778 #else
1779         _exit (1);
1780 #endif
1781     }
1782
1783 #endif
1784
1785   return pid;
1786 }
1787
1788 int
1789 __gnat_portable_wait (int *process_status)
1790 {
1791   int status = 0;
1792   int pid = 0;
1793
1794 #if defined (_WIN32)
1795
1796   pid = win32_wait (&status);
1797
1798 #elif defined (__EMX__) || defined (MSDOS)
1799   /* ??? See corresponding comment in portable_no_block_spawn.  */
1800
1801 #elif defined (__vxworks)
1802   /* Not sure what to do here, so do same as __EMX__ case, i.e., nothing but
1803      return zero.  */
1804 #else
1805
1806   pid = waitpid (-1, &status, 0);
1807   status = status & 0xffff;
1808 #endif
1809
1810   *process_status = status;
1811   return pid;
1812 }
1813
1814 int
1815 __gnat_waitpid (int pid)
1816 {
1817   int status = 0;
1818
1819 #if defined (_WIN32)
1820   cwait (&status, pid, _WAIT_CHILD);
1821 #elif defined (__EMX__) || defined (MSDOS) || defined (__vxworks)
1822   /* Status is already zero, so nothing to do.  */
1823 #else
1824   waitpid (pid, &status, 0);
1825   status =  WEXITSTATUS (status);
1826 #endif
1827
1828   return status;
1829 }
1830
1831 void
1832 __gnat_os_exit (int status)
1833 {
1834   exit (status);
1835 }
1836
1837 /* Locate a regular file, give a Path value.  */
1838
1839 char *
1840 __gnat_locate_regular_file (char *file_name, char *path_val)
1841 {
1842   char *ptr;
1843   int absolute = __gnat_is_absolute_path (file_name);
1844
1845   /* Handle absolute pathnames.  */
1846   if (absolute)
1847     {
1848      if (__gnat_is_regular_file (file_name))
1849        return xstrdup (file_name);
1850
1851       return 0;
1852     }
1853
1854   /* If file_name include directory separator(s), try it first as
1855      a path name relative to the current directory */
1856   for (ptr = file_name; *ptr && *ptr != '/' && *ptr != DIR_SEPARATOR; ptr++)
1857     ;
1858
1859   if (*ptr != 0)
1860     {
1861       if (__gnat_is_regular_file (file_name))
1862         return xstrdup (file_name);
1863     }
1864
1865   if (path_val == 0)
1866     return 0;
1867
1868   {
1869     /* The result has to be smaller than path_val + file_name.  */
1870     char *file_path = alloca (strlen (path_val) + strlen (file_name) + 2);
1871
1872     for (;;)
1873       {
1874         for (; *path_val == PATH_SEPARATOR; path_val++)
1875           ;
1876
1877       if (*path_val == 0)
1878         return 0;
1879
1880       for (ptr = file_path; *path_val && *path_val != PATH_SEPARATOR; )
1881         *ptr++ = *path_val++;
1882
1883       ptr--;
1884       if (*ptr != '/' && *ptr != DIR_SEPARATOR)
1885         *++ptr = DIR_SEPARATOR;
1886
1887       strcpy (++ptr, file_name);
1888
1889       if (__gnat_is_regular_file (file_path))
1890         return xstrdup (file_path);
1891       }
1892   }
1893
1894   return 0;
1895 }
1896
1897 /* Locate an executable given a Path argument. This routine is only used by
1898    gnatbl and should not be used otherwise.  Use locate_exec_on_path
1899    instead.  */
1900
1901 char *
1902 __gnat_locate_exec (char *exec_name, char *path_val)
1903 {
1904   if (!strstr (exec_name, HOST_EXECUTABLE_SUFFIX))
1905     {
1906       char *full_exec_name
1907         = alloca (strlen (exec_name) + strlen (HOST_EXECUTABLE_SUFFIX) + 1);
1908
1909       strcpy (full_exec_name, exec_name);
1910       strcat (full_exec_name, HOST_EXECUTABLE_SUFFIX);
1911       return __gnat_locate_regular_file (full_exec_name, path_val);
1912     }
1913   else
1914     return __gnat_locate_regular_file (exec_name, path_val);
1915 }
1916
1917 /* Locate an executable using the Systems default PATH.  */
1918
1919 char *
1920 __gnat_locate_exec_on_path (char *exec_name)
1921 {
1922   char *apath_val;
1923 #ifdef VMS
1924   char *path_val = "/VAXC$PATH";
1925 #else
1926   char *path_val = getenv ("PATH");
1927 #endif
1928 #ifdef _WIN32
1929   /* In Win32 systems we expand the PATH as for XP environment
1930      variables are not automatically expanded.  */
1931   int len = strlen (path_val) * 3;
1932   char *expanded_path_val = alloca (len + 1);
1933
1934   DWORD res = ExpandEnvironmentStrings (path_val, expanded_path_val, len);
1935
1936   if (res != 0)
1937     {
1938       path_val = expanded_path_val;
1939     }
1940 #endif
1941
1942   apath_val = alloca (strlen (path_val) + 1);
1943   strcpy (apath_val, path_val);
1944
1945   return __gnat_locate_exec (exec_name, apath_val);
1946 }
1947
1948 #ifdef VMS
1949
1950 /* These functions are used to translate to and from VMS and Unix syntax
1951    file, directory and path specifications.  */
1952
1953 #define MAXPATH  256
1954 #define MAXNAMES 256
1955 #define NEW_CANONICAL_FILELIST_INCREMENT 64
1956
1957 static char new_canonical_dirspec [MAXPATH];
1958 static char new_canonical_filespec [MAXPATH];
1959 static char new_canonical_pathspec [MAXNAMES*MAXPATH];
1960 static unsigned new_canonical_filelist_index;
1961 static unsigned new_canonical_filelist_in_use;
1962 static unsigned new_canonical_filelist_allocated;
1963 static char **new_canonical_filelist;
1964 static char new_host_pathspec [MAXNAMES*MAXPATH];
1965 static char new_host_dirspec [MAXPATH];
1966 static char new_host_filespec [MAXPATH];
1967
1968 /* Routine is called repeatedly by decc$from_vms via
1969    __gnat_to_canonical_file_list_init until it returns 0 or the expansion
1970    runs out. */
1971
1972 static int
1973 wildcard_translate_unix (char *name)
1974 {
1975   char *ver;
1976   char buff [MAXPATH];
1977
1978   strncpy (buff, name, MAXPATH);
1979   buff [MAXPATH - 1] = (char) 0;
1980   ver = strrchr (buff, '.');
1981
1982   /* Chop off the version.  */
1983   if (ver)
1984     *ver = 0;
1985
1986   /* Dynamically extend the allocation by the increment.  */
1987   if (new_canonical_filelist_in_use == new_canonical_filelist_allocated)
1988     {
1989       new_canonical_filelist_allocated += NEW_CANONICAL_FILELIST_INCREMENT;
1990       new_canonical_filelist = (char **) xrealloc
1991         (new_canonical_filelist,
1992          new_canonical_filelist_allocated * sizeof (char *));
1993     }
1994
1995   new_canonical_filelist[new_canonical_filelist_in_use++] = xstrdup (buff);
1996
1997   return 1;
1998 }
1999
2000 /* Translate a wildcard VMS file spec into a list of Unix file specs. First do
2001    full translation and copy the results into a list (_init), then return them
2002    one at a time (_next). If onlydirs set, only expand directory files.  */
2003
2004 int
2005 __gnat_to_canonical_file_list_init (char *filespec, int onlydirs)
2006 {
2007   int len;
2008   char buff [MAXPATH];
2009
2010   len = strlen (filespec);
2011   strncpy (buff, filespec, MAXPATH);
2012
2013   /* Only look for directories */
2014   if (onlydirs && !strstr (&buff [len-5], "*.dir"))
2015     strncat (buff, "*.dir", MAXPATH);
2016
2017   buff [MAXPATH - 1] = (char) 0;
2018
2019   decc$from_vms (buff, wildcard_translate_unix, 1);
2020
2021   /* Remove the .dir extension.  */
2022   if (onlydirs)
2023     {
2024       int i;
2025       char *ext;
2026
2027       for (i = 0; i < new_canonical_filelist_in_use; i++)
2028         {
2029           ext = strstr (new_canonical_filelist[i], ".dir");
2030           if (ext)
2031             *ext = 0;
2032         }
2033     }
2034
2035   return new_canonical_filelist_in_use;
2036 }
2037
2038 /* Return the next filespec in the list.  */
2039
2040 char *
2041 __gnat_to_canonical_file_list_next ()
2042 {
2043   return new_canonical_filelist[new_canonical_filelist_index++];
2044 }
2045
2046 /* Free storage used in the wildcard expansion.  */
2047
2048 void
2049 __gnat_to_canonical_file_list_free ()
2050 {
2051   int i;
2052
2053    for (i = 0; i < new_canonical_filelist_in_use; i++)
2054      free (new_canonical_filelist[i]);
2055
2056   free (new_canonical_filelist);
2057
2058   new_canonical_filelist_in_use = 0;
2059   new_canonical_filelist_allocated = 0;
2060   new_canonical_filelist_index = 0;
2061   new_canonical_filelist = 0;
2062 }
2063
2064 /* Translate a VMS syntax directory specification in to Unix syntax.  If
2065    PREFIXFLAG is set, append an underscore "/". If no indicators of VMS syntax
2066    found, return input string. Also translate a dirname that contains no
2067    slashes, in case it's a logical name.  */
2068
2069 char *
2070 __gnat_to_canonical_dir_spec (char *dirspec, int prefixflag)
2071 {
2072   int len;
2073
2074   strcpy (new_canonical_dirspec, "");
2075   if (strlen (dirspec))
2076     {
2077       char *dirspec1;
2078
2079       if (strchr (dirspec, ']') || strchr (dirspec, ':'))
2080         {
2081           strncpy (new_canonical_dirspec,
2082                    (char *) decc$translate_vms (dirspec),
2083                    MAXPATH);
2084         }
2085       else if (!strchr (dirspec, '/') && (dirspec1 = getenv (dirspec)) != 0)
2086         {
2087           strncpy (new_canonical_dirspec,
2088                   (char *) decc$translate_vms (dirspec1),
2089                   MAXPATH);
2090         }
2091       else
2092         {
2093           strncpy (new_canonical_dirspec, dirspec, MAXPATH);
2094         }
2095     }
2096
2097   len = strlen (new_canonical_dirspec);
2098   if (prefixflag && new_canonical_dirspec [len-1] != '/')
2099     strncat (new_canonical_dirspec, "/", MAXPATH);
2100
2101   new_canonical_dirspec [MAXPATH - 1] = (char) 0;
2102
2103   return new_canonical_dirspec;
2104
2105 }
2106
2107 /* Translate a VMS syntax file specification into Unix syntax.
2108    If no indicators of VMS syntax found, return input string.  */
2109
2110 char *
2111 __gnat_to_canonical_file_spec (char *filespec)
2112 {
2113   strncpy (new_canonical_filespec, "", MAXPATH);
2114
2115   if (strchr (filespec, ']') || strchr (filespec, ':'))
2116     {
2117       strncpy (new_canonical_filespec,
2118                (char *) decc$translate_vms (filespec),
2119                MAXPATH);
2120     }
2121   else
2122     {
2123       strncpy (new_canonical_filespec, filespec, MAXPATH);
2124     }
2125
2126   new_canonical_filespec [MAXPATH - 1] = (char) 0;
2127
2128   return new_canonical_filespec;
2129 }
2130
2131 /* Translate a VMS syntax path specification into Unix syntax.
2132    If no indicators of VMS syntax found, return input string.  */
2133
2134 char *
2135 __gnat_to_canonical_path_spec (char *pathspec)
2136 {
2137   char *curr, *next, buff [MAXPATH];
2138
2139   if (pathspec == 0)
2140     return pathspec;
2141
2142   /* If there are /'s, assume it's a Unix path spec and return.  */
2143   if (strchr (pathspec, '/'))
2144     return pathspec;
2145
2146   new_canonical_pathspec[0] = 0;
2147   curr = pathspec;
2148
2149   for (;;)
2150     {
2151       next = strchr (curr, ',');
2152       if (next == 0)
2153         next = strchr (curr, 0);
2154
2155       strncpy (buff, curr, next - curr);
2156       buff[next - curr] = 0;
2157
2158       /* Check for wildcards and expand if present.  */
2159       if (strchr (buff, '*') || strchr (buff, '%') || strstr (buff, "..."))
2160         {
2161           int i, dirs;
2162
2163           dirs = __gnat_to_canonical_file_list_init (buff, 1);
2164           for (i = 0; i < dirs; i++)
2165             {
2166               char *next_dir;
2167
2168               next_dir = __gnat_to_canonical_file_list_next ();
2169               strncat (new_canonical_pathspec, next_dir, MAXPATH);
2170
2171               /* Don't append the separator after the last expansion.  */
2172               if (i+1 < dirs)
2173                 strncat (new_canonical_pathspec, ":", MAXPATH);
2174             }
2175
2176           __gnat_to_canonical_file_list_free ();
2177         }
2178       else
2179         strncat (new_canonical_pathspec,
2180                 __gnat_to_canonical_dir_spec (buff, 0), MAXPATH);
2181
2182       if (*next == 0)
2183         break;
2184
2185       strncat (new_canonical_pathspec, ":", MAXPATH);
2186       curr = next + 1;
2187     }
2188
2189   new_canonical_pathspec [MAXPATH - 1] = (char) 0;
2190
2191   return new_canonical_pathspec;
2192 }
2193
2194 static char filename_buff [MAXPATH];
2195
2196 static int
2197 translate_unix (char *name, int type)
2198 {
2199   strncpy (filename_buff, name, MAXPATH);
2200   filename_buff [MAXPATH - 1] = (char) 0;
2201   return 0;
2202 }
2203
2204 /* Translate a Unix syntax path spec into a VMS style (comma separated list of
2205    directories.  */
2206
2207 static char *
2208 to_host_path_spec (char *pathspec)
2209 {
2210   char *curr, *next, buff [MAXPATH];
2211
2212   if (pathspec == 0)
2213     return pathspec;
2214
2215   /* Can't very well test for colons, since that's the Unix separator!  */
2216   if (strchr (pathspec, ']') || strchr (pathspec, ','))
2217     return pathspec;
2218
2219   new_host_pathspec[0] = 0;
2220   curr = pathspec;
2221
2222   for (;;)
2223     {
2224       next = strchr (curr, ':');
2225       if (next == 0)
2226         next = strchr (curr, 0);
2227
2228       strncpy (buff, curr, next - curr);
2229       buff[next - curr] = 0;
2230
2231       strncat (new_host_pathspec, __gnat_to_host_dir_spec (buff, 0), MAXPATH);
2232       if (*next == 0)
2233         break;
2234       strncat (new_host_pathspec, ",", MAXPATH);
2235       curr = next + 1;
2236     }
2237
2238   new_host_pathspec [MAXPATH - 1] = (char) 0;
2239
2240   return new_host_pathspec;
2241 }
2242
2243 /* Translate a Unix syntax directory specification into VMS syntax.  The
2244    PREFIXFLAG has no effect, but is kept for symmetry with
2245    to_canonical_dir_spec.  If indicators of VMS syntax found, return input
2246    string. */
2247
2248 char *
2249 __gnat_to_host_dir_spec (char *dirspec, int prefixflag ATTRIBUTE_UNUSED)
2250 {
2251   int len = strlen (dirspec);
2252
2253   strncpy (new_host_dirspec, dirspec, MAXPATH);
2254   new_host_dirspec [MAXPATH - 1] = (char) 0;
2255
2256   if (strchr (new_host_dirspec, ']') || strchr (new_host_dirspec, ':'))
2257     return new_host_dirspec;
2258
2259   while (len > 1 && new_host_dirspec[len - 1] == '/')
2260     {
2261       new_host_dirspec[len - 1] = 0;
2262       len--;
2263     }
2264
2265   decc$to_vms (new_host_dirspec, translate_unix, 1, 2);
2266   strncpy (new_host_dirspec, filename_buff, MAXPATH);
2267   new_host_dirspec [MAXPATH - 1] = (char) 0;
2268
2269   return new_host_dirspec;
2270 }
2271
2272 /* Translate a Unix syntax file specification into VMS syntax.
2273    If indicators of VMS syntax found, return input string.  */
2274
2275 char *
2276 __gnat_to_host_file_spec (char *filespec)
2277 {
2278   strncpy (new_host_filespec, "", MAXPATH);
2279   if (strchr (filespec, ']') || strchr (filespec, ':'))
2280     {
2281       strncpy (new_host_filespec, filespec, MAXPATH);
2282     }
2283   else
2284     {
2285       decc$to_vms (filespec, translate_unix, 1, 1);
2286       strncpy (new_host_filespec, filename_buff, MAXPATH);
2287     }
2288
2289   new_host_filespec [MAXPATH - 1] = (char) 0;
2290
2291   return new_host_filespec;
2292 }
2293
2294 void
2295 __gnat_adjust_os_resource_limits ()
2296 {
2297   SYS$ADJWSL (131072, 0);
2298 }
2299
2300 #else /* VMS */
2301
2302 /* Dummy functions for Osint import for non-VMS systems.  */
2303
2304 int
2305 __gnat_to_canonical_file_list_init
2306   (char *dirspec ATTRIBUTE_UNUSED, int onlydirs ATTRIBUTE_UNUSED)
2307 {
2308   return 0;
2309 }
2310
2311 char *
2312 __gnat_to_canonical_file_list_next (void)
2313 {
2314   return (char *) "";
2315 }
2316
2317 void
2318 __gnat_to_canonical_file_list_free (void)
2319 {
2320 }
2321
2322 char *
2323 __gnat_to_canonical_dir_spec (char *dirspec, int prefixflag ATTRIBUTE_UNUSED)
2324 {
2325   return dirspec;
2326 }
2327
2328 char *
2329 __gnat_to_canonical_file_spec (char *filespec)
2330 {
2331   return filespec;
2332 }
2333
2334 char *
2335 __gnat_to_canonical_path_spec (char *pathspec)
2336 {
2337   return pathspec;
2338 }
2339
2340 char *
2341 __gnat_to_host_dir_spec (char *dirspec, int prefixflag ATTRIBUTE_UNUSED)
2342 {
2343   return dirspec;
2344 }
2345
2346 char *
2347 __gnat_to_host_file_spec (char *filespec)
2348 {
2349   return filespec;
2350 }
2351
2352 void
2353 __gnat_adjust_os_resource_limits (void)
2354 {
2355 }
2356
2357 #endif
2358
2359 /* For EMX, we cannot include dummy in libgcc, since it is too difficult
2360    to coordinate this with the EMX distribution. Consequently, we put the
2361    definition of dummy which is used for exception handling, here.  */
2362
2363 #if defined (__EMX__)
2364 void __dummy () {}
2365 #endif
2366
2367 #if defined (__mips_vxworks)
2368 int
2369 _flush_cache()
2370 {
2371    CACHE_USER_FLUSH (0, ENTIRE_CACHE);
2372 }
2373 #endif
2374
2375 #if defined (CROSS_COMPILE)  \
2376   || (! (defined (sparc) && defined (sun) && defined (__SVR4)) \
2377       && ! (defined (linux) && defined (i386)) \
2378       && ! defined (hpux) \
2379       && ! defined (_AIX) \
2380       && ! (defined (__alpha__)  && defined (__osf__)) \
2381       && ! defined (__MINGW32__))
2382
2383 /* Dummy function to satisfy g-trasym.o.  Currently Solaris sparc, HP/UX,
2384    GNU/Linux x86, Tru64 & Windows provide a non-dummy version of this
2385    procedure in libaddr2line.a.  */
2386
2387 void
2388 convert_addresses (void *addrs ATTRIBUTE_UNUSED,
2389                    int n_addr ATTRIBUTE_UNUSED,
2390                    void *buf ATTRIBUTE_UNUSED,
2391                    int *len ATTRIBUTE_UNUSED)
2392 {
2393   *len = 0;
2394 }
2395 #endif
2396
2397 #if defined (_WIN32)
2398 int __gnat_argument_needs_quote = 1;
2399 #else
2400 int __gnat_argument_needs_quote = 0;
2401 #endif
2402
2403 /* This option is used to enable/disable object files handling from the
2404    binder file by the GNAT Project module. For example, this is disabled on
2405    Windows as it is already done by the mdll module. */
2406 #if defined (_WIN32)
2407 int __gnat_prj_add_obj_files = 0;
2408 #else
2409 int __gnat_prj_add_obj_files = 1;
2410 #endif
2411
2412 /* char used as prefix/suffix for environment variables */
2413 #if defined (_WIN32)
2414 char __gnat_environment_char = '%';
2415 #else
2416 char __gnat_environment_char = '$';
2417 #endif
2418
2419 /* This functions copy the file attributes from a source file to a
2420    destination file.
2421
2422    mode = 0  : In this mode copy only the file time stamps (last access and
2423                last modification time stamps).
2424
2425    mode = 1  : In this mode, time stamps and read/write/execute attributes are
2426                copied.
2427
2428    Returns 0 if operation was successful and -1 in case of error. */
2429
2430 int
2431 __gnat_copy_attribs (char *from, char *to, int mode)
2432 {
2433 #if defined (VMS) || defined (__vxworks)
2434   return -1;
2435 #else
2436   struct stat fbuf;
2437   struct utimbuf tbuf;
2438
2439   if (stat (from, &fbuf) == -1)
2440     {
2441       return -1;
2442     }
2443
2444   tbuf.actime = fbuf.st_atime;
2445   tbuf.modtime = fbuf.st_mtime;
2446
2447   if (utime (to, &tbuf) == -1)
2448     {
2449       return -1;
2450     }
2451
2452   if (mode == 1)
2453     {
2454       if (chmod (to, fbuf.st_mode) == -1)
2455         {
2456           return -1;
2457         }
2458     }
2459
2460   return 0;
2461 #endif
2462 }
2463
2464 /* This function is installed in libgcc.a.  */
2465 extern void __gnat_install_locks (void (*) (void), void (*) (void));
2466
2467 /* This function offers a hook for libgnarl to set the
2468    locking subprograms for libgcc_eh.
2469    This is only needed on OpenVMS, since other platforms use standard
2470    --enable-threads=posix option, or similar.  */
2471
2472 void
2473 __gnatlib_install_locks (void (*lock) (void) ATTRIBUTE_UNUSED,
2474                          void (*unlock) (void) ATTRIBUTE_UNUSED)
2475 {
2476 #if defined (IN_RTS) && defined (VMS)
2477   __gnat_install_locks (lock, unlock);
2478   /* There is a bootstrap path issue if adaint is build with this
2479      symbol unresolved for the stage1 compiler. Since the compiler
2480      does not use tasking, we simply make __gnatlib_install_locks
2481      a no-op in this case. */
2482 #endif
2483 }
2484
2485 int
2486 __gnat_lseek (int fd, long offset, int whence)
2487 {
2488   return (int) lseek (fd, offset, whence);
2489 }