OSDN Git Service

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