OSDN Git Service

2005-06-14 Ed Schonberg <schonberg@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   char *file_path = alloca (strlen (file_name) + 1);
1943   int absolute;
1944
1945   /* Remove quotes around file_name if present */
1946
1947   ptr = file_name;
1948   if (*ptr == '"')
1949     ptr++;
1950
1951   strcpy (file_path, ptr);
1952
1953   ptr = file_path + strlen (file_path) - 1;
1954
1955   if (*ptr == '"')
1956     *ptr = '\0';
1957
1958   /* Handle absolute pathnames.  */
1959
1960   absolute = __gnat_is_absolute_path (file_path, strlen (file_name));
1961
1962   if (absolute)
1963     {
1964      if (__gnat_is_regular_file (file_path))
1965        return xstrdup (file_path);
1966
1967       return 0;
1968     }
1969
1970   /* If file_name include directory separator(s), try it first as
1971      a path name relative to the current directory */
1972   for (ptr = file_name; *ptr && *ptr != '/' && *ptr != DIR_SEPARATOR; ptr++)
1973     ;
1974
1975   if (*ptr != 0)
1976     {
1977       if (__gnat_is_regular_file (file_name))
1978         return xstrdup (file_name);
1979     }
1980
1981   if (path_val == 0)
1982     return 0;
1983
1984   {
1985     /* The result has to be smaller than path_val + file_name.  */
1986     char *file_path = alloca (strlen (path_val) + strlen (file_name) + 2);
1987
1988     for (;;)
1989       {
1990         for (; *path_val == PATH_SEPARATOR; path_val++)
1991           ;
1992
1993       if (*path_val == 0)
1994         return 0;
1995
1996       /* Skip the starting quote */
1997
1998       if (*path_val == '"')
1999         path_val++;
2000
2001       for (ptr = file_path; *path_val && *path_val != PATH_SEPARATOR; )
2002         *ptr++ = *path_val++;
2003
2004       ptr--;
2005
2006       /* Skip the ending quote */
2007
2008       if (*ptr == '"')
2009         ptr--;
2010
2011       if (*ptr != '/' && *ptr != DIR_SEPARATOR)
2012         *++ptr = DIR_SEPARATOR;
2013
2014       strcpy (++ptr, file_name);
2015
2016       if (__gnat_is_regular_file (file_path))
2017         return xstrdup (file_path);
2018       }
2019   }
2020
2021   return 0;
2022 }
2023
2024 /* Locate an executable given a Path argument. This routine is only used by
2025    gnatbl and should not be used otherwise.  Use locate_exec_on_path
2026    instead.  */
2027
2028 char *
2029 __gnat_locate_exec (char *exec_name, char *path_val)
2030 {
2031   if (!strstr (exec_name, HOST_EXECUTABLE_SUFFIX))
2032     {
2033       char *full_exec_name
2034         = alloca (strlen (exec_name) + strlen (HOST_EXECUTABLE_SUFFIX) + 1);
2035
2036       strcpy (full_exec_name, exec_name);
2037       strcat (full_exec_name, HOST_EXECUTABLE_SUFFIX);
2038       return __gnat_locate_regular_file (full_exec_name, path_val);
2039     }
2040   else
2041     return __gnat_locate_regular_file (exec_name, path_val);
2042 }
2043
2044 /* Locate an executable using the Systems default PATH.  */
2045
2046 char *
2047 __gnat_locate_exec_on_path (char *exec_name)
2048 {
2049   char *apath_val;
2050 #ifdef VMS
2051   char *path_val = "/VAXC$PATH";
2052 #else
2053   char *path_val = getenv ("PATH");
2054 #endif
2055 #ifdef _WIN32
2056   /* In Win32 systems we expand the PATH as for XP environment
2057      variables are not automatically expanded. We also prepend the
2058      ".;" to the path to match normal NT path search semantics */
2059
2060   #define EXPAND_BUFFER_SIZE 32767
2061
2062   apath_val = alloca (EXPAND_BUFFER_SIZE);
2063
2064   apath_val [0] = '.';
2065   apath_val [1] = ';';
2066
2067   DWORD res = ExpandEnvironmentStrings
2068     (path_val, apath_val + 2, EXPAND_BUFFER_SIZE - 2);
2069
2070   if (!res) apath_val [0] = '\0';
2071 #else
2072   apath_val = alloca (strlen (path_val) + 1);
2073   strcpy (apath_val, path_val);
2074 #endif
2075
2076   return __gnat_locate_exec (exec_name, apath_val);
2077 }
2078
2079 #ifdef VMS
2080
2081 /* These functions are used to translate to and from VMS and Unix syntax
2082    file, directory and path specifications.  */
2083
2084 #define MAXPATH  256
2085 #define MAXNAMES 256
2086 #define NEW_CANONICAL_FILELIST_INCREMENT 64
2087
2088 static char new_canonical_dirspec [MAXPATH];
2089 static char new_canonical_filespec [MAXPATH];
2090 static char new_canonical_pathspec [MAXNAMES*MAXPATH];
2091 static unsigned new_canonical_filelist_index;
2092 static unsigned new_canonical_filelist_in_use;
2093 static unsigned new_canonical_filelist_allocated;
2094 static char **new_canonical_filelist;
2095 static char new_host_pathspec [MAXNAMES*MAXPATH];
2096 static char new_host_dirspec [MAXPATH];
2097 static char new_host_filespec [MAXPATH];
2098
2099 /* Routine is called repeatedly by decc$from_vms via
2100    __gnat_to_canonical_file_list_init until it returns 0 or the expansion
2101    runs out. */
2102
2103 static int
2104 wildcard_translate_unix (char *name)
2105 {
2106   char *ver;
2107   char buff [MAXPATH];
2108
2109   strncpy (buff, name, MAXPATH);
2110   buff [MAXPATH - 1] = (char) 0;
2111   ver = strrchr (buff, '.');
2112
2113   /* Chop off the version.  */
2114   if (ver)
2115     *ver = 0;
2116
2117   /* Dynamically extend the allocation by the increment.  */
2118   if (new_canonical_filelist_in_use == new_canonical_filelist_allocated)
2119     {
2120       new_canonical_filelist_allocated += NEW_CANONICAL_FILELIST_INCREMENT;
2121       new_canonical_filelist = (char **) xrealloc
2122         (new_canonical_filelist,
2123          new_canonical_filelist_allocated * sizeof (char *));
2124     }
2125
2126   new_canonical_filelist[new_canonical_filelist_in_use++] = xstrdup (buff);
2127
2128   return 1;
2129 }
2130
2131 /* Translate a wildcard VMS file spec into a list of Unix file specs. First do
2132    full translation and copy the results into a list (_init), then return them
2133    one at a time (_next). If onlydirs set, only expand directory files.  */
2134
2135 int
2136 __gnat_to_canonical_file_list_init (char *filespec, int onlydirs)
2137 {
2138   int len;
2139   char buff [MAXPATH];
2140
2141   len = strlen (filespec);
2142   strncpy (buff, filespec, MAXPATH);
2143
2144   /* Only look for directories */
2145   if (onlydirs && !strstr (&buff [len-5], "*.dir"))
2146     strncat (buff, "*.dir", MAXPATH);
2147
2148   buff [MAXPATH - 1] = (char) 0;
2149
2150   decc$from_vms (buff, wildcard_translate_unix, 1);
2151
2152   /* Remove the .dir extension.  */
2153   if (onlydirs)
2154     {
2155       int i;
2156       char *ext;
2157
2158       for (i = 0; i < new_canonical_filelist_in_use; i++)
2159         {
2160           ext = strstr (new_canonical_filelist[i], ".dir");
2161           if (ext)
2162             *ext = 0;
2163         }
2164     }
2165
2166   return new_canonical_filelist_in_use;
2167 }
2168
2169 /* Return the next filespec in the list.  */
2170
2171 char *
2172 __gnat_to_canonical_file_list_next ()
2173 {
2174   return new_canonical_filelist[new_canonical_filelist_index++];
2175 }
2176
2177 /* Free storage used in the wildcard expansion.  */
2178
2179 void
2180 __gnat_to_canonical_file_list_free ()
2181 {
2182   int i;
2183
2184    for (i = 0; i < new_canonical_filelist_in_use; i++)
2185      free (new_canonical_filelist[i]);
2186
2187   free (new_canonical_filelist);
2188
2189   new_canonical_filelist_in_use = 0;
2190   new_canonical_filelist_allocated = 0;
2191   new_canonical_filelist_index = 0;
2192   new_canonical_filelist = 0;
2193 }
2194
2195 /* Translate a VMS syntax directory specification in to Unix syntax.  If
2196    PREFIXFLAG is set, append an underscore "/". If no indicators of VMS syntax
2197    found, return input string. Also translate a dirname that contains no
2198    slashes, in case it's a logical name.  */
2199
2200 char *
2201 __gnat_to_canonical_dir_spec (char *dirspec, int prefixflag)
2202 {
2203   int len;
2204
2205   strcpy (new_canonical_dirspec, "");
2206   if (strlen (dirspec))
2207     {
2208       char *dirspec1;
2209
2210       if (strchr (dirspec, ']') || strchr (dirspec, ':'))
2211         {
2212           strncpy (new_canonical_dirspec,
2213                    (char *) decc$translate_vms (dirspec),
2214                    MAXPATH);
2215         }
2216       else if (!strchr (dirspec, '/') && (dirspec1 = getenv (dirspec)) != 0)
2217         {
2218           strncpy (new_canonical_dirspec,
2219                   (char *) decc$translate_vms (dirspec1),
2220                   MAXPATH);
2221         }
2222       else
2223         {
2224           strncpy (new_canonical_dirspec, dirspec, MAXPATH);
2225         }
2226     }
2227
2228   len = strlen (new_canonical_dirspec);
2229   if (prefixflag && new_canonical_dirspec [len-1] != '/')
2230     strncat (new_canonical_dirspec, "/", MAXPATH);
2231
2232   new_canonical_dirspec [MAXPATH - 1] = (char) 0;
2233
2234   return new_canonical_dirspec;
2235
2236 }
2237
2238 /* Translate a VMS syntax file specification into Unix syntax.
2239    If no indicators of VMS syntax found, check if it's an uppercase
2240    alphanumeric_ name and if so try it out as an environment
2241    variable (logical name). If all else fails return the
2242    input string.  */
2243
2244 char *
2245 __gnat_to_canonical_file_spec (char *filespec)
2246 {
2247   char *filespec1;
2248
2249   strncpy (new_canonical_filespec, "", MAXPATH);
2250
2251   if (strchr (filespec, ']') || strchr (filespec, ':'))
2252     {
2253       char *tspec = (char *) decc$translate_vms (filespec);
2254
2255       if (tspec != (char *) -1)
2256         strncpy (new_canonical_filespec, tspec, MAXPATH);
2257     }
2258   else if ((strlen (filespec) == strspn (filespec,
2259             "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_"))
2260         && (filespec1 = getenv (filespec)))
2261     {
2262       char *tspec = (char *) decc$translate_vms (filespec1);
2263
2264       if (tspec != (char *) -1)
2265         strncpy (new_canonical_filespec, tspec, MAXPATH);
2266     }
2267   else
2268     {
2269       strncpy (new_canonical_filespec, filespec, MAXPATH);
2270     }
2271
2272   new_canonical_filespec [MAXPATH - 1] = (char) 0;
2273
2274   return new_canonical_filespec;
2275 }
2276
2277 /* Translate a VMS syntax path specification into Unix syntax.
2278    If no indicators of VMS syntax found, return input string.  */
2279
2280 char *
2281 __gnat_to_canonical_path_spec (char *pathspec)
2282 {
2283   char *curr, *next, buff [MAXPATH];
2284
2285   if (pathspec == 0)
2286     return pathspec;
2287
2288   /* If there are /'s, assume it's a Unix path spec and return.  */
2289   if (strchr (pathspec, '/'))
2290     return pathspec;
2291
2292   new_canonical_pathspec[0] = 0;
2293   curr = pathspec;
2294
2295   for (;;)
2296     {
2297       next = strchr (curr, ',');
2298       if (next == 0)
2299         next = strchr (curr, 0);
2300
2301       strncpy (buff, curr, next - curr);
2302       buff[next - curr] = 0;
2303
2304       /* Check for wildcards and expand if present.  */
2305       if (strchr (buff, '*') || strchr (buff, '%') || strstr (buff, "..."))
2306         {
2307           int i, dirs;
2308
2309           dirs = __gnat_to_canonical_file_list_init (buff, 1);
2310           for (i = 0; i < dirs; i++)
2311             {
2312               char *next_dir;
2313
2314               next_dir = __gnat_to_canonical_file_list_next ();
2315               strncat (new_canonical_pathspec, next_dir, MAXPATH);
2316
2317               /* Don't append the separator after the last expansion.  */
2318               if (i+1 < dirs)
2319                 strncat (new_canonical_pathspec, ":", MAXPATH);
2320             }
2321
2322           __gnat_to_canonical_file_list_free ();
2323         }
2324       else
2325         strncat (new_canonical_pathspec,
2326                 __gnat_to_canonical_dir_spec (buff, 0), MAXPATH);
2327
2328       if (*next == 0)
2329         break;
2330
2331       strncat (new_canonical_pathspec, ":", MAXPATH);
2332       curr = next + 1;
2333     }
2334
2335   new_canonical_pathspec [MAXPATH - 1] = (char) 0;
2336
2337   return new_canonical_pathspec;
2338 }
2339
2340 static char filename_buff [MAXPATH];
2341
2342 static int
2343 translate_unix (char *name, int type)
2344 {
2345   strncpy (filename_buff, name, MAXPATH);
2346   filename_buff [MAXPATH - 1] = (char) 0;
2347   return 0;
2348 }
2349
2350 /* Translate a Unix syntax path spec into a VMS style (comma separated list of
2351    directories.  */
2352
2353 static char *
2354 to_host_path_spec (char *pathspec)
2355 {
2356   char *curr, *next, buff [MAXPATH];
2357
2358   if (pathspec == 0)
2359     return pathspec;
2360
2361   /* Can't very well test for colons, since that's the Unix separator!  */
2362   if (strchr (pathspec, ']') || strchr (pathspec, ','))
2363     return pathspec;
2364
2365   new_host_pathspec[0] = 0;
2366   curr = pathspec;
2367
2368   for (;;)
2369     {
2370       next = strchr (curr, ':');
2371       if (next == 0)
2372         next = strchr (curr, 0);
2373
2374       strncpy (buff, curr, next - curr);
2375       buff[next - curr] = 0;
2376
2377       strncat (new_host_pathspec, __gnat_to_host_dir_spec (buff, 0), MAXPATH);
2378       if (*next == 0)
2379         break;
2380       strncat (new_host_pathspec, ",", MAXPATH);
2381       curr = next + 1;
2382     }
2383
2384   new_host_pathspec [MAXPATH - 1] = (char) 0;
2385
2386   return new_host_pathspec;
2387 }
2388
2389 /* Translate a Unix syntax directory specification into VMS syntax.  The
2390    PREFIXFLAG has no effect, but is kept for symmetry with
2391    to_canonical_dir_spec.  If indicators of VMS syntax found, return input
2392    string. */
2393
2394 char *
2395 __gnat_to_host_dir_spec (char *dirspec, int prefixflag ATTRIBUTE_UNUSED)
2396 {
2397   int len = strlen (dirspec);
2398
2399   strncpy (new_host_dirspec, dirspec, MAXPATH);
2400   new_host_dirspec [MAXPATH - 1] = (char) 0;
2401
2402   if (strchr (new_host_dirspec, ']') || strchr (new_host_dirspec, ':'))
2403     return new_host_dirspec;
2404
2405   while (len > 1 && new_host_dirspec[len - 1] == '/')
2406     {
2407       new_host_dirspec[len - 1] = 0;
2408       len--;
2409     }
2410
2411   decc$to_vms (new_host_dirspec, translate_unix, 1, 2);
2412   strncpy (new_host_dirspec, filename_buff, MAXPATH);
2413   new_host_dirspec [MAXPATH - 1] = (char) 0;
2414
2415   return new_host_dirspec;
2416 }
2417
2418 /* Translate a Unix syntax file specification into VMS syntax.
2419    If indicators of VMS syntax found, return input string.  */
2420
2421 char *
2422 __gnat_to_host_file_spec (char *filespec)
2423 {
2424   strncpy (new_host_filespec, "", MAXPATH);
2425   if (strchr (filespec, ']') || strchr (filespec, ':'))
2426     {
2427       strncpy (new_host_filespec, filespec, MAXPATH);
2428     }
2429   else
2430     {
2431       decc$to_vms (filespec, translate_unix, 1, 1);
2432       strncpy (new_host_filespec, filename_buff, MAXPATH);
2433     }
2434
2435   new_host_filespec [MAXPATH - 1] = (char) 0;
2436
2437   return new_host_filespec;
2438 }
2439
2440 void
2441 __gnat_adjust_os_resource_limits ()
2442 {
2443   SYS$ADJWSL (131072, 0);
2444 }
2445
2446 #else /* VMS */
2447
2448 /* Dummy functions for Osint import for non-VMS systems.  */
2449
2450 int
2451 __gnat_to_canonical_file_list_init
2452   (char *dirspec ATTRIBUTE_UNUSED, int onlydirs ATTRIBUTE_UNUSED)
2453 {
2454   return 0;
2455 }
2456
2457 char *
2458 __gnat_to_canonical_file_list_next (void)
2459 {
2460   return (char *) "";
2461 }
2462
2463 void
2464 __gnat_to_canonical_file_list_free (void)
2465 {
2466 }
2467
2468 char *
2469 __gnat_to_canonical_dir_spec (char *dirspec, int prefixflag ATTRIBUTE_UNUSED)
2470 {
2471   return dirspec;
2472 }
2473
2474 char *
2475 __gnat_to_canonical_file_spec (char *filespec)
2476 {
2477   return filespec;
2478 }
2479
2480 char *
2481 __gnat_to_canonical_path_spec (char *pathspec)
2482 {
2483   return pathspec;
2484 }
2485
2486 char *
2487 __gnat_to_host_dir_spec (char *dirspec, int prefixflag ATTRIBUTE_UNUSED)
2488 {
2489   return dirspec;
2490 }
2491
2492 char *
2493 __gnat_to_host_file_spec (char *filespec)
2494 {
2495   return filespec;
2496 }
2497
2498 void
2499 __gnat_adjust_os_resource_limits (void)
2500 {
2501 }
2502
2503 #endif
2504
2505 /* For EMX, we cannot include dummy in libgcc, since it is too difficult
2506    to coordinate this with the EMX distribution. Consequently, we put the
2507    definition of dummy which is used for exception handling, here.  */
2508
2509 #if defined (__EMX__)
2510 void __dummy () {}
2511 #endif
2512
2513 #if defined (__mips_vxworks)
2514 int
2515 _flush_cache()
2516 {
2517    CACHE_USER_FLUSH (0, ENTIRE_CACHE);
2518 }
2519 #endif
2520
2521 #if defined (CROSS_COMPILE)  \
2522   || (! (defined (sparc) && defined (sun) && defined (__SVR4)) \
2523       && ! (defined (linux) && (defined (i386) || defined (__x86_64__))) \
2524       && ! defined (__FreeBSD__) \
2525       && ! defined (__hpux__) \
2526       && ! defined (__APPLE__) \
2527       && ! defined (_AIX) \
2528       && ! (defined (__alpha__)  && defined (__osf__)) \
2529       && ! defined (__MINGW32__) \
2530       && ! (defined (__mips) && defined (__sgi)))
2531
2532 /* Dummy function to satisfy g-trasym.o.  Currently Solaris sparc, HP/UX,
2533    GNU/Linux x86{_64}, Tru64 & Windows provide a non-dummy version of this
2534    procedure in libaddr2line.a.  */
2535
2536 void
2537 convert_addresses (void *addrs ATTRIBUTE_UNUSED,
2538                    int n_addr ATTRIBUTE_UNUSED,
2539                    void *buf ATTRIBUTE_UNUSED,
2540                    int *len ATTRIBUTE_UNUSED)
2541 {
2542   *len = 0;
2543 }
2544 #endif
2545
2546 #if defined (_WIN32)
2547 int __gnat_argument_needs_quote = 1;
2548 #else
2549 int __gnat_argument_needs_quote = 0;
2550 #endif
2551
2552 /* This option is used to enable/disable object files handling from the
2553    binder file by the GNAT Project module. For example, this is disabled on
2554    Windows (prior to GCC 3.4) as it is already done by the mdll module.
2555    Stating with GCC 3.4 the shared libraries are not based on mdll
2556    anymore as it uses the GCC's -shared option  */
2557 #if defined (_WIN32) \
2558     && ((__GNUC__ < 3) || ((__GNUC__ == 3) && (__GNUC_MINOR__ < 4)))
2559 int __gnat_prj_add_obj_files = 0;
2560 #else
2561 int __gnat_prj_add_obj_files = 1;
2562 #endif
2563
2564 /* char used as prefix/suffix for environment variables */
2565 #if defined (_WIN32)
2566 char __gnat_environment_char = '%';
2567 #else
2568 char __gnat_environment_char = '$';
2569 #endif
2570
2571 /* This functions copy the file attributes from a source file to a
2572    destination file.
2573
2574    mode = 0  : In this mode copy only the file time stamps (last access and
2575                last modification time stamps).
2576
2577    mode = 1  : In this mode, time stamps and read/write/execute attributes are
2578                copied.
2579
2580    Returns 0 if operation was successful and -1 in case of error. */
2581
2582 int
2583 __gnat_copy_attribs (char *from, char *to, int mode)
2584 {
2585 #if defined (VMS) || defined (__vxworks)
2586   return -1;
2587 #else
2588   struct stat fbuf;
2589   struct utimbuf tbuf;
2590
2591   if (stat (from, &fbuf) == -1)
2592     {
2593       return -1;
2594     }
2595
2596   tbuf.actime = fbuf.st_atime;
2597   tbuf.modtime = fbuf.st_mtime;
2598
2599   if (utime (to, &tbuf) == -1)
2600     {
2601       return -1;
2602     }
2603
2604   if (mode == 1)
2605     {
2606       if (chmod (to, fbuf.st_mode) == -1)
2607         {
2608           return -1;
2609         }
2610     }
2611
2612   return 0;
2613 #endif
2614 }
2615
2616 /* This function is installed in libgcc.a.  */
2617 extern void __gnat_install_locks (void (*) (void), void (*) (void));
2618
2619 /* This function offers a hook for libgnarl to set the
2620    locking subprograms for libgcc_eh.
2621    This is only needed on OpenVMS, since other platforms use standard
2622    --enable-threads=posix option, or similar.  */
2623
2624 void
2625 __gnatlib_install_locks (void (*lock) (void) ATTRIBUTE_UNUSED,
2626                          void (*unlock) (void) ATTRIBUTE_UNUSED)
2627 {
2628 #if defined (IN_RTS) && defined (VMS)
2629   __gnat_install_locks (lock, unlock);
2630   /* There is a bootstrap path issue if adaint is build with this
2631      symbol unresolved for the stage1 compiler. Since the compiler
2632      does not use tasking, we simply make __gnatlib_install_locks
2633      a no-op in this case. */
2634 #endif
2635 }
2636
2637 int
2638 __gnat_lseek (int fd, long offset, int whence)
2639 {
2640   return (int) lseek (fd, offset, whence);
2641 }
2642
2643 /* This function returns the version of GCC being used.  Here it's GCC 3.  */
2644 int
2645 get_gcc_version (void)
2646 {
2647   return 3;
2648 }
2649
2650 int
2651 __gnat_set_close_on_exec (int fd ATTRIBUTE_UNUSED,
2652                         int close_on_exec_p ATTRIBUTE_UNUSED)
2653 {
2654 #if defined (F_GETFD) && defined (FD_CLOEXEC) && ! defined (__vxworks)
2655   int flags = fcntl (fd, F_GETFD, 0);
2656   if (flags < 0)
2657     return flags;
2658   if (close_on_exec_p)
2659     flags |= FD_CLOEXEC;
2660   else
2661     flags &= ~FD_CLOEXEC;
2662   return fcntl (fd, F_SETFD, flags | FD_CLOEXEC);
2663 #else
2664   return -1;
2665   /* For the Windows case, we should use SetHandleInformation to remove
2666      the HANDLE_INHERIT property from fd. This is not implemented yet,
2667      but for our purposes (support of GNAT.Expect) this does not matter,
2668      as by default handles are *not* inherited. */
2669 #endif
2670 }