OSDN Git Service

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