OSDN Git Service

* config/rs6000/t-aix43 (BOOT_LDFLAGS): Define.
[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, (LPBYTE)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 (__APPLE__) || 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   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, (char* const*)args);
1561
1562   /* restore previous value */
1563   free (args[0]);
1564   args[0] = (char *)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 /* Create a copy of the given file descriptor.
1610    Return -1 if an error occurred.  */
1611
1612 int
1613 __gnat_dup (int oldfd)
1614 {
1615 #if defined (__vxworks)
1616    /* Not supported on VxWorks.  */
1617    return -1;
1618 #else
1619    return dup (oldfd);
1620 #endif
1621 }
1622
1623 /* Make newfd be the copy of oldfd, closing newfd first if necessary.
1624    Return -1 if an error occured.  */
1625
1626 int
1627 __gnat_dup2 (int oldfd, int newfd)
1628 {
1629 #if defined (__vxworks)
1630   /* Not supported on VxWorks.  */
1631   return -1;
1632 #else
1633   return dup2 (oldfd, newfd);
1634 #endif
1635 }
1636
1637 /* WIN32 code to implement a wait call that wait for any child process.  */
1638
1639 #ifdef _WIN32
1640
1641 /* Synchronization code, to be thread safe.  */
1642
1643 static CRITICAL_SECTION plist_cs;
1644
1645 void
1646 __gnat_plist_init (void)
1647 {
1648   InitializeCriticalSection (&plist_cs);
1649 }
1650
1651 static void
1652 plist_enter (void)
1653 {
1654   EnterCriticalSection (&plist_cs);
1655 }
1656
1657 static void
1658 plist_leave (void)
1659 {
1660   LeaveCriticalSection (&plist_cs);
1661 }
1662
1663 typedef struct _process_list
1664 {
1665   HANDLE h;
1666   struct _process_list *next;
1667 } Process_List;
1668
1669 static Process_List *PLIST = NULL;
1670
1671 static int plist_length = 0;
1672
1673 static void
1674 add_handle (HANDLE h)
1675 {
1676   Process_List *pl;
1677
1678   pl = (Process_List *) xmalloc (sizeof (Process_List));
1679
1680   plist_enter();
1681
1682   /* -------------------- critical section -------------------- */
1683   pl->h = h;
1684   pl->next = PLIST;
1685   PLIST = pl;
1686   ++plist_length;
1687   /* -------------------- critical section -------------------- */
1688
1689   plist_leave();
1690 }
1691
1692 static void
1693 remove_handle (HANDLE h)
1694 {
1695   Process_List *pl;
1696   Process_List *prev = NULL;
1697
1698   plist_enter();
1699
1700   /* -------------------- critical section -------------------- */
1701   pl = PLIST;
1702   while (pl)
1703     {
1704       if (pl->h == h)
1705         {
1706           if (pl == PLIST)
1707             PLIST = pl->next;
1708           else
1709             prev->next = pl->next;
1710           free (pl);
1711           break;
1712         }
1713       else
1714         {
1715           prev = pl;
1716           pl = pl->next;
1717         }
1718     }
1719
1720   --plist_length;
1721   /* -------------------- critical section -------------------- */
1722
1723   plist_leave();
1724 }
1725
1726 static int
1727 win32_no_block_spawn (char *command, char *args[])
1728 {
1729   BOOL result;
1730   STARTUPINFO SI;
1731   PROCESS_INFORMATION PI;
1732   SECURITY_ATTRIBUTES SA;
1733   int csize = 1;
1734   char *full_command;
1735   int k;
1736
1737   /* compute the total command line length */
1738   k = 0;
1739   while (args[k])
1740     {
1741       csize += strlen (args[k]) + 1;
1742       k++;
1743     }
1744
1745   full_command = (char *) xmalloc (csize);
1746
1747   /* Startup info. */
1748   SI.cb          = sizeof (STARTUPINFO);
1749   SI.lpReserved  = NULL;
1750   SI.lpReserved2 = NULL;
1751   SI.lpDesktop   = NULL;
1752   SI.cbReserved2 = 0;
1753   SI.lpTitle     = NULL;
1754   SI.dwFlags     = 0;
1755   SI.wShowWindow = SW_HIDE;
1756
1757   /* Security attributes. */
1758   SA.nLength = sizeof (SECURITY_ATTRIBUTES);
1759   SA.bInheritHandle = TRUE;
1760   SA.lpSecurityDescriptor = NULL;
1761
1762   /* Prepare the command string. */
1763   strcpy (full_command, command);
1764   strcat (full_command, " ");
1765
1766   k = 1;
1767   while (args[k])
1768     {
1769       strcat (full_command, args[k]);
1770       strcat (full_command, " ");
1771       k++;
1772     }
1773
1774   result = CreateProcess
1775              (NULL, (char *) full_command, &SA, NULL, TRUE,
1776               GetPriorityClass (GetCurrentProcess()), NULL, NULL, &SI, &PI);
1777
1778   free (full_command);
1779
1780   if (result == TRUE)
1781     {
1782       add_handle (PI.hProcess);
1783       CloseHandle (PI.hThread);
1784       return (int) PI.hProcess;
1785     }
1786   else
1787     return -1;
1788 }
1789
1790 static int
1791 win32_wait (int *status)
1792 {
1793   DWORD exitcode;
1794   HANDLE *hl;
1795   HANDLE h;
1796   DWORD res;
1797   int k;
1798   Process_List *pl;
1799
1800   if (plist_length == 0)
1801     {
1802       errno = ECHILD;
1803       return -1;
1804     }
1805
1806   hl = (HANDLE *) xmalloc (sizeof (HANDLE) * plist_length);
1807
1808   k = 0;
1809   plist_enter();
1810
1811   /* -------------------- critical section -------------------- */
1812   pl = PLIST;
1813   while (pl)
1814     {
1815       hl[k++] = pl->h;
1816       pl = pl->next;
1817     }
1818   /* -------------------- critical section -------------------- */
1819
1820   plist_leave();
1821
1822   res = WaitForMultipleObjects (plist_length, hl, FALSE, INFINITE);
1823   h = hl[res - WAIT_OBJECT_0];
1824   free (hl);
1825
1826   remove_handle (h);
1827
1828   GetExitCodeProcess (h, &exitcode);
1829   CloseHandle (h);
1830
1831   *status = (int) exitcode;
1832   return (int) h;
1833 }
1834
1835 #endif
1836
1837 int
1838 __gnat_portable_no_block_spawn (char *args[])
1839 {
1840   int pid = 0;
1841
1842 #if defined (__EMX__) || defined (MSDOS)
1843
1844   /* ??? For PC machines I (Franco) don't know the system calls to implement
1845      this routine. So I'll fake it as follows. This routine will behave
1846      exactly like the blocking portable_spawn and will systematically return
1847      a pid of 0 unless the spawned task did not complete successfully, in
1848      which case we return a pid of -1.  To synchronize with this the
1849      portable_wait below systematically returns a pid of 0 and reports that
1850      the subprocess terminated successfully. */
1851
1852   if (spawnvp (P_WAIT, args[0], args) != 0)
1853     return -1;
1854
1855 #elif defined (_WIN32)
1856
1857   pid = win32_no_block_spawn (args[0], args);
1858   return pid;
1859
1860 #elif defined (__vxworks)
1861   return -1;
1862
1863 #else
1864   pid = fork ();
1865
1866   if (pid == 0)
1867     {
1868       /* The child.  */
1869       if (execv (args[0], args) != 0)
1870 #if defined (VMS)
1871         return -1; /* execv is in parent context on VMS. */
1872 #else
1873         _exit (1);
1874 #endif
1875     }
1876
1877 #endif
1878
1879   return pid;
1880 }
1881
1882 int
1883 __gnat_portable_wait (int *process_status)
1884 {
1885   int status = 0;
1886   int pid = 0;
1887
1888 #if defined (_WIN32)
1889
1890   pid = win32_wait (&status);
1891
1892 #elif defined (__EMX__) || defined (MSDOS)
1893   /* ??? See corresponding comment in portable_no_block_spawn.  */
1894
1895 #elif defined (__vxworks)
1896   /* Not sure what to do here, so do same as __EMX__ case, i.e., nothing but
1897      return zero.  */
1898 #else
1899
1900   pid = waitpid (-1, &status, 0);
1901   status = status & 0xffff;
1902 #endif
1903
1904   *process_status = status;
1905   return pid;
1906 }
1907
1908 int
1909 __gnat_waitpid (int pid)
1910 {
1911   int status = 0;
1912
1913 #if defined (_WIN32)
1914   cwait (&status, pid, _WAIT_CHILD);
1915 #elif defined (__EMX__) || defined (MSDOS) || defined (__vxworks)
1916   /* Status is already zero, so nothing to do.  */
1917 #else
1918   waitpid (pid, &status, 0);
1919   status =  WEXITSTATUS (status);
1920 #endif
1921
1922   return status;
1923 }
1924
1925 void
1926 __gnat_os_exit (int status)
1927 {
1928   exit (status);
1929 }
1930
1931 /* Locate a regular file, give a Path value.  */
1932
1933 char *
1934 __gnat_locate_regular_file (char *file_name, char *path_val)
1935 {
1936   char *ptr;
1937   int absolute = __gnat_is_absolute_path (file_name, strlen (file_name));
1938
1939   /* Handle absolute pathnames.  */
1940   if (absolute)
1941     {
1942      if (__gnat_is_regular_file (file_name))
1943        return xstrdup (file_name);
1944
1945       return 0;
1946     }
1947
1948   /* If file_name include directory separator(s), try it first as
1949      a path name relative to the current directory */
1950   for (ptr = file_name; *ptr && *ptr != '/' && *ptr != DIR_SEPARATOR; ptr++)
1951     ;
1952
1953   if (*ptr != 0)
1954     {
1955       if (__gnat_is_regular_file (file_name))
1956         return xstrdup (file_name);
1957     }
1958
1959   if (path_val == 0)
1960     return 0;
1961
1962   {
1963     /* The result has to be smaller than path_val + file_name.  */
1964     char *file_path = alloca (strlen (path_val) + strlen (file_name) + 2);
1965
1966     for (;;)
1967       {
1968         for (; *path_val == PATH_SEPARATOR; path_val++)
1969           ;
1970
1971       if (*path_val == 0)
1972         return 0;
1973
1974       for (ptr = file_path; *path_val && *path_val != PATH_SEPARATOR; )
1975         *ptr++ = *path_val++;
1976
1977       ptr--;
1978       if (*ptr != '/' && *ptr != DIR_SEPARATOR)
1979         *++ptr = DIR_SEPARATOR;
1980
1981       strcpy (++ptr, file_name);
1982
1983       if (__gnat_is_regular_file (file_path))
1984         return xstrdup (file_path);
1985       }
1986   }
1987
1988   return 0;
1989 }
1990
1991 /* Locate an executable given a Path argument. This routine is only used by
1992    gnatbl and should not be used otherwise.  Use locate_exec_on_path
1993    instead.  */
1994
1995 char *
1996 __gnat_locate_exec (char *exec_name, char *path_val)
1997 {
1998   if (!strstr (exec_name, HOST_EXECUTABLE_SUFFIX))
1999     {
2000       char *full_exec_name
2001         = alloca (strlen (exec_name) + strlen (HOST_EXECUTABLE_SUFFIX) + 1);
2002
2003       strcpy (full_exec_name, exec_name);
2004       strcat (full_exec_name, HOST_EXECUTABLE_SUFFIX);
2005       return __gnat_locate_regular_file (full_exec_name, path_val);
2006     }
2007   else
2008     return __gnat_locate_regular_file (exec_name, path_val);
2009 }
2010
2011 /* Locate an executable using the Systems default PATH.  */
2012
2013 char *
2014 __gnat_locate_exec_on_path (char *exec_name)
2015 {
2016   char *apath_val;
2017 #ifdef VMS
2018   char *path_val = "/VAXC$PATH";
2019 #else
2020   char *path_val = getenv ("PATH");
2021 #endif
2022 #ifdef _WIN32
2023   /* In Win32 systems we expand the PATH as for XP environment
2024      variables are not automatically expanded.  */
2025   int len = strlen (path_val) * 3;
2026   char *expanded_path_val = alloca (len + 1);
2027
2028   DWORD res = ExpandEnvironmentStrings (path_val, expanded_path_val, len);
2029
2030   if (res != 0)
2031     {
2032       path_val = expanded_path_val;
2033     }
2034 #endif
2035
2036   apath_val = alloca (strlen (path_val) + 1);
2037   strcpy (apath_val, path_val);
2038
2039   return __gnat_locate_exec (exec_name, apath_val);
2040 }
2041
2042 #ifdef VMS
2043
2044 /* These functions are used to translate to and from VMS and Unix syntax
2045    file, directory and path specifications.  */
2046
2047 #define MAXPATH  256
2048 #define MAXNAMES 256
2049 #define NEW_CANONICAL_FILELIST_INCREMENT 64
2050
2051 static char new_canonical_dirspec [MAXPATH];
2052 static char new_canonical_filespec [MAXPATH];
2053 static char new_canonical_pathspec [MAXNAMES*MAXPATH];
2054 static unsigned new_canonical_filelist_index;
2055 static unsigned new_canonical_filelist_in_use;
2056 static unsigned new_canonical_filelist_allocated;
2057 static char **new_canonical_filelist;
2058 static char new_host_pathspec [MAXNAMES*MAXPATH];
2059 static char new_host_dirspec [MAXPATH];
2060 static char new_host_filespec [MAXPATH];
2061
2062 /* Routine is called repeatedly by decc$from_vms via
2063    __gnat_to_canonical_file_list_init until it returns 0 or the expansion
2064    runs out. */
2065
2066 static int
2067 wildcard_translate_unix (char *name)
2068 {
2069   char *ver;
2070   char buff [MAXPATH];
2071
2072   strncpy (buff, name, MAXPATH);
2073   buff [MAXPATH - 1] = (char) 0;
2074   ver = strrchr (buff, '.');
2075
2076   /* Chop off the version.  */
2077   if (ver)
2078     *ver = 0;
2079
2080   /* Dynamically extend the allocation by the increment.  */
2081   if (new_canonical_filelist_in_use == new_canonical_filelist_allocated)
2082     {
2083       new_canonical_filelist_allocated += NEW_CANONICAL_FILELIST_INCREMENT;
2084       new_canonical_filelist = (char **) xrealloc
2085         (new_canonical_filelist,
2086          new_canonical_filelist_allocated * sizeof (char *));
2087     }
2088
2089   new_canonical_filelist[new_canonical_filelist_in_use++] = xstrdup (buff);
2090
2091   return 1;
2092 }
2093
2094 /* Translate a wildcard VMS file spec into a list of Unix file specs. First do
2095    full translation and copy the results into a list (_init), then return them
2096    one at a time (_next). If onlydirs set, only expand directory files.  */
2097
2098 int
2099 __gnat_to_canonical_file_list_init (char *filespec, int onlydirs)
2100 {
2101   int len;
2102   char buff [MAXPATH];
2103
2104   len = strlen (filespec);
2105   strncpy (buff, filespec, MAXPATH);
2106
2107   /* Only look for directories */
2108   if (onlydirs && !strstr (&buff [len-5], "*.dir"))
2109     strncat (buff, "*.dir", MAXPATH);
2110
2111   buff [MAXPATH - 1] = (char) 0;
2112
2113   decc$from_vms (buff, wildcard_translate_unix, 1);
2114
2115   /* Remove the .dir extension.  */
2116   if (onlydirs)
2117     {
2118       int i;
2119       char *ext;
2120
2121       for (i = 0; i < new_canonical_filelist_in_use; i++)
2122         {
2123           ext = strstr (new_canonical_filelist[i], ".dir");
2124           if (ext)
2125             *ext = 0;
2126         }
2127     }
2128
2129   return new_canonical_filelist_in_use;
2130 }
2131
2132 /* Return the next filespec in the list.  */
2133
2134 char *
2135 __gnat_to_canonical_file_list_next ()
2136 {
2137   return new_canonical_filelist[new_canonical_filelist_index++];
2138 }
2139
2140 /* Free storage used in the wildcard expansion.  */
2141
2142 void
2143 __gnat_to_canonical_file_list_free ()
2144 {
2145   int i;
2146
2147    for (i = 0; i < new_canonical_filelist_in_use; i++)
2148      free (new_canonical_filelist[i]);
2149
2150   free (new_canonical_filelist);
2151
2152   new_canonical_filelist_in_use = 0;
2153   new_canonical_filelist_allocated = 0;
2154   new_canonical_filelist_index = 0;
2155   new_canonical_filelist = 0;
2156 }
2157
2158 /* Translate a VMS syntax directory specification in to Unix syntax.  If
2159    PREFIXFLAG is set, append an underscore "/". If no indicators of VMS syntax
2160    found, return input string. Also translate a dirname that contains no
2161    slashes, in case it's a logical name.  */
2162
2163 char *
2164 __gnat_to_canonical_dir_spec (char *dirspec, int prefixflag)
2165 {
2166   int len;
2167
2168   strcpy (new_canonical_dirspec, "");
2169   if (strlen (dirspec))
2170     {
2171       char *dirspec1;
2172
2173       if (strchr (dirspec, ']') || strchr (dirspec, ':'))
2174         {
2175           strncpy (new_canonical_dirspec,
2176                    (char *) decc$translate_vms (dirspec),
2177                    MAXPATH);
2178         }
2179       else if (!strchr (dirspec, '/') && (dirspec1 = getenv (dirspec)) != 0)
2180         {
2181           strncpy (new_canonical_dirspec,
2182                   (char *) decc$translate_vms (dirspec1),
2183                   MAXPATH);
2184         }
2185       else
2186         {
2187           strncpy (new_canonical_dirspec, dirspec, MAXPATH);
2188         }
2189     }
2190
2191   len = strlen (new_canonical_dirspec);
2192   if (prefixflag && new_canonical_dirspec [len-1] != '/')
2193     strncat (new_canonical_dirspec, "/", MAXPATH);
2194
2195   new_canonical_dirspec [MAXPATH - 1] = (char) 0;
2196
2197   return new_canonical_dirspec;
2198
2199 }
2200
2201 /* Translate a VMS syntax file specification into Unix syntax.
2202    If no indicators of VMS syntax found, return input string.  */
2203
2204 char *
2205 __gnat_to_canonical_file_spec (char *filespec)
2206 {
2207   strncpy (new_canonical_filespec, "", MAXPATH);
2208
2209   if (strchr (filespec, ']') || strchr (filespec, ':'))
2210     {
2211       strncpy (new_canonical_filespec,
2212                (char *) decc$translate_vms (filespec),
2213                MAXPATH);
2214     }
2215   else
2216     {
2217       strncpy (new_canonical_filespec, filespec, MAXPATH);
2218     }
2219
2220   new_canonical_filespec [MAXPATH - 1] = (char) 0;
2221
2222   return new_canonical_filespec;
2223 }
2224
2225 /* Translate a VMS syntax path specification into Unix syntax.
2226    If no indicators of VMS syntax found, return input string.  */
2227
2228 char *
2229 __gnat_to_canonical_path_spec (char *pathspec)
2230 {
2231   char *curr, *next, buff [MAXPATH];
2232
2233   if (pathspec == 0)
2234     return pathspec;
2235
2236   /* If there are /'s, assume it's a Unix path spec and return.  */
2237   if (strchr (pathspec, '/'))
2238     return pathspec;
2239
2240   new_canonical_pathspec[0] = 0;
2241   curr = pathspec;
2242
2243   for (;;)
2244     {
2245       next = strchr (curr, ',');
2246       if (next == 0)
2247         next = strchr (curr, 0);
2248
2249       strncpy (buff, curr, next - curr);
2250       buff[next - curr] = 0;
2251
2252       /* Check for wildcards and expand if present.  */
2253       if (strchr (buff, '*') || strchr (buff, '%') || strstr (buff, "..."))
2254         {
2255           int i, dirs;
2256
2257           dirs = __gnat_to_canonical_file_list_init (buff, 1);
2258           for (i = 0; i < dirs; i++)
2259             {
2260               char *next_dir;
2261
2262               next_dir = __gnat_to_canonical_file_list_next ();
2263               strncat (new_canonical_pathspec, next_dir, MAXPATH);
2264
2265               /* Don't append the separator after the last expansion.  */
2266               if (i+1 < dirs)
2267                 strncat (new_canonical_pathspec, ":", MAXPATH);
2268             }
2269
2270           __gnat_to_canonical_file_list_free ();
2271         }
2272       else
2273         strncat (new_canonical_pathspec,
2274                 __gnat_to_canonical_dir_spec (buff, 0), MAXPATH);
2275
2276       if (*next == 0)
2277         break;
2278
2279       strncat (new_canonical_pathspec, ":", MAXPATH);
2280       curr = next + 1;
2281     }
2282
2283   new_canonical_pathspec [MAXPATH - 1] = (char) 0;
2284
2285   return new_canonical_pathspec;
2286 }
2287
2288 static char filename_buff [MAXPATH];
2289
2290 static int
2291 translate_unix (char *name, int type)
2292 {
2293   strncpy (filename_buff, name, MAXPATH);
2294   filename_buff [MAXPATH - 1] = (char) 0;
2295   return 0;
2296 }
2297
2298 /* Translate a Unix syntax path spec into a VMS style (comma separated list of
2299    directories.  */
2300
2301 static char *
2302 to_host_path_spec (char *pathspec)
2303 {
2304   char *curr, *next, buff [MAXPATH];
2305
2306   if (pathspec == 0)
2307     return pathspec;
2308
2309   /* Can't very well test for colons, since that's the Unix separator!  */
2310   if (strchr (pathspec, ']') || strchr (pathspec, ','))
2311     return pathspec;
2312
2313   new_host_pathspec[0] = 0;
2314   curr = pathspec;
2315
2316   for (;;)
2317     {
2318       next = strchr (curr, ':');
2319       if (next == 0)
2320         next = strchr (curr, 0);
2321
2322       strncpy (buff, curr, next - curr);
2323       buff[next - curr] = 0;
2324
2325       strncat (new_host_pathspec, __gnat_to_host_dir_spec (buff, 0), MAXPATH);
2326       if (*next == 0)
2327         break;
2328       strncat (new_host_pathspec, ",", MAXPATH);
2329       curr = next + 1;
2330     }
2331
2332   new_host_pathspec [MAXPATH - 1] = (char) 0;
2333
2334   return new_host_pathspec;
2335 }
2336
2337 /* Translate a Unix syntax directory specification into VMS syntax.  The
2338    PREFIXFLAG has no effect, but is kept for symmetry with
2339    to_canonical_dir_spec.  If indicators of VMS syntax found, return input
2340    string. */
2341
2342 char *
2343 __gnat_to_host_dir_spec (char *dirspec, int prefixflag ATTRIBUTE_UNUSED)
2344 {
2345   int len = strlen (dirspec);
2346
2347   strncpy (new_host_dirspec, dirspec, MAXPATH);
2348   new_host_dirspec [MAXPATH - 1] = (char) 0;
2349
2350   if (strchr (new_host_dirspec, ']') || strchr (new_host_dirspec, ':'))
2351     return new_host_dirspec;
2352
2353   while (len > 1 && new_host_dirspec[len - 1] == '/')
2354     {
2355       new_host_dirspec[len - 1] = 0;
2356       len--;
2357     }
2358
2359   decc$to_vms (new_host_dirspec, translate_unix, 1, 2);
2360   strncpy (new_host_dirspec, filename_buff, MAXPATH);
2361   new_host_dirspec [MAXPATH - 1] = (char) 0;
2362
2363   return new_host_dirspec;
2364 }
2365
2366 /* Translate a Unix syntax file specification into VMS syntax.
2367    If indicators of VMS syntax found, return input string.  */
2368
2369 char *
2370 __gnat_to_host_file_spec (char *filespec)
2371 {
2372   strncpy (new_host_filespec, "", MAXPATH);
2373   if (strchr (filespec, ']') || strchr (filespec, ':'))
2374     {
2375       strncpy (new_host_filespec, filespec, MAXPATH);
2376     }
2377   else
2378     {
2379       decc$to_vms (filespec, translate_unix, 1, 1);
2380       strncpy (new_host_filespec, filename_buff, MAXPATH);
2381     }
2382
2383   new_host_filespec [MAXPATH - 1] = (char) 0;
2384
2385   return new_host_filespec;
2386 }
2387
2388 void
2389 __gnat_adjust_os_resource_limits ()
2390 {
2391   SYS$ADJWSL (131072, 0);
2392 }
2393
2394 #else /* VMS */
2395
2396 /* Dummy functions for Osint import for non-VMS systems.  */
2397
2398 int
2399 __gnat_to_canonical_file_list_init
2400   (char *dirspec ATTRIBUTE_UNUSED, int onlydirs ATTRIBUTE_UNUSED)
2401 {
2402   return 0;
2403 }
2404
2405 char *
2406 __gnat_to_canonical_file_list_next (void)
2407 {
2408   return (char *) "";
2409 }
2410
2411 void
2412 __gnat_to_canonical_file_list_free (void)
2413 {
2414 }
2415
2416 char *
2417 __gnat_to_canonical_dir_spec (char *dirspec, int prefixflag ATTRIBUTE_UNUSED)
2418 {
2419   return dirspec;
2420 }
2421
2422 char *
2423 __gnat_to_canonical_file_spec (char *filespec)
2424 {
2425   return filespec;
2426 }
2427
2428 char *
2429 __gnat_to_canonical_path_spec (char *pathspec)
2430 {
2431   return pathspec;
2432 }
2433
2434 char *
2435 __gnat_to_host_dir_spec (char *dirspec, int prefixflag ATTRIBUTE_UNUSED)
2436 {
2437   return dirspec;
2438 }
2439
2440 char *
2441 __gnat_to_host_file_spec (char *filespec)
2442 {
2443   return filespec;
2444 }
2445
2446 void
2447 __gnat_adjust_os_resource_limits (void)
2448 {
2449 }
2450
2451 #endif
2452
2453 /* For EMX, we cannot include dummy in libgcc, since it is too difficult
2454    to coordinate this with the EMX distribution. Consequently, we put the
2455    definition of dummy which is used for exception handling, here.  */
2456
2457 #if defined (__EMX__)
2458 void __dummy () {}
2459 #endif
2460
2461 #if defined (__mips_vxworks)
2462 int
2463 _flush_cache()
2464 {
2465    CACHE_USER_FLUSH (0, ENTIRE_CACHE);
2466 }
2467 #endif
2468
2469 #if defined (CROSS_COMPILE)  \
2470   || (! (defined (sparc) && defined (sun) && defined (__SVR4)) \
2471       && ! (defined (linux) && defined (i386)) \
2472       && ! defined (__FreeBSD__) \
2473       && ! defined (__hpux__) \
2474       && ! defined (_AIX) \
2475       && ! (defined (__alpha__)  && defined (__osf__)) \
2476       && ! defined (__MINGW32__) \
2477       && ! (defined (__mips) && defined (__sgi)))
2478
2479 /* Dummy function to satisfy g-trasym.o.  Currently Solaris sparc, HP/UX,
2480    GNU/Linux x86, Tru64 & Windows provide a non-dummy version of this
2481    procedure in libaddr2line.a.  */
2482
2483 void
2484 convert_addresses (void *addrs ATTRIBUTE_UNUSED,
2485                    int n_addr ATTRIBUTE_UNUSED,
2486                    void *buf ATTRIBUTE_UNUSED,
2487                    int *len ATTRIBUTE_UNUSED)
2488 {
2489   *len = 0;
2490 }
2491 #endif
2492
2493 #if defined (_WIN32)
2494 int __gnat_argument_needs_quote = 1;
2495 #else
2496 int __gnat_argument_needs_quote = 0;
2497 #endif
2498
2499 /* This option is used to enable/disable object files handling from the
2500    binder file by the GNAT Project module. For example, this is disabled on
2501    Windows (prior to GCC 3.4) as it is already done by the mdll module.
2502    Stating with GCC 3.4 the shared libraries are not based on mdll
2503    anymore as it uses the GCC's -shared option  */
2504 #if defined (_WIN32) \
2505     && ((__GNUC__ < 3) || ((__GNUC__ == 3) && (__GNUC_MINOR__ < 4)))
2506 int __gnat_prj_add_obj_files = 0;
2507 #else
2508 int __gnat_prj_add_obj_files = 1;
2509 #endif
2510
2511 /* char used as prefix/suffix for environment variables */
2512 #if defined (_WIN32)
2513 char __gnat_environment_char = '%';
2514 #else
2515 char __gnat_environment_char = '$';
2516 #endif
2517
2518 /* This functions copy the file attributes from a source file to a
2519    destination file.
2520
2521    mode = 0  : In this mode copy only the file time stamps (last access and
2522                last modification time stamps).
2523
2524    mode = 1  : In this mode, time stamps and read/write/execute attributes are
2525                copied.
2526
2527    Returns 0 if operation was successful and -1 in case of error. */
2528
2529 int
2530 __gnat_copy_attribs (char *from, char *to, int mode)
2531 {
2532 #if defined (VMS) || defined (__vxworks)
2533   return -1;
2534 #else
2535   struct stat fbuf;
2536   struct utimbuf tbuf;
2537
2538   if (stat (from, &fbuf) == -1)
2539     {
2540       return -1;
2541     }
2542
2543   tbuf.actime = fbuf.st_atime;
2544   tbuf.modtime = fbuf.st_mtime;
2545
2546   if (utime (to, &tbuf) == -1)
2547     {
2548       return -1;
2549     }
2550
2551   if (mode == 1)
2552     {
2553       if (chmod (to, fbuf.st_mode) == -1)
2554         {
2555           return -1;
2556         }
2557     }
2558
2559   return 0;
2560 #endif
2561 }
2562
2563 /* This function is installed in libgcc.a.  */
2564 extern void __gnat_install_locks (void (*) (void), void (*) (void));
2565
2566 /* This function offers a hook for libgnarl to set the
2567    locking subprograms for libgcc_eh.
2568    This is only needed on OpenVMS, since other platforms use standard
2569    --enable-threads=posix option, or similar.  */
2570
2571 void
2572 __gnatlib_install_locks (void (*lock) (void) ATTRIBUTE_UNUSED,
2573                          void (*unlock) (void) ATTRIBUTE_UNUSED)
2574 {
2575 #if defined (IN_RTS) && defined (VMS)
2576   __gnat_install_locks (lock, unlock);
2577   /* There is a bootstrap path issue if adaint is build with this
2578      symbol unresolved for the stage1 compiler. Since the compiler
2579      does not use tasking, we simply make __gnatlib_install_locks
2580      a no-op in this case. */
2581 #endif
2582 }
2583
2584 int
2585 __gnat_lseek (int fd, long offset, int whence)
2586 {
2587   return (int) lseek (fd, offset, whence);
2588 }
2589
2590 /* This function returns the version of GCC being used.  Here it's GCC 3.  */
2591 int
2592 get_gcc_version (void)
2593 {
2594   return 3;
2595 }