1 /****************************************************************************
3 * GNAT COMPILER COMPONENTS *
7 * C Implementation File *
9 * Copyright (C) 1992-2009, Free Software Foundation, Inc. *
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 3, 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. *
18 * As a special exception under Section 7 of GPL version 3, you are granted *
19 * additional permissions described in the GCC Runtime Library Exception, *
20 * version 3.1, as published by the Free Software Foundation. *
22 * You should have received a copy of the GNU General Public License and *
23 * a copy of the GCC Runtime Library Exception along with this program; *
24 * see the files COPYING3 and COPYING.RUNTIME respectively. If not, see *
25 * <http://www.gnu.org/licenses/>. *
27 * GNAT was originally developed by the GNAT team at New York University. *
28 * Extensive contributions were provided by Ada Core Technologies Inc. *
30 ****************************************************************************/
32 /* This file contains those routines named by Import pragmas in
33 packages in the GNAT hierarchy (especially GNAT.OS_Lib) and in
34 package Osint. Many of the subprograms in OS_Lib import standard
35 library calls directly. This file contains all other routines. */
39 /* No need to redefine exit here. */
42 /* We want to use the POSIX variants of include files. */
46 #if defined (__mips_vxworks)
48 #endif /* __mips_vxworks */
54 #define HOST_EXECUTABLE_SUFFIX ".exe"
55 #define HOST_OBJECT_SUFFIX ".obj"
69 /* We don't have libiberty, so use malloc. */
70 #define xmalloc(S) malloc (S)
71 #define xrealloc(V,S) realloc (V,S)
78 #if defined (__MINGW32__)
86 /* Current code page to use, set in initialize.c. */
90 #include <sys/utime.h>
92 /* For isalpha-like tests in the compiler, we're expected to resort to
93 safe-ctype.h/ISALPHA. This isn't available for the runtime library
94 build, so we fallback on ctype.h/isalpha there. */
98 #define ISALPHA isalpha
101 #elif defined (__Lynx__)
103 /* Lynx utime.h only defines the entities of interest to us if
104 defined (VMOS_DEV), so ... */
113 /* wait.h processing */
116 #include <sys/wait.h>
118 #elif defined (__vxworks) && defined (__RTP__)
120 #elif defined (__Lynx__)
121 /* ??? We really need wait.h and it includes resource.h on Lynx. GCC
122 has a resource.h header as well, included instead of the lynx
123 version in our setup, causing lots of errors. We don't really need
124 the lynx contents of this file, so just workaround the issue by
125 preventing the inclusion of the GCC header from doing anything. */
126 #define GCC_RESOURCE_H
127 #include <sys/wait.h>
128 #elif defined (__nucleus__)
129 /* No wait() or waitpid() calls available */
132 #include <sys/wait.h>
135 #if defined (__EMX__) || defined (MSDOS) || defined (_WIN32)
138 /* Header files and definitions for __gnat_set_file_time_name. */
140 #define __NEW_STARLET 1
142 #include <vms/atrdef.h>
143 #include <vms/fibdef.h>
144 #include <vms/stsdef.h>
145 #include <vms/iodef.h>
147 #include <vms/descrip.h>
151 /* Use native 64-bit arithmetic. */
152 #define unix_time_to_vms(X,Y) \
153 { unsigned long long reftime, tmptime = (X); \
154 $DESCRIPTOR (unixtime,"1-JAN-1970 0:00:00.00"); \
155 SYS$BINTIM (&unixtime, &reftime); \
156 Y = tmptime * 10000000 + reftime; }
158 /* descrip.h doesn't have everything ... */
159 typedef struct fibdef* __fibdef_ptr32 __attribute__ (( mode (SI) ));
160 struct dsc$descriptor_fib
162 unsigned int fib$l_len;
163 __fibdef_ptr32 fib$l_addr;
166 /* I/O Status Block. */
169 unsigned short status, count;
173 static char *tryfile;
175 /* Variable length string. */
179 char string[NAM$C_MAXRSS+1];
186 #if defined (__EMX__) || defined (MSDOS) || defined (_WIN32)
197 #define DIR_SEPARATOR '\\'
202 /* Define symbols O_BINARY and O_TEXT as harmless zeroes if they are not
203 defined in the current system. On DOS-like systems these flags control
204 whether the file is opened/created in text-translation mode (CR/LF in
205 external file mapped to LF in internal file), but in Unix-like systems,
206 no text translation is required, so these flags have no effect. */
208 #if defined (__EMX__)
224 #ifndef HOST_EXECUTABLE_SUFFIX
225 #define HOST_EXECUTABLE_SUFFIX ""
228 #ifndef HOST_OBJECT_SUFFIX
229 #define HOST_OBJECT_SUFFIX ".o"
232 #ifndef PATH_SEPARATOR
233 #define PATH_SEPARATOR ':'
236 #ifndef DIR_SEPARATOR
237 #define DIR_SEPARATOR '/'
240 /* Check for cross-compilation */
241 #if defined (CROSS_COMPILE) || defined (CROSS_DIRECTORY_STRUCTURE)
243 int __gnat_is_cross_compiler = 1;
246 int __gnat_is_cross_compiler = 0;
249 char __gnat_dir_separator = DIR_SEPARATOR;
251 char __gnat_path_separator = PATH_SEPARATOR;
253 /* The GNAT_LIBRARY_TEMPLATE contains a list of expressions that define
254 the base filenames that libraries specified with -lsomelib options
255 may have. This is used by GNATMAKE to check whether an executable
256 is up-to-date or not. The syntax is
258 library_template ::= { pattern ; } pattern NUL
259 pattern ::= [ prefix ] * [ postfix ]
261 These should only specify names of static libraries as it makes
262 no sense to determine at link time if dynamic-link libraries are
263 up to date or not. Any libraries that are not found are supposed
266 * if they are needed but not present, the link
269 * otherwise they are libraries in the system paths and so
270 they are considered part of the system and not checked
273 ??? This should be part of a GNAT host-specific compiler
274 file instead of being included in all user applications
275 as well. This is only a temporary work-around for 3.11b. */
277 #ifndef GNAT_LIBRARY_TEMPLATE
278 #if defined (__EMX__)
279 #define GNAT_LIBRARY_TEMPLATE "*.a"
281 #define GNAT_LIBRARY_TEMPLATE "*.olb"
283 #define GNAT_LIBRARY_TEMPLATE "lib*.a"
287 const char *__gnat_library_template = GNAT_LIBRARY_TEMPLATE;
289 /* This variable is used in hostparm.ads to say whether the host is a VMS
292 const int __gnat_vmsp = 1;
294 const int __gnat_vmsp = 0;
298 #define GNAT_MAX_PATH_LEN MAX_PATH
301 #define GNAT_MAX_PATH_LEN 256 /* PATH_MAX */
303 #elif defined (__vxworks) || defined (__OPENNT) || defined(__nucleus__)
304 #define GNAT_MAX_PATH_LEN PATH_MAX
308 #if defined (__MINGW32__)
312 #include <sys/param.h>
316 #include <sys/param.h>
320 #define GNAT_MAX_PATH_LEN MAXPATHLEN
322 #define GNAT_MAX_PATH_LEN 256
327 /* The __gnat_max_path_len variable is used to export the maximum
328 length of a path name to Ada code. max_path_len is also provided
329 for compatibility with older GNAT versions, please do not use
332 int __gnat_max_path_len = GNAT_MAX_PATH_LEN;
333 int max_path_len = GNAT_MAX_PATH_LEN;
335 /* Control whether we can use ACL on Windows. */
337 int __gnat_use_acl = 1;
339 /* The following macro HAVE_READDIR_R should be defined if the
340 system provides the routine readdir_r. */
341 #undef HAVE_READDIR_R
343 #if defined(VMS) && defined (__LONG_POINTERS)
345 /* Return a 32 bit pointer to an array of 32 bit pointers
346 given a 64 bit pointer to an array of 64 bit pointers */
348 typedef __char_ptr32 *__char_ptr_char_ptr32 __attribute__ ((mode (SI)));
350 static __char_ptr_char_ptr32
351 to_ptr32 (char **ptr64)
354 __char_ptr_char_ptr32 short_argv;
356 for (argc=0; ptr64[argc]; argc++);
358 /* Reallocate argv with 32 bit pointers. */
359 short_argv = (__char_ptr_char_ptr32) decc$malloc
360 (sizeof (__char_ptr32) * (argc + 1));
362 for (argc=0; ptr64[argc]; argc++)
363 short_argv[argc] = (__char_ptr32) decc$strdup (ptr64[argc]);
365 short_argv[argc] = (__char_ptr32) 0;
369 #define MAYBE_TO_PTR32(argv) to_ptr32 (argv)
371 #define MAYBE_TO_PTR32(argv) argv
378 time_t res = time (NULL);
379 return (OS_Time) res;
382 /* Return the current local time as a string in the ISO 8601 format of
383 "YYYY-MM-DD HH:MM:SS.SS". The returned string is 22 + 1 (NULL) characters
387 __gnat_current_time_string
390 const char *format = "%Y-%m-%d %H:%M:%S";
391 /* Format string necessary to describe the ISO 8601 format */
393 const time_t t_val = time (NULL);
395 strftime (result, 22, format, localtime (&t_val));
396 /* Convert the local time into a string following the ISO format, copying
397 at most 22 characters into the result string. */
402 /* The sub-seconds are manually set to zero since type time_t lacks the
403 precision necessary for nanoseconds. */
417 time_t time = (time_t) *p_time;
420 /* On Windows systems, the time is sometimes rounded up to the nearest
421 even second, so if the number of seconds is odd, increment it. */
427 res = localtime (&time);
429 res = gmtime (&time);
434 *p_year = res->tm_year;
435 *p_month = res->tm_mon;
436 *p_day = res->tm_mday;
437 *p_hours = res->tm_hour;
438 *p_mins = res->tm_min;
439 *p_secs = res->tm_sec;
442 *p_year = *p_month = *p_day = *p_hours = *p_mins = *p_secs = 0;
445 /* Place the contents of the symbolic link named PATH in the buffer BUF,
446 which has size BUFSIZ. If PATH is a symbolic link, then return the number
447 of characters of its content in BUF. Otherwise, return -1.
448 For systems not supporting symbolic links, always return -1. */
451 __gnat_readlink (char *path ATTRIBUTE_UNUSED,
452 char *buf ATTRIBUTE_UNUSED,
453 size_t bufsiz ATTRIBUTE_UNUSED)
455 #if defined (MSDOS) || defined (_WIN32) || defined (__EMX__) \
456 || defined (VMS) || defined(__vxworks) || defined (__nucleus__)
459 return readlink (path, buf, bufsiz);
463 /* Creates a symbolic link named NEWPATH which contains the string OLDPATH.
464 If NEWPATH exists it will NOT be overwritten.
465 For systems not supporting symbolic links, always return -1. */
468 __gnat_symlink (char *oldpath ATTRIBUTE_UNUSED,
469 char *newpath ATTRIBUTE_UNUSED)
471 #if defined (MSDOS) || defined (_WIN32) || defined (__EMX__) \
472 || defined (VMS) || defined(__vxworks) || defined (__nucleus__)
475 return symlink (oldpath, newpath);
479 /* Try to lock a file, return 1 if success. */
481 #if defined (__vxworks) || defined (__nucleus__) || defined (MSDOS) \
482 || defined (_WIN32) || defined (__EMX__) || defined (VMS)
484 /* Version that does not use link. */
487 __gnat_try_lock (char *dir, char *file)
491 TCHAR wfull_path[GNAT_MAX_PATH_LEN];
492 TCHAR wfile[GNAT_MAX_PATH_LEN];
493 TCHAR wdir[GNAT_MAX_PATH_LEN];
495 S2WSC (wdir, dir, GNAT_MAX_PATH_LEN);
496 S2WSC (wfile, file, GNAT_MAX_PATH_LEN);
498 _stprintf (wfull_path, _T("%s%c%s"), wdir, _T(DIR_SEPARATOR), wfile);
499 fd = _topen (wfull_path, O_CREAT | O_EXCL, 0600);
503 sprintf (full_path, "%s%c%s", dir, DIR_SEPARATOR, file);
504 fd = open (full_path, O_CREAT | O_EXCL, 0600);
516 /* Version using link(), more secure over NFS. */
517 /* See TN 6913-016 for discussion ??? */
520 __gnat_try_lock (char *dir, char *file)
524 GNAT_STRUCT_STAT stat_result;
527 sprintf (full_path, "%s%c%s", dir, DIR_SEPARATOR, file);
528 sprintf (temp_file, "%s%cTMP-%ld-%ld",
529 dir, DIR_SEPARATOR, (long)getpid(), (long)getppid ());
531 /* Create the temporary file and write the process number. */
532 fd = open (temp_file, O_CREAT | O_WRONLY, 0600);
538 /* Link it with the new file. */
539 link (temp_file, full_path);
541 /* Count the references on the old one. If we have a count of two, then
542 the link did succeed. Remove the temporary file before returning. */
543 __gnat_stat (temp_file, &stat_result);
545 return stat_result.st_nlink == 2;
549 /* Return the maximum file name length. */
552 __gnat_get_maximum_file_name_length (void)
557 if (getenv ("GNAT$EXTENDED_FILE_SPECIFICATIONS"))
566 /* Return nonzero if file names are case sensitive. */
569 __gnat_get_file_names_case_sensitive (void)
571 #if defined (__EMX__) || defined (MSDOS) || defined (VMS) || defined (WINNT)
579 __gnat_get_default_identifier_character_set (void)
581 #if defined (__EMX__) || defined (MSDOS)
588 /* Return the current working directory. */
591 __gnat_get_current_dir (char *dir, int *length)
593 #if defined (__MINGW32__)
594 TCHAR wdir[GNAT_MAX_PATH_LEN];
596 _tgetcwd (wdir, *length);
598 WS2SC (dir, wdir, GNAT_MAX_PATH_LEN);
601 /* Force Unix style, which is what GNAT uses internally. */
602 getcwd (dir, *length, 0);
604 getcwd (dir, *length);
607 *length = strlen (dir);
609 if (dir [*length - 1] != DIR_SEPARATOR)
611 dir [*length] = DIR_SEPARATOR;
617 /* Return the suffix for object files. */
620 __gnat_get_object_suffix_ptr (int *len, const char **value)
622 *value = HOST_OBJECT_SUFFIX;
627 *len = strlen (*value);
632 /* Return the suffix for executable files. */
635 __gnat_get_executable_suffix_ptr (int *len, const char **value)
637 *value = HOST_EXECUTABLE_SUFFIX;
641 *len = strlen (*value);
646 /* Return the suffix for debuggable files. Usually this is the same as the
647 executable extension. */
650 __gnat_get_debuggable_suffix_ptr (int *len, const char **value)
653 *value = HOST_EXECUTABLE_SUFFIX;
655 /* On DOS, the extensionless COFF file is what gdb likes. */
662 *len = strlen (*value);
667 /* Returns the OS filename and corresponding encoding. */
670 __gnat_os_filename (char *filename ATTRIBUTE_UNUSED,
671 char *w_filename ATTRIBUTE_UNUSED,
672 char *os_name, int *o_length,
673 char *encoding ATTRIBUTE_UNUSED, int *e_length)
675 #if defined (_WIN32) && ! defined (__vxworks) && ! defined (IS_CROSS)
676 WS2SC (os_name, (TCHAR *)w_filename, (DWORD)o_length);
677 *o_length = strlen (os_name);
678 strcpy (encoding, "encoding=utf8");
679 *e_length = strlen (encoding);
681 strcpy (os_name, filename);
682 *o_length = strlen (filename);
690 __gnat_unlink (char *path)
692 #if defined (__MINGW32__) && ! defined (__vxworks) && ! defined (IS_CROSS)
694 TCHAR wpath[GNAT_MAX_PATH_LEN];
696 S2WSC (wpath, path, GNAT_MAX_PATH_LEN);
697 return _tunlink (wpath);
700 return unlink (path);
707 __gnat_rename (char *from, char *to)
709 #if defined (__MINGW32__) && ! defined (__vxworks) && ! defined (IS_CROSS)
711 TCHAR wfrom[GNAT_MAX_PATH_LEN], wto[GNAT_MAX_PATH_LEN];
713 S2WSC (wfrom, from, GNAT_MAX_PATH_LEN);
714 S2WSC (wto, to, GNAT_MAX_PATH_LEN);
715 return _trename (wfrom, wto);
718 return rename (from, to);
722 /* Changing directory. */
725 __gnat_chdir (char *path)
727 #if defined (__MINGW32__) && ! defined (__vxworks) && ! defined (IS_CROSS)
729 TCHAR wpath[GNAT_MAX_PATH_LEN];
731 S2WSC (wpath, path, GNAT_MAX_PATH_LEN);
732 return _tchdir (wpath);
739 /* Removing a directory. */
742 __gnat_rmdir (char *path)
744 #if defined (__MINGW32__) && ! defined (__vxworks) && ! defined (IS_CROSS)
746 TCHAR wpath[GNAT_MAX_PATH_LEN];
748 S2WSC (wpath, path, GNAT_MAX_PATH_LEN);
749 return _trmdir (wpath);
751 #elif defined (VTHREADS)
752 /* rmdir not available */
760 __gnat_fopen (char *path, char *mode, int encoding ATTRIBUTE_UNUSED)
762 #if defined (_WIN32) && ! defined (__vxworks) && ! defined (IS_CROSS)
763 TCHAR wpath[GNAT_MAX_PATH_LEN];
766 S2WS (wmode, mode, 10);
768 if (encoding == Encoding_Unspecified)
769 S2WSC (wpath, path, GNAT_MAX_PATH_LEN);
770 else if (encoding == Encoding_UTF8)
771 S2WSU (wpath, path, GNAT_MAX_PATH_LEN);
773 S2WS (wpath, path, GNAT_MAX_PATH_LEN);
775 return _tfopen (wpath, wmode);
777 return decc$fopen (path, mode);
779 return GNAT_FOPEN (path, mode);
784 __gnat_freopen (char *path, char *mode, FILE *stream, int encoding ATTRIBUTE_UNUSED)
786 #if defined (_WIN32) && ! defined (__vxworks) && ! defined (IS_CROSS)
787 TCHAR wpath[GNAT_MAX_PATH_LEN];
790 S2WS (wmode, mode, 10);
792 if (encoding == Encoding_Unspecified)
793 S2WSC (wpath, path, GNAT_MAX_PATH_LEN);
794 else if (encoding == Encoding_UTF8)
795 S2WSU (wpath, path, GNAT_MAX_PATH_LEN);
797 S2WS (wpath, path, GNAT_MAX_PATH_LEN);
799 return _tfreopen (wpath, wmode, stream);
801 return decc$freopen (path, mode, stream);
803 return freopen (path, mode, stream);
808 __gnat_open_read (char *path, int fmode)
811 int o_fmode = O_BINARY;
817 /* Optional arguments mbc,deq,fop increase read performance. */
818 fd = open (path, O_RDONLY | o_fmode, 0444,
819 "mbc=16", "deq=64", "fop=tef");
820 #elif defined (__vxworks)
821 fd = open (path, O_RDONLY | o_fmode, 0444);
822 #elif defined (__MINGW32__)
824 TCHAR wpath[GNAT_MAX_PATH_LEN];
826 S2WSC (wpath, path, GNAT_MAX_PATH_LEN);
827 fd = _topen (wpath, O_RDONLY | o_fmode, 0444);
830 fd = open (path, O_RDONLY | o_fmode);
833 return fd < 0 ? -1 : fd;
836 #if defined (__EMX__) || defined (__MINGW32__)
837 #define PERM (S_IREAD | S_IWRITE)
839 /* Excerpt from DECC C RTL Reference Manual:
840 To create files with OpenVMS RMS default protections using the UNIX
841 system-call functions umask, mkdir, creat, and open, call mkdir, creat,
842 and open with a file-protection mode argument of 0777 in a program
843 that never specifically calls umask. These default protections include
844 correctly establishing protections based on ACLs, previous versions of
848 #define PERM (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH)
852 __gnat_open_rw (char *path, int fmode)
855 int o_fmode = O_BINARY;
861 fd = open (path, O_RDWR | o_fmode, PERM,
862 "mbc=16", "deq=64", "fop=tef");
863 #elif defined (__MINGW32__)
865 TCHAR wpath[GNAT_MAX_PATH_LEN];
867 S2WSC (wpath, path, GNAT_MAX_PATH_LEN);
868 fd = _topen (wpath, O_RDWR | o_fmode, PERM);
871 fd = open (path, O_RDWR | o_fmode, PERM);
874 return fd < 0 ? -1 : fd;
878 __gnat_open_create (char *path, int fmode)
881 int o_fmode = O_BINARY;
887 fd = open (path, O_WRONLY | O_CREAT | O_TRUNC | o_fmode, PERM,
888 "mbc=16", "deq=64", "fop=tef");
889 #elif defined (__MINGW32__)
891 TCHAR wpath[GNAT_MAX_PATH_LEN];
893 S2WSC (wpath, path, GNAT_MAX_PATH_LEN);
894 fd = _topen (wpath, O_WRONLY | O_CREAT | O_TRUNC | o_fmode, PERM);
897 fd = open (path, O_WRONLY | O_CREAT | O_TRUNC | o_fmode, PERM);
900 return fd < 0 ? -1 : fd;
904 __gnat_create_output_file (char *path)
908 fd = open (path, O_WRONLY | O_CREAT | O_TRUNC | O_TEXT, PERM,
909 "rfm=stmlf", "ctx=rec", "rat=none", "rop=nlk",
910 "shr=del,get,put,upd");
911 #elif defined (__MINGW32__)
913 TCHAR wpath[GNAT_MAX_PATH_LEN];
915 S2WSC (wpath, path, GNAT_MAX_PATH_LEN);
916 fd = _topen (wpath, O_WRONLY | O_CREAT | O_TRUNC | O_TEXT, PERM);
919 fd = open (path, O_WRONLY | O_CREAT | O_TRUNC | O_TEXT, PERM);
922 return fd < 0 ? -1 : fd;
926 __gnat_create_output_file_new (char *path)
930 fd = open (path, O_WRONLY | O_CREAT | O_TRUNC | O_TEXT | O_EXCL, PERM,
931 "rfm=stmlf", "ctx=rec", "rat=none", "rop=nlk",
932 "shr=del,get,put,upd");
933 #elif defined (__MINGW32__)
935 TCHAR wpath[GNAT_MAX_PATH_LEN];
937 S2WSC (wpath, path, GNAT_MAX_PATH_LEN);
938 fd = _topen (wpath, O_WRONLY | O_CREAT | O_TRUNC | O_TEXT | O_EXCL, PERM);
941 fd = open (path, O_WRONLY | O_CREAT | O_TRUNC | O_TEXT | O_EXCL, PERM);
944 return fd < 0 ? -1 : fd;
948 __gnat_open_append (char *path, int fmode)
951 int o_fmode = O_BINARY;
957 fd = open (path, O_WRONLY | O_CREAT | O_APPEND | o_fmode, PERM,
958 "mbc=16", "deq=64", "fop=tef");
959 #elif defined (__MINGW32__)
961 TCHAR wpath[GNAT_MAX_PATH_LEN];
963 S2WSC (wpath, path, GNAT_MAX_PATH_LEN);
964 fd = _topen (wpath, O_WRONLY | O_CREAT | O_APPEND | o_fmode, PERM);
967 fd = open (path, O_WRONLY | O_CREAT | O_APPEND | o_fmode, PERM);
970 return fd < 0 ? -1 : fd;
973 /* Open a new file. Return error (-1) if the file already exists. */
976 __gnat_open_new (char *path, int fmode)
979 int o_fmode = O_BINARY;
985 fd = open (path, O_WRONLY | O_CREAT | O_EXCL | o_fmode, PERM,
986 "mbc=16", "deq=64", "fop=tef");
987 #elif defined (__MINGW32__)
989 TCHAR wpath[GNAT_MAX_PATH_LEN];
991 S2WSC (wpath, path, GNAT_MAX_PATH_LEN);
992 fd = _topen (wpath, O_WRONLY | O_CREAT | O_EXCL | o_fmode, PERM);
995 fd = open (path, O_WRONLY | O_CREAT | O_EXCL | o_fmode, PERM);
998 return fd < 0 ? -1 : fd;
1001 /* Open a new temp file. Return error (-1) if the file already exists.
1002 Special options for VMS allow the file to be shared between parent and child
1003 processes, however they really slow down output. Used in gnatchop. */
1006 __gnat_open_new_temp (char *path, int fmode)
1009 int o_fmode = O_BINARY;
1011 strcpy (path, "GNAT-XXXXXX");
1013 #if (defined (__FreeBSD__) || defined (__NetBSD__) || defined (__OpenBSD__) \
1014 || defined (linux) || defined(__GLIBC__)) && !defined (__vxworks)
1015 return mkstemp (path);
1016 #elif defined (__Lynx__)
1018 #elif defined (__nucleus__)
1021 if (mktemp (path) == NULL)
1029 fd = open (path, O_WRONLY | O_CREAT | O_EXCL | o_fmode, PERM,
1030 "rfm=stmlf", "ctx=rec", "rat=none", "shr=del,get,put,upd",
1031 "mbc=16", "deq=64", "fop=tef");
1033 fd = open (path, O_WRONLY | O_CREAT | O_EXCL | o_fmode, PERM);
1036 return fd < 0 ? -1 : fd;
1039 /* Return the number of bytes in the specified file. */
1042 __gnat_file_length (int fd)
1045 GNAT_STRUCT_STAT statbuf;
1047 ret = GNAT_FSTAT (fd, &statbuf);
1048 if (ret || !S_ISREG (statbuf.st_mode))
1051 /* st_size may be 32 bits, or 64 bits which is converted to long. We
1052 don't return a useful value for files larger than 2 gigabytes in
1055 return (statbuf.st_size);
1058 /* Return the number of bytes in the specified named file. */
1061 __gnat_named_file_length (char *name)
1064 GNAT_STRUCT_STAT statbuf;
1066 ret = __gnat_stat (name, &statbuf);
1067 if (ret || !S_ISREG (statbuf.st_mode))
1070 /* st_size may be 32 bits, or 64 bits which is converted to long. We
1071 don't return a useful value for files larger than 2 gigabytes in
1074 return (statbuf.st_size);
1077 /* Create a temporary filename and put it in string pointed to by
1081 __gnat_tmp_name (char *tmp_filename)
1084 /* Variable used to create a series of unique names */
1085 static int counter = 0;
1087 /* RTX in RTSS mode does not support tempnam nor tmpnam so we emulate it */
1088 strcpy (tmp_filename, "c:\\WINDOWS\\Temp\\gnat-");
1089 sprintf (&tmp_filename[strlen (tmp_filename)], "%d\0", counter++);
1091 #elif defined (__MINGW32__)
1095 /* tempnam tries to create a temporary file in directory pointed to by
1096 TMP environment variable, in c:\temp if TMP is not set, and in
1097 directory specified by P_tmpdir in stdio.h if c:\temp does not
1098 exist. The filename will be created with the prefix "gnat-". */
1100 pname = (char *) tempnam ("c:\\temp", "gnat-");
1102 /* if pname is NULL, the file was not created properly, the disk is full
1103 or there is no more free temporary files */
1106 *tmp_filename = '\0';
1108 /* If pname start with a back slash and not path information it means that
1109 the filename is valid for the current working directory. */
1111 else if (pname[0] == '\\')
1113 strcpy (tmp_filename, ".\\");
1114 strcat (tmp_filename, pname+1);
1117 strcpy (tmp_filename, pname);
1122 #elif defined (linux) || defined (__FreeBSD__) || defined (__NetBSD__) \
1123 || defined (__OpenBSD__) || defined(__GLIBC__)
1124 #define MAX_SAFE_PATH 1000
1125 char *tmpdir = getenv ("TMPDIR");
1127 /* If tmpdir is longer than MAX_SAFE_PATH, revert to default value to avoid
1128 a buffer overflow. */
1129 if (tmpdir == NULL || strlen (tmpdir) > MAX_SAFE_PATH)
1130 strcpy (tmp_filename, "/tmp/gnat-XXXXXX");
1132 sprintf (tmp_filename, "%s/gnat-XXXXXX", tmpdir);
1134 close (mkstemp(tmp_filename));
1136 tmpnam (tmp_filename);
1140 /* Open directory and returns a DIR pointer. */
1142 DIR* __gnat_opendir (char *name)
1145 /* Not supported in RTX */
1149 #elif defined (__MINGW32__)
1150 TCHAR wname[GNAT_MAX_PATH_LEN];
1152 S2WSC (wname, name, GNAT_MAX_PATH_LEN);
1153 return (DIR*)_topendir (wname);
1156 return opendir (name);
1160 /* Read the next entry in a directory. The returned string points somewhere
1164 __gnat_readdir (DIR *dirp, char *buffer, int *len)
1167 /* Not supported in RTX */
1171 #elif defined (__MINGW32__)
1172 struct _tdirent *dirent = _treaddir ((_TDIR*)dirp);
1176 WS2SC (buffer, dirent->d_name, GNAT_MAX_PATH_LEN);
1177 *len = strlen (buffer);
1184 #elif defined (HAVE_READDIR_R)
1185 /* If possible, try to use the thread-safe version. */
1186 if (readdir_r (dirp, buffer) != NULL)
1188 *len = strlen (((struct dirent*) buffer)->d_name);
1189 return ((struct dirent*) buffer)->d_name;
1195 struct dirent *dirent = (struct dirent *) readdir (dirp);
1199 strcpy (buffer, dirent->d_name);
1200 *len = strlen (buffer);
1209 /* Close a directory entry. */
1211 int __gnat_closedir (DIR *dirp)
1214 /* Not supported in RTX */
1218 #elif defined (__MINGW32__)
1219 return _tclosedir ((_TDIR*)dirp);
1222 return closedir (dirp);
1226 /* Returns 1 if readdir is thread safe, 0 otherwise. */
1229 __gnat_readdir_is_thread_safe (void)
1231 #ifdef HAVE_READDIR_R
1238 #if defined (_WIN32) && !defined (RTX)
1239 /* Number of seconds between <Jan 1st 1601> and <Jan 1st 1970>. */
1240 static const unsigned long long w32_epoch_offset = 11644473600ULL;
1242 /* Returns the file modification timestamp using Win32 routines which are
1243 immune against daylight saving time change. It is in fact not possible to
1244 use fstat for this purpose as the DST modify the st_mtime field of the
1248 win32_filetime (HANDLE h)
1253 unsigned long long ull_time;
1256 /* GetFileTime returns FILETIME data which are the number of 100 nanosecs
1257 since <Jan 1st 1601>. This function must return the number of seconds
1258 since <Jan 1st 1970>. */
1260 if (GetFileTime (h, NULL, NULL, &t_write.ft_time))
1261 return (time_t) (t_write.ull_time / 10000000ULL - w32_epoch_offset);
1266 /* Return a GNAT time stamp given a file name. */
1269 __gnat_file_time_name (char *name)
1272 #if defined (__EMX__) || defined (MSDOS)
1273 int fd = open (name, O_RDONLY | O_BINARY);
1274 time_t ret = __gnat_file_time_fd (fd);
1276 return (OS_Time)ret;
1278 #elif defined (_WIN32) && !defined (RTX)
1280 TCHAR wname[GNAT_MAX_PATH_LEN];
1282 S2WSC (wname, name, GNAT_MAX_PATH_LEN);
1284 HANDLE h = CreateFile
1285 (wname, GENERIC_READ, FILE_SHARE_READ, 0,
1286 OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0);
1288 if (h != INVALID_HANDLE_VALUE)
1290 ret = win32_filetime (h);
1293 return (OS_Time) ret;
1295 GNAT_STRUCT_STAT statbuf;
1296 if (__gnat_stat (name, &statbuf) != 0) {
1300 /* VMS has file versioning. */
1301 return (OS_Time)statbuf.st_ctime;
1303 return (OS_Time)statbuf.st_mtime;
1309 /* Return a GNAT time stamp given a file descriptor. */
1312 __gnat_file_time_fd (int fd)
1314 /* The following workaround code is due to the fact that under EMX and
1315 DJGPP fstat attempts to convert time values to GMT rather than keep the
1316 actual OS timestamp of the file. By using the OS2/DOS functions directly
1317 the GNAT timestamp are independent of this behavior, which is desired to
1318 facilitate the distribution of GNAT compiled libraries. */
1320 #if defined (__EMX__) || defined (MSDOS)
1324 int ret = DosQueryFileInfo (fd, 1, (unsigned char *) &fs,
1325 sizeof (FILESTATUS));
1327 unsigned file_year = fs.fdateLastWrite.year;
1328 unsigned file_month = fs.fdateLastWrite.month;
1329 unsigned file_day = fs.fdateLastWrite.day;
1330 unsigned file_hour = fs.ftimeLastWrite.hours;
1331 unsigned file_min = fs.ftimeLastWrite.minutes;
1332 unsigned file_tsec = fs.ftimeLastWrite.twosecs;
1336 int ret = getftime (fd, &fs);
1338 unsigned file_year = fs.ft_year;
1339 unsigned file_month = fs.ft_month;
1340 unsigned file_day = fs.ft_day;
1341 unsigned file_hour = fs.ft_hour;
1342 unsigned file_min = fs.ft_min;
1343 unsigned file_tsec = fs.ft_tsec;
1346 /* Calculate the seconds since epoch from the time components. First count
1347 the whole days passed. The value for years returned by the DOS and OS2
1348 functions count years from 1980, so to compensate for the UNIX epoch which
1349 begins in 1970 start with 10 years worth of days and add days for each
1350 four year period since then. */
1353 int cum_days[12] = {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334};
1354 int days_passed = 3652 + (file_year / 4) * 1461;
1355 int years_since_leap = file_year % 4;
1357 if (years_since_leap == 1)
1359 else if (years_since_leap == 2)
1361 else if (years_since_leap == 3)
1362 days_passed += 1096;
1367 days_passed += cum_days[file_month - 1];
1368 if (years_since_leap == 0 && file_year != 20 && file_month > 2)
1371 days_passed += file_day - 1;
1373 /* OK - have whole days. Multiply -- then add in other parts. */
1375 tot_secs = days_passed * 86400;
1376 tot_secs += file_hour * 3600;
1377 tot_secs += file_min * 60;
1378 tot_secs += file_tsec * 2;
1379 return (OS_Time) tot_secs;
1381 #elif defined (_WIN32) && !defined (RTX)
1382 HANDLE h = (HANDLE) _get_osfhandle (fd);
1383 time_t ret = win32_filetime (h);
1384 return (OS_Time) ret;
1387 GNAT_STRUCT_STAT statbuf;
1389 if (GNAT_FSTAT (fd, &statbuf) != 0) {
1390 return (OS_Time) -1;
1393 /* VMS has file versioning. */
1394 return (OS_Time) statbuf.st_ctime;
1396 return (OS_Time) statbuf.st_mtime;
1402 /* Set the file time stamp. */
1405 __gnat_set_file_time_name (char *name, time_t time_stamp)
1407 #if defined (__EMX__) || defined (MSDOS) || defined (__vxworks)
1409 /* Code to implement __gnat_set_file_time_name for these systems. */
1411 #elif defined (_WIN32) && !defined (RTX)
1415 unsigned long long ull_time;
1417 TCHAR wname[GNAT_MAX_PATH_LEN];
1419 S2WSC (wname, name, GNAT_MAX_PATH_LEN);
1421 HANDLE h = CreateFile
1422 (wname, GENERIC_WRITE, FILE_SHARE_WRITE, NULL,
1423 OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS,
1425 if (h == INVALID_HANDLE_VALUE)
1427 /* Add number of seconds between <Jan 1st 1601> and <Jan 1st 1970> */
1428 t_write.ull_time = ((unsigned long long)time_stamp + w32_epoch_offset);
1429 /* Convert to 100 nanosecond units */
1430 t_write.ull_time *= 10000000ULL;
1432 SetFileTime(h, NULL, NULL, &t_write.ft_time);
1442 unsigned long long backup, create, expire, revise;
1446 unsigned short value;
1449 unsigned system : 4;
1455 } Fat = { 0, 0, 0, 0, 0, { 0 }};
1459 { ATR$S_CREDATE, ATR$C_CREDATE, &Fat.create },
1460 { ATR$S_REVDATE, ATR$C_REVDATE, &Fat.revise },
1461 { ATR$S_EXPDATE, ATR$C_EXPDATE, &Fat.expire },
1462 { ATR$S_BAKDATE, ATR$C_BAKDATE, &Fat.backup },
1463 { ATR$S_FPRO, ATR$C_FPRO, &Fat.prot },
1464 { ATR$S_UIC, ATR$C_UIC, &Fat.uic },
1469 struct dsc$descriptor_fib fibdsc = {sizeof (fib), (void *) &fib};
1473 unsigned long long newtime;
1474 unsigned long long revtime;
1478 struct vstring file;
1479 struct dsc$descriptor_s filedsc
1480 = {NAM$C_MAXRSS, DSC$K_DTYPE_T, DSC$K_CLASS_S, (void *) file.string};
1481 struct vstring device;
1482 struct dsc$descriptor_s devicedsc
1483 = {NAM$C_MAXRSS, DSC$K_DTYPE_T, DSC$K_CLASS_S, (void *) device.string};
1484 struct vstring timev;
1485 struct dsc$descriptor_s timedsc
1486 = {NAM$C_MAXRSS, DSC$K_DTYPE_T, DSC$K_CLASS_S, (void *) timev.string};
1487 struct vstring result;
1488 struct dsc$descriptor_s resultdsc
1489 = {NAM$C_MAXRSS, DSC$K_DTYPE_VT, DSC$K_CLASS_VS, (void *) result.string};
1491 /* Convert parameter name (a file spec) to host file form. Note that this
1492 is needed on VMS to prepare for subsequent calls to VMS RMS library
1493 routines. Note that it would not work to call __gnat_to_host_dir_spec
1494 as was done in a previous version, since this fails silently unless
1495 the feature logical DECC$EFS_CHARSET is enabled, in which case a DNF
1496 (directory not found) condition is signalled. */
1497 tryfile = (char *) __gnat_to_host_file_spec (name);
1499 /* Allocate and initialize a FAB and NAM structures. */
1503 nam.nam$l_esa = file.string;
1504 nam.nam$b_ess = NAM$C_MAXRSS;
1505 nam.nam$l_rsa = result.string;
1506 nam.nam$b_rss = NAM$C_MAXRSS;
1507 fab.fab$l_fna = tryfile;
1508 fab.fab$b_fns = strlen (tryfile);
1509 fab.fab$l_nam = &nam;
1511 /* Validate filespec syntax and device existence. */
1512 status = SYS$PARSE (&fab, 0, 0);
1513 if ((status & 1) != 1)
1514 LIB$SIGNAL (status);
1516 file.string[nam.nam$b_esl] = 0;
1518 /* Find matching filespec. */
1519 status = SYS$SEARCH (&fab, 0, 0);
1520 if ((status & 1) != 1)
1521 LIB$SIGNAL (status);
1523 file.string[nam.nam$b_esl] = 0;
1524 result.string[result.length=nam.nam$b_rsl] = 0;
1526 /* Get the device name and assign an IO channel. */
1527 strncpy (device.string, nam.nam$l_dev, nam.nam$b_dev);
1528 devicedsc.dsc$w_length = nam.nam$b_dev;
1530 status = SYS$ASSIGN (&devicedsc, &chan, 0, 0, 0);
1531 if ((status & 1) != 1)
1532 LIB$SIGNAL (status);
1534 /* Initialize the FIB and fill in the directory id field. */
1535 memset (&fib, 0, sizeof (fib));
1536 fib.fib$w_did[0] = nam.nam$w_did[0];
1537 fib.fib$w_did[1] = nam.nam$w_did[1];
1538 fib.fib$w_did[2] = nam.nam$w_did[2];
1539 fib.fib$l_acctl = 0;
1541 strcpy (file.string, (strrchr (result.string, ']') + 1));
1542 filedsc.dsc$w_length = strlen (file.string);
1543 result.string[result.length = 0] = 0;
1545 /* Open and close the file to fill in the attributes. */
1547 = SYS$QIOW (0, chan, IO$_ACCESS|IO$M_ACCESS, &iosb, 0, 0,
1548 &fibdsc, &filedsc, &result.length, &resultdsc, &atrlst, 0);
1549 if ((status & 1) != 1)
1550 LIB$SIGNAL (status);
1551 if ((iosb.status & 1) != 1)
1552 LIB$SIGNAL (iosb.status);
1554 result.string[result.length] = 0;
1555 status = SYS$QIOW (0, chan, IO$_DEACCESS, &iosb, 0, 0, &fibdsc, 0, 0, 0,
1557 if ((status & 1) != 1)
1558 LIB$SIGNAL (status);
1559 if ((iosb.status & 1) != 1)
1560 LIB$SIGNAL (iosb.status);
1565 /* Set creation time to requested time. */
1566 unix_time_to_vms (time_stamp, newtime);
1568 t = time ((time_t) 0);
1570 /* Set revision time to now in local time. */
1571 unix_time_to_vms (t, revtime);
1574 /* Reopen the file, modify the times and then close. */
1575 fib.fib$l_acctl = FIB$M_WRITE;
1577 = SYS$QIOW (0, chan, IO$_ACCESS|IO$M_ACCESS, &iosb, 0, 0,
1578 &fibdsc, &filedsc, &result.length, &resultdsc, &atrlst, 0);
1579 if ((status & 1) != 1)
1580 LIB$SIGNAL (status);
1581 if ((iosb.status & 1) != 1)
1582 LIB$SIGNAL (iosb.status);
1584 Fat.create = newtime;
1585 Fat.revise = revtime;
1587 status = SYS$QIOW (0, chan, IO$_DEACCESS, &iosb, 0, 0,
1588 &fibdsc, 0, 0, 0, &atrlst, 0);
1589 if ((status & 1) != 1)
1590 LIB$SIGNAL (status);
1591 if ((iosb.status & 1) != 1)
1592 LIB$SIGNAL (iosb.status);
1594 /* Deassign the channel and exit. */
1595 status = SYS$DASSGN (chan);
1596 if ((status & 1) != 1)
1597 LIB$SIGNAL (status);
1599 struct utimbuf utimbuf;
1602 /* Set modification time to requested time. */
1603 utimbuf.modtime = time_stamp;
1605 /* Set access time to now in local time. */
1606 t = time ((time_t) 0);
1607 utimbuf.actime = mktime (localtime (&t));
1609 utime (name, &utimbuf);
1613 /* Get the list of installed standard libraries from the
1614 HKEY_LOCAL_MACHINE\SOFTWARE\Ada Core Technologies\GNAT\Standard Libraries
1618 __gnat_get_libraries_from_registry (void)
1620 char *result = (char *) xmalloc (1);
1624 #if defined (_WIN32) && ! defined (__vxworks) && ! defined (IS_CROSS) \
1628 DWORD name_size, value_size;
1635 /* First open the key. */
1636 res = RegOpenKeyExA (HKEY_LOCAL_MACHINE, "SOFTWARE", 0, KEY_READ, ®_key);
1638 if (res == ERROR_SUCCESS)
1639 res = RegOpenKeyExA (reg_key, "Ada Core Technologies", 0,
1640 KEY_READ, ®_key);
1642 if (res == ERROR_SUCCESS)
1643 res = RegOpenKeyExA (reg_key, "GNAT", 0, KEY_READ, ®_key);
1645 if (res == ERROR_SUCCESS)
1646 res = RegOpenKeyExA (reg_key, "Standard Libraries", 0, KEY_READ, ®_key);
1648 /* If the key exists, read out all the values in it and concatenate them
1650 for (index = 0; res == ERROR_SUCCESS; index++)
1652 value_size = name_size = 256;
1653 res = RegEnumValueA (reg_key, index, name, &name_size, 0,
1654 &type, (LPBYTE)value, &value_size);
1656 if (res == ERROR_SUCCESS && type == REG_SZ)
1658 char *old_result = result;
1660 result = (char *) xmalloc (strlen (old_result) + value_size + 2);
1661 strcpy (result, old_result);
1662 strcat (result, value);
1663 strcat (result, ";");
1668 /* Remove the trailing ";". */
1670 result[strlen (result) - 1] = 0;
1677 __gnat_stat (char *name, GNAT_STRUCT_STAT *statbuf)
1680 /* Under Windows the directory name for the stat function must not be
1681 terminated by a directory separator except if just after a drive name
1682 or with UNC path without directory (only the name of the shared
1683 resource), for example: \\computer\share\ */
1685 TCHAR wname [GNAT_MAX_PATH_LEN + 2];
1688 int dirsep_count = 0;
1690 S2WSC (wname, name, GNAT_MAX_PATH_LEN + 2);
1691 name_len = _tcslen (wname);
1693 if (name_len > GNAT_MAX_PATH_LEN)
1696 last_char = wname[name_len - 1];
1698 while (name_len > 1 && (last_char == _T('\\') || last_char == _T('/')))
1700 wname[name_len - 1] = _T('\0');
1702 last_char = wname[name_len - 1];
1705 /* Count back-slashes. */
1707 for (k=0; k<name_len; k++)
1708 if (wname[k] == _T('\\') || wname[k] == _T('/'))
1711 /* Only a drive letter followed by ':', we must add a directory separator
1712 for the stat routine to work properly. */
1713 if ((name_len == 2 && wname[1] == _T(':'))
1714 || (name_len > 3 && wname[0] == _T('\\') && wname[1] == _T('\\')
1715 && dirsep_count == 3))
1716 _tcscat (wname, _T("\\"));
1718 return _tstat (wname, (struct _stat *)statbuf);
1721 return GNAT_STAT (name, statbuf);
1726 __gnat_file_exists (char *name)
1729 /* On Windows do not use __gnat_stat() because a bug in Microsoft
1730 _stat() routine. When the system time-zone is set with a negative
1731 offset the _stat() routine fails on specific files like CON: */
1732 TCHAR wname [GNAT_MAX_PATH_LEN + 2];
1734 S2WSC (wname, name, GNAT_MAX_PATH_LEN + 2);
1735 return GetFileAttributes (wname) != INVALID_FILE_ATTRIBUTES;
1737 GNAT_STRUCT_STAT statbuf;
1739 return !__gnat_stat (name, &statbuf);
1744 __gnat_is_absolute_path (char *name, int length)
1747 /* On VxWorks systems, an absolute path can be represented (depending on
1748 the host platform) as either /dir/file, or device:/dir/file, or
1749 device:drive_letter:/dir/file. */
1756 for (index = 0; index < length; index++)
1758 if (name[index] == ':' &&
1759 ((name[index + 1] == '/') ||
1760 (isalpha (name[index + 1]) && index + 2 <= length &&
1761 name[index + 2] == '/')))
1764 else if (name[index] == '/')
1769 return (length != 0) &&
1770 (*name == '/' || *name == DIR_SEPARATOR
1771 #if defined (__EMX__) || defined (MSDOS) || defined (WINNT)
1772 || (length > 1 && ISALPHA (name[0]) && name[1] == ':')
1779 __gnat_is_regular_file (char *name)
1782 GNAT_STRUCT_STAT statbuf;
1784 ret = __gnat_stat (name, &statbuf);
1785 return (!ret && S_ISREG (statbuf.st_mode));
1789 __gnat_is_directory (char *name)
1792 GNAT_STRUCT_STAT statbuf;
1794 ret = __gnat_stat (name, &statbuf);
1795 return (!ret && S_ISDIR (statbuf.st_mode));
1798 #if defined (_WIN32) && !defined (RTX)
1800 /* Returns the same constant as GetDriveType but takes a pathname as
1804 GetDriveTypeFromPath (TCHAR *wfullpath)
1806 TCHAR wdrv[MAX_PATH];
1807 TCHAR wpath[MAX_PATH];
1808 TCHAR wfilename[MAX_PATH];
1809 TCHAR wext[MAX_PATH];
1811 _tsplitpath (wfullpath, wdrv, wpath, wfilename, wext);
1813 if (_tcslen (wdrv) != 0)
1815 /* we have a drive specified. */
1816 _tcscat (wdrv, _T("\\"));
1817 return GetDriveType (wdrv);
1821 /* No drive specified. */
1823 /* Is this a relative path, if so get current drive type. */
1824 if (wpath[0] != _T('\\') ||
1825 (_tcslen (wpath) > 2 && wpath[0] == _T('\\') && wpath[1] != _T('\\')))
1826 return GetDriveType (NULL);
1828 UINT result = GetDriveType (wpath);
1830 /* Cannot guess the drive type, is this \\.\ ? */
1832 if (result == DRIVE_NO_ROOT_DIR &&
1833 _tcslen (wpath) >= 4 && wpath[0] == _T('\\') && wpath[1] == _T('\\')
1834 && wpath[2] == _T('.') && wpath[3] == _T('\\'))
1836 if (_tcslen (wpath) == 4)
1837 _tcscat (wpath, wfilename);
1839 LPTSTR p = &wpath[4];
1840 LPTSTR b = _tcschr (p, _T('\\'));
1843 { /* logical drive \\.\c\dir\file */
1849 _tcscat (p, _T(":\\"));
1851 return GetDriveType (p);
1858 /* This MingW section contains code to work with ACL. */
1860 __gnat_check_OWNER_ACL
1862 DWORD CheckAccessDesired,
1863 GENERIC_MAPPING CheckGenericMapping)
1865 DWORD dwAccessDesired, dwAccessAllowed;
1866 PRIVILEGE_SET PrivilegeSet;
1867 DWORD dwPrivSetSize = sizeof (PRIVILEGE_SET);
1868 BOOL fAccessGranted = FALSE;
1869 HANDLE hToken = NULL;
1871 SECURITY_DESCRIPTOR* pSD = NULL;
1874 (wname, OWNER_SECURITY_INFORMATION |
1875 GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION,
1878 if ((pSD = (PSECURITY_DESCRIPTOR) HeapAlloc
1879 (GetProcessHeap (), HEAP_ZERO_MEMORY, nLength)) == NULL)
1882 /* Obtain the security descriptor. */
1884 if (!GetFileSecurity
1885 (wname, OWNER_SECURITY_INFORMATION |
1886 GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION,
1887 pSD, nLength, &nLength))
1890 if (!ImpersonateSelf (SecurityImpersonation))
1893 if (!OpenThreadToken
1894 (GetCurrentThread(), TOKEN_DUPLICATE | TOKEN_QUERY, FALSE, &hToken))
1897 /* Undoes the effect of ImpersonateSelf. */
1901 /* We want to test for write permissions. */
1903 dwAccessDesired = CheckAccessDesired;
1905 MapGenericMask (&dwAccessDesired, &CheckGenericMapping);
1908 (pSD , /* security descriptor to check */
1909 hToken, /* impersonation token */
1910 dwAccessDesired, /* requested access rights */
1911 &CheckGenericMapping, /* pointer to GENERIC_MAPPING */
1912 &PrivilegeSet, /* receives privileges used in check */
1913 &dwPrivSetSize, /* size of PrivilegeSet buffer */
1914 &dwAccessAllowed, /* receives mask of allowed access rights */
1918 CloseHandle (hToken);
1919 HeapFree (GetProcessHeap (), 0, pSD);
1920 return fAccessGranted;
1924 CloseHandle (hToken);
1925 HeapFree (GetProcessHeap (), 0, pSD);
1930 __gnat_set_OWNER_ACL
1933 DWORD AccessPermissions)
1935 PACL pOldDACL = NULL;
1936 PACL pNewDACL = NULL;
1937 PSECURITY_DESCRIPTOR pSD = NULL;
1939 TCHAR username [100];
1942 /* Get current user, he will act as the owner */
1944 if (!GetUserName (username, &unsize))
1947 if (GetNamedSecurityInfo
1950 DACL_SECURITY_INFORMATION,
1951 NULL, NULL, &pOldDACL, NULL, &pSD) != ERROR_SUCCESS)
1954 BuildExplicitAccessWithName
1955 (&ea, username, AccessPermissions, AccessMode, NO_INHERITANCE);
1957 if (AccessMode == SET_ACCESS)
1959 /* SET_ACCESS, we want to set an explicte set of permissions, do not
1960 merge with current DACL. */
1961 if (SetEntriesInAcl (1, &ea, NULL, &pNewDACL) != ERROR_SUCCESS)
1965 if (SetEntriesInAcl (1, &ea, pOldDACL, &pNewDACL) != ERROR_SUCCESS)
1968 if (SetNamedSecurityInfo
1969 (wname, SE_FILE_OBJECT,
1970 DACL_SECURITY_INFORMATION, NULL, NULL, pNewDACL, NULL) != ERROR_SUCCESS)
1974 LocalFree (pNewDACL);
1977 /* Check if it is possible to use ACL for wname, the file must not be on a
1981 __gnat_can_use_acl (TCHAR *wname)
1983 return __gnat_use_acl && GetDriveTypeFromPath (wname) != DRIVE_REMOTE;
1986 #endif /* defined (_WIN32) && !defined (RTX) */
1989 __gnat_is_readable_file (char *name)
1991 #if defined (_WIN32) && !defined (RTX)
1992 TCHAR wname [GNAT_MAX_PATH_LEN + 2];
1993 GENERIC_MAPPING GenericMapping;
1995 S2WSC (wname, name, GNAT_MAX_PATH_LEN + 2);
1997 if (__gnat_can_use_acl (wname))
1999 ZeroMemory (&GenericMapping, sizeof (GENERIC_MAPPING));
2000 GenericMapping.GenericRead = GENERIC_READ;
2002 return __gnat_check_OWNER_ACL (wname, FILE_READ_DATA, GenericMapping);
2005 return GetFileAttributes (wname) != INVALID_FILE_ATTRIBUTES;
2010 GNAT_STRUCT_STAT statbuf;
2012 ret = GNAT_STAT (name, &statbuf);
2013 mode = statbuf.st_mode & S_IRUSR;
2014 return (!ret && mode);
2019 __gnat_is_writable_file (char *name)
2021 #if defined (_WIN32) && !defined (RTX)
2022 TCHAR wname [GNAT_MAX_PATH_LEN + 2];
2023 GENERIC_MAPPING GenericMapping;
2025 S2WSC (wname, name, GNAT_MAX_PATH_LEN + 2);
2027 if (__gnat_can_use_acl (wname))
2029 ZeroMemory (&GenericMapping, sizeof (GENERIC_MAPPING));
2030 GenericMapping.GenericWrite = GENERIC_WRITE;
2032 return __gnat_check_OWNER_ACL
2033 (wname, FILE_WRITE_DATA | FILE_APPEND_DATA, GenericMapping)
2034 && !(GetFileAttributes (wname) & FILE_ATTRIBUTE_READONLY);
2037 return !(GetFileAttributes (wname) & FILE_ATTRIBUTE_READONLY);
2042 GNAT_STRUCT_STAT statbuf;
2044 ret = GNAT_STAT (name, &statbuf);
2045 mode = statbuf.st_mode & S_IWUSR;
2046 return (!ret && mode);
2051 __gnat_is_executable_file (char *name)
2053 #if defined (_WIN32) && !defined (RTX)
2054 TCHAR wname [GNAT_MAX_PATH_LEN + 2];
2055 GENERIC_MAPPING GenericMapping;
2057 S2WSC (wname, name, GNAT_MAX_PATH_LEN + 2);
2059 if (__gnat_can_use_acl (wname))
2061 ZeroMemory (&GenericMapping, sizeof (GENERIC_MAPPING));
2062 GenericMapping.GenericExecute = GENERIC_EXECUTE;
2064 return __gnat_check_OWNER_ACL (wname, FILE_EXECUTE, GenericMapping);
2067 return GetFileAttributes (wname) != INVALID_FILE_ATTRIBUTES
2068 && _tcsstr (wname, _T(".exe")) - wname == (int) (_tcslen (wname) - 4);
2072 GNAT_STRUCT_STAT statbuf;
2074 ret = GNAT_STAT (name, &statbuf);
2075 mode = statbuf.st_mode & S_IXUSR;
2076 return (!ret && mode);
2081 __gnat_set_writable (char *name)
2083 #if defined (_WIN32) && !defined (RTX)
2084 TCHAR wname [GNAT_MAX_PATH_LEN + 2];
2086 S2WSC (wname, name, GNAT_MAX_PATH_LEN + 2);
2088 if (__gnat_can_use_acl (wname))
2089 __gnat_set_OWNER_ACL (wname, GRANT_ACCESS, FILE_GENERIC_WRITE);
2092 (wname, GetFileAttributes (wname) & ~FILE_ATTRIBUTE_READONLY);
2093 #elif ! defined (__vxworks) && ! defined(__nucleus__)
2094 GNAT_STRUCT_STAT statbuf;
2096 if (GNAT_STAT (name, &statbuf) == 0)
2098 statbuf.st_mode = statbuf.st_mode | S_IWUSR;
2099 chmod (name, statbuf.st_mode);
2105 __gnat_set_executable (char *name)
2107 #if defined (_WIN32) && !defined (RTX)
2108 TCHAR wname [GNAT_MAX_PATH_LEN + 2];
2110 S2WSC (wname, name, GNAT_MAX_PATH_LEN + 2);
2112 if (__gnat_can_use_acl (wname))
2113 __gnat_set_OWNER_ACL (wname, GRANT_ACCESS, FILE_GENERIC_EXECUTE);
2115 #elif ! defined (__vxworks) && ! defined(__nucleus__)
2116 GNAT_STRUCT_STAT statbuf;
2118 if (GNAT_STAT (name, &statbuf) == 0)
2120 statbuf.st_mode = statbuf.st_mode | S_IXUSR;
2121 chmod (name, statbuf.st_mode);
2127 __gnat_set_non_writable (char *name)
2129 #if defined (_WIN32) && !defined (RTX)
2130 TCHAR wname [GNAT_MAX_PATH_LEN + 2];
2132 S2WSC (wname, name, GNAT_MAX_PATH_LEN + 2);
2134 if (__gnat_can_use_acl (wname))
2135 __gnat_set_OWNER_ACL
2136 (wname, DENY_ACCESS,
2137 FILE_WRITE_DATA | FILE_APPEND_DATA |
2138 FILE_WRITE_EA | FILE_WRITE_ATTRIBUTES);
2141 (wname, GetFileAttributes (wname) | FILE_ATTRIBUTE_READONLY);
2142 #elif ! defined (__vxworks) && ! defined(__nucleus__)
2143 GNAT_STRUCT_STAT statbuf;
2145 if (GNAT_STAT (name, &statbuf) == 0)
2147 statbuf.st_mode = statbuf.st_mode & 07577;
2148 chmod (name, statbuf.st_mode);
2154 __gnat_set_readable (char *name)
2156 #if defined (_WIN32) && !defined (RTX)
2157 TCHAR wname [GNAT_MAX_PATH_LEN + 2];
2159 S2WSC (wname, name, GNAT_MAX_PATH_LEN + 2);
2161 if (__gnat_can_use_acl (wname))
2162 __gnat_set_OWNER_ACL (wname, GRANT_ACCESS, FILE_GENERIC_READ);
2164 #elif ! defined (__vxworks) && ! defined(__nucleus__)
2165 GNAT_STRUCT_STAT statbuf;
2167 if (GNAT_STAT (name, &statbuf) == 0)
2169 chmod (name, statbuf.st_mode | S_IREAD);
2175 __gnat_set_non_readable (char *name)
2177 #if defined (_WIN32) && !defined (RTX)
2178 TCHAR wname [GNAT_MAX_PATH_LEN + 2];
2180 S2WSC (wname, name, GNAT_MAX_PATH_LEN + 2);
2182 if (__gnat_can_use_acl (wname))
2183 __gnat_set_OWNER_ACL (wname, DENY_ACCESS, FILE_GENERIC_READ);
2185 #elif ! defined (__vxworks) && ! defined(__nucleus__)
2186 GNAT_STRUCT_STAT statbuf;
2188 if (GNAT_STAT (name, &statbuf) == 0)
2190 chmod (name, statbuf.st_mode & (~S_IREAD));
2196 __gnat_is_symbolic_link (char *name ATTRIBUTE_UNUSED)
2198 #if defined (__vxworks) || defined (__nucleus__)
2201 #elif defined (_AIX) || defined (__APPLE__) || defined (__unix__)
2203 GNAT_STRUCT_STAT statbuf;
2205 ret = GNAT_LSTAT (name, &statbuf);
2206 return (!ret && S_ISLNK (statbuf.st_mode));
2213 #if defined (sun) && defined (__SVR4)
2214 /* Using fork on Solaris will duplicate all the threads. fork1, which
2215 duplicates only the active thread, must be used instead, or spawning
2216 subprocess from a program with tasking will lead into numerous problems. */
2221 __gnat_portable_spawn (char *args[])
2224 int finished ATTRIBUTE_UNUSED;
2225 int pid ATTRIBUTE_UNUSED;
2227 #if defined (__vxworks) || defined(__nucleus__) || defined(RTX)
2230 #elif defined (MSDOS) || defined (_WIN32)
2231 /* args[0] must be quotes as it could contain a full pathname with spaces */
2232 char *args_0 = args[0];
2233 args[0] = (char *)xmalloc (strlen (args_0) + 3);
2234 strcpy (args[0], "\"");
2235 strcat (args[0], args_0);
2236 strcat (args[0], "\"");
2238 status = spawnvp (P_WAIT, args_0, (const char* const*)args);
2240 /* restore previous value */
2242 args[0] = (char *)args_0;
2252 pid = spawnvp (P_NOWAIT, args[0], args);
2264 if (execv (args[0], MAYBE_TO_PTR32 (args)) != 0)
2266 return -1; /* execv is in parent context on VMS. */
2274 finished = waitpid (pid, &status, 0);
2276 if (finished != pid || WIFEXITED (status) == 0)
2279 return WEXITSTATUS (status);
2285 /* Create a copy of the given file descriptor.
2286 Return -1 if an error occurred. */
2289 __gnat_dup (int oldfd)
2291 #if defined (__vxworks) && !defined (__RTP__)
2292 /* Not supported on VxWorks 5.x, but supported on VxWorks 6.0 when using
2300 /* Make newfd be the copy of oldfd, closing newfd first if necessary.
2301 Return -1 if an error occurred. */
2304 __gnat_dup2 (int oldfd, int newfd)
2306 #if defined (__vxworks) && !defined (__RTP__)
2307 /* Not supported on VxWorks 5.x, but supported on VxWorks 6.0 when using
2311 return dup2 (oldfd, newfd);
2315 /* WIN32 code to implement a wait call that wait for any child process. */
2317 #if defined (_WIN32) && !defined (RTX)
2319 /* Synchronization code, to be thread safe. */
2323 /* For the Cert run times on native Windows we use dummy functions
2324 for locking and unlocking tasks since we do not support multiple
2325 threads on this configuration (Cert run time on native Windows). */
2327 void dummy (void) {}
2329 void (*Lock_Task) () = &dummy;
2330 void (*Unlock_Task) () = &dummy;
2334 #define Lock_Task system__soft_links__lock_task
2335 extern void (*Lock_Task) (void);
2337 #define Unlock_Task system__soft_links__unlock_task
2338 extern void (*Unlock_Task) (void);
2342 static HANDLE *HANDLES_LIST = NULL;
2343 static int *PID_LIST = NULL, plist_length = 0, plist_max_length = 0;
2346 add_handle (HANDLE h)
2349 /* -------------------- critical section -------------------- */
2352 if (plist_length == plist_max_length)
2354 plist_max_length += 1000;
2356 xrealloc (HANDLES_LIST, sizeof (HANDLE) * plist_max_length);
2358 xrealloc (PID_LIST, sizeof (int) * plist_max_length);
2361 HANDLES_LIST[plist_length] = h;
2362 PID_LIST[plist_length] = GetProcessId (h);
2366 /* -------------------- critical section -------------------- */
2370 __gnat_win32_remove_handle (HANDLE h, int pid)
2374 /* -------------------- critical section -------------------- */
2377 for (j = 0; j < plist_length; j++)
2379 if ((HANDLES_LIST[j] == h) || (PID_LIST[j] == pid))
2383 HANDLES_LIST[j] = HANDLES_LIST[plist_length];
2384 PID_LIST[j] = PID_LIST[plist_length];
2390 /* -------------------- critical section -------------------- */
2394 win32_no_block_spawn (char *command, char *args[])
2398 PROCESS_INFORMATION PI;
2399 SECURITY_ATTRIBUTES SA;
2404 /* compute the total command line length */
2408 csize += strlen (args[k]) + 1;
2412 full_command = (char *) xmalloc (csize);
2415 SI.cb = sizeof (STARTUPINFO);
2416 SI.lpReserved = NULL;
2417 SI.lpReserved2 = NULL;
2418 SI.lpDesktop = NULL;
2422 SI.wShowWindow = SW_HIDE;
2424 /* Security attributes. */
2425 SA.nLength = sizeof (SECURITY_ATTRIBUTES);
2426 SA.bInheritHandle = TRUE;
2427 SA.lpSecurityDescriptor = NULL;
2429 /* Prepare the command string. */
2430 strcpy (full_command, command);
2431 strcat (full_command, " ");
2436 strcat (full_command, args[k]);
2437 strcat (full_command, " ");
2442 int wsize = csize * 2;
2443 TCHAR *wcommand = (TCHAR *) xmalloc (wsize);
2445 S2WSC (wcommand, full_command, wsize);
2447 free (full_command);
2449 result = CreateProcess
2450 (NULL, wcommand, &SA, NULL, TRUE,
2451 GetPriorityClass (GetCurrentProcess()), NULL, NULL, &SI, &PI);
2458 CloseHandle (PI.hThread);
2466 win32_wait (int *status)
2468 DWORD exitcode, pid;
2475 if (plist_length == 0)
2483 /* -------------------- critical section -------------------- */
2486 hl_len = plist_length;
2488 hl = (HANDLE *) xmalloc (sizeof (HANDLE) * hl_len);
2490 memmove (hl, HANDLES_LIST, sizeof (HANDLE) * hl_len);
2493 /* -------------------- critical section -------------------- */
2495 res = WaitForMultipleObjects (hl_len, hl, FALSE, INFINITE);
2496 h = hl[res - WAIT_OBJECT_0];
2498 GetExitCodeProcess (h, &exitcode);
2499 pid = GetProcessId (h);
2500 __gnat_win32_remove_handle (h, -1);
2504 *status = (int) exitcode;
2511 __gnat_portable_no_block_spawn (char *args[])
2514 #if defined (__vxworks) || defined (__nucleus__) || defined (RTX)
2517 #elif defined (__EMX__) || defined (MSDOS)
2519 /* ??? For PC machines I (Franco) don't know the system calls to implement
2520 this routine. So I'll fake it as follows. This routine will behave
2521 exactly like the blocking portable_spawn and will systematically return
2522 a pid of 0 unless the spawned task did not complete successfully, in
2523 which case we return a pid of -1. To synchronize with this the
2524 portable_wait below systematically returns a pid of 0 and reports that
2525 the subprocess terminated successfully. */
2527 if (spawnvp (P_WAIT, args[0], args) != 0)
2530 #elif defined (_WIN32)
2534 h = win32_no_block_spawn (args[0], args);
2538 return GetProcessId (h);
2550 if (execv (args[0], MAYBE_TO_PTR32 (args)) != 0)
2552 return -1; /* execv is in parent context on VMS. */
2564 __gnat_portable_wait (int *process_status)
2569 #if defined (__vxworks) || defined (__nucleus__) || defined (RTX)
2570 /* Not sure what to do here, so do same as __EMX__ case, i.e., nothing but
2573 #elif defined (_WIN32)
2575 pid = win32_wait (&status);
2577 #elif defined (__EMX__) || defined (MSDOS)
2578 /* ??? See corresponding comment in portable_no_block_spawn. */
2582 pid = waitpid (-1, &status, 0);
2583 status = status & 0xffff;
2586 *process_status = status;
2591 __gnat_os_exit (int status)
2596 /* Locate a regular file, give a Path value. */
2599 __gnat_locate_regular_file (char *file_name, char *path_val)
2602 char *file_path = (char *) alloca (strlen (file_name) + 1);
2605 /* Return immediately if file_name is empty */
2607 if (*file_name == '\0')
2610 /* Remove quotes around file_name if present */
2616 strcpy (file_path, ptr);
2618 ptr = file_path + strlen (file_path) - 1;
2623 /* Handle absolute pathnames. */
2625 absolute = __gnat_is_absolute_path (file_path, strlen (file_name));
2629 if (__gnat_is_regular_file (file_path))
2630 return xstrdup (file_path);
2635 /* If file_name include directory separator(s), try it first as
2636 a path name relative to the current directory */
2637 for (ptr = file_name; *ptr && *ptr != '/' && *ptr != DIR_SEPARATOR; ptr++)
2642 if (__gnat_is_regular_file (file_name))
2643 return xstrdup (file_name);
2650 /* The result has to be smaller than path_val + file_name. */
2651 char *file_path = (char *) alloca (strlen (path_val) + strlen (file_name) + 2);
2655 for (; *path_val == PATH_SEPARATOR; path_val++)
2661 /* Skip the starting quote */
2663 if (*path_val == '"')
2666 for (ptr = file_path; *path_val && *path_val != PATH_SEPARATOR; )
2667 *ptr++ = *path_val++;
2671 /* Skip the ending quote */
2676 if (*ptr != '/' && *ptr != DIR_SEPARATOR)
2677 *++ptr = DIR_SEPARATOR;
2679 strcpy (++ptr, file_name);
2681 if (__gnat_is_regular_file (file_path))
2682 return xstrdup (file_path);
2689 /* Locate an executable given a Path argument. This routine is only used by
2690 gnatbl and should not be used otherwise. Use locate_exec_on_path
2694 __gnat_locate_exec (char *exec_name, char *path_val)
2697 if (!strstr (exec_name, HOST_EXECUTABLE_SUFFIX))
2699 char *full_exec_name
2700 = (char *) alloca (strlen (exec_name) + strlen (HOST_EXECUTABLE_SUFFIX) + 1);
2702 strcpy (full_exec_name, exec_name);
2703 strcat (full_exec_name, HOST_EXECUTABLE_SUFFIX);
2704 ptr = __gnat_locate_regular_file (full_exec_name, path_val);
2707 return __gnat_locate_regular_file (exec_name, path_val);
2711 return __gnat_locate_regular_file (exec_name, path_val);
2714 /* Locate an executable using the Systems default PATH. */
2717 __gnat_locate_exec_on_path (char *exec_name)
2721 #if defined (_WIN32) && !defined (RTX)
2722 TCHAR *wpath_val = _tgetenv (_T("PATH"));
2724 /* In Win32 systems we expand the PATH as for XP environment
2725 variables are not automatically expanded. We also prepend the
2726 ".;" to the path to match normal NT path search semantics */
2728 #define EXPAND_BUFFER_SIZE 32767
2730 wapath_val = alloca (EXPAND_BUFFER_SIZE);
2732 wapath_val [0] = '.';
2733 wapath_val [1] = ';';
2735 DWORD res = ExpandEnvironmentStrings
2736 (wpath_val, &wapath_val[2], EXPAND_BUFFER_SIZE - 2);
2738 if (!res) wapath_val [0] = _T('\0');
2740 apath_val = alloca (EXPAND_BUFFER_SIZE);
2742 WS2SC (apath_val, wapath_val, EXPAND_BUFFER_SIZE);
2743 return __gnat_locate_exec (exec_name, apath_val);
2748 char *path_val = "/VAXC$PATH";
2750 char *path_val = getenv ("PATH");
2752 if (path_val == NULL) return NULL;
2753 apath_val = (char *) alloca (strlen (path_val) + 1);
2754 strcpy (apath_val, path_val);
2755 return __gnat_locate_exec (exec_name, apath_val);
2761 /* These functions are used to translate to and from VMS and Unix syntax
2762 file, directory and path specifications. */
2765 #define MAXNAMES 256
2766 #define NEW_CANONICAL_FILELIST_INCREMENT 64
2768 static char new_canonical_dirspec [MAXPATH];
2769 static char new_canonical_filespec [MAXPATH];
2770 static char new_canonical_pathspec [MAXNAMES*MAXPATH];
2771 static unsigned new_canonical_filelist_index;
2772 static unsigned new_canonical_filelist_in_use;
2773 static unsigned new_canonical_filelist_allocated;
2774 static char **new_canonical_filelist;
2775 static char new_host_pathspec [MAXNAMES*MAXPATH];
2776 static char new_host_dirspec [MAXPATH];
2777 static char new_host_filespec [MAXPATH];
2779 /* Routine is called repeatedly by decc$from_vms via
2780 __gnat_to_canonical_file_list_init until it returns 0 or the expansion
2784 wildcard_translate_unix (char *name)
2787 char buff [MAXPATH];
2789 strncpy (buff, name, MAXPATH);
2790 buff [MAXPATH - 1] = (char) 0;
2791 ver = strrchr (buff, '.');
2793 /* Chop off the version. */
2797 /* Dynamically extend the allocation by the increment. */
2798 if (new_canonical_filelist_in_use == new_canonical_filelist_allocated)
2800 new_canonical_filelist_allocated += NEW_CANONICAL_FILELIST_INCREMENT;
2801 new_canonical_filelist = (char **) xrealloc
2802 (new_canonical_filelist,
2803 new_canonical_filelist_allocated * sizeof (char *));
2806 new_canonical_filelist[new_canonical_filelist_in_use++] = xstrdup (buff);
2811 /* Translate a wildcard VMS file spec into a list of Unix file specs. First do
2812 full translation and copy the results into a list (_init), then return them
2813 one at a time (_next). If onlydirs set, only expand directory files. */
2816 __gnat_to_canonical_file_list_init (char *filespec, int onlydirs)
2819 char buff [MAXPATH];
2821 len = strlen (filespec);
2822 strncpy (buff, filespec, MAXPATH);
2824 /* Only look for directories */
2825 if (onlydirs && !strstr (&buff [len-5], "*.dir"))
2826 strncat (buff, "*.dir", MAXPATH);
2828 buff [MAXPATH - 1] = (char) 0;
2830 decc$from_vms (buff, wildcard_translate_unix, 1);
2832 /* Remove the .dir extension. */
2838 for (i = 0; i < new_canonical_filelist_in_use; i++)
2840 ext = strstr (new_canonical_filelist[i], ".dir");
2846 return new_canonical_filelist_in_use;
2849 /* Return the next filespec in the list. */
2852 __gnat_to_canonical_file_list_next ()
2854 return new_canonical_filelist[new_canonical_filelist_index++];
2857 /* Free storage used in the wildcard expansion. */
2860 __gnat_to_canonical_file_list_free ()
2864 for (i = 0; i < new_canonical_filelist_in_use; i++)
2865 free (new_canonical_filelist[i]);
2867 free (new_canonical_filelist);
2869 new_canonical_filelist_in_use = 0;
2870 new_canonical_filelist_allocated = 0;
2871 new_canonical_filelist_index = 0;
2872 new_canonical_filelist = 0;
2875 /* The functional equivalent of decc$translate_vms routine.
2876 Designed to produce the same output, but is protected against
2877 malformed paths (original version ACCVIOs in this case) and
2878 does not require VMS-specific DECC RTL */
2880 #define NAM$C_MAXRSS 1024
2883 __gnat_translate_vms (char *src)
2885 static char retbuf [NAM$C_MAXRSS+1];
2886 char *srcendpos, *pos1, *pos2, *retpos;
2887 int disp, path_present = 0;
2889 if (!src) return NULL;
2891 srcendpos = strchr (src, '\0');
2894 /* Look for the node and/or device in front of the path */
2896 pos2 = strchr (pos1, ':');
2898 if (pos2 && (pos2 < srcendpos) && (*(pos2 + 1) == ':')) {
2899 /* There is a node name. "node_name::" becomes "node_name!" */
2901 strncpy (retbuf, pos1, disp);
2902 retpos [disp] = '!';
2903 retpos = retpos + disp + 1;
2905 pos2 = strchr (pos1, ':');
2909 /* There is a device name. "dev_name:" becomes "/dev_name/" */
2912 strncpy (retpos, pos1, disp);
2913 retpos = retpos + disp;
2918 /* No explicit device; we must look ahead and prepend /sys$disk/ if
2919 the path is absolute */
2920 if ((*pos1 == '[' || *pos1 == '<') && (pos1 < srcendpos)
2921 && !strchr (".-]>", *(pos1 + 1))) {
2922 strncpy (retpos, "/sys$disk/", 10);
2926 /* Process the path part */
2927 while (*pos1 == '[' || *pos1 == '<') {
2930 if (*pos1 == ']' || *pos1 == '>') {
2931 /* Special case, [] translates to '.' */
2936 /* '[000000' means root dir. It can be present in the middle of
2937 the path due to expansion of logical devices, in which case
2939 if (!strncmp (pos1, "000000", 6) && path_present > 1 &&
2940 (*(pos1 + 6) == ']' || *(pos1 + 6) == '>' || *(pos1 + 6) == '.')) {
2942 if (*pos1 == '.') pos1++;
2944 else if (*pos1 == '.') {
2949 /* There is a qualified path */
2950 while (*pos1 && *pos1 != ']' && *pos1 != '>') {
2953 /* '.' is used to separate directories. Replace it with '/' but
2954 only if there isn't already '/' just before */
2955 if (*(retpos - 1) != '/') *(retpos++) = '/';
2957 if (pos1 + 1 < srcendpos && *pos1 == '.' && *(pos1 + 1) == '.') {
2958 /* ellipsis refers to entire subtree; replace with '**' */
2959 *(retpos++) = '*'; *(retpos++) = '*'; *(retpos++) = '/';
2964 /* When after '.' '[' '<' is equivalent to Unix ".." but there
2965 may be several in a row */
2966 if (*(pos1 - 1) == '.' || *(pos1 - 1) == '[' ||
2967 *(pos1 - 1) == '<') {
2968 while (*pos1 == '-') {
2970 *(retpos++) = '.'; *(retpos++) = '.'; *(retpos++) = '/';
2975 /* otherwise fall through to default */
2977 *(retpos++) = *(pos1++);
2984 if (pos1 < srcendpos) {
2985 /* Now add the actual file name, until the version suffix if any */
2986 if (path_present) *(retpos++) = '/';
2987 pos2 = strchr (pos1, ';');
2988 disp = pos2? (pos2 - pos1) : (srcendpos - pos1);
2989 strncpy (retpos, pos1, disp);
2991 if (pos2 && pos2 < srcendpos) {
2992 /* There is a non-empty version suffix. ";<ver>" becomes ".<ver>" */
2994 disp = srcendpos - pos2 - 1;
2995 strncpy (retpos, pos2 + 1, disp);
3006 /* Translate a VMS syntax directory specification in to Unix syntax. If
3007 PREFIXFLAG is set, append an underscore "/". If no indicators of VMS syntax
3008 found, return input string. Also translate a dirname that contains no
3009 slashes, in case it's a logical name. */
3012 __gnat_to_canonical_dir_spec (char *dirspec, int prefixflag)
3016 strcpy (new_canonical_dirspec, "");
3017 if (strlen (dirspec))
3021 if (strchr (dirspec, ']') || strchr (dirspec, ':'))
3023 strncpy (new_canonical_dirspec,
3024 __gnat_translate_vms (dirspec),
3027 else if (!strchr (dirspec, '/') && (dirspec1 = getenv (dirspec)) != 0)
3029 strncpy (new_canonical_dirspec,
3030 __gnat_translate_vms (dirspec1),
3035 strncpy (new_canonical_dirspec, dirspec, MAXPATH);
3039 len = strlen (new_canonical_dirspec);
3040 if (prefixflag && new_canonical_dirspec [len-1] != '/')
3041 strncat (new_canonical_dirspec, "/", MAXPATH);
3043 new_canonical_dirspec [MAXPATH - 1] = (char) 0;
3045 return new_canonical_dirspec;
3049 /* Translate a VMS syntax file specification into Unix syntax.
3050 If no indicators of VMS syntax found, check if it's an uppercase
3051 alphanumeric_ name and if so try it out as an environment
3052 variable (logical name). If all else fails return the
3056 __gnat_to_canonical_file_spec (char *filespec)
3060 strncpy (new_canonical_filespec, "", MAXPATH);
3062 if (strchr (filespec, ']') || strchr (filespec, ':'))
3064 char *tspec = (char *) __gnat_translate_vms (filespec);
3066 if (tspec != (char *) -1)
3067 strncpy (new_canonical_filespec, tspec, MAXPATH);
3069 else if ((strlen (filespec) == strspn (filespec,
3070 "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_"))
3071 && (filespec1 = getenv (filespec)))
3073 char *tspec = (char *) __gnat_translate_vms (filespec1);
3075 if (tspec != (char *) -1)
3076 strncpy (new_canonical_filespec, tspec, MAXPATH);
3080 strncpy (new_canonical_filespec, filespec, MAXPATH);
3083 new_canonical_filespec [MAXPATH - 1] = (char) 0;
3085 return new_canonical_filespec;
3088 /* Translate a VMS syntax path specification into Unix syntax.
3089 If no indicators of VMS syntax found, return input string. */
3092 __gnat_to_canonical_path_spec (char *pathspec)
3094 char *curr, *next, buff [MAXPATH];
3099 /* If there are /'s, assume it's a Unix path spec and return. */
3100 if (strchr (pathspec, '/'))
3103 new_canonical_pathspec[0] = 0;
3108 next = strchr (curr, ',');
3110 next = strchr (curr, 0);
3112 strncpy (buff, curr, next - curr);
3113 buff[next - curr] = 0;
3115 /* Check for wildcards and expand if present. */
3116 if (strchr (buff, '*') || strchr (buff, '%') || strstr (buff, "..."))
3120 dirs = __gnat_to_canonical_file_list_init (buff, 1);
3121 for (i = 0; i < dirs; i++)
3125 next_dir = __gnat_to_canonical_file_list_next ();
3126 strncat (new_canonical_pathspec, next_dir, MAXPATH);
3128 /* Don't append the separator after the last expansion. */
3130 strncat (new_canonical_pathspec, ":", MAXPATH);
3133 __gnat_to_canonical_file_list_free ();
3136 strncat (new_canonical_pathspec,
3137 __gnat_to_canonical_dir_spec (buff, 0), MAXPATH);
3142 strncat (new_canonical_pathspec, ":", MAXPATH);
3146 new_canonical_pathspec [MAXPATH - 1] = (char) 0;
3148 return new_canonical_pathspec;
3151 static char filename_buff [MAXPATH];
3154 translate_unix (char *name, int type)
3156 strncpy (filename_buff, name, MAXPATH);
3157 filename_buff [MAXPATH - 1] = (char) 0;
3161 /* Translate a Unix syntax path spec into a VMS style (comma separated list of
3165 to_host_path_spec (char *pathspec)
3167 char *curr, *next, buff [MAXPATH];
3172 /* Can't very well test for colons, since that's the Unix separator! */
3173 if (strchr (pathspec, ']') || strchr (pathspec, ','))
3176 new_host_pathspec[0] = 0;
3181 next = strchr (curr, ':');
3183 next = strchr (curr, 0);
3185 strncpy (buff, curr, next - curr);
3186 buff[next - curr] = 0;
3188 strncat (new_host_pathspec, __gnat_to_host_dir_spec (buff, 0), MAXPATH);
3191 strncat (new_host_pathspec, ",", MAXPATH);
3195 new_host_pathspec [MAXPATH - 1] = (char) 0;
3197 return new_host_pathspec;
3200 /* Translate a Unix syntax directory specification into VMS syntax. The
3201 PREFIXFLAG has no effect, but is kept for symmetry with
3202 to_canonical_dir_spec. If indicators of VMS syntax found, return input
3206 __gnat_to_host_dir_spec (char *dirspec, int prefixflag ATTRIBUTE_UNUSED)
3208 int len = strlen (dirspec);
3210 strncpy (new_host_dirspec, dirspec, MAXPATH);
3211 new_host_dirspec [MAXPATH - 1] = (char) 0;
3213 if (strchr (new_host_dirspec, ']') || strchr (new_host_dirspec, ':'))
3214 return new_host_dirspec;
3216 while (len > 1 && new_host_dirspec[len - 1] == '/')
3218 new_host_dirspec[len - 1] = 0;
3222 decc$to_vms (new_host_dirspec, translate_unix, 1, 2);
3223 strncpy (new_host_dirspec, filename_buff, MAXPATH);
3224 new_host_dirspec [MAXPATH - 1] = (char) 0;
3226 return new_host_dirspec;
3229 /* Translate a Unix syntax file specification into VMS syntax.
3230 If indicators of VMS syntax found, return input string. */
3233 __gnat_to_host_file_spec (char *filespec)
3235 strncpy (new_host_filespec, "", MAXPATH);
3236 if (strchr (filespec, ']') || strchr (filespec, ':'))
3238 strncpy (new_host_filespec, filespec, MAXPATH);
3242 decc$to_vms (filespec, translate_unix, 1, 1);
3243 strncpy (new_host_filespec, filename_buff, MAXPATH);
3246 new_host_filespec [MAXPATH - 1] = (char) 0;
3248 return new_host_filespec;
3252 __gnat_adjust_os_resource_limits ()
3254 SYS$ADJWSL (131072, 0);
3259 /* Dummy functions for Osint import for non-VMS systems. */
3262 __gnat_to_canonical_file_list_init
3263 (char *dirspec ATTRIBUTE_UNUSED, int onlydirs ATTRIBUTE_UNUSED)
3269 __gnat_to_canonical_file_list_next (void)
3271 static char *empty = "";
3276 __gnat_to_canonical_file_list_free (void)
3281 __gnat_to_canonical_dir_spec (char *dirspec, int prefixflag ATTRIBUTE_UNUSED)
3287 __gnat_to_canonical_file_spec (char *filespec)
3293 __gnat_to_canonical_path_spec (char *pathspec)
3299 __gnat_to_host_dir_spec (char *dirspec, int prefixflag ATTRIBUTE_UNUSED)
3305 __gnat_to_host_file_spec (char *filespec)
3311 __gnat_adjust_os_resource_limits (void)
3317 /* For EMX, we cannot include dummy in libgcc, since it is too difficult
3318 to coordinate this with the EMX distribution. Consequently, we put the
3319 definition of dummy which is used for exception handling, here. */
3321 #if defined (__EMX__)
3325 #if defined (__mips_vxworks)
3329 CACHE_USER_FLUSH (0, ENTIRE_CACHE);
3333 #if defined (IS_CROSS) \
3334 || (! ((defined (sparc) || defined (i386)) && defined (sun) \
3335 && defined (__SVR4)) \
3336 && ! (defined (linux) && (defined (i386) || defined (__x86_64__))) \
3337 && ! (defined (linux) && defined (__ia64__)) \
3338 && ! (defined (linux) && defined (powerpc)) \
3339 && ! defined (__FreeBSD__) \
3340 && ! defined (__Lynx__) \
3341 && ! defined (__hpux__) \
3342 && ! defined (__APPLE__) \
3343 && ! defined (_AIX) \
3344 && ! (defined (__alpha__) && defined (__osf__)) \
3345 && ! defined (VMS) \
3346 && ! defined (__MINGW32__) \
3347 && ! (defined (__mips) && defined (__sgi)))
3349 /* Dummy function to satisfy g-trasym.o. See the preprocessor conditional
3350 just above for a list of native platforms that provide a non-dummy
3351 version of this procedure in libaddr2line.a. */
3354 convert_addresses (const char *file_name ATTRIBUTE_UNUSED,
3355 void *addrs ATTRIBUTE_UNUSED,
3356 int n_addr ATTRIBUTE_UNUSED,
3357 void *buf ATTRIBUTE_UNUSED,
3358 int *len ATTRIBUTE_UNUSED)
3364 #if defined (_WIN32)
3365 int __gnat_argument_needs_quote = 1;
3367 int __gnat_argument_needs_quote = 0;
3370 /* This option is used to enable/disable object files handling from the
3371 binder file by the GNAT Project module. For example, this is disabled on
3372 Windows (prior to GCC 3.4) as it is already done by the mdll module.
3373 Stating with GCC 3.4 the shared libraries are not based on mdll
3374 anymore as it uses the GCC's -shared option */
3375 #if defined (_WIN32) \
3376 && ((__GNUC__ < 3) || ((__GNUC__ == 3) && (__GNUC_MINOR__ < 4)))
3377 int __gnat_prj_add_obj_files = 0;
3379 int __gnat_prj_add_obj_files = 1;
3382 /* char used as prefix/suffix for environment variables */
3383 #if defined (_WIN32)
3384 char __gnat_environment_char = '%';
3386 char __gnat_environment_char = '$';
3389 /* This functions copy the file attributes from a source file to a
3392 mode = 0 : In this mode copy only the file time stamps (last access and
3393 last modification time stamps).
3395 mode = 1 : In this mode, time stamps and read/write/execute attributes are
3398 Returns 0 if operation was successful and -1 in case of error. */
3401 __gnat_copy_attribs (char *from, char *to, int mode)
3403 #if defined (VMS) || defined (__vxworks) || defined (__nucleus__)
3406 #elif defined (_WIN32) && !defined (RTX)
3407 TCHAR wfrom [GNAT_MAX_PATH_LEN + 2];
3408 TCHAR wto [GNAT_MAX_PATH_LEN + 2];
3410 FILETIME fct, flat, flwt;
3413 S2WSC (wfrom, from, GNAT_MAX_PATH_LEN + 2);
3414 S2WSC (wto, to, GNAT_MAX_PATH_LEN + 2);
3416 /* retrieve from times */
3419 (wfrom, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
3421 if (hfrom == INVALID_HANDLE_VALUE)
3424 res = GetFileTime (hfrom, &fct, &flat, &flwt);
3426 CloseHandle (hfrom);
3431 /* retrieve from times */
3434 (wto, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
3436 if (hto == INVALID_HANDLE_VALUE)
3439 res = SetFileTime (hto, NULL, &flat, &flwt);
3446 /* Set file attributes in full mode. */
3450 DWORD attribs = GetFileAttributes (wfrom);
3452 if (attribs == INVALID_FILE_ATTRIBUTES)
3455 res = SetFileAttributes (wto, attribs);
3463 GNAT_STRUCT_STAT fbuf;
3464 struct utimbuf tbuf;
3466 if (GNAT_STAT (from, &fbuf) == -1)
3471 tbuf.actime = fbuf.st_atime;
3472 tbuf.modtime = fbuf.st_mtime;
3474 if (utime (to, &tbuf) == -1)
3481 if (chmod (to, fbuf.st_mode) == -1)
3492 __gnat_lseek (int fd, long offset, int whence)
3494 return (int) lseek (fd, offset, whence);
3497 /* This function returns the major version number of GCC being used. */
3499 get_gcc_version (void)
3504 return (int) (version_string[0] - '0');
3509 __gnat_set_close_on_exec (int fd ATTRIBUTE_UNUSED,
3510 int close_on_exec_p ATTRIBUTE_UNUSED)
3512 #if defined (F_GETFD) && defined (FD_CLOEXEC) && ! defined (__vxworks)
3513 int flags = fcntl (fd, F_GETFD, 0);
3516 if (close_on_exec_p)
3517 flags |= FD_CLOEXEC;
3519 flags &= ~FD_CLOEXEC;
3520 return fcntl (fd, F_SETFD, flags | FD_CLOEXEC);
3521 #elif defined(_WIN32)
3522 HANDLE h = (HANDLE) _get_osfhandle (fd);
3523 if (h == (HANDLE) -1)
3525 if (close_on_exec_p)
3526 return ! SetHandleInformation (h, HANDLE_FLAG_INHERIT, 0);
3527 return ! SetHandleInformation (h, HANDLE_FLAG_INHERIT,
3528 HANDLE_FLAG_INHERIT);
3530 /* TODO: Unimplemented. */
3535 /* Indicates if platforms supports automatic initialization through the
3536 constructor mechanism */
3538 __gnat_binder_supports_auto_init (void)
3547 /* Indicates that Stand-Alone Libraries are automatically initialized through
3548 the constructor mechanism */
3550 __gnat_sals_init_using_constructors (void)
3552 #if defined (__vxworks) || defined (__Lynx__) || defined (VMS)
3561 /* In RTX mode, the procedure to get the time (as file time) is different
3562 in RTSS mode and Win32 mode. In order to avoid duplicating an Ada file,
3563 we introduce an intermediate procedure to link against the corresponding
3564 one in each situation. */
3566 extern void GetTimeAsFileTime(LPFILETIME pTime);
3568 void GetTimeAsFileTime(LPFILETIME pTime)
3571 RtGetRtssTimeAsFileTime (pTime); /* RTSS interface */
3573 GetSystemTimeAsFileTime (pTime); /* w32 interface */
3578 /* Add symbol that is required to link. It would otherwise be taken from
3579 libgcc.a and it would try to use the gcc constructors that are not
3580 supported by Microsoft linker. */
3582 extern void __main (void);
3584 void __main (void) {}
3588 #if defined (linux) || defined(__GLIBC__)
3589 /* pthread affinity support */
3591 int __gnat_pthread_setaffinity_np (pthread_t th,
3593 const void *cpuset);
3596 #include <pthread.h>
3598 __gnat_pthread_setaffinity_np (pthread_t th,
3600 const cpu_set_t *cpuset)
3602 return pthread_setaffinity_np (th, cpusetsize, cpuset);
3606 __gnat_pthread_setaffinity_np (pthread_t th ATTRIBUTE_UNUSED,
3607 size_t cpusetsize ATTRIBUTE_UNUSED,
3608 const void *cpuset ATTRIBUTE_UNUSED)
3616 /* There is no function in the glibc to retrieve the LWP of the current
3617 thread. We need to do a system call in order to retrieve this
3619 #include <sys/syscall.h>
3620 void *__gnat_lwp_self (void)
3622 return (void *) syscall (__NR_gettid);