Merged with mainline at revision 128810.
[official-gcc.git] / gcc / ada / adaint.c
blob74fb670f30d076fdd6dbe1ddb37cfb7c0687e273
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 ****************************************************************************/
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. */
38 #ifdef __vxworks
40 /* No need to redefine exit here. */
41 #undef exit
43 /* We want to use the POSIX variants of include files. */
44 #define POSIX
45 #include "vxWorks.h"
47 #if defined (__mips_vxworks)
48 #include "cacheLib.h"
49 #endif /* __mips_vxworks */
51 #endif /* VxWorks */
53 #ifdef VMS
54 #define _POSIX_EXIT 1
55 #define HOST_EXECUTABLE_SUFFIX ".exe"
56 #define HOST_OBJECT_SUFFIX ".obj"
57 #endif
59 #ifdef IN_RTS
60 #include "tconfig.h"
61 #include "tsystem.h"
63 #include <sys/stat.h>
64 #include <fcntl.h>
65 #include <time.h>
66 #ifdef VMS
67 #include <unixio.h>
68 #endif
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
79 #if defined (__MINGW32__)
81 #include "mingw32.h"
82 #include <sys/utime.h>
83 #include <ctype.h>
85 #elif defined (__Lynx__)
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
93 #elif !defined (VMS)
94 #include <utime.h>
95 #endif
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
115 #if defined (__EMX__) || defined (MSDOS) || defined (_WIN32)
116 #elif defined (VMS)
118 /* Header files and definitions for __gnat_set_file_time_name. */
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>
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; }
138 /* descrip.h doesn't have everything ... */
139 typedef struct fibdef* __fibdef_ptr32 __attribute__ (( mode (SI) ));
140 struct dsc$descriptor_fib
142 unsigned int fib$l_len;
143 __fibdef_ptr32 fib$l_addr;
146 /* I/O Status Block. */
147 struct IOSB
149 unsigned short status, count;
150 unsigned int devdep;
153 static char *tryfile;
155 /* Variable length string. */
156 struct vstring
158 short length;
159 char string[NAM$C_MAXRSS+1];
162 #else
163 #include <utime.h>
164 #endif
166 #if defined (__EMX__) || defined (MSDOS) || defined (_WIN32)
167 #include <process.h>
168 #endif
170 #if defined (_WIN32)
171 #include <dir.h>
172 #include <windows.h>
173 #undef DIR_SEPARATOR
174 #define DIR_SEPARATOR '\\'
175 #endif
177 #include "adaint.h"
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. */
185 #if defined (__EMX__)
186 #include <os2.h>
187 #endif
189 #if defined (MSDOS)
190 #include <dos.h>
191 #endif
193 #ifndef O_BINARY
194 #define O_BINARY 0
195 #endif
197 #ifndef O_TEXT
198 #define O_TEXT 0
199 #endif
201 #ifndef HOST_EXECUTABLE_SUFFIX
202 #define HOST_EXECUTABLE_SUFFIX ""
203 #endif
205 #ifndef HOST_OBJECT_SUFFIX
206 #define HOST_OBJECT_SUFFIX ".o"
207 #endif
209 #ifndef PATH_SEPARATOR
210 #define PATH_SEPARATOR ':'
211 #endif
213 #ifndef DIR_SEPARATOR
214 #define DIR_SEPARATOR '/'
215 #endif
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
224 char __gnat_dir_separator = DIR_SEPARATOR;
226 char __gnat_path_separator = PATH_SEPARATOR;
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
233 library_template ::= { pattern ; } pattern NUL
234 pattern ::= [ prefix ] * [ postfix ]
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:
241 * if they are needed but not present, the link
242 will fail,
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.
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. */
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
262 const char *__gnat_library_template = GNAT_LIBRARY_TEMPLATE;
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
272 #ifdef __EMX__
273 #define GNAT_MAX_PATH_LEN MAX_PATH
275 #elif defined (VMS)
276 #define GNAT_MAX_PATH_LEN 256 /* PATH_MAX */
278 #elif defined (__vxworks) || defined (__OPENNT)
279 #define GNAT_MAX_PATH_LEN PATH_MAX
281 #else
283 #if defined (__MINGW32__)
284 #include "mingw32.h"
286 #if OLD_MINGW
287 #include <sys/param.h>
288 #endif
290 #else
291 #include <sys/param.h>
292 #endif
294 #ifdef MAXPATHLEN
295 #define GNAT_MAX_PATH_LEN MAXPATHLEN
296 #else
297 #define GNAT_MAX_PATH_LEN 256
298 #endif
300 #endif
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. */
307 int __gnat_max_path_len = GNAT_MAX_PATH_LEN;
308 int max_path_len = GNAT_MAX_PATH_LEN;
310 /* The following macro HAVE_READDIR_R should be defined if the
311 system provides the routine readdir_r. */
312 #undef HAVE_READDIR_R
314 #if defined(VMS) && defined (__LONG_POINTERS)
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 */
319 typedef __char_ptr32 *__char_ptr_char_ptr32 __attribute__ ((mode (SI)));
321 static __char_ptr_char_ptr32
322 to_ptr32 (char **ptr64)
324 int argc;
325 __char_ptr_char_ptr32 short_argv;
327 for (argc=0; ptr64[argc]; argc++);
329 /* Reallocate argv with 32 bit pointers. */
330 short_argv = (__char_ptr_char_ptr32) decc$malloc
331 (sizeof (__char_ptr32) * (argc + 1));
333 for (argc=0; ptr64[argc]; argc++)
334 short_argv[argc] = (__char_ptr32) decc$strdup (ptr64[argc]);
336 short_argv[argc] = (__char_ptr32) 0;
337 return short_argv;
340 #define MAYBE_TO_PTR32(argv) to_ptr32 (argv)
341 #else
342 #define MAYBE_TO_PTR32(argv) argv
343 #endif
345 OS_Time
346 __gnat_current_time
347 (void)
349 time_t res = time (NULL);
350 return (OS_Time) res;
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)
363 struct tm *res;
364 time_t time = (time_t) *p_time;
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
373 #ifdef VMS
374 res = localtime (&time);
375 #else
376 res = gmtime (&time);
377 #endif
379 if (res)
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;
388 else
389 *p_year = *p_month = *p_day = *p_hours = *p_mins = *p_secs = 0;
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. */
398 __gnat_readlink (char *path ATTRIBUTE_UNUSED,
399 char *buf ATTRIBUTE_UNUSED,
400 size_t bufsiz ATTRIBUTE_UNUSED)
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
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. */
418 __gnat_symlink (char *oldpath ATTRIBUTE_UNUSED,
419 char *newpath ATTRIBUTE_UNUSED)
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
432 /* Try to lock a file, return 1 if success. */
434 #if defined (__vxworks) || defined (MSDOS) || defined (_WIN32)
436 /* Version that does not use link. */
439 __gnat_try_lock (char *dir, char *file)
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];
447 S2WSU (wdir, dir, GNAT_MAX_PATH_LEN);
448 S2WSU (wfile, file, GNAT_MAX_PATH_LEN);
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];
455 sprintf (full_path, "%s%c%s", dir, DIR_SEPARATOR, file);
456 fd = open (full_path, O_CREAT | O_EXCL, 0600);
457 #endif
459 if (fd < 0)
460 return 0;
462 close (fd);
463 return 1;
466 #elif defined (__EMX__) || defined (VMS)
468 /* More cases that do not use link; identical code, to solve too long
469 line problem ??? */
472 __gnat_try_lock (char *dir, char *file)
474 char full_path[256];
475 int fd;
477 sprintf (full_path, "%s%c%s", dir, DIR_SEPARATOR, file);
478 fd = open (full_path, O_CREAT | O_EXCL, 0600);
480 if (fd < 0)
481 return 0;
483 close (fd);
484 return 1;
487 #else
489 /* Version using link(), more secure over NFS. */
490 /* See TN 6913-016 for discussion ??? */
493 __gnat_try_lock (char *dir, char *file)
495 char full_path[256];
496 char temp_file[256];
497 struct stat stat_result;
498 int fd;
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 ());
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;
509 close (fd);
511 /* Link it with the new file. */
512 link (temp_file, full_path);
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;
520 #endif
522 /* Return the maximum file name length. */
525 __gnat_get_maximum_file_name_length (void)
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
539 /* Return nonzero if file names are case sensitive. */
542 __gnat_get_file_names_case_sensitive (void)
544 #if defined (__EMX__) || defined (MSDOS) || defined (VMS) || defined (WINNT)
545 return 0;
546 #else
547 return 1;
548 #endif
551 char
552 __gnat_get_default_identifier_character_set (void)
554 #if defined (__EMX__) || defined (MSDOS)
555 return 'p';
556 #else
557 return '1';
558 #endif
561 /* Return the current working directory. */
563 void
564 __gnat_get_current_dir (char *dir, int *length)
566 #if defined (__MINGW32__)
567 TCHAR wdir[GNAT_MAX_PATH_LEN];
569 _tgetcwd (wdir, *length);
571 WS2SU (dir, wdir, GNAT_MAX_PATH_LEN);
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
580 *length = strlen (dir);
582 if (dir [*length - 1] != DIR_SEPARATOR)
584 dir [*length] = DIR_SEPARATOR;
585 ++(*length);
587 dir[*length] = '\0';
590 /* Return the suffix for object files. */
592 void
593 __gnat_get_object_suffix_ptr (int *len, const char **value)
595 *value = HOST_OBJECT_SUFFIX;
597 if (*value == 0)
598 *len = 0;
599 else
600 *len = strlen (*value);
602 return;
605 /* Return the suffix for executable files. */
607 void
608 __gnat_get_executable_suffix_ptr (int *len, const char **value)
610 *value = HOST_EXECUTABLE_SUFFIX;
611 if (!*value)
612 *len = 0;
613 else
614 *len = strlen (*value);
616 return;
619 /* Return the suffix for debuggable files. Usually this is the same as the
620 executable extension. */
622 void
623 __gnat_get_debuggable_suffix_ptr (int *len, const char **value)
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
632 if (*value == 0)
633 *len = 0;
634 else
635 *len = strlen (*value);
637 return;
640 /* Returns the OS filename and corresponding encoding. */
642 void
643 __gnat_os_filename (char *filename, char *w_filename,
644 char *os_name, int *o_length,
645 char *encoding, int *e_length)
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
659 FILE *
660 __gnat_fopen (char *path, char *mode, int encoding)
662 #if defined (_WIN32) && ! defined (__vxworks) && ! defined (CROSS_DIRECTORY_STRUCTURE)
663 TCHAR wpath[GNAT_MAX_PATH_LEN];
664 TCHAR wmode[10];
666 S2WS (wmode, mode, 10);
668 if (encoding == Encoding_UTF8)
669 S2WSU (wpath, path, GNAT_MAX_PATH_LEN);
670 else
671 S2WS (wpath, path, GNAT_MAX_PATH_LEN);
673 return _tfopen (wpath, wmode);
674 #elif defined (VMS)
675 return decc$fopen (path, mode);
676 #else
677 return fopen (path, mode);
678 #endif
681 FILE *
682 __gnat_freopen (char *path, char *mode, FILE *stream, int encoding)
684 #if defined (_WIN32) && ! defined (__vxworks) && ! defined (CROSS_DIRECTORY_STRUCTURE)
685 TCHAR wpath[GNAT_MAX_PATH_LEN];
686 TCHAR wmode[10];
688 S2WS (wmode, mode, 10);
690 if (encoding == Encoding_UTF8)
691 S2WSU (wpath, path, GNAT_MAX_PATH_LEN);
692 else
693 S2WS (wpath, path, GNAT_MAX_PATH_LEN);
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
704 __gnat_open_read (char *path, int fmode)
706 int fd;
707 int o_fmode = O_BINARY;
709 if (fmode)
710 o_fmode = O_TEXT;
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__)
720 TCHAR wpath[GNAT_MAX_PATH_LEN];
722 S2WSU (wpath, path, GNAT_MAX_PATH_LEN);
723 fd = _topen (wpath, O_RDONLY | o_fmode, 0444);
725 #else
726 fd = open (path, O_RDONLY | o_fmode);
727 #endif
729 return fd < 0 ? -1 : fd;
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
748 __gnat_open_rw (char *path, int fmode)
750 int fd;
751 int o_fmode = O_BINARY;
753 if (fmode)
754 o_fmode = O_TEXT;
756 #if defined (VMS)
757 fd = open (path, O_RDWR | o_fmode, PERM,
758 "mbc=16", "deq=64", "fop=tef");
759 #elif defined (__MINGW32__)
761 TCHAR wpath[GNAT_MAX_PATH_LEN];
763 S2WSU (wpath, path, GNAT_MAX_PATH_LEN);
764 fd = _topen (wpath, O_RDWR | o_fmode, PERM);
766 #else
767 fd = open (path, O_RDWR | o_fmode, PERM);
768 #endif
770 return fd < 0 ? -1 : fd;
774 __gnat_open_create (char *path, int fmode)
776 int fd;
777 int o_fmode = O_BINARY;
779 if (fmode)
780 o_fmode = O_TEXT;
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__)
787 TCHAR wpath[GNAT_MAX_PATH_LEN];
789 S2WSU (wpath, path, GNAT_MAX_PATH_LEN);
790 fd = _topen (wpath, O_WRONLY | O_CREAT | O_TRUNC | o_fmode, PERM);
792 #else
793 fd = open (path, O_WRONLY | O_CREAT | O_TRUNC | o_fmode, PERM);
794 #endif
796 return fd < 0 ? -1 : fd;
800 __gnat_create_output_file (char *path)
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__)
809 TCHAR wpath[GNAT_MAX_PATH_LEN];
811 S2WSU (wpath, path, GNAT_MAX_PATH_LEN);
812 fd = _topen (wpath, O_WRONLY | O_CREAT | O_TRUNC | O_TEXT, PERM);
814 #else
815 fd = open (path, O_WRONLY | O_CREAT | O_TRUNC | O_TEXT, PERM);
816 #endif
818 return fd < 0 ? -1 : fd;
822 __gnat_open_append (char *path, int fmode)
824 int fd;
825 int o_fmode = O_BINARY;
827 if (fmode)
828 o_fmode = O_TEXT;
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__)
835 TCHAR wpath[GNAT_MAX_PATH_LEN];
837 S2WSU (wpath, path, GNAT_MAX_PATH_LEN);
838 fd = _topen (wpath, O_WRONLY | O_CREAT | O_APPEND | o_fmode, PERM);
840 #else
841 fd = open (path, O_WRONLY | O_CREAT | O_APPEND | o_fmode, PERM);
842 #endif
844 return fd < 0 ? -1 : fd;
847 /* Open a new file. Return error (-1) if the file already exists. */
850 __gnat_open_new (char *path, int fmode)
852 int fd;
853 int o_fmode = O_BINARY;
855 if (fmode)
856 o_fmode = O_TEXT;
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__)
863 TCHAR wpath[GNAT_MAX_PATH_LEN];
865 S2WSU (wpath, path, GNAT_MAX_PATH_LEN);
866 fd = _topen (wpath, O_WRONLY | O_CREAT | O_EXCL | o_fmode, PERM);
868 #else
869 fd = open (path, O_WRONLY | O_CREAT | O_EXCL | o_fmode, PERM);
870 #endif
872 return fd < 0 ? -1 : fd;
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. */
880 __gnat_open_new_temp (char *path, int fmode)
882 int fd;
883 int o_fmode = O_BINARY;
885 strcpy (path, "GNAT-XXXXXX");
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
896 if (fmode)
897 o_fmode = O_TEXT;
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
907 return fd < 0 ? -1 : fd;
910 /* Return the number of bytes in the specified file. */
912 long
913 __gnat_file_length (int fd)
915 int ret;
916 struct stat statbuf;
918 ret = fstat (fd, &statbuf);
919 if (ret || !S_ISREG (statbuf.st_mode))
920 return 0;
922 return (statbuf.st_size);
925 /* Return the number of bytes in the specified named file. */
927 long
928 __gnat_named_file_length (char *name)
930 int ret;
931 struct stat statbuf;
933 ret = __gnat_stat (name, &statbuf);
934 if (ret || !S_ISREG (statbuf.st_mode))
935 return 0;
937 return (statbuf.st_size);
940 /* Create a temporary filename and put it in string pointed to by
941 TMP_FILENAME. */
943 void
944 __gnat_tmp_name (char *tmp_filename)
946 #ifdef __MINGW32__
948 char *pname;
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-". */
955 pname = (char *) tempnam ("c:\\temp", "gnat-");
957 /* if pname is NULL, the file was not created properly, the disk is full
958 or there is no more free temporary files */
960 if (pname == NULL)
961 *tmp_filename = '\0';
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. */
966 else if (pname[0] == '\\')
968 strcpy (tmp_filename, ".\\");
969 strcat (tmp_filename, pname+1);
971 else
972 strcpy (tmp_filename, pname);
974 free (pname);
977 #elif defined (linux) || defined (__FreeBSD__)
978 #define MAX_SAFE_PATH 1000
979 char *tmpdir = getenv ("TMPDIR");
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);
988 close (mkstemp(tmp_filename));
989 #else
990 tmpnam (tmp_filename);
991 #endif
994 /* Open directory and returns a DIR pointer. */
996 DIR* __gnat_opendir (char *name)
998 #ifdef __MINGW32__
999 TCHAR wname[GNAT_MAX_PATH_LEN];
1001 S2WSU (wname, name, GNAT_MAX_PATH_LEN);
1002 return (DIR*)_topendir (wname);
1004 #else
1005 return opendir (name);
1006 #endif
1009 /* Read the next entry in a directory. The returned string points somewhere
1010 in the buffer. */
1012 char *
1013 __gnat_readdir (DIR *dirp, char *buffer, int *len)
1015 #if defined (__MINGW32__)
1016 struct _tdirent *dirent = _treaddir ((_TDIR*)dirp);
1018 if (dirent != NULL)
1020 WS2SU (buffer, dirent->d_name, GNAT_MAX_PATH_LEN);
1021 *len = strlen (buffer);
1023 return buffer;
1025 else
1026 return NULL;
1028 #elif defined (HAVE_READDIR_R)
1029 /* If possible, try to use the thread-safe version. */
1030 if (readdir_r (dirp, buffer) != NULL)
1032 *len = strlen (((struct dirent*) buffer)->d_name);
1033 return ((struct dirent*) buffer)->d_name;
1035 else
1036 return NULL;
1038 #else
1039 struct dirent *dirent = (struct dirent *) readdir (dirp);
1041 if (dirent != NULL)
1043 strcpy (buffer, dirent->d_name);
1044 *len = strlen (buffer);
1045 return buffer;
1047 else
1048 return NULL;
1050 #endif
1053 /* Close a directory entry. */
1055 int __gnat_closedir (DIR *dirp)
1057 #ifdef __MINGW32__
1058 return _tclosedir ((_TDIR*)dirp);
1060 #else
1061 return closedir (dirp);
1062 #endif
1065 /* Returns 1 if readdir is thread safe, 0 otherwise. */
1068 __gnat_readdir_is_thread_safe (void)
1070 #ifdef HAVE_READDIR_R
1071 return 1;
1072 #else
1073 return 0;
1074 #endif
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;
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. */
1086 static time_t
1087 win32_filetime (HANDLE h)
1089 union
1091 FILETIME ft_time;
1092 unsigned long long ull_time;
1093 } t_write;
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>. */
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;
1103 #endif
1105 /* Return a GNAT time stamp given a file name. */
1107 OS_Time
1108 __gnat_file_time_name (char *name)
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;
1117 #elif defined (_WIN32)
1118 time_t ret = -1;
1119 TCHAR wname[GNAT_MAX_PATH_LEN];
1121 S2WSU (wname, name, GNAT_MAX_PATH_LEN);
1123 HANDLE h = CreateFile
1124 (wname, GENERIC_READ, FILE_SHARE_READ, 0,
1125 OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0);
1127 if (h != INVALID_HANDLE_VALUE)
1129 ret = win32_filetime (h);
1130 CloseHandle (h);
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
1145 #endif
1148 /* Return a GNAT time stamp given a file descriptor. */
1150 OS_Time
1151 __gnat_file_time_fd (int fd)
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. */
1159 #if defined (__EMX__) || defined (MSDOS)
1160 #ifdef __EMX__
1162 FILESTATUS fs;
1163 int ret = DosQueryFileInfo (fd, 1, (unsigned char *) &fs,
1164 sizeof (FILESTATUS));
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;
1173 #else
1174 struct ftime fs;
1175 int ret = getftime (fd, &fs);
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
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. */
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;
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;
1203 if (file_year > 20)
1204 days_passed -= 1;
1206 days_passed += cum_days[file_month - 1];
1207 if (years_since_leap == 0 && file_year != 20 && file_month > 2)
1208 days_passed++;
1210 days_passed += file_day - 1;
1212 /* OK - have whole days. Multiply -- then add in other parts. */
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;
1220 #elif defined (_WIN32)
1221 HANDLE h = (HANDLE) _get_osfhandle (fd);
1222 time_t ret = win32_filetime (h);
1223 return (OS_Time) ret;
1225 #else
1226 struct stat statbuf;
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
1238 #endif
1241 /* Set the file time stamp. */
1243 void
1244 __gnat_set_file_time_name (char *name, time_t time_stamp)
1246 #if defined (__EMX__) || defined (MSDOS) || defined (__vxworks)
1248 /* Code to implement __gnat_set_file_time_name for these systems. */
1250 #elif defined (_WIN32)
1251 union
1253 FILETIME ft_time;
1254 unsigned long long ull_time;
1255 } t_write;
1256 TCHAR wname[GNAT_MAX_PATH_LEN];
1258 S2WSU (wname, name, GNAT_MAX_PATH_LEN);
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;
1271 SetFileTime(h, NULL, NULL, &t_write.ft_time);
1272 CloseHandle (h);
1273 return;
1275 #elif defined (VMS)
1276 struct FAB fab;
1277 struct NAM nam;
1279 struct
1281 unsigned long long backup, create, expire, revise;
1282 unsigned int uic;
1283 union
1285 unsigned short value;
1286 struct
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 }};
1296 ATRDEF atrlst[]
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}
1307 FIBDEF fib;
1308 struct dsc$descriptor_fib fibdsc = {sizeof (fib), (void *) &fib};
1310 struct IOSB iosb;
1312 unsigned long long newtime;
1313 unsigned long long revtime;
1314 long status;
1315 short chan;
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};
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);
1338 /* Allocate and initialize a FAB and NAM structures. */
1339 fab = cc$rms_fab;
1340 nam = cc$rms_nam;
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;
1350 /* Validate filespec syntax and device existence. */
1351 status = SYS$PARSE (&fab, 0, 0);
1352 if ((status & 1) != 1)
1353 LIB$SIGNAL (status);
1355 file.string[nam.nam$b_esl] = 0;
1357 /* Find matching filespec. */
1358 status = SYS$SEARCH (&fab, 0, 0);
1359 if ((status & 1) != 1)
1360 LIB$SIGNAL (status);
1362 file.string[nam.nam$b_esl] = 0;
1363 result.string[result.length=nam.nam$b_rsl] = 0;
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);
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;
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);
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);
1402 time_t t;
1404 /* Set creation time to requested time. */
1405 unix_time_to_vms (time_stamp, newtime);
1407 t = time ((time_t) 0);
1409 /* Set revision time to now in local time. */
1410 unix_time_to_vms (t, revtime);
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);
1423 Fat.create = newtime;
1424 Fat.revise = revtime;
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);
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;
1441 /* Set modification time to requested time. */
1442 utimbuf.modtime = time_stamp;
1444 /* Set access time to now in local time. */
1445 t = time ((time_t) 0);
1446 utimbuf.actime = mktime (localtime (&t));
1448 utime (name, &utimbuf);
1449 #endif
1452 #ifdef _WIN32
1453 #include <windows.h>
1454 #endif
1456 /* Get the list of installed standard libraries from the
1457 HKEY_LOCAL_MACHINE\SOFTWARE\Ada Core Technologies\GNAT\Standard Libraries
1458 key. */
1460 char *
1461 __gnat_get_libraries_from_registry (void)
1463 char *result = (char *) "";
1465 #if defined (_WIN32) && ! defined (__vxworks) && ! defined (CROSS_DIRECTORY_STRUCTURE)
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;
1475 /* First open the key. */
1476 res = RegOpenKeyExA (HKEY_LOCAL_MACHINE, "SOFTWARE", 0, KEY_READ, &reg_key);
1478 if (res == ERROR_SUCCESS)
1479 res = RegOpenKeyExA (reg_key, "Ada Core Technologies", 0,
1480 KEY_READ, &reg_key);
1482 if (res == ERROR_SUCCESS)
1483 res = RegOpenKeyExA (reg_key, "GNAT", 0, KEY_READ, &reg_key);
1485 if (res == ERROR_SUCCESS)
1486 res = RegOpenKeyExA (reg_key, "Standard Libraries", 0, KEY_READ, &reg_key);
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++)
1492 value_size = name_size = 256;
1493 res = RegEnumValueA (reg_key, index, (TCHAR*)name, &name_size, 0,
1494 &type, (LPBYTE)value, &value_size);
1496 if (res == ERROR_SUCCESS && type == REG_SZ)
1498 char *old_result = result;
1500 result = (char *) xmalloc (strlen (old_result) + value_size + 2);
1501 strcpy (result, old_result);
1502 strcat (result, value);
1503 strcat (result, ";");
1507 /* Remove the trailing ";". */
1508 if (result[0] != 0)
1509 result[strlen (result) - 1] = 0;
1511 #endif
1512 return result;
1516 __gnat_stat (char *name, struct stat *statbuf)
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;
1525 S2WSU (wname, name, GNAT_MAX_PATH_LEN + 2);
1526 name_len = _tcslen (wname);
1528 if (name_len > GNAT_MAX_PATH_LEN)
1529 return -1;
1531 last_char = wname[name_len - 1];
1533 while (name_len > 1 && (last_char == _T('\\') || last_char == _T('/')))
1535 wname[name_len - 1] = _T('\0');
1536 name_len--;
1537 last_char = wname[name_len - 1];
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("\\"));
1545 return _tstat (wname, statbuf);
1547 #else
1548 return stat (name, statbuf);
1549 #endif
1553 __gnat_file_exists (char *name)
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];
1561 S2WSU (wname, name, GNAT_MAX_PATH_LEN + 2);
1562 return GetFileAttributes (wname) != INVALID_FILE_ATTRIBUTES;
1563 #else
1564 struct stat statbuf;
1566 return !__gnat_stat (name, &statbuf);
1567 #endif
1571 __gnat_is_absolute_path (char *name, int length)
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. */
1578 int index;
1580 if (name[0] == '/')
1581 return 1;
1583 for (index = 0; index < length; index++)
1585 if (name[index] == ':' &&
1586 ((name[index + 1] == '/') ||
1587 (isalpha (name[index + 1]) && index + 2 <= length &&
1588 name[index + 2] == '/')))
1589 return 1;
1591 else if (name[index] == '/')
1592 return 0;
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
1602 #endif
1606 __gnat_is_regular_file (char *name)
1608 int ret;
1609 struct stat statbuf;
1611 ret = __gnat_stat (name, &statbuf);
1612 return (!ret && S_ISREG (statbuf.st_mode));
1616 __gnat_is_directory (char *name)
1618 int ret;
1619 struct stat statbuf;
1621 ret = __gnat_stat (name, &statbuf);
1622 return (!ret && S_ISDIR (statbuf.st_mode));
1626 __gnat_is_readable_file (char *name)
1628 int ret;
1629 int mode;
1630 struct stat statbuf;
1632 ret = __gnat_stat (name, &statbuf);
1633 mode = statbuf.st_mode & S_IRUSR;
1634 return (!ret && mode);
1638 __gnat_is_writable_file (char *name)
1640 int ret;
1641 int mode;
1642 struct stat statbuf;
1644 ret = __gnat_stat (name, &statbuf);
1645 mode = statbuf.st_mode & S_IWUSR;
1646 return (!ret && mode);
1649 void
1650 __gnat_set_writable (char *name)
1652 #ifndef __vxworks
1653 struct stat statbuf;
1655 if (stat (name, &statbuf) == 0)
1657 statbuf.st_mode = statbuf.st_mode | S_IWUSR;
1658 chmod (name, statbuf.st_mode);
1660 #endif
1663 void
1664 __gnat_set_executable (char *name)
1666 #ifndef __vxworks
1667 struct stat statbuf;
1669 if (stat (name, &statbuf) == 0)
1671 statbuf.st_mode = statbuf.st_mode | S_IXUSR;
1672 chmod (name, statbuf.st_mode);
1674 #endif
1677 void
1678 __gnat_set_readonly (char *name)
1680 #ifndef __vxworks
1681 struct stat statbuf;
1683 if (stat (name, &statbuf) == 0)
1685 statbuf.st_mode = statbuf.st_mode & 07577;
1686 chmod (name, statbuf.st_mode);
1688 #endif
1692 __gnat_is_symbolic_link (char *name ATTRIBUTE_UNUSED)
1694 #if defined (__vxworks)
1695 return 0;
1697 #elif defined (_AIX) || defined (__APPLE__) || defined (__unix__)
1698 int ret;
1699 struct stat statbuf;
1701 ret = lstat (name, &statbuf);
1702 return (!ret && S_ISLNK (statbuf.st_mode));
1704 #else
1705 return 0;
1706 #endif
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
1717 __gnat_portable_spawn (char *args[])
1719 int status = 0;
1720 int finished ATTRIBUTE_UNUSED;
1721 int pid ATTRIBUTE_UNUSED;
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], "\"");
1731 status = spawnvp (P_WAIT, args_0, (const char* const*)args);
1733 /* restore previous value */
1734 free (args[0]);
1735 args[0] = (char *)args_0;
1737 if (status < 0)
1738 return -1;
1739 else
1740 return status;
1742 #elif defined (__vxworks)
1743 return -1;
1744 #else
1746 #ifdef __EMX__
1747 pid = spawnvp (P_NOWAIT, args[0], args);
1748 if (pid == -1)
1749 return -1;
1751 #else
1752 pid = fork ();
1753 if (pid < 0)
1754 return -1;
1756 if (pid == 0)
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
1766 #endif
1768 /* The parent. */
1769 finished = waitpid (pid, &status, 0);
1771 if (finished != pid || WIFEXITED (status) == 0)
1772 return -1;
1774 return WEXITSTATUS (status);
1775 #endif
1777 return 0;
1780 /* Create a copy of the given file descriptor.
1781 Return -1 if an error occurred. */
1784 __gnat_dup (int oldfd)
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
1795 /* Make newfd be the copy of oldfd, closing newfd first if necessary.
1796 Return -1 if an error occurred. */
1799 __gnat_dup2 (int oldfd, int newfd)
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
1810 /* WIN32 code to implement a wait call that wait for any child process. */
1812 #ifdef _WIN32
1814 /* Synchronization code, to be thread safe. */
1816 static CRITICAL_SECTION plist_cs;
1818 void
1819 __gnat_plist_init (void)
1821 InitializeCriticalSection (&plist_cs);
1824 static void
1825 plist_enter (void)
1827 EnterCriticalSection (&plist_cs);
1830 static void
1831 plist_leave (void)
1833 LeaveCriticalSection (&plist_cs);
1836 typedef struct _process_list
1838 HANDLE h;
1839 struct _process_list *next;
1840 } Process_List;
1842 static Process_List *PLIST = NULL;
1844 static int plist_length = 0;
1846 static void
1847 add_handle (HANDLE h)
1849 Process_List *pl;
1851 pl = (Process_List *) xmalloc (sizeof (Process_List));
1853 plist_enter();
1855 /* -------------------- critical section -------------------- */
1856 pl->h = h;
1857 pl->next = PLIST;
1858 PLIST = pl;
1859 ++plist_length;
1860 /* -------------------- critical section -------------------- */
1862 plist_leave();
1865 static void
1866 remove_handle (HANDLE h)
1868 Process_List *pl;
1869 Process_List *prev = NULL;
1871 plist_enter();
1873 /* -------------------- critical section -------------------- */
1874 pl = PLIST;
1875 while (pl)
1877 if (pl->h == h)
1879 if (pl == PLIST)
1880 PLIST = pl->next;
1881 else
1882 prev->next = pl->next;
1883 free (pl);
1884 break;
1886 else
1888 prev = pl;
1889 pl = pl->next;
1893 --plist_length;
1894 /* -------------------- critical section -------------------- */
1896 plist_leave();
1899 static int
1900 win32_no_block_spawn (char *command, char *args[])
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;
1910 /* compute the total command line length */
1911 k = 0;
1912 while (args[k])
1914 csize += strlen (args[k]) + 1;
1915 k++;
1918 full_command = (char *) xmalloc (csize);
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;
1930 /* Security attributes. */
1931 SA.nLength = sizeof (SECURITY_ATTRIBUTES);
1932 SA.bInheritHandle = TRUE;
1933 SA.lpSecurityDescriptor = NULL;
1935 /* Prepare the command string. */
1936 strcpy (full_command, command);
1937 strcat (full_command, " ");
1939 k = 1;
1940 while (args[k])
1942 strcat (full_command, args[k]);
1943 strcat (full_command, " ");
1944 k++;
1948 int wsize = csize * 2;
1949 TCHAR *wcommand = (TCHAR *) xmalloc (wsize);
1951 S2WSU (wcommand, full_command, wsize);
1953 free (full_command);
1955 result = CreateProcess
1956 (NULL, wcommand, &SA, NULL, TRUE,
1957 GetPriorityClass (GetCurrentProcess()), NULL, NULL, &SI, &PI);
1959 free (wcommand);
1962 if (result == TRUE)
1964 add_handle (PI.hProcess);
1965 CloseHandle (PI.hThread);
1966 return (int) PI.hProcess;
1968 else
1969 return -1;
1972 static int
1973 win32_wait (int *status)
1975 DWORD exitcode;
1976 HANDLE *hl;
1977 HANDLE h;
1978 DWORD res;
1979 int k;
1980 Process_List *pl;
1982 if (plist_length == 0)
1984 errno = ECHILD;
1985 return -1;
1988 hl = (HANDLE *) xmalloc (sizeof (HANDLE) * plist_length);
1990 k = 0;
1991 plist_enter();
1993 /* -------------------- critical section -------------------- */
1994 pl = PLIST;
1995 while (pl)
1997 hl[k++] = pl->h;
1998 pl = pl->next;
2000 /* -------------------- critical section -------------------- */
2002 plist_leave();
2004 res = WaitForMultipleObjects (plist_length, hl, FALSE, INFINITE);
2005 h = hl[res - WAIT_OBJECT_0];
2006 free (hl);
2008 remove_handle (h);
2010 GetExitCodeProcess (h, &exitcode);
2011 CloseHandle (h);
2013 *status = (int) exitcode;
2014 return (int) h;
2017 #endif
2020 __gnat_portable_no_block_spawn (char *args[])
2022 int pid = 0;
2024 #if defined (__EMX__) || defined (MSDOS)
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. */
2034 if (spawnvp (P_WAIT, args[0], args) != 0)
2035 return -1;
2037 #elif defined (_WIN32)
2039 pid = win32_no_block_spawn (args[0], args);
2040 return pid;
2042 #elif defined (__vxworks)
2043 return -1;
2045 #else
2046 pid = fork ();
2048 if (pid == 0)
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
2059 #endif
2061 return pid;
2065 __gnat_portable_wait (int *process_status)
2067 int status = 0;
2068 int pid = 0;
2070 #if defined (_WIN32)
2072 pid = win32_wait (&status);
2074 #elif defined (__EMX__) || defined (MSDOS)
2075 /* ??? See corresponding comment in portable_no_block_spawn. */
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
2082 pid = waitpid (-1, &status, 0);
2083 status = status & 0xffff;
2084 #endif
2086 *process_status = status;
2087 return pid;
2090 void
2091 __gnat_os_exit (int status)
2093 exit (status);
2096 /* Locate a regular file, give a Path value. */
2098 char *
2099 __gnat_locate_regular_file (char *file_name, char *path_val)
2101 char *ptr;
2102 char *file_path = alloca (strlen (file_name) + 1);
2103 int absolute;
2105 /* Return immediately if file_name is empty */
2107 if (*file_name == '\0')
2108 return 0;
2110 /* Remove quotes around file_name if present */
2112 ptr = file_name;
2113 if (*ptr == '"')
2114 ptr++;
2116 strcpy (file_path, ptr);
2118 ptr = file_path + strlen (file_path) - 1;
2120 if (*ptr == '"')
2121 *ptr = '\0';
2123 /* Handle absolute pathnames. */
2125 absolute = __gnat_is_absolute_path (file_path, strlen (file_name));
2127 if (absolute)
2129 if (__gnat_is_regular_file (file_path))
2130 return xstrdup (file_path);
2132 return 0;
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++)
2140 if (*ptr != 0)
2142 if (__gnat_is_regular_file (file_name))
2143 return xstrdup (file_name);
2146 if (path_val == 0)
2147 return 0;
2150 /* The result has to be smaller than path_val + file_name. */
2151 char *file_path = alloca (strlen (path_val) + strlen (file_name) + 2);
2153 for (;;)
2155 for (; *path_val == PATH_SEPARATOR; path_val++)
2158 if (*path_val == 0)
2159 return 0;
2161 /* Skip the starting quote */
2163 if (*path_val == '"')
2164 path_val++;
2166 for (ptr = file_path; *path_val && *path_val != PATH_SEPARATOR; )
2167 *ptr++ = *path_val++;
2169 ptr--;
2171 /* Skip the ending quote */
2173 if (*ptr == '"')
2174 ptr--;
2176 if (*ptr != '/' && *ptr != DIR_SEPARATOR)
2177 *++ptr = DIR_SEPARATOR;
2179 strcpy (++ptr, file_name);
2181 if (__gnat_is_regular_file (file_path))
2182 return xstrdup (file_path);
2186 return 0;
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. */
2193 char *
2194 __gnat_locate_exec (char *exec_name, char *path_val)
2196 char *ptr;
2197 if (!strstr (exec_name, HOST_EXECUTABLE_SUFFIX))
2199 char *full_exec_name
2200 = alloca (strlen (exec_name) + strlen (HOST_EXECUTABLE_SUFFIX) + 1);
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);
2206 if (ptr == 0)
2207 return __gnat_locate_regular_file (exec_name, path_val);
2208 return ptr;
2210 else
2211 return __gnat_locate_regular_file (exec_name, path_val);
2214 /* Locate an executable using the Systems default PATH. */
2216 char *
2217 __gnat_locate_exec_on_path (char *exec_name)
2219 char *apath_val;
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 */
2228 #define EXPAND_BUFFER_SIZE 32767
2230 wapath_val = alloca (EXPAND_BUFFER_SIZE);
2232 wapath_val [0] = '.';
2233 wapath_val [1] = ';';
2235 DWORD res = ExpandEnvironmentStrings
2236 (wpath_val, &wapath_val[2], EXPAND_BUFFER_SIZE - 2);
2238 if (!res) wapath_val [0] = _T('\0');
2240 apath_val = alloca (EXPAND_BUFFER_SIZE);
2242 WS2SU (apath_val, wapath_val, EXPAND_BUFFER_SIZE);
2243 return __gnat_locate_exec (exec_name, apath_val);
2245 #else
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
2259 #ifdef VMS
2261 /* These functions are used to translate to and from VMS and Unix syntax
2262 file, directory and path specifications. */
2264 #define MAXPATH 256
2265 #define MAXNAMES 256
2266 #define NEW_CANONICAL_FILELIST_INCREMENT 64
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];
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. */
2283 static int
2284 wildcard_translate_unix (char *name)
2286 char *ver;
2287 char buff [MAXPATH];
2289 strncpy (buff, name, MAXPATH);
2290 buff [MAXPATH - 1] = (char) 0;
2291 ver = strrchr (buff, '.');
2293 /* Chop off the version. */
2294 if (ver)
2295 *ver = 0;
2297 /* Dynamically extend the allocation by the increment. */
2298 if (new_canonical_filelist_in_use == new_canonical_filelist_allocated)
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 *));
2306 new_canonical_filelist[new_canonical_filelist_in_use++] = xstrdup (buff);
2308 return 1;
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. */
2316 __gnat_to_canonical_file_list_init (char *filespec, int onlydirs)
2318 int len;
2319 char buff [MAXPATH];
2321 len = strlen (filespec);
2322 strncpy (buff, filespec, MAXPATH);
2324 /* Only look for directories */
2325 if (onlydirs && !strstr (&buff [len-5], "*.dir"))
2326 strncat (buff, "*.dir", MAXPATH);
2328 buff [MAXPATH - 1] = (char) 0;
2330 decc$from_vms (buff, wildcard_translate_unix, 1);
2332 /* Remove the .dir extension. */
2333 if (onlydirs)
2335 int i;
2336 char *ext;
2338 for (i = 0; i < new_canonical_filelist_in_use; i++)
2340 ext = strstr (new_canonical_filelist[i], ".dir");
2341 if (ext)
2342 *ext = 0;
2346 return new_canonical_filelist_in_use;
2349 /* Return the next filespec in the list. */
2351 char *
2352 __gnat_to_canonical_file_list_next ()
2354 return new_canonical_filelist[new_canonical_filelist_index++];
2357 /* Free storage used in the wildcard expansion. */
2359 void
2360 __gnat_to_canonical_file_list_free ()
2362 int i;
2364 for (i = 0; i < new_canonical_filelist_in_use; i++)
2365 free (new_canonical_filelist[i]);
2367 free (new_canonical_filelist);
2369 new_canonical_filelist_in_use = 0;
2370 new_canonical_filelist_allocated = 0;
2371 new_canonical_filelist_index = 0;
2372 new_canonical_filelist = 0;
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 */
2380 #define NAM$C_MAXRSS 1024
2382 char *
2383 __gnat_translate_vms (char *src)
2385 static char retbuf [NAM$C_MAXRSS+1];
2386 char *srcendpos, *pos1, *pos2, *retpos;
2387 int disp, path_present = 0;
2389 if (!src) return NULL;
2391 srcendpos = strchr (src, '\0');
2392 retpos = retbuf;
2394 /* Look for the node and/or device in front of the path */
2395 pos1 = src;
2396 pos2 = strchr (pos1, ':');
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, ':');
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++) = '/';
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;
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++;
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++;
2444 else if (*pos1 == '.') {
2445 /* Relative path */
2446 *(retpos++) = '.';
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;
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++) = '/';
2472 retpos--;
2473 break;
2475 /* otherwise fall through to default */
2476 default:
2477 *(retpos++) = *(pos1++);
2480 pos1++;
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;
2500 *retpos = '\0';
2502 return retbuf;
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. */
2511 char *
2512 __gnat_to_canonical_dir_spec (char *dirspec, int prefixflag)
2514 int len;
2516 strcpy (new_canonical_dirspec, "");
2517 if (strlen (dirspec))
2519 char *dirspec1;
2521 if (strchr (dirspec, ']') || strchr (dirspec, ':'))
2523 strncpy (new_canonical_dirspec,
2524 __gnat_translate_vms (dirspec),
2525 MAXPATH);
2527 else if (!strchr (dirspec, '/') && (dirspec1 = getenv (dirspec)) != 0)
2529 strncpy (new_canonical_dirspec,
2530 __gnat_translate_vms (dirspec1),
2531 MAXPATH);
2533 else
2535 strncpy (new_canonical_dirspec, dirspec, MAXPATH);
2539 len = strlen (new_canonical_dirspec);
2540 if (prefixflag && new_canonical_dirspec [len-1] != '/')
2541 strncat (new_canonical_dirspec, "/", MAXPATH);
2543 new_canonical_dirspec [MAXPATH - 1] = (char) 0;
2545 return new_canonical_dirspec;
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. */
2555 char *
2556 __gnat_to_canonical_file_spec (char *filespec)
2558 char *filespec1;
2560 strncpy (new_canonical_filespec, "", MAXPATH);
2562 if (strchr (filespec, ']') || strchr (filespec, ':'))
2564 char *tspec = (char *) __gnat_translate_vms (filespec);
2566 if (tspec != (char *) -1)
2567 strncpy (new_canonical_filespec, tspec, MAXPATH);
2569 else if ((strlen (filespec) == strspn (filespec,
2570 "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_"))
2571 && (filespec1 = getenv (filespec)))
2573 char *tspec = (char *) __gnat_translate_vms (filespec1);
2575 if (tspec != (char *) -1)
2576 strncpy (new_canonical_filespec, tspec, MAXPATH);
2578 else
2580 strncpy (new_canonical_filespec, filespec, MAXPATH);
2583 new_canonical_filespec [MAXPATH - 1] = (char) 0;
2585 return new_canonical_filespec;
2588 /* Translate a VMS syntax path specification into Unix syntax.
2589 If no indicators of VMS syntax found, return input string. */
2591 char *
2592 __gnat_to_canonical_path_spec (char *pathspec)
2594 char *curr, *next, buff [MAXPATH];
2596 if (pathspec == 0)
2597 return pathspec;
2599 /* If there are /'s, assume it's a Unix path spec and return. */
2600 if (strchr (pathspec, '/'))
2601 return pathspec;
2603 new_canonical_pathspec[0] = 0;
2604 curr = pathspec;
2606 for (;;)
2608 next = strchr (curr, ',');
2609 if (next == 0)
2610 next = strchr (curr, 0);
2612 strncpy (buff, curr, next - curr);
2613 buff[next - curr] = 0;
2615 /* Check for wildcards and expand if present. */
2616 if (strchr (buff, '*') || strchr (buff, '%') || strstr (buff, "..."))
2618 int i, dirs;
2620 dirs = __gnat_to_canonical_file_list_init (buff, 1);
2621 for (i = 0; i < dirs; i++)
2623 char *next_dir;
2625 next_dir = __gnat_to_canonical_file_list_next ();
2626 strncat (new_canonical_pathspec, next_dir, MAXPATH);
2628 /* Don't append the separator after the last expansion. */
2629 if (i+1 < dirs)
2630 strncat (new_canonical_pathspec, ":", MAXPATH);
2633 __gnat_to_canonical_file_list_free ();
2635 else
2636 strncat (new_canonical_pathspec,
2637 __gnat_to_canonical_dir_spec (buff, 0), MAXPATH);
2639 if (*next == 0)
2640 break;
2642 strncat (new_canonical_pathspec, ":", MAXPATH);
2643 curr = next + 1;
2646 new_canonical_pathspec [MAXPATH - 1] = (char) 0;
2648 return new_canonical_pathspec;
2651 static char filename_buff [MAXPATH];
2653 static int
2654 translate_unix (char *name, int type)
2656 strncpy (filename_buff, name, MAXPATH);
2657 filename_buff [MAXPATH - 1] = (char) 0;
2658 return 0;
2661 /* Translate a Unix syntax path spec into a VMS style (comma separated list of
2662 directories. */
2664 static char *
2665 to_host_path_spec (char *pathspec)
2667 char *curr, *next, buff [MAXPATH];
2669 if (pathspec == 0)
2670 return pathspec;
2672 /* Can't very well test for colons, since that's the Unix separator! */
2673 if (strchr (pathspec, ']') || strchr (pathspec, ','))
2674 return pathspec;
2676 new_host_pathspec[0] = 0;
2677 curr = pathspec;
2679 for (;;)
2681 next = strchr (curr, ':');
2682 if (next == 0)
2683 next = strchr (curr, 0);
2685 strncpy (buff, curr, next - curr);
2686 buff[next - curr] = 0;
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;
2695 new_host_pathspec [MAXPATH - 1] = (char) 0;
2697 return new_host_pathspec;
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. */
2705 char *
2706 __gnat_to_host_dir_spec (char *dirspec, int prefixflag ATTRIBUTE_UNUSED)
2708 int len = strlen (dirspec);
2710 strncpy (new_host_dirspec, dirspec, MAXPATH);
2711 new_host_dirspec [MAXPATH - 1] = (char) 0;
2713 if (strchr (new_host_dirspec, ']') || strchr (new_host_dirspec, ':'))
2714 return new_host_dirspec;
2716 while (len > 1 && new_host_dirspec[len - 1] == '/')
2718 new_host_dirspec[len - 1] = 0;
2719 len--;
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;
2726 return new_host_dirspec;
2729 /* Translate a Unix syntax file specification into VMS syntax.
2730 If indicators of VMS syntax found, return input string. */
2732 char *
2733 __gnat_to_host_file_spec (char *filespec)
2735 strncpy (new_host_filespec, "", MAXPATH);
2736 if (strchr (filespec, ']') || strchr (filespec, ':'))
2738 strncpy (new_host_filespec, filespec, MAXPATH);
2740 else
2742 decc$to_vms (filespec, translate_unix, 1, 1);
2743 strncpy (new_host_filespec, filename_buff, MAXPATH);
2746 new_host_filespec [MAXPATH - 1] = (char) 0;
2748 return new_host_filespec;
2751 void
2752 __gnat_adjust_os_resource_limits ()
2754 SYS$ADJWSL (131072, 0);
2757 #else /* VMS */
2759 /* Dummy functions for Osint import for non-VMS systems. */
2762 __gnat_to_canonical_file_list_init
2763 (char *dirspec ATTRIBUTE_UNUSED, int onlydirs ATTRIBUTE_UNUSED)
2765 return 0;
2768 char *
2769 __gnat_to_canonical_file_list_next (void)
2771 return (char *) "";
2774 void
2775 __gnat_to_canonical_file_list_free (void)
2779 char *
2780 __gnat_to_canonical_dir_spec (char *dirspec, int prefixflag ATTRIBUTE_UNUSED)
2782 return dirspec;
2785 char *
2786 __gnat_to_canonical_file_spec (char *filespec)
2788 return filespec;
2791 char *
2792 __gnat_to_canonical_path_spec (char *pathspec)
2794 return pathspec;
2797 char *
2798 __gnat_to_host_dir_spec (char *dirspec, int prefixflag ATTRIBUTE_UNUSED)
2800 return dirspec;
2803 char *
2804 __gnat_to_host_file_spec (char *filespec)
2806 return filespec;
2809 void
2810 __gnat_adjust_os_resource_limits (void)
2814 #endif
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. */
2820 #if defined (__EMX__)
2821 void __dummy () {}
2822 #endif
2824 #if defined (__mips_vxworks)
2826 _flush_cache()
2828 CACHE_USER_FLUSH (0, ENTIRE_CACHE);
2830 #endif
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)))
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. */
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)
2857 *len = 0;
2859 #endif
2861 #if defined (_WIN32)
2862 int __gnat_argument_needs_quote = 1;
2863 #else
2864 int __gnat_argument_needs_quote = 0;
2865 #endif
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
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
2886 /* This functions copy the file attributes from a source file to a
2887 destination file.
2889 mode = 0 : In this mode copy only the file time stamps (last access and
2890 last modification time stamps).
2892 mode = 1 : In this mode, time stamps and read/write/execute attributes are
2893 copied.
2895 Returns 0 if operation was successful and -1 in case of error. */
2898 __gnat_copy_attribs (char *from, char *to, int mode)
2900 #if defined (VMS) || defined (__vxworks)
2901 return -1;
2902 #else
2903 struct stat fbuf;
2904 struct utimbuf tbuf;
2906 if (stat (from, &fbuf) == -1)
2908 return -1;
2911 tbuf.actime = fbuf.st_atime;
2912 tbuf.modtime = fbuf.st_mtime;
2914 if (utime (to, &tbuf) == -1)
2916 return -1;
2919 if (mode == 1)
2921 if (chmod (to, fbuf.st_mode) == -1)
2923 return -1;
2927 return 0;
2928 #endif
2932 __gnat_lseek (int fd, long offset, int whence)
2934 return (int) lseek (fd, offset, whence);
2937 /* This function returns the major version number of GCC being used. */
2939 get_gcc_version (void)
2941 #ifdef IN_RTS
2942 return __GNUC__;
2943 #else
2944 return (int) (version_string[0] - '0');
2945 #endif
2949 __gnat_set_close_on_exec (int fd ATTRIBUTE_UNUSED,
2950 int close_on_exec_p ATTRIBUTE_UNUSED)
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
2970 /* Indicates if platforms supports automatic initialization through the
2971 constructor mechanism */
2973 __gnat_binder_supports_auto_init ()
2975 #ifdef VMS
2976 return 0;
2977 #else
2978 return 1;
2979 #endif
2982 /* Indicates that Stand-Alone Libraries are automatically initialized through
2983 the constructor mechanism */
2985 __gnat_sals_init_using_constructors ()
2987 #if defined (__vxworks) || defined (__Lynx__) || defined (VMS)
2988 return 0;
2989 #else
2990 return 1;
2991 #endif