OSDN Git Service

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