OSDN Git Service

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