OSDN Git Service

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