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 /* Used for Ada bindings */
328 const int __gnat_size_of_file_attributes = sizeof (struct file_attributes);
330 /* Reset the file attributes as if no system call had been performed */
331 void __gnat_stat_to_attr (int fd, char* name, struct file_attributes* attr);
333 /* The __gnat_max_path_len variable is used to export the maximum
334 length of a path name to Ada code. max_path_len is also provided
335 for compatibility with older GNAT versions, please do not use
338 int __gnat_max_path_len = GNAT_MAX_PATH_LEN;
339 int max_path_len = GNAT_MAX_PATH_LEN;
341 /* Control whether we can use ACL on Windows. */
343 int __gnat_use_acl = 1;
345 /* The following macro HAVE_READDIR_R should be defined if the
346 system provides the routine readdir_r. */
347 #undef HAVE_READDIR_R
349 #if defined(VMS) && defined (__LONG_POINTERS)
351 /* Return a 32 bit pointer to an array of 32 bit pointers
352 given a 64 bit pointer to an array of 64 bit pointers */
354 typedef __char_ptr32 *__char_ptr_char_ptr32 __attribute__ ((mode (SI)));
356 static __char_ptr_char_ptr32
357 to_ptr32 (char **ptr64)
360 __char_ptr_char_ptr32 short_argv;
362 for (argc=0; ptr64[argc]; argc++);
364 /* Reallocate argv with 32 bit pointers. */
365 short_argv = (__char_ptr_char_ptr32) decc$malloc
366 (sizeof (__char_ptr32) * (argc + 1));
368 for (argc=0; ptr64[argc]; argc++)
369 short_argv[argc] = (__char_ptr32) decc$strdup (ptr64[argc]);
371 short_argv[argc] = (__char_ptr32) 0;
375 #define MAYBE_TO_PTR32(argv) to_ptr32 (argv)
377 #define MAYBE_TO_PTR32(argv) argv
381 __gnat_reset_attributes
382 (struct file_attributes* attr)
388 attr->executable = -1;
391 attr->symbolic_link = -1;
392 attr->directory = -1;
394 attr->timestamp = (OS_Time)-2;
395 attr->file_length = -1;
402 time_t res = time (NULL);
403 return (OS_Time) res;
406 /* Return the current local time as a string in the ISO 8601 format of
407 "YYYY-MM-DD HH:MM:SS.SS". The returned string is 22 + 1 (NULL) characters
411 __gnat_current_time_string
414 const char *format = "%Y-%m-%d %H:%M:%S";
415 /* Format string necessary to describe the ISO 8601 format */
417 const time_t t_val = time (NULL);
419 strftime (result, 22, format, localtime (&t_val));
420 /* Convert the local time into a string following the ISO format, copying
421 at most 22 characters into the result string. */
426 /* The sub-seconds are manually set to zero since type time_t lacks the
427 precision necessary for nanoseconds. */
441 time_t time = (time_t) *p_time;
444 /* On Windows systems, the time is sometimes rounded up to the nearest
445 even second, so if the number of seconds is odd, increment it. */
451 res = localtime (&time);
453 res = gmtime (&time);
458 *p_year = res->tm_year;
459 *p_month = res->tm_mon;
460 *p_day = res->tm_mday;
461 *p_hours = res->tm_hour;
462 *p_mins = res->tm_min;
463 *p_secs = res->tm_sec;
466 *p_year = *p_month = *p_day = *p_hours = *p_mins = *p_secs = 0;
469 /* Place the contents of the symbolic link named PATH in the buffer BUF,
470 which has size BUFSIZ. If PATH is a symbolic link, then return the number
471 of characters of its content in BUF. Otherwise, return -1.
472 For systems not supporting symbolic links, always return -1. */
475 __gnat_readlink (char *path ATTRIBUTE_UNUSED,
476 char *buf ATTRIBUTE_UNUSED,
477 size_t bufsiz ATTRIBUTE_UNUSED)
479 #if defined (MSDOS) || defined (_WIN32) || defined (__EMX__) \
480 || defined (VMS) || defined(__vxworks) || defined (__nucleus__)
483 return readlink (path, buf, bufsiz);
487 /* Creates a symbolic link named NEWPATH which contains the string OLDPATH.
488 If NEWPATH exists it will NOT be overwritten.
489 For systems not supporting symbolic links, always return -1. */
492 __gnat_symlink (char *oldpath ATTRIBUTE_UNUSED,
493 char *newpath ATTRIBUTE_UNUSED)
495 #if defined (MSDOS) || defined (_WIN32) || defined (__EMX__) \
496 || defined (VMS) || defined(__vxworks) || defined (__nucleus__)
499 return symlink (oldpath, newpath);
503 /* Try to lock a file, return 1 if success. */
505 #if defined (__vxworks) || defined (__nucleus__) || defined (MSDOS) \
506 || defined (_WIN32) || defined (__EMX__) || defined (VMS)
508 /* Version that does not use link. */
511 __gnat_try_lock (char *dir, char *file)
515 TCHAR wfull_path[GNAT_MAX_PATH_LEN];
516 TCHAR wfile[GNAT_MAX_PATH_LEN];
517 TCHAR wdir[GNAT_MAX_PATH_LEN];
519 S2WSC (wdir, dir, GNAT_MAX_PATH_LEN);
520 S2WSC (wfile, file, GNAT_MAX_PATH_LEN);
522 _stprintf (wfull_path, _T("%s%c%s"), wdir, _T(DIR_SEPARATOR), wfile);
523 fd = _topen (wfull_path, O_CREAT | O_EXCL, 0600);
527 sprintf (full_path, "%s%c%s", dir, DIR_SEPARATOR, file);
528 fd = open (full_path, O_CREAT | O_EXCL, 0600);
540 /* Version using link(), more secure over NFS. */
541 /* See TN 6913-016 for discussion ??? */
544 __gnat_try_lock (char *dir, char *file)
548 GNAT_STRUCT_STAT stat_result;
551 sprintf (full_path, "%s%c%s", dir, DIR_SEPARATOR, file);
552 sprintf (temp_file, "%s%cTMP-%ld-%ld",
553 dir, DIR_SEPARATOR, (long)getpid(), (long)getppid ());
555 /* Create the temporary file and write the process number. */
556 fd = open (temp_file, O_CREAT | O_WRONLY, 0600);
562 /* Link it with the new file. */
563 link (temp_file, full_path);
565 /* Count the references on the old one. If we have a count of two, then
566 the link did succeed. Remove the temporary file before returning. */
567 __gnat_stat (temp_file, &stat_result);
569 return stat_result.st_nlink == 2;
573 /* Return the maximum file name length. */
576 __gnat_get_maximum_file_name_length (void)
581 if (getenv ("GNAT$EXTENDED_FILE_SPECIFICATIONS"))
590 /* Return nonzero if file names are case sensitive. */
593 __gnat_get_file_names_case_sensitive (void)
595 #if defined (__EMX__) || defined (MSDOS) || defined (VMS) || defined (WINNT)
603 __gnat_get_default_identifier_character_set (void)
605 #if defined (__EMX__) || defined (MSDOS)
612 /* Return the current working directory. */
615 __gnat_get_current_dir (char *dir, int *length)
617 #if defined (__MINGW32__)
618 TCHAR wdir[GNAT_MAX_PATH_LEN];
620 _tgetcwd (wdir, *length);
622 WS2SC (dir, wdir, GNAT_MAX_PATH_LEN);
625 /* Force Unix style, which is what GNAT uses internally. */
626 getcwd (dir, *length, 0);
628 getcwd (dir, *length);
631 *length = strlen (dir);
633 if (dir [*length - 1] != DIR_SEPARATOR)
635 dir [*length] = DIR_SEPARATOR;
641 /* Return the suffix for object files. */
644 __gnat_get_object_suffix_ptr (int *len, const char **value)
646 *value = HOST_OBJECT_SUFFIX;
651 *len = strlen (*value);
656 /* Return the suffix for executable files. */
659 __gnat_get_executable_suffix_ptr (int *len, const char **value)
661 *value = HOST_EXECUTABLE_SUFFIX;
665 *len = strlen (*value);
670 /* Return the suffix for debuggable files. Usually this is the same as the
671 executable extension. */
674 __gnat_get_debuggable_suffix_ptr (int *len, const char **value)
677 *value = HOST_EXECUTABLE_SUFFIX;
679 /* On DOS, the extensionless COFF file is what gdb likes. */
686 *len = strlen (*value);
691 /* Returns the OS filename and corresponding encoding. */
694 __gnat_os_filename (char *filename ATTRIBUTE_UNUSED,
695 char *w_filename ATTRIBUTE_UNUSED,
696 char *os_name, int *o_length,
697 char *encoding ATTRIBUTE_UNUSED, int *e_length)
699 #if defined (_WIN32) && ! defined (__vxworks) && ! defined (IS_CROSS)
700 WS2SC (os_name, (TCHAR *)w_filename, (DWORD)*o_length);
701 *o_length = strlen (os_name);
702 strcpy (encoding, "encoding=utf8");
703 *e_length = strlen (encoding);
705 strcpy (os_name, filename);
706 *o_length = strlen (filename);
714 __gnat_unlink (char *path)
716 #if defined (__MINGW32__) && ! defined (__vxworks) && ! defined (IS_CROSS)
718 TCHAR wpath[GNAT_MAX_PATH_LEN];
720 S2WSC (wpath, path, GNAT_MAX_PATH_LEN);
721 return _tunlink (wpath);
724 return unlink (path);
731 __gnat_rename (char *from, char *to)
733 #if defined (__MINGW32__) && ! defined (__vxworks) && ! defined (IS_CROSS)
735 TCHAR wfrom[GNAT_MAX_PATH_LEN], wto[GNAT_MAX_PATH_LEN];
737 S2WSC (wfrom, from, GNAT_MAX_PATH_LEN);
738 S2WSC (wto, to, GNAT_MAX_PATH_LEN);
739 return _trename (wfrom, wto);
742 return rename (from, to);
746 /* Changing directory. */
749 __gnat_chdir (char *path)
751 #if defined (__MINGW32__) && ! defined (__vxworks) && ! defined (IS_CROSS)
753 TCHAR wpath[GNAT_MAX_PATH_LEN];
755 S2WSC (wpath, path, GNAT_MAX_PATH_LEN);
756 return _tchdir (wpath);
763 /* Removing a directory. */
766 __gnat_rmdir (char *path)
768 #if defined (__MINGW32__) && ! defined (__vxworks) && ! defined (IS_CROSS)
770 TCHAR wpath[GNAT_MAX_PATH_LEN];
772 S2WSC (wpath, path, GNAT_MAX_PATH_LEN);
773 return _trmdir (wpath);
775 #elif defined (VTHREADS)
776 /* rmdir not available */
784 __gnat_fopen (char *path, char *mode, 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 _tfopen (wpath, wmode);
801 return decc$fopen (path, mode);
803 return GNAT_FOPEN (path, mode);
808 __gnat_freopen (char *path, char *mode, FILE *stream, int encoding ATTRIBUTE_UNUSED)
810 #if defined (_WIN32) && ! defined (__vxworks) && ! defined (IS_CROSS)
811 TCHAR wpath[GNAT_MAX_PATH_LEN];
814 S2WS (wmode, mode, 10);
816 if (encoding == Encoding_Unspecified)
817 S2WSC (wpath, path, GNAT_MAX_PATH_LEN);
818 else if (encoding == Encoding_UTF8)
819 S2WSU (wpath, path, GNAT_MAX_PATH_LEN);
821 S2WS (wpath, path, GNAT_MAX_PATH_LEN);
823 return _tfreopen (wpath, wmode, stream);
825 return decc$freopen (path, mode, stream);
827 return freopen (path, mode, stream);
832 __gnat_open_read (char *path, int fmode)
835 int o_fmode = O_BINARY;
841 /* Optional arguments mbc,deq,fop increase read performance. */
842 fd = open (path, O_RDONLY | o_fmode, 0444,
843 "mbc=16", "deq=64", "fop=tef");
844 #elif defined (__vxworks)
845 fd = open (path, O_RDONLY | o_fmode, 0444);
846 #elif defined (__MINGW32__)
848 TCHAR wpath[GNAT_MAX_PATH_LEN];
850 S2WSC (wpath, path, GNAT_MAX_PATH_LEN);
851 fd = _topen (wpath, O_RDONLY | o_fmode, 0444);
854 fd = open (path, O_RDONLY | o_fmode);
857 return fd < 0 ? -1 : fd;
860 #if defined (__EMX__) || defined (__MINGW32__)
861 #define PERM (S_IREAD | S_IWRITE)
863 /* Excerpt from DECC C RTL Reference Manual:
864 To create files with OpenVMS RMS default protections using the UNIX
865 system-call functions umask, mkdir, creat, and open, call mkdir, creat,
866 and open with a file-protection mode argument of 0777 in a program
867 that never specifically calls umask. These default protections include
868 correctly establishing protections based on ACLs, previous versions of
872 #define PERM (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH)
876 __gnat_open_rw (char *path, int fmode)
879 int o_fmode = O_BINARY;
885 fd = open (path, O_RDWR | o_fmode, PERM,
886 "mbc=16", "deq=64", "fop=tef");
887 #elif defined (__MINGW32__)
889 TCHAR wpath[GNAT_MAX_PATH_LEN];
891 S2WSC (wpath, path, GNAT_MAX_PATH_LEN);
892 fd = _topen (wpath, O_RDWR | o_fmode, PERM);
895 fd = open (path, O_RDWR | o_fmode, PERM);
898 return fd < 0 ? -1 : fd;
902 __gnat_open_create (char *path, int fmode)
905 int o_fmode = O_BINARY;
911 fd = open (path, O_WRONLY | O_CREAT | O_TRUNC | o_fmode, PERM,
912 "mbc=16", "deq=64", "fop=tef");
913 #elif defined (__MINGW32__)
915 TCHAR wpath[GNAT_MAX_PATH_LEN];
917 S2WSC (wpath, path, GNAT_MAX_PATH_LEN);
918 fd = _topen (wpath, O_WRONLY | O_CREAT | O_TRUNC | o_fmode, PERM);
921 fd = open (path, O_WRONLY | O_CREAT | O_TRUNC | o_fmode, PERM);
924 return fd < 0 ? -1 : fd;
928 __gnat_create_output_file (char *path)
932 fd = open (path, O_WRONLY | O_CREAT | O_TRUNC | O_TEXT, PERM,
933 "rfm=stmlf", "ctx=rec", "rat=none", "rop=nlk",
934 "shr=del,get,put,upd");
935 #elif defined (__MINGW32__)
937 TCHAR wpath[GNAT_MAX_PATH_LEN];
939 S2WSC (wpath, path, GNAT_MAX_PATH_LEN);
940 fd = _topen (wpath, O_WRONLY | O_CREAT | O_TRUNC | O_TEXT, PERM);
943 fd = open (path, O_WRONLY | O_CREAT | O_TRUNC | O_TEXT, PERM);
946 return fd < 0 ? -1 : fd;
950 __gnat_create_output_file_new (char *path)
954 fd = open (path, O_WRONLY | O_CREAT | O_TRUNC | O_TEXT | O_EXCL, PERM,
955 "rfm=stmlf", "ctx=rec", "rat=none", "rop=nlk",
956 "shr=del,get,put,upd");
957 #elif defined (__MINGW32__)
959 TCHAR wpath[GNAT_MAX_PATH_LEN];
961 S2WSC (wpath, path, GNAT_MAX_PATH_LEN);
962 fd = _topen (wpath, O_WRONLY | O_CREAT | O_TRUNC | O_TEXT | O_EXCL, PERM);
965 fd = open (path, O_WRONLY | O_CREAT | O_TRUNC | O_TEXT | O_EXCL, PERM);
968 return fd < 0 ? -1 : fd;
972 __gnat_open_append (char *path, int fmode)
975 int o_fmode = O_BINARY;
981 fd = open (path, O_WRONLY | O_CREAT | O_APPEND | o_fmode, PERM,
982 "mbc=16", "deq=64", "fop=tef");
983 #elif defined (__MINGW32__)
985 TCHAR wpath[GNAT_MAX_PATH_LEN];
987 S2WSC (wpath, path, GNAT_MAX_PATH_LEN);
988 fd = _topen (wpath, O_WRONLY | O_CREAT | O_APPEND | o_fmode, PERM);
991 fd = open (path, O_WRONLY | O_CREAT | O_APPEND | o_fmode, PERM);
994 return fd < 0 ? -1 : fd;
997 /* Open a new file. Return error (-1) if the file already exists. */
1000 __gnat_open_new (char *path, int fmode)
1003 int o_fmode = O_BINARY;
1009 fd = open (path, O_WRONLY | O_CREAT | O_EXCL | o_fmode, PERM,
1010 "mbc=16", "deq=64", "fop=tef");
1011 #elif defined (__MINGW32__)
1013 TCHAR wpath[GNAT_MAX_PATH_LEN];
1015 S2WSC (wpath, path, GNAT_MAX_PATH_LEN);
1016 fd = _topen (wpath, O_WRONLY | O_CREAT | O_EXCL | o_fmode, PERM);
1019 fd = open (path, O_WRONLY | O_CREAT | O_EXCL | o_fmode, PERM);
1022 return fd < 0 ? -1 : fd;
1025 /* Open a new temp file. Return error (-1) if the file already exists.
1026 Special options for VMS allow the file to be shared between parent and child
1027 processes, however they really slow down output. Used in gnatchop. */
1030 __gnat_open_new_temp (char *path, int fmode)
1033 int o_fmode = O_BINARY;
1035 strcpy (path, "GNAT-XXXXXX");
1037 #if (defined (__FreeBSD__) || defined (__NetBSD__) || defined (__OpenBSD__) \
1038 || defined (linux) || defined(__GLIBC__)) && !defined (__vxworks)
1039 return mkstemp (path);
1040 #elif defined (__Lynx__)
1042 #elif defined (__nucleus__)
1045 if (mktemp (path) == NULL)
1053 fd = open (path, O_WRONLY | O_CREAT | O_EXCL | o_fmode, PERM,
1054 "rfm=stmlf", "ctx=rec", "rat=none", "shr=del,get,put,upd",
1055 "mbc=16", "deq=64", "fop=tef");
1057 fd = open (path, O_WRONLY | O_CREAT | O_EXCL | o_fmode, PERM);
1060 return fd < 0 ? -1 : fd;
1063 /****************************************************************
1064 ** Perform a call to GNAT_STAT or GNAT_FSTAT, and extract as much information
1065 ** as possible from it, storing the result in a cache for later reuse
1066 ****************************************************************/
1069 __gnat_stat_to_attr (int fd, char* name, struct file_attributes* attr)
1071 GNAT_STRUCT_STAT statbuf;
1075 ret = GNAT_FSTAT (fd, &statbuf);
1077 ret = __gnat_stat (name, &statbuf);
1079 attr->regular = (!ret && S_ISREG (statbuf.st_mode));
1080 attr->directory = (!ret && S_ISDIR (statbuf.st_mode));
1083 attr->file_length = 0;
1085 /* st_size may be 32 bits, or 64 bits which is converted to long. We
1086 don't return a useful value for files larger than 2 gigabytes in
1088 attr->file_length = statbuf.st_size; /* all systems */
1091 /* on Windows requires extra system call, see comment in __gnat_file_exists_attr */
1092 attr->exists = !ret;
1095 #if !defined (_WIN32) || defined (RTX)
1096 /* on Windows requires extra system call, see __gnat_is_readable_file_attr */
1097 attr->readable = (!ret && (statbuf.st_mode & S_IRUSR));
1098 attr->writable = (!ret && (statbuf.st_mode & S_IWUSR));
1099 attr->executable = (!ret && (statbuf.st_mode & S_IXUSR));
1102 #if !defined (__EMX__) && !defined (MSDOS) && (!defined (_WIN32) || defined (RTX))
1103 /* on Windows requires extra system call, see __gnat_file_time_name_attr */
1105 attr->timestamp = (OS_Time)-1;
1108 /* VMS has file versioning. */
1109 attr->timestamp = (OS_Time)statbuf.st_ctime;
1111 attr->timestamp = (OS_Time)statbuf.st_mtime;
1118 /****************************************************************
1119 ** Return the number of bytes in the specified file
1120 ****************************************************************/
1123 __gnat_file_length_attr (int fd, char* name, struct file_attributes* attr)
1125 if (attr->file_length == -1) {
1126 __gnat_stat_to_attr (fd, name, attr);
1129 return attr->file_length;
1133 __gnat_file_length (int fd)
1135 struct file_attributes attr;
1136 __gnat_reset_attributes (&attr);
1137 return __gnat_file_length_attr (fd, NULL, &attr);
1141 __gnat_named_file_length (char *name)
1143 struct file_attributes attr;
1144 __gnat_reset_attributes (&attr);
1145 return __gnat_file_length_attr (-1, name, &attr);
1148 /* Create a temporary filename and put it in string pointed to by
1152 __gnat_tmp_name (char *tmp_filename)
1155 /* Variable used to create a series of unique names */
1156 static int counter = 0;
1158 /* RTX in RTSS mode does not support tempnam nor tmpnam so we emulate it */
1159 strcpy (tmp_filename, "c:\\WINDOWS\\Temp\\gnat-");
1160 sprintf (&tmp_filename[strlen (tmp_filename)], "%d\0", counter++);
1162 #elif defined (__MINGW32__)
1166 /* tempnam tries to create a temporary file in directory pointed to by
1167 TMP environment variable, in c:\temp if TMP is not set, and in
1168 directory specified by P_tmpdir in stdio.h if c:\temp does not
1169 exist. The filename will be created with the prefix "gnat-". */
1171 pname = (char *) tempnam ("c:\\temp", "gnat-");
1173 /* if pname is NULL, the file was not created properly, the disk is full
1174 or there is no more free temporary files */
1177 *tmp_filename = '\0';
1179 /* If pname start with a back slash and not path information it means that
1180 the filename is valid for the current working directory. */
1182 else if (pname[0] == '\\')
1184 strcpy (tmp_filename, ".\\");
1185 strcat (tmp_filename, pname+1);
1188 strcpy (tmp_filename, pname);
1193 #elif defined (linux) || defined (__FreeBSD__) || defined (__NetBSD__) \
1194 || defined (__OpenBSD__) || defined(__GLIBC__)
1195 #define MAX_SAFE_PATH 1000
1196 char *tmpdir = getenv ("TMPDIR");
1198 /* If tmpdir is longer than MAX_SAFE_PATH, revert to default value to avoid
1199 a buffer overflow. */
1200 if (tmpdir == NULL || strlen (tmpdir) > MAX_SAFE_PATH)
1201 strcpy (tmp_filename, "/tmp/gnat-XXXXXX");
1203 sprintf (tmp_filename, "%s/gnat-XXXXXX", tmpdir);
1205 close (mkstemp(tmp_filename));
1207 tmpnam (tmp_filename);
1211 /* Open directory and returns a DIR pointer. */
1213 DIR* __gnat_opendir (char *name)
1216 /* Not supported in RTX */
1220 #elif defined (__MINGW32__)
1221 TCHAR wname[GNAT_MAX_PATH_LEN];
1223 S2WSC (wname, name, GNAT_MAX_PATH_LEN);
1224 return (DIR*)_topendir (wname);
1227 return opendir (name);
1231 /* Read the next entry in a directory. The returned string points somewhere
1235 __gnat_readdir (DIR *dirp, char *buffer, int *len)
1238 /* Not supported in RTX */
1242 #elif defined (__MINGW32__)
1243 struct _tdirent *dirent = _treaddir ((_TDIR*)dirp);
1247 WS2SC (buffer, dirent->d_name, GNAT_MAX_PATH_LEN);
1248 *len = strlen (buffer);
1255 #elif defined (HAVE_READDIR_R)
1256 /* If possible, try to use the thread-safe version. */
1257 if (readdir_r (dirp, buffer) != NULL)
1259 *len = strlen (((struct dirent*) buffer)->d_name);
1260 return ((struct dirent*) buffer)->d_name;
1266 struct dirent *dirent = (struct dirent *) readdir (dirp);
1270 strcpy (buffer, dirent->d_name);
1271 *len = strlen (buffer);
1280 /* Close a directory entry. */
1282 int __gnat_closedir (DIR *dirp)
1285 /* Not supported in RTX */
1289 #elif defined (__MINGW32__)
1290 return _tclosedir ((_TDIR*)dirp);
1293 return closedir (dirp);
1297 /* Returns 1 if readdir is thread safe, 0 otherwise. */
1300 __gnat_readdir_is_thread_safe (void)
1302 #ifdef HAVE_READDIR_R
1309 #if defined (_WIN32) && !defined (RTX)
1310 /* Number of seconds between <Jan 1st 1601> and <Jan 1st 1970>. */
1311 static const unsigned long long w32_epoch_offset = 11644473600ULL;
1313 /* Returns the file modification timestamp using Win32 routines which are
1314 immune against daylight saving time change. It is in fact not possible to
1315 use fstat for this purpose as the DST modify the st_mtime field of the
1319 win32_filetime (HANDLE h)
1324 unsigned long long ull_time;
1327 /* GetFileTime returns FILETIME data which are the number of 100 nanosecs
1328 since <Jan 1st 1601>. This function must return the number of seconds
1329 since <Jan 1st 1970>. */
1331 if (GetFileTime (h, NULL, NULL, &t_write.ft_time))
1332 return (time_t) (t_write.ull_time / 10000000ULL - w32_epoch_offset);
1337 /* Return a GNAT time stamp given a file name. */
1340 __gnat_file_time_name_attr (char* name, struct file_attributes* attr)
1342 if (attr->timestamp == (OS_Time)-2) {
1343 #if defined (__EMX__) || defined (MSDOS)
1344 int fd = open (name, O_RDONLY | O_BINARY);
1345 time_t ret = __gnat_file_time_fd (fd);
1347 attr->timestamp = (OS_Time)ret;
1349 #elif defined (_WIN32) && !defined (RTX)
1351 TCHAR wname[GNAT_MAX_PATH_LEN];
1352 S2WSC (wname, name, GNAT_MAX_PATH_LEN);
1354 HANDLE h = CreateFile
1355 (wname, GENERIC_READ, FILE_SHARE_READ, 0,
1356 OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0);
1358 if (h != INVALID_HANDLE_VALUE) {
1359 ret = win32_filetime (h);
1362 attr->timestamp = (OS_Time) ret;
1364 __gnat_stat_to_attr (-1, name, attr);
1367 return attr->timestamp;
1371 __gnat_file_time_name (char *name)
1373 struct file_attributes attr;
1374 __gnat_reset_attributes (&attr);
1375 return __gnat_file_time_name_attr (name, &attr);
1378 /* Return a GNAT time stamp given a file descriptor. */
1381 __gnat_file_time_fd_attr (int fd, struct file_attributes* attr)
1383 if (attr->timestamp == (OS_Time)-2) {
1384 /* The following workaround code is due to the fact that under EMX and
1385 DJGPP fstat attempts to convert time values to GMT rather than keep the
1386 actual OS timestamp of the file. By using the OS2/DOS functions directly
1387 the GNAT timestamp are independent of this behavior, which is desired to
1388 facilitate the distribution of GNAT compiled libraries. */
1390 #if defined (__EMX__) || defined (MSDOS)
1394 int ret = DosQueryFileInfo (fd, 1, (unsigned char *) &fs,
1395 sizeof (FILESTATUS));
1397 unsigned file_year = fs.fdateLastWrite.year;
1398 unsigned file_month = fs.fdateLastWrite.month;
1399 unsigned file_day = fs.fdateLastWrite.day;
1400 unsigned file_hour = fs.ftimeLastWrite.hours;
1401 unsigned file_min = fs.ftimeLastWrite.minutes;
1402 unsigned file_tsec = fs.ftimeLastWrite.twosecs;
1406 int ret = getftime (fd, &fs);
1408 unsigned file_year = fs.ft_year;
1409 unsigned file_month = fs.ft_month;
1410 unsigned file_day = fs.ft_day;
1411 unsigned file_hour = fs.ft_hour;
1412 unsigned file_min = fs.ft_min;
1413 unsigned file_tsec = fs.ft_tsec;
1416 /* Calculate the seconds since epoch from the time components. First count
1417 the whole days passed. The value for years returned by the DOS and OS2
1418 functions count years from 1980, so to compensate for the UNIX epoch which
1419 begins in 1970 start with 10 years worth of days and add days for each
1420 four year period since then. */
1423 int cum_days[12] = {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334};
1424 int days_passed = 3652 + (file_year / 4) * 1461;
1425 int years_since_leap = file_year % 4;
1427 if (years_since_leap == 1)
1429 else if (years_since_leap == 2)
1431 else if (years_since_leap == 3)
1432 days_passed += 1096;
1437 days_passed += cum_days[file_month - 1];
1438 if (years_since_leap == 0 && file_year != 20 && file_month > 2)
1441 days_passed += file_day - 1;
1443 /* OK - have whole days. Multiply -- then add in other parts. */
1445 tot_secs = days_passed * 86400;
1446 tot_secs += file_hour * 3600;
1447 tot_secs += file_min * 60;
1448 tot_secs += file_tsec * 2;
1449 attr->timestamp = (OS_Time) tot_secs;
1451 #elif defined (_WIN32) && !defined (RTX)
1452 HANDLE h = (HANDLE) _get_osfhandle (fd);
1453 time_t ret = win32_filetime (h);
1454 attr->timestamp = (OS_Time) ret;
1457 __gnat_stat_to_attr (fd, NULL, attr);
1461 return attr->timestamp;
1465 __gnat_file_time_fd (int fd)
1467 struct file_attributes attr;
1468 __gnat_reset_attributes (&attr);
1469 return __gnat_file_time_fd_attr (fd, &attr);
1472 /* Set the file time stamp. */
1475 __gnat_set_file_time_name (char *name, time_t time_stamp)
1477 #if defined (__EMX__) || defined (MSDOS) || defined (__vxworks)
1479 /* Code to implement __gnat_set_file_time_name for these systems. */
1481 #elif defined (_WIN32) && !defined (RTX)
1485 unsigned long long ull_time;
1487 TCHAR wname[GNAT_MAX_PATH_LEN];
1489 S2WSC (wname, name, GNAT_MAX_PATH_LEN);
1491 HANDLE h = CreateFile
1492 (wname, GENERIC_WRITE, FILE_SHARE_WRITE, NULL,
1493 OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS,
1495 if (h == INVALID_HANDLE_VALUE)
1497 /* Add number of seconds between <Jan 1st 1601> and <Jan 1st 1970> */
1498 t_write.ull_time = ((unsigned long long)time_stamp + w32_epoch_offset);
1499 /* Convert to 100 nanosecond units */
1500 t_write.ull_time *= 10000000ULL;
1502 SetFileTime(h, NULL, NULL, &t_write.ft_time);
1512 unsigned long long backup, create, expire, revise;
1516 unsigned short value;
1519 unsigned system : 4;
1525 } Fat = { 0, 0, 0, 0, 0, { 0 }};
1529 { ATR$S_CREDATE, ATR$C_CREDATE, &Fat.create },
1530 { ATR$S_REVDATE, ATR$C_REVDATE, &Fat.revise },
1531 { ATR$S_EXPDATE, ATR$C_EXPDATE, &Fat.expire },
1532 { ATR$S_BAKDATE, ATR$C_BAKDATE, &Fat.backup },
1533 { ATR$S_FPRO, ATR$C_FPRO, &Fat.prot },
1534 { ATR$S_UIC, ATR$C_UIC, &Fat.uic },
1539 struct dsc$descriptor_fib fibdsc = {sizeof (fib), (void *) &fib};
1543 unsigned long long newtime;
1544 unsigned long long revtime;
1548 struct vstring file;
1549 struct dsc$descriptor_s filedsc
1550 = {NAM$C_MAXRSS, DSC$K_DTYPE_T, DSC$K_CLASS_S, (void *) file.string};
1551 struct vstring device;
1552 struct dsc$descriptor_s devicedsc
1553 = {NAM$C_MAXRSS, DSC$K_DTYPE_T, DSC$K_CLASS_S, (void *) device.string};
1554 struct vstring timev;
1555 struct dsc$descriptor_s timedsc
1556 = {NAM$C_MAXRSS, DSC$K_DTYPE_T, DSC$K_CLASS_S, (void *) timev.string};
1557 struct vstring result;
1558 struct dsc$descriptor_s resultdsc
1559 = {NAM$C_MAXRSS, DSC$K_DTYPE_VT, DSC$K_CLASS_VS, (void *) result.string};
1561 /* Convert parameter name (a file spec) to host file form. Note that this
1562 is needed on VMS to prepare for subsequent calls to VMS RMS library
1563 routines. Note that it would not work to call __gnat_to_host_dir_spec
1564 as was done in a previous version, since this fails silently unless
1565 the feature logical DECC$EFS_CHARSET is enabled, in which case a DNF
1566 (directory not found) condition is signalled. */
1567 tryfile = (char *) __gnat_to_host_file_spec (name);
1569 /* Allocate and initialize a FAB and NAM structures. */
1573 nam.nam$l_esa = file.string;
1574 nam.nam$b_ess = NAM$C_MAXRSS;
1575 nam.nam$l_rsa = result.string;
1576 nam.nam$b_rss = NAM$C_MAXRSS;
1577 fab.fab$l_fna = tryfile;
1578 fab.fab$b_fns = strlen (tryfile);
1579 fab.fab$l_nam = &nam;
1581 /* Validate filespec syntax and device existence. */
1582 status = SYS$PARSE (&fab, 0, 0);
1583 if ((status & 1) != 1)
1584 LIB$SIGNAL (status);
1586 file.string[nam.nam$b_esl] = 0;
1588 /* Find matching filespec. */
1589 status = SYS$SEARCH (&fab, 0, 0);
1590 if ((status & 1) != 1)
1591 LIB$SIGNAL (status);
1593 file.string[nam.nam$b_esl] = 0;
1594 result.string[result.length=nam.nam$b_rsl] = 0;
1596 /* Get the device name and assign an IO channel. */
1597 strncpy (device.string, nam.nam$l_dev, nam.nam$b_dev);
1598 devicedsc.dsc$w_length = nam.nam$b_dev;
1600 status = SYS$ASSIGN (&devicedsc, &chan, 0, 0, 0);
1601 if ((status & 1) != 1)
1602 LIB$SIGNAL (status);
1604 /* Initialize the FIB and fill in the directory id field. */
1605 memset (&fib, 0, sizeof (fib));
1606 fib.fib$w_did[0] = nam.nam$w_did[0];
1607 fib.fib$w_did[1] = nam.nam$w_did[1];
1608 fib.fib$w_did[2] = nam.nam$w_did[2];
1609 fib.fib$l_acctl = 0;
1611 strcpy (file.string, (strrchr (result.string, ']') + 1));
1612 filedsc.dsc$w_length = strlen (file.string);
1613 result.string[result.length = 0] = 0;
1615 /* Open and close the file to fill in the attributes. */
1617 = SYS$QIOW (0, chan, IO$_ACCESS|IO$M_ACCESS, &iosb, 0, 0,
1618 &fibdsc, &filedsc, &result.length, &resultdsc, &atrlst, 0);
1619 if ((status & 1) != 1)
1620 LIB$SIGNAL (status);
1621 if ((iosb.status & 1) != 1)
1622 LIB$SIGNAL (iosb.status);
1624 result.string[result.length] = 0;
1625 status = SYS$QIOW (0, chan, IO$_DEACCESS, &iosb, 0, 0, &fibdsc, 0, 0, 0,
1627 if ((status & 1) != 1)
1628 LIB$SIGNAL (status);
1629 if ((iosb.status & 1) != 1)
1630 LIB$SIGNAL (iosb.status);
1635 /* Set creation time to requested time. */
1636 unix_time_to_vms (time_stamp, newtime);
1638 t = time ((time_t) 0);
1640 /* Set revision time to now in local time. */
1641 unix_time_to_vms (t, revtime);
1644 /* Reopen the file, modify the times and then close. */
1645 fib.fib$l_acctl = FIB$M_WRITE;
1647 = SYS$QIOW (0, chan, IO$_ACCESS|IO$M_ACCESS, &iosb, 0, 0,
1648 &fibdsc, &filedsc, &result.length, &resultdsc, &atrlst, 0);
1649 if ((status & 1) != 1)
1650 LIB$SIGNAL (status);
1651 if ((iosb.status & 1) != 1)
1652 LIB$SIGNAL (iosb.status);
1654 Fat.create = newtime;
1655 Fat.revise = revtime;
1657 status = SYS$QIOW (0, chan, IO$_DEACCESS, &iosb, 0, 0,
1658 &fibdsc, 0, 0, 0, &atrlst, 0);
1659 if ((status & 1) != 1)
1660 LIB$SIGNAL (status);
1661 if ((iosb.status & 1) != 1)
1662 LIB$SIGNAL (iosb.status);
1664 /* Deassign the channel and exit. */
1665 status = SYS$DASSGN (chan);
1666 if ((status & 1) != 1)
1667 LIB$SIGNAL (status);
1669 struct utimbuf utimbuf;
1672 /* Set modification time to requested time. */
1673 utimbuf.modtime = time_stamp;
1675 /* Set access time to now in local time. */
1676 t = time ((time_t) 0);
1677 utimbuf.actime = mktime (localtime (&t));
1679 utime (name, &utimbuf);
1683 /* Get the list of installed standard libraries from the
1684 HKEY_LOCAL_MACHINE\SOFTWARE\Ada Core Technologies\GNAT\Standard Libraries
1688 __gnat_get_libraries_from_registry (void)
1690 char *result = (char *) xmalloc (1);
1694 #if defined (_WIN32) && ! defined (__vxworks) && ! defined (IS_CROSS) \
1698 DWORD name_size, value_size;
1705 /* First open the key. */
1706 res = RegOpenKeyExA (HKEY_LOCAL_MACHINE, "SOFTWARE", 0, KEY_READ, ®_key);
1708 if (res == ERROR_SUCCESS)
1709 res = RegOpenKeyExA (reg_key, "Ada Core Technologies", 0,
1710 KEY_READ, ®_key);
1712 if (res == ERROR_SUCCESS)
1713 res = RegOpenKeyExA (reg_key, "GNAT", 0, KEY_READ, ®_key);
1715 if (res == ERROR_SUCCESS)
1716 res = RegOpenKeyExA (reg_key, "Standard Libraries", 0, KEY_READ, ®_key);
1718 /* If the key exists, read out all the values in it and concatenate them
1720 for (index = 0; res == ERROR_SUCCESS; index++)
1722 value_size = name_size = 256;
1723 res = RegEnumValueA (reg_key, index, name, &name_size, 0,
1724 &type, (LPBYTE)value, &value_size);
1726 if (res == ERROR_SUCCESS && type == REG_SZ)
1728 char *old_result = result;
1730 result = (char *) xmalloc (strlen (old_result) + value_size + 2);
1731 strcpy (result, old_result);
1732 strcat (result, value);
1733 strcat (result, ";");
1738 /* Remove the trailing ";". */
1740 result[strlen (result) - 1] = 0;
1747 __gnat_stat (char *name, GNAT_STRUCT_STAT *statbuf)
1750 /* Under Windows the directory name for the stat function must not be
1751 terminated by a directory separator except if just after a drive name
1752 or with UNC path without directory (only the name of the shared
1753 resource), for example: \\computer\share\ */
1755 TCHAR wname [GNAT_MAX_PATH_LEN + 2];
1758 int dirsep_count = 0;
1760 S2WSC (wname, name, GNAT_MAX_PATH_LEN + 2);
1761 name_len = _tcslen (wname);
1763 if (name_len > GNAT_MAX_PATH_LEN)
1766 last_char = wname[name_len - 1];
1768 while (name_len > 1 && (last_char == _T('\\') || last_char == _T('/')))
1770 wname[name_len - 1] = _T('\0');
1772 last_char = wname[name_len - 1];
1775 /* Count back-slashes. */
1777 for (k=0; k<name_len; k++)
1778 if (wname[k] == _T('\\') || wname[k] == _T('/'))
1781 /* Only a drive letter followed by ':', we must add a directory separator
1782 for the stat routine to work properly. */
1783 if ((name_len == 2 && wname[1] == _T(':'))
1784 || (name_len > 3 && wname[0] == _T('\\') && wname[1] == _T('\\')
1785 && dirsep_count == 3))
1786 _tcscat (wname, _T("\\"));
1788 return _tstat (wname, (struct _stat *)statbuf);
1791 return GNAT_STAT (name, statbuf);
1795 /*************************************************************************
1796 ** Check whether a file exists
1797 *************************************************************************/
1800 __gnat_file_exists_attr (char* name, struct file_attributes* attr)
1802 if (attr->exists == -1) {
1804 /* On Windows do not use __gnat_stat() because of a bug in Microsoft
1805 _stat() routine. When the system time-zone is set with a negative
1806 offset the _stat() routine fails on specific files like CON: */
1807 TCHAR wname [GNAT_MAX_PATH_LEN + 2];
1808 S2WSC (wname, name, GNAT_MAX_PATH_LEN + 2);
1809 attr->exists = GetFileAttributes (wname) != INVALID_FILE_ATTRIBUTES;
1811 __gnat_stat_to_attr (-1, name, attr);
1815 return attr->exists;
1819 __gnat_file_exists (char *name)
1821 struct file_attributes attr;
1822 __gnat_reset_attributes (&attr);
1823 return __gnat_file_exists_attr (name, &attr);
1826 /**********************************************************************
1827 ** Whether name is an absolute path
1828 **********************************************************************/
1831 __gnat_is_absolute_path (char *name, int length)
1834 /* On VxWorks systems, an absolute path can be represented (depending on
1835 the host platform) as either /dir/file, or device:/dir/file, or
1836 device:drive_letter:/dir/file. */
1843 for (index = 0; index < length; index++)
1845 if (name[index] == ':' &&
1846 ((name[index + 1] == '/') ||
1847 (isalpha (name[index + 1]) && index + 2 <= length &&
1848 name[index + 2] == '/')))
1851 else if (name[index] == '/')
1856 return (length != 0) &&
1857 (*name == '/' || *name == DIR_SEPARATOR
1858 #if defined (__EMX__) || defined (MSDOS) || defined (WINNT)
1859 || (length > 1 && ISALPHA (name[0]) && name[1] == ':')
1866 __gnat_is_regular_file_attr (char* name, struct file_attributes* attr)
1868 if (attr->regular == -1) {
1869 __gnat_stat_to_attr (-1, name, attr);
1872 return attr->regular;
1876 __gnat_is_regular_file (char *name)
1878 struct file_attributes attr;
1879 __gnat_reset_attributes (&attr);
1880 return __gnat_is_regular_file_attr (name, &attr);
1884 __gnat_is_directory_attr (char* name, struct file_attributes* attr)
1886 if (attr->directory == -1) {
1887 __gnat_stat_to_attr (-1, name, attr);
1890 return attr->directory;
1894 __gnat_is_directory (char *name)
1896 struct file_attributes attr;
1897 __gnat_reset_attributes (&attr);
1898 return __gnat_is_directory_attr (name, &attr);
1901 #if defined (_WIN32) && !defined (RTX)
1903 /* Returns the same constant as GetDriveType but takes a pathname as
1907 GetDriveTypeFromPath (TCHAR *wfullpath)
1909 TCHAR wdrv[MAX_PATH];
1910 TCHAR wpath[MAX_PATH];
1911 TCHAR wfilename[MAX_PATH];
1912 TCHAR wext[MAX_PATH];
1914 _tsplitpath (wfullpath, wdrv, wpath, wfilename, wext);
1916 if (_tcslen (wdrv) != 0)
1918 /* we have a drive specified. */
1919 _tcscat (wdrv, _T("\\"));
1920 return GetDriveType (wdrv);
1924 /* No drive specified. */
1926 /* Is this a relative path, if so get current drive type. */
1927 if (wpath[0] != _T('\\') ||
1928 (_tcslen (wpath) > 2 && wpath[0] == _T('\\') && wpath[1] != _T('\\')))
1929 return GetDriveType (NULL);
1931 UINT result = GetDriveType (wpath);
1933 /* Cannot guess the drive type, is this \\.\ ? */
1935 if (result == DRIVE_NO_ROOT_DIR &&
1936 _tcslen (wpath) >= 4 && wpath[0] == _T('\\') && wpath[1] == _T('\\')
1937 && wpath[2] == _T('.') && wpath[3] == _T('\\'))
1939 if (_tcslen (wpath) == 4)
1940 _tcscat (wpath, wfilename);
1942 LPTSTR p = &wpath[4];
1943 LPTSTR b = _tcschr (p, _T('\\'));
1946 { /* logical drive \\.\c\dir\file */
1952 _tcscat (p, _T(":\\"));
1954 return GetDriveType (p);
1961 /* This MingW section contains code to work with ACL. */
1963 __gnat_check_OWNER_ACL
1965 DWORD CheckAccessDesired,
1966 GENERIC_MAPPING CheckGenericMapping)
1968 DWORD dwAccessDesired, dwAccessAllowed;
1969 PRIVILEGE_SET PrivilegeSet;
1970 DWORD dwPrivSetSize = sizeof (PRIVILEGE_SET);
1971 BOOL fAccessGranted = FALSE;
1972 HANDLE hToken = NULL;
1974 SECURITY_DESCRIPTOR* pSD = NULL;
1977 (wname, OWNER_SECURITY_INFORMATION |
1978 GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION,
1981 if ((pSD = (PSECURITY_DESCRIPTOR) HeapAlloc
1982 (GetProcessHeap (), HEAP_ZERO_MEMORY, nLength)) == NULL)
1985 /* Obtain the security descriptor. */
1987 if (!GetFileSecurity
1988 (wname, OWNER_SECURITY_INFORMATION |
1989 GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION,
1990 pSD, nLength, &nLength))
1993 if (!ImpersonateSelf (SecurityImpersonation))
1996 if (!OpenThreadToken
1997 (GetCurrentThread(), TOKEN_DUPLICATE | TOKEN_QUERY, FALSE, &hToken))
2000 /* Undoes the effect of ImpersonateSelf. */
2004 /* We want to test for write permissions. */
2006 dwAccessDesired = CheckAccessDesired;
2008 MapGenericMask (&dwAccessDesired, &CheckGenericMapping);
2011 (pSD , /* security descriptor to check */
2012 hToken, /* impersonation token */
2013 dwAccessDesired, /* requested access rights */
2014 &CheckGenericMapping, /* pointer to GENERIC_MAPPING */
2015 &PrivilegeSet, /* receives privileges used in check */
2016 &dwPrivSetSize, /* size of PrivilegeSet buffer */
2017 &dwAccessAllowed, /* receives mask of allowed access rights */
2021 CloseHandle (hToken);
2022 HeapFree (GetProcessHeap (), 0, pSD);
2023 return fAccessGranted;
2027 CloseHandle (hToken);
2028 HeapFree (GetProcessHeap (), 0, pSD);
2033 __gnat_set_OWNER_ACL
2036 DWORD AccessPermissions)
2038 PACL pOldDACL = NULL;
2039 PACL pNewDACL = NULL;
2040 PSECURITY_DESCRIPTOR pSD = NULL;
2042 TCHAR username [100];
2045 /* Get current user, he will act as the owner */
2047 if (!GetUserName (username, &unsize))
2050 if (GetNamedSecurityInfo
2053 DACL_SECURITY_INFORMATION,
2054 NULL, NULL, &pOldDACL, NULL, &pSD) != ERROR_SUCCESS)
2057 BuildExplicitAccessWithName
2058 (&ea, username, AccessPermissions, AccessMode, NO_INHERITANCE);
2060 if (AccessMode == SET_ACCESS)
2062 /* SET_ACCESS, we want to set an explicte set of permissions, do not
2063 merge with current DACL. */
2064 if (SetEntriesInAcl (1, &ea, NULL, &pNewDACL) != ERROR_SUCCESS)
2068 if (SetEntriesInAcl (1, &ea, pOldDACL, &pNewDACL) != ERROR_SUCCESS)
2071 if (SetNamedSecurityInfo
2072 (wname, SE_FILE_OBJECT,
2073 DACL_SECURITY_INFORMATION, NULL, NULL, pNewDACL, NULL) != ERROR_SUCCESS)
2077 LocalFree (pNewDACL);
2080 /* Check if it is possible to use ACL for wname, the file must not be on a
2084 __gnat_can_use_acl (TCHAR *wname)
2086 return __gnat_use_acl && GetDriveTypeFromPath (wname) != DRIVE_REMOTE;
2089 #endif /* defined (_WIN32) && !defined (RTX) */
2092 __gnat_is_readable_file_attr (char* name, struct file_attributes* attr)
2094 if (attr->readable == -1) {
2095 #if defined (_WIN32) && !defined (RTX)
2096 TCHAR wname [GNAT_MAX_PATH_LEN + 2];
2097 GENERIC_MAPPING GenericMapping;
2099 S2WSC (wname, name, GNAT_MAX_PATH_LEN + 2);
2101 if (__gnat_can_use_acl (wname))
2103 ZeroMemory (&GenericMapping, sizeof (GENERIC_MAPPING));
2104 GenericMapping.GenericRead = GENERIC_READ;
2105 attr->readable = __gnat_check_OWNER_ACL (wname, FILE_READ_DATA, GenericMapping);
2108 attr->readable = GetFileAttributes (wname) != INVALID_FILE_ATTRIBUTES;
2110 __gnat_stat_to_attr (-1, name, attr);
2114 return attr->readable;
2118 __gnat_is_readable_file (char *name)
2120 struct file_attributes attr;
2121 __gnat_reset_attributes (&attr);
2122 return __gnat_is_readable_file_attr (name, &attr);
2126 __gnat_is_writable_file_attr (char* name, struct file_attributes* attr)
2128 if (attr->writable == -1) {
2129 #if defined (_WIN32) && !defined (RTX)
2130 TCHAR wname [GNAT_MAX_PATH_LEN + 2];
2131 GENERIC_MAPPING GenericMapping;
2133 S2WSC (wname, name, GNAT_MAX_PATH_LEN + 2);
2135 if (__gnat_can_use_acl (wname))
2137 ZeroMemory (&GenericMapping, sizeof (GENERIC_MAPPING));
2138 GenericMapping.GenericWrite = GENERIC_WRITE;
2140 attr->writable = __gnat_check_OWNER_ACL
2141 (wname, FILE_WRITE_DATA | FILE_APPEND_DATA, GenericMapping)
2142 && !(GetFileAttributes (wname) & FILE_ATTRIBUTE_READONLY);
2145 attr->writable = !(GetFileAttributes (wname) & FILE_ATTRIBUTE_READONLY);
2148 __gnat_stat_to_attr (-1, name, attr);
2152 return attr->writable;
2156 __gnat_is_writable_file (char *name)
2158 struct file_attributes attr;
2159 __gnat_reset_attributes (&attr);
2160 return __gnat_is_writable_file_attr (name, &attr);
2164 __gnat_is_executable_file_attr (char* name, struct file_attributes* attr)
2166 if (attr->executable == -1) {
2167 #if defined (_WIN32) && !defined (RTX)
2168 TCHAR wname [GNAT_MAX_PATH_LEN + 2];
2169 GENERIC_MAPPING GenericMapping;
2171 S2WSC (wname, name, GNAT_MAX_PATH_LEN + 2);
2173 if (__gnat_can_use_acl (wname))
2175 ZeroMemory (&GenericMapping, sizeof (GENERIC_MAPPING));
2176 GenericMapping.GenericExecute = GENERIC_EXECUTE;
2178 attr->executable = __gnat_check_OWNER_ACL (wname, FILE_EXECUTE, GenericMapping);
2181 attr->executable = GetFileAttributes (wname) != INVALID_FILE_ATTRIBUTES
2182 && _tcsstr (wname, _T(".exe")) - wname == (int) (_tcslen (wname) - 4);
2184 __gnat_stat_to_attr (-1, name, attr);
2188 return attr->executable;
2192 __gnat_is_executable_file (char *name)
2194 struct file_attributes attr;
2195 __gnat_reset_attributes (&attr);
2196 return __gnat_is_executable_file_attr (name, &attr);
2200 __gnat_set_writable (char *name)
2202 #if defined (_WIN32) && !defined (RTX)
2203 TCHAR wname [GNAT_MAX_PATH_LEN + 2];
2205 S2WSC (wname, name, GNAT_MAX_PATH_LEN + 2);
2207 if (__gnat_can_use_acl (wname))
2208 __gnat_set_OWNER_ACL (wname, GRANT_ACCESS, FILE_GENERIC_WRITE);
2211 (wname, GetFileAttributes (wname) & ~FILE_ATTRIBUTE_READONLY);
2212 #elif ! defined (__vxworks) && ! defined(__nucleus__)
2213 GNAT_STRUCT_STAT statbuf;
2215 if (GNAT_STAT (name, &statbuf) == 0)
2217 statbuf.st_mode = statbuf.st_mode | S_IWUSR;
2218 chmod (name, statbuf.st_mode);
2224 __gnat_set_executable (char *name)
2226 #if defined (_WIN32) && !defined (RTX)
2227 TCHAR wname [GNAT_MAX_PATH_LEN + 2];
2229 S2WSC (wname, name, GNAT_MAX_PATH_LEN + 2);
2231 if (__gnat_can_use_acl (wname))
2232 __gnat_set_OWNER_ACL (wname, GRANT_ACCESS, FILE_GENERIC_EXECUTE);
2234 #elif ! defined (__vxworks) && ! defined(__nucleus__)
2235 GNAT_STRUCT_STAT statbuf;
2237 if (GNAT_STAT (name, &statbuf) == 0)
2239 statbuf.st_mode = statbuf.st_mode | S_IXUSR;
2240 chmod (name, statbuf.st_mode);
2246 __gnat_set_non_writable (char *name)
2248 #if defined (_WIN32) && !defined (RTX)
2249 TCHAR wname [GNAT_MAX_PATH_LEN + 2];
2251 S2WSC (wname, name, GNAT_MAX_PATH_LEN + 2);
2253 if (__gnat_can_use_acl (wname))
2254 __gnat_set_OWNER_ACL
2255 (wname, DENY_ACCESS,
2256 FILE_WRITE_DATA | FILE_APPEND_DATA |
2257 FILE_WRITE_EA | FILE_WRITE_ATTRIBUTES);
2260 (wname, GetFileAttributes (wname) | FILE_ATTRIBUTE_READONLY);
2261 #elif ! defined (__vxworks) && ! defined(__nucleus__)
2262 GNAT_STRUCT_STAT statbuf;
2264 if (GNAT_STAT (name, &statbuf) == 0)
2266 statbuf.st_mode = statbuf.st_mode & 07577;
2267 chmod (name, statbuf.st_mode);
2273 __gnat_set_readable (char *name)
2275 #if defined (_WIN32) && !defined (RTX)
2276 TCHAR wname [GNAT_MAX_PATH_LEN + 2];
2278 S2WSC (wname, name, GNAT_MAX_PATH_LEN + 2);
2280 if (__gnat_can_use_acl (wname))
2281 __gnat_set_OWNER_ACL (wname, GRANT_ACCESS, FILE_GENERIC_READ);
2283 #elif ! defined (__vxworks) && ! defined(__nucleus__)
2284 GNAT_STRUCT_STAT statbuf;
2286 if (GNAT_STAT (name, &statbuf) == 0)
2288 chmod (name, statbuf.st_mode | S_IREAD);
2294 __gnat_set_non_readable (char *name)
2296 #if defined (_WIN32) && !defined (RTX)
2297 TCHAR wname [GNAT_MAX_PATH_LEN + 2];
2299 S2WSC (wname, name, GNAT_MAX_PATH_LEN + 2);
2301 if (__gnat_can_use_acl (wname))
2302 __gnat_set_OWNER_ACL (wname, DENY_ACCESS, FILE_GENERIC_READ);
2304 #elif ! defined (__vxworks) && ! defined(__nucleus__)
2305 GNAT_STRUCT_STAT statbuf;
2307 if (GNAT_STAT (name, &statbuf) == 0)
2309 chmod (name, statbuf.st_mode & (~S_IREAD));
2315 __gnat_is_symbolic_link_attr (char* name, struct file_attributes* attr)
2317 if (attr->symbolic_link == -1) {
2318 #if defined (__vxworks) || defined (__nucleus__)
2319 attr->symbolic_link = 0;
2321 #elif defined (_AIX) || defined (__APPLE__) || defined (__unix__)
2323 GNAT_STRUCT_STAT statbuf;
2324 ret = GNAT_LSTAT (name, &statbuf);
2325 attr->symbolic_link = (!ret && S_ISLNK (statbuf.st_mode));
2327 attr->symbolic_link = 0;
2330 return attr->symbolic_link;
2334 __gnat_is_symbolic_link (char *name ATTRIBUTE_UNUSED)
2336 struct file_attributes attr;
2337 __gnat_reset_attributes (&attr);
2338 return __gnat_is_symbolic_link_attr (name, &attr);
2342 #if defined (sun) && defined (__SVR4)
2343 /* Using fork on Solaris will duplicate all the threads. fork1, which
2344 duplicates only the active thread, must be used instead, or spawning
2345 subprocess from a program with tasking will lead into numerous problems. */
2350 __gnat_portable_spawn (char *args[])
2353 int finished ATTRIBUTE_UNUSED;
2354 int pid ATTRIBUTE_UNUSED;
2356 #if defined (__vxworks) || defined(__nucleus__) || defined(RTX)
2359 #elif defined (MSDOS) || defined (_WIN32)
2360 /* args[0] must be quotes as it could contain a full pathname with spaces */
2361 char *args_0 = args[0];
2362 args[0] = (char *)xmalloc (strlen (args_0) + 3);
2363 strcpy (args[0], "\"");
2364 strcat (args[0], args_0);
2365 strcat (args[0], "\"");
2367 status = spawnvp (P_WAIT, args_0, (const char* const*)args);
2369 /* restore previous value */
2371 args[0] = (char *)args_0;
2381 pid = spawnvp (P_NOWAIT, args[0], args);
2393 if (execv (args[0], MAYBE_TO_PTR32 (args)) != 0)
2395 return -1; /* execv is in parent context on VMS. */
2403 finished = waitpid (pid, &status, 0);
2405 if (finished != pid || WIFEXITED (status) == 0)
2408 return WEXITSTATUS (status);
2414 /* Create a copy of the given file descriptor.
2415 Return -1 if an error occurred. */
2418 __gnat_dup (int oldfd)
2420 #if defined (__vxworks) && !defined (__RTP__)
2421 /* Not supported on VxWorks 5.x, but supported on VxWorks 6.0 when using
2429 /* Make newfd be the copy of oldfd, closing newfd first if necessary.
2430 Return -1 if an error occurred. */
2433 __gnat_dup2 (int oldfd, int newfd)
2435 #if defined (__vxworks) && !defined (__RTP__)
2436 /* Not supported on VxWorks 5.x, but supported on VxWorks 6.0 when using
2440 return dup2 (oldfd, newfd);
2444 /* WIN32 code to implement a wait call that wait for any child process. */
2446 #if defined (_WIN32) && !defined (RTX)
2448 /* Synchronization code, to be thread safe. */
2452 /* For the Cert run times on native Windows we use dummy functions
2453 for locking and unlocking tasks since we do not support multiple
2454 threads on this configuration (Cert run time on native Windows). */
2456 void dummy (void) {}
2458 void (*Lock_Task) () = &dummy;
2459 void (*Unlock_Task) () = &dummy;
2463 #define Lock_Task system__soft_links__lock_task
2464 extern void (*Lock_Task) (void);
2466 #define Unlock_Task system__soft_links__unlock_task
2467 extern void (*Unlock_Task) (void);
2471 static HANDLE *HANDLES_LIST = NULL;
2472 static int *PID_LIST = NULL, plist_length = 0, plist_max_length = 0;
2475 add_handle (HANDLE h)
2478 /* -------------------- critical section -------------------- */
2481 if (plist_length == plist_max_length)
2483 plist_max_length += 1000;
2485 xrealloc (HANDLES_LIST, sizeof (HANDLE) * plist_max_length);
2487 xrealloc (PID_LIST, sizeof (int) * plist_max_length);
2490 HANDLES_LIST[plist_length] = h;
2491 PID_LIST[plist_length] = GetProcessId (h);
2495 /* -------------------- critical section -------------------- */
2499 __gnat_win32_remove_handle (HANDLE h, int pid)
2503 /* -------------------- critical section -------------------- */
2506 for (j = 0; j < plist_length; j++)
2508 if ((HANDLES_LIST[j] == h) || (PID_LIST[j] == pid))
2512 HANDLES_LIST[j] = HANDLES_LIST[plist_length];
2513 PID_LIST[j] = PID_LIST[plist_length];
2519 /* -------------------- critical section -------------------- */
2523 win32_no_block_spawn (char *command, char *args[])
2527 PROCESS_INFORMATION PI;
2528 SECURITY_ATTRIBUTES SA;
2533 /* compute the total command line length */
2537 csize += strlen (args[k]) + 1;
2541 full_command = (char *) xmalloc (csize);
2544 SI.cb = sizeof (STARTUPINFO);
2545 SI.lpReserved = NULL;
2546 SI.lpReserved2 = NULL;
2547 SI.lpDesktop = NULL;
2551 SI.wShowWindow = SW_HIDE;
2553 /* Security attributes. */
2554 SA.nLength = sizeof (SECURITY_ATTRIBUTES);
2555 SA.bInheritHandle = TRUE;
2556 SA.lpSecurityDescriptor = NULL;
2558 /* Prepare the command string. */
2559 strcpy (full_command, command);
2560 strcat (full_command, " ");
2565 strcat (full_command, args[k]);
2566 strcat (full_command, " ");
2571 int wsize = csize * 2;
2572 TCHAR *wcommand = (TCHAR *) xmalloc (wsize);
2574 S2WSC (wcommand, full_command, wsize);
2576 free (full_command);
2578 result = CreateProcess
2579 (NULL, wcommand, &SA, NULL, TRUE,
2580 GetPriorityClass (GetCurrentProcess()), NULL, NULL, &SI, &PI);
2587 CloseHandle (PI.hThread);
2595 win32_wait (int *status)
2597 DWORD exitcode, pid;
2604 if (plist_length == 0)
2612 /* -------------------- critical section -------------------- */
2615 hl_len = plist_length;
2617 hl = (HANDLE *) xmalloc (sizeof (HANDLE) * hl_len);
2619 memmove (hl, HANDLES_LIST, sizeof (HANDLE) * hl_len);
2622 /* -------------------- critical section -------------------- */
2624 res = WaitForMultipleObjects (hl_len, hl, FALSE, INFINITE);
2625 h = hl[res - WAIT_OBJECT_0];
2627 GetExitCodeProcess (h, &exitcode);
2628 pid = GetProcessId (h);
2629 __gnat_win32_remove_handle (h, -1);
2633 *status = (int) exitcode;
2640 __gnat_portable_no_block_spawn (char *args[])
2643 #if defined (__vxworks) || defined (__nucleus__) || defined (RTX)
2646 #elif defined (__EMX__) || defined (MSDOS)
2648 /* ??? For PC machines I (Franco) don't know the system calls to implement
2649 this routine. So I'll fake it as follows. This routine will behave
2650 exactly like the blocking portable_spawn and will systematically return
2651 a pid of 0 unless the spawned task did not complete successfully, in
2652 which case we return a pid of -1. To synchronize with this the
2653 portable_wait below systematically returns a pid of 0 and reports that
2654 the subprocess terminated successfully. */
2656 if (spawnvp (P_WAIT, args[0], args) != 0)
2659 #elif defined (_WIN32)
2663 h = win32_no_block_spawn (args[0], args);
2667 return GetProcessId (h);
2679 if (execv (args[0], MAYBE_TO_PTR32 (args)) != 0)
2681 return -1; /* execv is in parent context on VMS. */
2693 __gnat_portable_wait (int *process_status)
2698 #if defined (__vxworks) || defined (__nucleus__) || defined (RTX)
2699 /* Not sure what to do here, so do same as __EMX__ case, i.e., nothing but
2702 #elif defined (_WIN32)
2704 pid = win32_wait (&status);
2706 #elif defined (__EMX__) || defined (MSDOS)
2707 /* ??? See corresponding comment in portable_no_block_spawn. */
2711 pid = waitpid (-1, &status, 0);
2712 status = status & 0xffff;
2715 *process_status = status;
2720 __gnat_os_exit (int status)
2725 /* Locate a regular file, give a Path value. */
2728 __gnat_locate_regular_file (char *file_name, char *path_val)
2731 char *file_path = (char *) alloca (strlen (file_name) + 1);
2734 /* Return immediately if file_name is empty */
2736 if (*file_name == '\0')
2739 /* Remove quotes around file_name if present */
2745 strcpy (file_path, ptr);
2747 ptr = file_path + strlen (file_path) - 1;
2752 /* Handle absolute pathnames. */
2754 absolute = __gnat_is_absolute_path (file_path, strlen (file_name));
2758 if (__gnat_is_regular_file (file_path))
2759 return xstrdup (file_path);
2764 /* If file_name include directory separator(s), try it first as
2765 a path name relative to the current directory */
2766 for (ptr = file_name; *ptr && *ptr != '/' && *ptr != DIR_SEPARATOR; ptr++)
2771 if (__gnat_is_regular_file (file_name))
2772 return xstrdup (file_name);
2779 /* The result has to be smaller than path_val + file_name. */
2780 char *file_path = (char *) alloca (strlen (path_val) + strlen (file_name) + 2);
2784 for (; *path_val == PATH_SEPARATOR; path_val++)
2790 /* Skip the starting quote */
2792 if (*path_val == '"')
2795 for (ptr = file_path; *path_val && *path_val != PATH_SEPARATOR; )
2796 *ptr++ = *path_val++;
2800 /* Skip the ending quote */
2805 if (*ptr != '/' && *ptr != DIR_SEPARATOR)
2806 *++ptr = DIR_SEPARATOR;
2808 strcpy (++ptr, file_name);
2810 if (__gnat_is_regular_file (file_path))
2811 return xstrdup (file_path);
2818 /* Locate an executable given a Path argument. This routine is only used by
2819 gnatbl and should not be used otherwise. Use locate_exec_on_path
2823 __gnat_locate_exec (char *exec_name, char *path_val)
2826 if (!strstr (exec_name, HOST_EXECUTABLE_SUFFIX))
2828 char *full_exec_name
2829 = (char *) alloca (strlen (exec_name) + strlen (HOST_EXECUTABLE_SUFFIX) + 1);
2831 strcpy (full_exec_name, exec_name);
2832 strcat (full_exec_name, HOST_EXECUTABLE_SUFFIX);
2833 ptr = __gnat_locate_regular_file (full_exec_name, path_val);
2836 return __gnat_locate_regular_file (exec_name, path_val);
2840 return __gnat_locate_regular_file (exec_name, path_val);
2843 /* Locate an executable using the Systems default PATH. */
2846 __gnat_locate_exec_on_path (char *exec_name)
2850 #if defined (_WIN32) && !defined (RTX)
2851 TCHAR *wpath_val = _tgetenv (_T("PATH"));
2853 /* In Win32 systems we expand the PATH as for XP environment
2854 variables are not automatically expanded. We also prepend the
2855 ".;" to the path to match normal NT path search semantics */
2857 #define EXPAND_BUFFER_SIZE 32767
2859 wapath_val = alloca (EXPAND_BUFFER_SIZE);
2861 wapath_val [0] = '.';
2862 wapath_val [1] = ';';
2864 DWORD res = ExpandEnvironmentStrings
2865 (wpath_val, &wapath_val[2], EXPAND_BUFFER_SIZE - 2);
2867 if (!res) wapath_val [0] = _T('\0');
2869 apath_val = alloca (EXPAND_BUFFER_SIZE);
2871 WS2SC (apath_val, wapath_val, EXPAND_BUFFER_SIZE);
2872 return __gnat_locate_exec (exec_name, apath_val);
2877 char *path_val = "/VAXC$PATH";
2879 char *path_val = getenv ("PATH");
2881 if (path_val == NULL) return NULL;
2882 apath_val = (char *) alloca (strlen (path_val) + 1);
2883 strcpy (apath_val, path_val);
2884 return __gnat_locate_exec (exec_name, apath_val);
2890 /* These functions are used to translate to and from VMS and Unix syntax
2891 file, directory and path specifications. */
2894 #define MAXNAMES 256
2895 #define NEW_CANONICAL_FILELIST_INCREMENT 64
2897 static char new_canonical_dirspec [MAXPATH];
2898 static char new_canonical_filespec [MAXPATH];
2899 static char new_canonical_pathspec [MAXNAMES*MAXPATH];
2900 static unsigned new_canonical_filelist_index;
2901 static unsigned new_canonical_filelist_in_use;
2902 static unsigned new_canonical_filelist_allocated;
2903 static char **new_canonical_filelist;
2904 static char new_host_pathspec [MAXNAMES*MAXPATH];
2905 static char new_host_dirspec [MAXPATH];
2906 static char new_host_filespec [MAXPATH];
2908 /* Routine is called repeatedly by decc$from_vms via
2909 __gnat_to_canonical_file_list_init until it returns 0 or the expansion
2913 wildcard_translate_unix (char *name)
2916 char buff [MAXPATH];
2918 strncpy (buff, name, MAXPATH);
2919 buff [MAXPATH - 1] = (char) 0;
2920 ver = strrchr (buff, '.');
2922 /* Chop off the version. */
2926 /* Dynamically extend the allocation by the increment. */
2927 if (new_canonical_filelist_in_use == new_canonical_filelist_allocated)
2929 new_canonical_filelist_allocated += NEW_CANONICAL_FILELIST_INCREMENT;
2930 new_canonical_filelist = (char **) xrealloc
2931 (new_canonical_filelist,
2932 new_canonical_filelist_allocated * sizeof (char *));
2935 new_canonical_filelist[new_canonical_filelist_in_use++] = xstrdup (buff);
2940 /* Translate a wildcard VMS file spec into a list of Unix file specs. First do
2941 full translation and copy the results into a list (_init), then return them
2942 one at a time (_next). If onlydirs set, only expand directory files. */
2945 __gnat_to_canonical_file_list_init (char *filespec, int onlydirs)
2948 char buff [MAXPATH];
2950 len = strlen (filespec);
2951 strncpy (buff, filespec, MAXPATH);
2953 /* Only look for directories */
2954 if (onlydirs && !strstr (&buff [len-5], "*.dir"))
2955 strncat (buff, "*.dir", MAXPATH);
2957 buff [MAXPATH - 1] = (char) 0;
2959 decc$from_vms (buff, wildcard_translate_unix, 1);
2961 /* Remove the .dir extension. */
2967 for (i = 0; i < new_canonical_filelist_in_use; i++)
2969 ext = strstr (new_canonical_filelist[i], ".dir");
2975 return new_canonical_filelist_in_use;
2978 /* Return the next filespec in the list. */
2981 __gnat_to_canonical_file_list_next ()
2983 return new_canonical_filelist[new_canonical_filelist_index++];
2986 /* Free storage used in the wildcard expansion. */
2989 __gnat_to_canonical_file_list_free ()
2993 for (i = 0; i < new_canonical_filelist_in_use; i++)
2994 free (new_canonical_filelist[i]);
2996 free (new_canonical_filelist);
2998 new_canonical_filelist_in_use = 0;
2999 new_canonical_filelist_allocated = 0;
3000 new_canonical_filelist_index = 0;
3001 new_canonical_filelist = 0;
3004 /* The functional equivalent of decc$translate_vms routine.
3005 Designed to produce the same output, but is protected against
3006 malformed paths (original version ACCVIOs in this case) and
3007 does not require VMS-specific DECC RTL */
3009 #define NAM$C_MAXRSS 1024
3012 __gnat_translate_vms (char *src)
3014 static char retbuf [NAM$C_MAXRSS+1];
3015 char *srcendpos, *pos1, *pos2, *retpos;
3016 int disp, path_present = 0;
3018 if (!src) return NULL;
3020 srcendpos = strchr (src, '\0');
3023 /* Look for the node and/or device in front of the path */
3025 pos2 = strchr (pos1, ':');
3027 if (pos2 && (pos2 < srcendpos) && (*(pos2 + 1) == ':')) {
3028 /* There is a node name. "node_name::" becomes "node_name!" */
3030 strncpy (retbuf, pos1, disp);
3031 retpos [disp] = '!';
3032 retpos = retpos + disp + 1;
3034 pos2 = strchr (pos1, ':');
3038 /* There is a device name. "dev_name:" becomes "/dev_name/" */
3041 strncpy (retpos, pos1, disp);
3042 retpos = retpos + disp;
3047 /* No explicit device; we must look ahead and prepend /sys$disk/ if
3048 the path is absolute */
3049 if ((*pos1 == '[' || *pos1 == '<') && (pos1 < srcendpos)
3050 && !strchr (".-]>", *(pos1 + 1))) {
3051 strncpy (retpos, "/sys$disk/", 10);
3055 /* Process the path part */
3056 while (*pos1 == '[' || *pos1 == '<') {
3059 if (*pos1 == ']' || *pos1 == '>') {
3060 /* Special case, [] translates to '.' */
3065 /* '[000000' means root dir. It can be present in the middle of
3066 the path due to expansion of logical devices, in which case
3068 if (!strncmp (pos1, "000000", 6) && path_present > 1 &&
3069 (*(pos1 + 6) == ']' || *(pos1 + 6) == '>' || *(pos1 + 6) == '.')) {
3071 if (*pos1 == '.') pos1++;
3073 else if (*pos1 == '.') {
3078 /* There is a qualified path */
3079 while (*pos1 && *pos1 != ']' && *pos1 != '>') {
3082 /* '.' is used to separate directories. Replace it with '/' but
3083 only if there isn't already '/' just before */
3084 if (*(retpos - 1) != '/') *(retpos++) = '/';
3086 if (pos1 + 1 < srcendpos && *pos1 == '.' && *(pos1 + 1) == '.') {
3087 /* ellipsis refers to entire subtree; replace with '**' */
3088 *(retpos++) = '*'; *(retpos++) = '*'; *(retpos++) = '/';
3093 /* When after '.' '[' '<' is equivalent to Unix ".." but there
3094 may be several in a row */
3095 if (*(pos1 - 1) == '.' || *(pos1 - 1) == '[' ||
3096 *(pos1 - 1) == '<') {
3097 while (*pos1 == '-') {
3099 *(retpos++) = '.'; *(retpos++) = '.'; *(retpos++) = '/';
3104 /* otherwise fall through to default */
3106 *(retpos++) = *(pos1++);
3113 if (pos1 < srcendpos) {
3114 /* Now add the actual file name, until the version suffix if any */
3115 if (path_present) *(retpos++) = '/';
3116 pos2 = strchr (pos1, ';');
3117 disp = pos2? (pos2 - pos1) : (srcendpos - pos1);
3118 strncpy (retpos, pos1, disp);
3120 if (pos2 && pos2 < srcendpos) {
3121 /* There is a non-empty version suffix. ";<ver>" becomes ".<ver>" */
3123 disp = srcendpos - pos2 - 1;
3124 strncpy (retpos, pos2 + 1, disp);
3135 /* Translate a VMS syntax directory specification in to Unix syntax. If
3136 PREFIXFLAG is set, append an underscore "/". If no indicators of VMS syntax
3137 found, return input string. Also translate a dirname that contains no
3138 slashes, in case it's a logical name. */
3141 __gnat_to_canonical_dir_spec (char *dirspec, int prefixflag)
3145 strcpy (new_canonical_dirspec, "");
3146 if (strlen (dirspec))
3150 if (strchr (dirspec, ']') || strchr (dirspec, ':'))
3152 strncpy (new_canonical_dirspec,
3153 __gnat_translate_vms (dirspec),
3156 else if (!strchr (dirspec, '/') && (dirspec1 = getenv (dirspec)) != 0)
3158 strncpy (new_canonical_dirspec,
3159 __gnat_translate_vms (dirspec1),
3164 strncpy (new_canonical_dirspec, dirspec, MAXPATH);
3168 len = strlen (new_canonical_dirspec);
3169 if (prefixflag && new_canonical_dirspec [len-1] != '/')
3170 strncat (new_canonical_dirspec, "/", MAXPATH);
3172 new_canonical_dirspec [MAXPATH - 1] = (char) 0;
3174 return new_canonical_dirspec;
3178 /* Translate a VMS syntax file specification into Unix syntax.
3179 If no indicators of VMS syntax found, check if it's an uppercase
3180 alphanumeric_ name and if so try it out as an environment
3181 variable (logical name). If all else fails return the
3185 __gnat_to_canonical_file_spec (char *filespec)
3189 strncpy (new_canonical_filespec, "", MAXPATH);
3191 if (strchr (filespec, ']') || strchr (filespec, ':'))
3193 char *tspec = (char *) __gnat_translate_vms (filespec);
3195 if (tspec != (char *) -1)
3196 strncpy (new_canonical_filespec, tspec, MAXPATH);
3198 else if ((strlen (filespec) == strspn (filespec,
3199 "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_"))
3200 && (filespec1 = getenv (filespec)))
3202 char *tspec = (char *) __gnat_translate_vms (filespec1);
3204 if (tspec != (char *) -1)
3205 strncpy (new_canonical_filespec, tspec, MAXPATH);
3209 strncpy (new_canonical_filespec, filespec, MAXPATH);
3212 new_canonical_filespec [MAXPATH - 1] = (char) 0;
3214 return new_canonical_filespec;
3217 /* Translate a VMS syntax path specification into Unix syntax.
3218 If no indicators of VMS syntax found, return input string. */
3221 __gnat_to_canonical_path_spec (char *pathspec)
3223 char *curr, *next, buff [MAXPATH];
3228 /* If there are /'s, assume it's a Unix path spec and return. */
3229 if (strchr (pathspec, '/'))
3232 new_canonical_pathspec[0] = 0;
3237 next = strchr (curr, ',');
3239 next = strchr (curr, 0);
3241 strncpy (buff, curr, next - curr);
3242 buff[next - curr] = 0;
3244 /* Check for wildcards and expand if present. */
3245 if (strchr (buff, '*') || strchr (buff, '%') || strstr (buff, "..."))
3249 dirs = __gnat_to_canonical_file_list_init (buff, 1);
3250 for (i = 0; i < dirs; i++)
3254 next_dir = __gnat_to_canonical_file_list_next ();
3255 strncat (new_canonical_pathspec, next_dir, MAXPATH);
3257 /* Don't append the separator after the last expansion. */
3259 strncat (new_canonical_pathspec, ":", MAXPATH);
3262 __gnat_to_canonical_file_list_free ();
3265 strncat (new_canonical_pathspec,
3266 __gnat_to_canonical_dir_spec (buff, 0), MAXPATH);
3271 strncat (new_canonical_pathspec, ":", MAXPATH);
3275 new_canonical_pathspec [MAXPATH - 1] = (char) 0;
3277 return new_canonical_pathspec;
3280 static char filename_buff [MAXPATH];
3283 translate_unix (char *name, int type)
3285 strncpy (filename_buff, name, MAXPATH);
3286 filename_buff [MAXPATH - 1] = (char) 0;
3290 /* Translate a Unix syntax path spec into a VMS style (comma separated list of
3294 to_host_path_spec (char *pathspec)
3296 char *curr, *next, buff [MAXPATH];
3301 /* Can't very well test for colons, since that's the Unix separator! */
3302 if (strchr (pathspec, ']') || strchr (pathspec, ','))
3305 new_host_pathspec[0] = 0;
3310 next = strchr (curr, ':');
3312 next = strchr (curr, 0);
3314 strncpy (buff, curr, next - curr);
3315 buff[next - curr] = 0;
3317 strncat (new_host_pathspec, __gnat_to_host_dir_spec (buff, 0), MAXPATH);
3320 strncat (new_host_pathspec, ",", MAXPATH);
3324 new_host_pathspec [MAXPATH - 1] = (char) 0;
3326 return new_host_pathspec;
3329 /* Translate a Unix syntax directory specification into VMS syntax. The
3330 PREFIXFLAG has no effect, but is kept for symmetry with
3331 to_canonical_dir_spec. If indicators of VMS syntax found, return input
3335 __gnat_to_host_dir_spec (char *dirspec, int prefixflag ATTRIBUTE_UNUSED)
3337 int len = strlen (dirspec);
3339 strncpy (new_host_dirspec, dirspec, MAXPATH);
3340 new_host_dirspec [MAXPATH - 1] = (char) 0;
3342 if (strchr (new_host_dirspec, ']') || strchr (new_host_dirspec, ':'))
3343 return new_host_dirspec;
3345 while (len > 1 && new_host_dirspec[len - 1] == '/')
3347 new_host_dirspec[len - 1] = 0;
3351 decc$to_vms (new_host_dirspec, translate_unix, 1, 2);
3352 strncpy (new_host_dirspec, filename_buff, MAXPATH);
3353 new_host_dirspec [MAXPATH - 1] = (char) 0;
3355 return new_host_dirspec;
3358 /* Translate a Unix syntax file specification into VMS syntax.
3359 If indicators of VMS syntax found, return input string. */
3362 __gnat_to_host_file_spec (char *filespec)
3364 strncpy (new_host_filespec, "", MAXPATH);
3365 if (strchr (filespec, ']') || strchr (filespec, ':'))
3367 strncpy (new_host_filespec, filespec, MAXPATH);
3371 decc$to_vms (filespec, translate_unix, 1, 1);
3372 strncpy (new_host_filespec, filename_buff, MAXPATH);
3375 new_host_filespec [MAXPATH - 1] = (char) 0;
3377 return new_host_filespec;
3381 __gnat_adjust_os_resource_limits ()
3383 SYS$ADJWSL (131072, 0);
3388 /* Dummy functions for Osint import for non-VMS systems. */
3391 __gnat_to_canonical_file_list_init
3392 (char *dirspec ATTRIBUTE_UNUSED, int onlydirs ATTRIBUTE_UNUSED)
3398 __gnat_to_canonical_file_list_next (void)
3400 static char *empty = "";
3405 __gnat_to_canonical_file_list_free (void)
3410 __gnat_to_canonical_dir_spec (char *dirspec, int prefixflag ATTRIBUTE_UNUSED)
3416 __gnat_to_canonical_file_spec (char *filespec)
3422 __gnat_to_canonical_path_spec (char *pathspec)
3428 __gnat_to_host_dir_spec (char *dirspec, int prefixflag ATTRIBUTE_UNUSED)
3434 __gnat_to_host_file_spec (char *filespec)
3440 __gnat_adjust_os_resource_limits (void)
3446 /* For EMX, we cannot include dummy in libgcc, since it is too difficult
3447 to coordinate this with the EMX distribution. Consequently, we put the
3448 definition of dummy which is used for exception handling, here. */
3450 #if defined (__EMX__)
3454 #if defined (__mips_vxworks)
3458 CACHE_USER_FLUSH (0, ENTIRE_CACHE);
3462 #if defined (IS_CROSS) \
3463 || (! ((defined (sparc) || defined (i386)) && defined (sun) \
3464 && defined (__SVR4)) \
3465 && ! (defined (linux) && (defined (i386) || defined (__x86_64__))) \
3466 && ! (defined (linux) && defined (__ia64__)) \
3467 && ! (defined (linux) && defined (powerpc)) \
3468 && ! defined (__FreeBSD__) \
3469 && ! defined (__Lynx__) \
3470 && ! defined (__hpux__) \
3471 && ! defined (__APPLE__) \
3472 && ! defined (_AIX) \
3473 && ! (defined (__alpha__) && defined (__osf__)) \
3474 && ! defined (VMS) \
3475 && ! defined (__MINGW32__) \
3476 && ! (defined (__mips) && defined (__sgi)))
3478 /* Dummy function to satisfy g-trasym.o. See the preprocessor conditional
3479 just above for a list of native platforms that provide a non-dummy
3480 version of this procedure in libaddr2line.a. */
3483 convert_addresses (const char *file_name ATTRIBUTE_UNUSED,
3484 void *addrs ATTRIBUTE_UNUSED,
3485 int n_addr ATTRIBUTE_UNUSED,
3486 void *buf ATTRIBUTE_UNUSED,
3487 int *len ATTRIBUTE_UNUSED)
3493 #if defined (_WIN32)
3494 int __gnat_argument_needs_quote = 1;
3496 int __gnat_argument_needs_quote = 0;
3499 /* This option is used to enable/disable object files handling from the
3500 binder file by the GNAT Project module. For example, this is disabled on
3501 Windows (prior to GCC 3.4) as it is already done by the mdll module.
3502 Stating with GCC 3.4 the shared libraries are not based on mdll
3503 anymore as it uses the GCC's -shared option */
3504 #if defined (_WIN32) \
3505 && ((__GNUC__ < 3) || ((__GNUC__ == 3) && (__GNUC_MINOR__ < 4)))
3506 int __gnat_prj_add_obj_files = 0;
3508 int __gnat_prj_add_obj_files = 1;
3511 /* char used as prefix/suffix for environment variables */
3512 #if defined (_WIN32)
3513 char __gnat_environment_char = '%';
3515 char __gnat_environment_char = '$';
3518 /* This functions copy the file attributes from a source file to a
3521 mode = 0 : In this mode copy only the file time stamps (last access and
3522 last modification time stamps).
3524 mode = 1 : In this mode, time stamps and read/write/execute attributes are
3527 Returns 0 if operation was successful and -1 in case of error. */
3530 __gnat_copy_attribs (char *from, char *to, int mode)
3532 #if defined (VMS) || defined (__vxworks) || defined (__nucleus__)
3535 #elif defined (_WIN32) && !defined (RTX)
3536 TCHAR wfrom [GNAT_MAX_PATH_LEN + 2];
3537 TCHAR wto [GNAT_MAX_PATH_LEN + 2];
3539 FILETIME fct, flat, flwt;
3542 S2WSC (wfrom, from, GNAT_MAX_PATH_LEN + 2);
3543 S2WSC (wto, to, GNAT_MAX_PATH_LEN + 2);
3545 /* retrieve from times */
3548 (wfrom, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
3550 if (hfrom == INVALID_HANDLE_VALUE)
3553 res = GetFileTime (hfrom, &fct, &flat, &flwt);
3555 CloseHandle (hfrom);
3560 /* retrieve from times */
3563 (wto, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
3565 if (hto == INVALID_HANDLE_VALUE)
3568 res = SetFileTime (hto, NULL, &flat, &flwt);
3575 /* Set file attributes in full mode. */
3579 DWORD attribs = GetFileAttributes (wfrom);
3581 if (attribs == INVALID_FILE_ATTRIBUTES)
3584 res = SetFileAttributes (wto, attribs);
3592 GNAT_STRUCT_STAT fbuf;
3593 struct utimbuf tbuf;
3595 if (GNAT_STAT (from, &fbuf) == -1)
3600 tbuf.actime = fbuf.st_atime;
3601 tbuf.modtime = fbuf.st_mtime;
3603 if (utime (to, &tbuf) == -1)
3610 if (chmod (to, fbuf.st_mode) == -1)
3621 __gnat_lseek (int fd, long offset, int whence)
3623 return (int) lseek (fd, offset, whence);
3626 /* This function returns the major version number of GCC being used. */
3628 get_gcc_version (void)
3633 return (int) (version_string[0] - '0');
3638 __gnat_set_close_on_exec (int fd ATTRIBUTE_UNUSED,
3639 int close_on_exec_p ATTRIBUTE_UNUSED)
3641 #if defined (F_GETFD) && defined (FD_CLOEXEC) && ! defined (__vxworks)
3642 int flags = fcntl (fd, F_GETFD, 0);
3645 if (close_on_exec_p)
3646 flags |= FD_CLOEXEC;
3648 flags &= ~FD_CLOEXEC;
3649 return fcntl (fd, F_SETFD, flags | FD_CLOEXEC);
3650 #elif defined(_WIN32)
3651 HANDLE h = (HANDLE) _get_osfhandle (fd);
3652 if (h == (HANDLE) -1)
3654 if (close_on_exec_p)
3655 return ! SetHandleInformation (h, HANDLE_FLAG_INHERIT, 0);
3656 return ! SetHandleInformation (h, HANDLE_FLAG_INHERIT,
3657 HANDLE_FLAG_INHERIT);
3659 /* TODO: Unimplemented. */
3664 /* Indicates if platforms supports automatic initialization through the
3665 constructor mechanism */
3667 __gnat_binder_supports_auto_init (void)
3676 /* Indicates that Stand-Alone Libraries are automatically initialized through
3677 the constructor mechanism */
3679 __gnat_sals_init_using_constructors (void)
3681 #if defined (__vxworks) || defined (__Lynx__) || defined (VMS)
3690 /* In RTX mode, the procedure to get the time (as file time) is different
3691 in RTSS mode and Win32 mode. In order to avoid duplicating an Ada file,
3692 we introduce an intermediate procedure to link against the corresponding
3693 one in each situation. */
3695 extern void GetTimeAsFileTime(LPFILETIME pTime);
3697 void GetTimeAsFileTime(LPFILETIME pTime)
3700 RtGetRtssTimeAsFileTime (pTime); /* RTSS interface */
3702 GetSystemTimeAsFileTime (pTime); /* w32 interface */
3707 /* Add symbol that is required to link. It would otherwise be taken from
3708 libgcc.a and it would try to use the gcc constructors that are not
3709 supported by Microsoft linker. */
3711 extern void __main (void);
3713 void __main (void) {}
3717 #if defined (linux) || defined(__GLIBC__)
3718 /* pthread affinity support */
3720 int __gnat_pthread_setaffinity_np (pthread_t th,
3722 const void *cpuset);
3725 #include <pthread.h>
3727 __gnat_pthread_setaffinity_np (pthread_t th,
3729 const cpu_set_t *cpuset)
3731 return pthread_setaffinity_np (th, cpusetsize, cpuset);
3735 __gnat_pthread_setaffinity_np (pthread_t th ATTRIBUTE_UNUSED,
3736 size_t cpusetsize ATTRIBUTE_UNUSED,
3737 const void *cpuset ATTRIBUTE_UNUSED)
3745 /* There is no function in the glibc to retrieve the LWP of the current
3746 thread. We need to do a system call in order to retrieve this
3748 #include <sys/syscall.h>
3749 void *__gnat_lwp_self (void)
3751 return (void *) syscall (__NR_gettid);