1 /****************************************************************************
3 * GNAT COMPILER COMPONENTS *
7 * C Implementation File *
9 * Copyright (C) 1992-2010, 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>
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];
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. */
216 #ifndef HOST_EXECUTABLE_SUFFIX
217 #define HOST_EXECUTABLE_SUFFIX ""
220 #ifndef HOST_OBJECT_SUFFIX
221 #define HOST_OBJECT_SUFFIX ".o"
224 #ifndef PATH_SEPARATOR
225 #define PATH_SEPARATOR ':'
228 #ifndef DIR_SEPARATOR
229 #define DIR_SEPARATOR '/'
232 /* Check for cross-compilation */
233 #if defined (CROSS_COMPILE) || defined (CROSS_DIRECTORY_STRUCTURE)
235 int __gnat_is_cross_compiler = 1;
238 int __gnat_is_cross_compiler = 0;
241 char __gnat_dir_separator = DIR_SEPARATOR;
243 char __gnat_path_separator = PATH_SEPARATOR;
245 /* The GNAT_LIBRARY_TEMPLATE contains a list of expressions that define
246 the base filenames that libraries specified with -lsomelib options
247 may have. This is used by GNATMAKE to check whether an executable
248 is up-to-date or not. The syntax is
250 library_template ::= { pattern ; } pattern NUL
251 pattern ::= [ prefix ] * [ postfix ]
253 These should only specify names of static libraries as it makes
254 no sense to determine at link time if dynamic-link libraries are
255 up to date or not. Any libraries that are not found are supposed
258 * if they are needed but not present, the link
261 * otherwise they are libraries in the system paths and so
262 they are considered part of the system and not checked
265 ??? This should be part of a GNAT host-specific compiler
266 file instead of being included in all user applications
267 as well. This is only a temporary work-around for 3.11b. */
269 #ifndef GNAT_LIBRARY_TEMPLATE
271 #define GNAT_LIBRARY_TEMPLATE "*.olb"
273 #define GNAT_LIBRARY_TEMPLATE "lib*.a"
277 const char *__gnat_library_template = GNAT_LIBRARY_TEMPLATE;
279 /* This variable is used in hostparm.ads to say whether the host is a VMS
282 const int __gnat_vmsp = 1;
284 const int __gnat_vmsp = 0;
288 #define GNAT_MAX_PATH_LEN 256 /* PATH_MAX */
290 #elif defined (__vxworks) || defined (__OPENNT) || defined(__nucleus__)
291 #define GNAT_MAX_PATH_LEN PATH_MAX
295 #if defined (__MINGW32__)
299 #include <sys/param.h>
303 #include <sys/param.h>
307 #define GNAT_MAX_PATH_LEN MAXPATHLEN
309 #define GNAT_MAX_PATH_LEN 256
314 /* Used for Ada bindings */
315 const int __gnat_size_of_file_attributes = sizeof (struct file_attributes);
317 /* Reset the file attributes as if no system call had been performed */
318 void __gnat_stat_to_attr (int fd, char* name, struct file_attributes* attr);
320 /* The __gnat_max_path_len variable is used to export the maximum
321 length of a path name to Ada code. max_path_len is also provided
322 for compatibility with older GNAT versions, please do not use
325 int __gnat_max_path_len = GNAT_MAX_PATH_LEN;
326 int max_path_len = GNAT_MAX_PATH_LEN;
328 /* Control whether we can use ACL on Windows. */
330 int __gnat_use_acl = 1;
332 /* The following macro HAVE_READDIR_R should be defined if the
333 system provides the routine readdir_r. */
334 #undef HAVE_READDIR_R
336 #if defined(VMS) && defined (__LONG_POINTERS)
338 /* Return a 32 bit pointer to an array of 32 bit pointers
339 given a 64 bit pointer to an array of 64 bit pointers */
341 typedef __char_ptr32 *__char_ptr_char_ptr32 __attribute__ ((mode (SI)));
343 static __char_ptr_char_ptr32
344 to_ptr32 (char **ptr64)
347 __char_ptr_char_ptr32 short_argv;
349 for (argc=0; ptr64[argc]; argc++);
351 /* Reallocate argv with 32 bit pointers. */
352 short_argv = (__char_ptr_char_ptr32) decc$malloc
353 (sizeof (__char_ptr32) * (argc + 1));
355 for (argc=0; ptr64[argc]; argc++)
356 short_argv[argc] = (__char_ptr32) decc$strdup (ptr64[argc]);
358 short_argv[argc] = (__char_ptr32) 0;
362 #define MAYBE_TO_PTR32(argv) to_ptr32 (argv)
364 #define MAYBE_TO_PTR32(argv) argv
367 static const char ATTR_UNSET = 127;
370 __gnat_reset_attributes
371 (struct file_attributes* attr)
373 attr->exists = ATTR_UNSET;
375 attr->writable = ATTR_UNSET;
376 attr->readable = ATTR_UNSET;
377 attr->executable = ATTR_UNSET;
379 attr->regular = ATTR_UNSET;
380 attr->symbolic_link = ATTR_UNSET;
381 attr->directory = ATTR_UNSET;
383 attr->timestamp = (OS_Time)-2;
384 attr->file_length = -1;
391 time_t res = time (NULL);
392 return (OS_Time) res;
395 /* Return the current local time as a string in the ISO 8601 format of
396 "YYYY-MM-DD HH:MM:SS.SS". The returned string is 22 + 1 (NULL) characters
400 __gnat_current_time_string
403 const char *format = "%Y-%m-%d %H:%M:%S";
404 /* Format string necessary to describe the ISO 8601 format */
406 const time_t t_val = time (NULL);
408 strftime (result, 22, format, localtime (&t_val));
409 /* Convert the local time into a string following the ISO format, copying
410 at most 22 characters into the result string. */
415 /* The sub-seconds are manually set to zero since type time_t lacks the
416 precision necessary for nanoseconds. */
430 time_t time = (time_t) *p_time;
433 /* On Windows systems, the time is sometimes rounded up to the nearest
434 even second, so if the number of seconds is odd, increment it. */
440 res = localtime (&time);
442 res = gmtime (&time);
447 *p_year = res->tm_year;
448 *p_month = res->tm_mon;
449 *p_day = res->tm_mday;
450 *p_hours = res->tm_hour;
451 *p_mins = res->tm_min;
452 *p_secs = res->tm_sec;
455 *p_year = *p_month = *p_day = *p_hours = *p_mins = *p_secs = 0;
458 /* Place the contents of the symbolic link named PATH in the buffer BUF,
459 which has size BUFSIZ. If PATH is a symbolic link, then return the number
460 of characters of its content in BUF. Otherwise, return -1.
461 For systems not supporting symbolic links, always return -1. */
464 __gnat_readlink (char *path ATTRIBUTE_UNUSED,
465 char *buf ATTRIBUTE_UNUSED,
466 size_t bufsiz ATTRIBUTE_UNUSED)
468 #if defined (_WIN32) || defined (VMS) \
469 || defined(__vxworks) || defined (__nucleus__)
472 return readlink (path, buf, bufsiz);
476 /* Creates a symbolic link named NEWPATH which contains the string OLDPATH.
477 If NEWPATH exists it will NOT be overwritten.
478 For systems not supporting symbolic links, always return -1. */
481 __gnat_symlink (char *oldpath ATTRIBUTE_UNUSED,
482 char *newpath ATTRIBUTE_UNUSED)
484 #if defined (_WIN32) || defined (VMS) \
485 || defined(__vxworks) || defined (__nucleus__)
488 return symlink (oldpath, newpath);
492 /* Try to lock a file, return 1 if success. */
494 #if defined (__vxworks) || defined (__nucleus__) \
495 || defined (_WIN32) || defined (VMS)
497 /* Version that does not use link. */
500 __gnat_try_lock (char *dir, char *file)
504 TCHAR wfull_path[GNAT_MAX_PATH_LEN];
505 TCHAR wfile[GNAT_MAX_PATH_LEN];
506 TCHAR wdir[GNAT_MAX_PATH_LEN];
508 S2WSC (wdir, dir, GNAT_MAX_PATH_LEN);
509 S2WSC (wfile, file, GNAT_MAX_PATH_LEN);
511 _stprintf (wfull_path, _T("%s%c%s"), wdir, _T(DIR_SEPARATOR), wfile);
512 fd = _topen (wfull_path, O_CREAT | O_EXCL, 0600);
516 sprintf (full_path, "%s%c%s", dir, DIR_SEPARATOR, file);
517 fd = open (full_path, O_CREAT | O_EXCL, 0600);
529 /* Version using link(), more secure over NFS. */
530 /* See TN 6913-016 for discussion ??? */
533 __gnat_try_lock (char *dir, char *file)
537 GNAT_STRUCT_STAT stat_result;
540 sprintf (full_path, "%s%c%s", dir, DIR_SEPARATOR, file);
541 sprintf (temp_file, "%s%cTMP-%ld-%ld",
542 dir, DIR_SEPARATOR, (long)getpid(), (long)getppid ());
544 /* Create the temporary file and write the process number. */
545 fd = open (temp_file, O_CREAT | O_WRONLY, 0600);
551 /* Link it with the new file. */
552 link (temp_file, full_path);
554 /* Count the references on the old one. If we have a count of two, then
555 the link did succeed. Remove the temporary file before returning. */
556 __gnat_stat (temp_file, &stat_result);
558 return stat_result.st_nlink == 2;
562 /* Return the maximum file name length. */
565 __gnat_get_maximum_file_name_length (void)
568 if (getenv ("GNAT$EXTENDED_FILE_SPECIFICATIONS"))
577 /* Return nonzero if file names are case sensitive. */
580 __gnat_get_file_names_case_sensitive (void)
582 const char *sensitive = getenv ("GNAT_FILE_NAME_CASE_SENSITIVE");
584 if (sensitive != NULL
585 && (sensitive[0] == '0' || sensitive[0] == '1')
586 && sensitive[1] == '\0')
587 return sensitive[0] - '0';
589 #if defined (VMS) || defined (WINNT) || defined (__APPLE__)
596 /* Return nonzero if environment variables are case sensitive. */
599 __gnat_get_env_vars_case_sensitive (void)
601 #if defined (VMS) || defined (WINNT)
609 __gnat_get_default_identifier_character_set (void)
614 /* Return the current working directory. */
617 __gnat_get_current_dir (char *dir, int *length)
619 #if defined (__MINGW32__)
620 TCHAR wdir[GNAT_MAX_PATH_LEN];
622 _tgetcwd (wdir, *length);
624 WS2SC (dir, wdir, GNAT_MAX_PATH_LEN);
627 /* Force Unix style, which is what GNAT uses internally. */
628 getcwd (dir, *length, 0);
630 getcwd (dir, *length);
633 *length = strlen (dir);
635 if (dir [*length - 1] != DIR_SEPARATOR)
637 dir [*length] = DIR_SEPARATOR;
643 /* Return the suffix for object files. */
646 __gnat_get_object_suffix_ptr (int *len, const char **value)
648 *value = HOST_OBJECT_SUFFIX;
653 *len = strlen (*value);
658 /* Return the suffix for executable files. */
661 __gnat_get_executable_suffix_ptr (int *len, const char **value)
663 *value = HOST_EXECUTABLE_SUFFIX;
667 *len = strlen (*value);
672 /* Return the suffix for debuggable files. Usually this is the same as the
673 executable extension. */
676 __gnat_get_debuggable_suffix_ptr (int *len, const char **value)
678 *value = HOST_EXECUTABLE_SUFFIX;
683 *len = strlen (*value);
688 /* Returns the OS filename and corresponding encoding. */
691 __gnat_os_filename (char *filename ATTRIBUTE_UNUSED,
692 char *w_filename ATTRIBUTE_UNUSED,
693 char *os_name, int *o_length,
694 char *encoding ATTRIBUTE_UNUSED, int *e_length)
696 #if defined (_WIN32) && ! defined (__vxworks) && ! defined (IS_CROSS)
697 WS2SC (os_name, (TCHAR *)w_filename, (DWORD)*o_length);
698 *o_length = strlen (os_name);
699 strcpy (encoding, "encoding=utf8");
700 *e_length = strlen (encoding);
702 strcpy (os_name, filename);
703 *o_length = strlen (filename);
711 __gnat_unlink (char *path)
713 #if defined (__MINGW32__) && ! defined (__vxworks) && ! defined (IS_CROSS)
715 TCHAR wpath[GNAT_MAX_PATH_LEN];
717 S2WSC (wpath, path, GNAT_MAX_PATH_LEN);
718 return _tunlink (wpath);
721 return unlink (path);
728 __gnat_rename (char *from, char *to)
730 #if defined (__MINGW32__) && ! defined (__vxworks) && ! defined (IS_CROSS)
732 TCHAR wfrom[GNAT_MAX_PATH_LEN], wto[GNAT_MAX_PATH_LEN];
734 S2WSC (wfrom, from, GNAT_MAX_PATH_LEN);
735 S2WSC (wto, to, GNAT_MAX_PATH_LEN);
736 return _trename (wfrom, wto);
739 return rename (from, to);
743 /* Changing directory. */
746 __gnat_chdir (char *path)
748 #if defined (__MINGW32__) && ! defined (__vxworks) && ! defined (IS_CROSS)
750 TCHAR wpath[GNAT_MAX_PATH_LEN];
752 S2WSC (wpath, path, GNAT_MAX_PATH_LEN);
753 return _tchdir (wpath);
760 /* Removing a directory. */
763 __gnat_rmdir (char *path)
765 #if defined (__MINGW32__) && ! defined (__vxworks) && ! defined (IS_CROSS)
767 TCHAR wpath[GNAT_MAX_PATH_LEN];
769 S2WSC (wpath, path, GNAT_MAX_PATH_LEN);
770 return _trmdir (wpath);
772 #elif defined (VTHREADS)
773 /* rmdir not available */
781 __gnat_fopen (char *path, char *mode, int encoding ATTRIBUTE_UNUSED)
783 #if defined (_WIN32) && ! defined (__vxworks) && ! defined (IS_CROSS)
784 TCHAR wpath[GNAT_MAX_PATH_LEN];
787 S2WS (wmode, mode, 10);
789 if (encoding == Encoding_Unspecified)
790 S2WSC (wpath, path, GNAT_MAX_PATH_LEN);
791 else if (encoding == Encoding_UTF8)
792 S2WSU (wpath, path, GNAT_MAX_PATH_LEN);
794 S2WS (wpath, path, GNAT_MAX_PATH_LEN);
796 return _tfopen (wpath, wmode);
798 return decc$fopen (path, mode);
800 return GNAT_FOPEN (path, mode);
805 __gnat_freopen (char *path, char *mode, FILE *stream, int encoding ATTRIBUTE_UNUSED)
807 #if defined (_WIN32) && ! defined (__vxworks) && ! defined (IS_CROSS)
808 TCHAR wpath[GNAT_MAX_PATH_LEN];
811 S2WS (wmode, mode, 10);
813 if (encoding == Encoding_Unspecified)
814 S2WSC (wpath, path, GNAT_MAX_PATH_LEN);
815 else if (encoding == Encoding_UTF8)
816 S2WSU (wpath, path, GNAT_MAX_PATH_LEN);
818 S2WS (wpath, path, GNAT_MAX_PATH_LEN);
820 return _tfreopen (wpath, wmode, stream);
822 return decc$freopen (path, mode, stream);
824 return freopen (path, mode, stream);
829 __gnat_open_read (char *path, int fmode)
832 int o_fmode = O_BINARY;
838 /* Optional arguments mbc,deq,fop increase read performance. */
839 fd = open (path, O_RDONLY | o_fmode, 0444,
840 "mbc=16", "deq=64", "fop=tef");
841 #elif defined (__vxworks)
842 fd = open (path, O_RDONLY | o_fmode, 0444);
843 #elif defined (__MINGW32__)
845 TCHAR wpath[GNAT_MAX_PATH_LEN];
847 S2WSC (wpath, path, GNAT_MAX_PATH_LEN);
848 fd = _topen (wpath, O_RDONLY | o_fmode, 0444);
851 fd = open (path, O_RDONLY | o_fmode);
854 return fd < 0 ? -1 : fd;
857 #if defined (__MINGW32__)
858 #define PERM (S_IREAD | S_IWRITE)
860 /* Excerpt from DECC C RTL Reference Manual:
861 To create files with OpenVMS RMS default protections using the UNIX
862 system-call functions umask, mkdir, creat, and open, call mkdir, creat,
863 and open with a file-protection mode argument of 0777 in a program
864 that never specifically calls umask. These default protections include
865 correctly establishing protections based on ACLs, previous versions of
869 #define PERM (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH)
873 __gnat_open_rw (char *path, int fmode)
876 int o_fmode = O_BINARY;
882 fd = open (path, O_RDWR | o_fmode, PERM,
883 "mbc=16", "deq=64", "fop=tef");
884 #elif defined (__MINGW32__)
886 TCHAR wpath[GNAT_MAX_PATH_LEN];
888 S2WSC (wpath, path, GNAT_MAX_PATH_LEN);
889 fd = _topen (wpath, O_RDWR | o_fmode, PERM);
892 fd = open (path, O_RDWR | o_fmode, PERM);
895 return fd < 0 ? -1 : fd;
899 __gnat_open_create (char *path, int fmode)
902 int o_fmode = O_BINARY;
908 fd = open (path, O_WRONLY | O_CREAT | O_TRUNC | o_fmode, PERM,
909 "mbc=16", "deq=64", "fop=tef");
910 #elif defined (__MINGW32__)
912 TCHAR wpath[GNAT_MAX_PATH_LEN];
914 S2WSC (wpath, path, GNAT_MAX_PATH_LEN);
915 fd = _topen (wpath, O_WRONLY | O_CREAT | O_TRUNC | o_fmode, PERM);
918 fd = open (path, O_WRONLY | O_CREAT | O_TRUNC | o_fmode, PERM);
921 return fd < 0 ? -1 : fd;
925 __gnat_create_output_file (char *path)
929 fd = open (path, O_WRONLY | O_CREAT | O_TRUNC | O_TEXT, PERM,
930 "rfm=stmlf", "ctx=rec", "rat=none", "rop=nlk",
931 "shr=del,get,put,upd");
932 #elif defined (__MINGW32__)
934 TCHAR wpath[GNAT_MAX_PATH_LEN];
936 S2WSC (wpath, path, GNAT_MAX_PATH_LEN);
937 fd = _topen (wpath, O_WRONLY | O_CREAT | O_TRUNC | O_TEXT, PERM);
940 fd = open (path, O_WRONLY | O_CREAT | O_TRUNC | O_TEXT, PERM);
943 return fd < 0 ? -1 : fd;
947 __gnat_create_output_file_new (char *path)
951 fd = open (path, O_WRONLY | O_CREAT | O_TRUNC | O_TEXT | O_EXCL, PERM,
952 "rfm=stmlf", "ctx=rec", "rat=none", "rop=nlk",
953 "shr=del,get,put,upd");
954 #elif defined (__MINGW32__)
956 TCHAR wpath[GNAT_MAX_PATH_LEN];
958 S2WSC (wpath, path, GNAT_MAX_PATH_LEN);
959 fd = _topen (wpath, O_WRONLY | O_CREAT | O_TRUNC | O_TEXT | O_EXCL, PERM);
962 fd = open (path, O_WRONLY | O_CREAT | O_TRUNC | O_TEXT | O_EXCL, PERM);
965 return fd < 0 ? -1 : fd;
969 __gnat_open_append (char *path, int fmode)
972 int o_fmode = O_BINARY;
978 fd = open (path, O_WRONLY | O_CREAT | O_APPEND | o_fmode, PERM,
979 "mbc=16", "deq=64", "fop=tef");
980 #elif defined (__MINGW32__)
982 TCHAR wpath[GNAT_MAX_PATH_LEN];
984 S2WSC (wpath, path, GNAT_MAX_PATH_LEN);
985 fd = _topen (wpath, O_WRONLY | O_CREAT | O_APPEND | o_fmode, PERM);
988 fd = open (path, O_WRONLY | O_CREAT | O_APPEND | o_fmode, PERM);
991 return fd < 0 ? -1 : fd;
994 /* Open a new file. Return error (-1) if the file already exists. */
997 __gnat_open_new (char *path, int fmode)
1000 int o_fmode = O_BINARY;
1006 fd = open (path, O_WRONLY | O_CREAT | O_EXCL | o_fmode, PERM,
1007 "mbc=16", "deq=64", "fop=tef");
1008 #elif defined (__MINGW32__)
1010 TCHAR wpath[GNAT_MAX_PATH_LEN];
1012 S2WSC (wpath, path, GNAT_MAX_PATH_LEN);
1013 fd = _topen (wpath, O_WRONLY | O_CREAT | O_EXCL | o_fmode, PERM);
1016 fd = open (path, O_WRONLY | O_CREAT | O_EXCL | o_fmode, PERM);
1019 return fd < 0 ? -1 : fd;
1022 /* Open a new temp file. Return error (-1) if the file already exists.
1023 Special options for VMS allow the file to be shared between parent and child
1024 processes, however they really slow down output. Used in gnatchop. */
1027 __gnat_open_new_temp (char *path, int fmode)
1030 int o_fmode = O_BINARY;
1032 strcpy (path, "GNAT-XXXXXX");
1034 #if (defined (__FreeBSD__) || defined (__NetBSD__) || defined (__OpenBSD__) \
1035 || defined (linux) || defined(__GLIBC__)) && !defined (__vxworks)
1036 return mkstemp (path);
1037 #elif defined (__Lynx__)
1039 #elif defined (__nucleus__)
1042 if (mktemp (path) == NULL)
1050 fd = open (path, O_WRONLY | O_CREAT | O_EXCL | o_fmode, PERM,
1051 "rfm=stmlf", "ctx=rec", "rat=none", "shr=del,get,put,upd",
1052 "mbc=16", "deq=64", "fop=tef");
1054 fd = open (path, O_WRONLY | O_CREAT | O_EXCL | o_fmode, PERM);
1057 return fd < 0 ? -1 : fd;
1060 /****************************************************************
1061 ** Perform a call to GNAT_STAT or GNAT_FSTAT, and extract as much information
1062 ** as possible from it, storing the result in a cache for later reuse
1063 ****************************************************************/
1066 __gnat_stat_to_attr (int fd, char* name, struct file_attributes* attr)
1068 GNAT_STRUCT_STAT statbuf;
1072 ret = GNAT_FSTAT (fd, &statbuf);
1074 ret = __gnat_stat (name, &statbuf);
1076 attr->regular = (!ret && S_ISREG (statbuf.st_mode));
1077 attr->directory = (!ret && S_ISDIR (statbuf.st_mode));
1080 attr->file_length = 0;
1082 /* st_size may be 32 bits, or 64 bits which is converted to long. We
1083 don't return a useful value for files larger than 2 gigabytes in
1085 attr->file_length = statbuf.st_size; /* all systems */
1088 /* on Windows requires extra system call, see comment in __gnat_file_exists_attr */
1089 attr->exists = !ret;
1092 #if !defined (_WIN32) || defined (RTX)
1093 /* on Windows requires extra system call, see __gnat_is_readable_file_attr */
1094 attr->readable = (!ret && (statbuf.st_mode & S_IRUSR));
1095 attr->writable = (!ret && (statbuf.st_mode & S_IWUSR));
1096 attr->executable = (!ret && (statbuf.st_mode & S_IXUSR));
1099 #if !defined (_WIN32) || defined (RTX)
1100 /* on Windows requires extra system call, see __gnat_file_time_name_attr */
1102 attr->timestamp = (OS_Time)-1;
1105 /* VMS has file versioning. */
1106 attr->timestamp = (OS_Time)statbuf.st_ctime;
1108 attr->timestamp = (OS_Time)statbuf.st_mtime;
1115 /****************************************************************
1116 ** Return the number of bytes in the specified file
1117 ****************************************************************/
1120 __gnat_file_length_attr (int fd, char* name, struct file_attributes* attr)
1122 if (attr->file_length == -1) {
1123 __gnat_stat_to_attr (fd, name, attr);
1126 return attr->file_length;
1130 __gnat_file_length (int fd)
1132 struct file_attributes attr;
1133 __gnat_reset_attributes (&attr);
1134 return __gnat_file_length_attr (fd, NULL, &attr);
1138 __gnat_named_file_length (char *name)
1140 struct file_attributes attr;
1141 __gnat_reset_attributes (&attr);
1142 return __gnat_file_length_attr (-1, name, &attr);
1145 /* Create a temporary filename and put it in string pointed to by
1149 __gnat_tmp_name (char *tmp_filename)
1152 /* Variable used to create a series of unique names */
1153 static int counter = 0;
1155 /* RTX in RTSS mode does not support tempnam nor tmpnam so we emulate it */
1156 strcpy (tmp_filename, "c:\\WINDOWS\\Temp\\gnat-");
1157 sprintf (&tmp_filename[strlen (tmp_filename)], "%d\0", counter++);
1159 #elif defined (__MINGW32__)
1163 /* tempnam tries to create a temporary file in directory pointed to by
1164 TMP environment variable, in c:\temp if TMP is not set, and in
1165 directory specified by P_tmpdir in stdio.h if c:\temp does not
1166 exist. The filename will be created with the prefix "gnat-". */
1168 pname = (char *) tempnam ("c:\\temp", "gnat-");
1170 /* if pname is NULL, the file was not created properly, the disk is full
1171 or there is no more free temporary files */
1174 *tmp_filename = '\0';
1176 /* If pname start with a back slash and not path information it means that
1177 the filename is valid for the current working directory. */
1179 else if (pname[0] == '\\')
1181 strcpy (tmp_filename, ".\\");
1182 strcat (tmp_filename, pname+1);
1185 strcpy (tmp_filename, pname);
1190 #elif defined (linux) || defined (__FreeBSD__) || defined (__NetBSD__) \
1191 || defined (__OpenBSD__) || defined(__GLIBC__)
1192 #define MAX_SAFE_PATH 1000
1193 char *tmpdir = getenv ("TMPDIR");
1195 /* If tmpdir is longer than MAX_SAFE_PATH, revert to default value to avoid
1196 a buffer overflow. */
1197 if (tmpdir == NULL || strlen (tmpdir) > MAX_SAFE_PATH)
1198 strcpy (tmp_filename, "/tmp/gnat-XXXXXX");
1200 sprintf (tmp_filename, "%s/gnat-XXXXXX", tmpdir);
1202 close (mkstemp(tmp_filename));
1204 tmpnam (tmp_filename);
1208 /* Open directory and returns a DIR pointer. */
1210 DIR* __gnat_opendir (char *name)
1213 /* Not supported in RTX */
1217 #elif defined (__MINGW32__)
1218 TCHAR wname[GNAT_MAX_PATH_LEN];
1220 S2WSC (wname, name, GNAT_MAX_PATH_LEN);
1221 return (DIR*)_topendir (wname);
1224 return opendir (name);
1228 /* Read the next entry in a directory. The returned string points somewhere
1232 __gnat_readdir (DIR *dirp, char *buffer, int *len)
1235 /* Not supported in RTX */
1239 #elif defined (__MINGW32__)
1240 struct _tdirent *dirent = _treaddir ((_TDIR*)dirp);
1244 WS2SC (buffer, dirent->d_name, GNAT_MAX_PATH_LEN);
1245 *len = strlen (buffer);
1252 #elif defined (HAVE_READDIR_R)
1253 /* If possible, try to use the thread-safe version. */
1254 if (readdir_r (dirp, buffer) != NULL)
1256 *len = strlen (((struct dirent*) buffer)->d_name);
1257 return ((struct dirent*) buffer)->d_name;
1263 struct dirent *dirent = (struct dirent *) readdir (dirp);
1267 strcpy (buffer, dirent->d_name);
1268 *len = strlen (buffer);
1277 /* Close a directory entry. */
1279 int __gnat_closedir (DIR *dirp)
1282 /* Not supported in RTX */
1286 #elif defined (__MINGW32__)
1287 return _tclosedir ((_TDIR*)dirp);
1290 return closedir (dirp);
1294 /* Returns 1 if readdir is thread safe, 0 otherwise. */
1297 __gnat_readdir_is_thread_safe (void)
1299 #ifdef HAVE_READDIR_R
1306 #if defined (_WIN32) && !defined (RTX)
1307 /* Number of seconds between <Jan 1st 1601> and <Jan 1st 1970>. */
1308 static const unsigned long long w32_epoch_offset = 11644473600ULL;
1310 /* Returns the file modification timestamp using Win32 routines which are
1311 immune against daylight saving time change. It is in fact not possible to
1312 use fstat for this purpose as the DST modify the st_mtime field of the
1316 win32_filetime (HANDLE h)
1321 unsigned long long ull_time;
1324 /* GetFileTime returns FILETIME data which are the number of 100 nanosecs
1325 since <Jan 1st 1601>. This function must return the number of seconds
1326 since <Jan 1st 1970>. */
1328 if (GetFileTime (h, NULL, NULL, &t_write.ft_time))
1329 return (time_t) (t_write.ull_time / 10000000ULL - w32_epoch_offset);
1334 /* Return a GNAT time stamp given a file name. */
1337 __gnat_file_time_name_attr (char* name, struct file_attributes* attr)
1339 if (attr->timestamp == (OS_Time)-2) {
1340 #if defined (_WIN32) && !defined (RTX)
1342 TCHAR wname[GNAT_MAX_PATH_LEN];
1343 S2WSC (wname, name, GNAT_MAX_PATH_LEN);
1345 HANDLE h = CreateFile
1346 (wname, GENERIC_READ, FILE_SHARE_READ, 0,
1347 OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0);
1349 if (h != INVALID_HANDLE_VALUE) {
1350 ret = win32_filetime (h);
1353 attr->timestamp = (OS_Time) ret;
1355 __gnat_stat_to_attr (-1, name, attr);
1358 return attr->timestamp;
1362 __gnat_file_time_name (char *name)
1364 struct file_attributes attr;
1365 __gnat_reset_attributes (&attr);
1366 return __gnat_file_time_name_attr (name, &attr);
1369 /* Return a GNAT time stamp given a file descriptor. */
1372 __gnat_file_time_fd_attr (int fd, struct file_attributes* attr)
1374 if (attr->timestamp == (OS_Time)-2) {
1375 #if defined (_WIN32) && !defined (RTX)
1376 HANDLE h = (HANDLE) _get_osfhandle (fd);
1377 time_t ret = win32_filetime (h);
1378 attr->timestamp = (OS_Time) ret;
1381 __gnat_stat_to_attr (fd, NULL, attr);
1385 return attr->timestamp;
1389 __gnat_file_time_fd (int fd)
1391 struct file_attributes attr;
1392 __gnat_reset_attributes (&attr);
1393 return __gnat_file_time_fd_attr (fd, &attr);
1396 /* Set the file time stamp. */
1399 __gnat_set_file_time_name (char *name, time_t time_stamp)
1401 #if defined (__vxworks)
1403 /* Code to implement __gnat_set_file_time_name for these systems. */
1405 #elif defined (_WIN32) && !defined (RTX)
1409 unsigned long long ull_time;
1411 TCHAR wname[GNAT_MAX_PATH_LEN];
1413 S2WSC (wname, name, GNAT_MAX_PATH_LEN);
1415 HANDLE h = CreateFile
1416 (wname, GENERIC_WRITE, FILE_SHARE_WRITE, NULL,
1417 OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS,
1419 if (h == INVALID_HANDLE_VALUE)
1421 /* Add number of seconds between <Jan 1st 1601> and <Jan 1st 1970> */
1422 t_write.ull_time = ((unsigned long long)time_stamp + w32_epoch_offset);
1423 /* Convert to 100 nanosecond units */
1424 t_write.ull_time *= 10000000ULL;
1426 SetFileTime(h, NULL, NULL, &t_write.ft_time);
1436 unsigned long long backup, create, expire, revise;
1440 unsigned short value;
1443 unsigned system : 4;
1449 } Fat = { 0, 0, 0, 0, 0, { 0 }};
1453 { ATR$S_CREDATE, ATR$C_CREDATE, &Fat.create },
1454 { ATR$S_REVDATE, ATR$C_REVDATE, &Fat.revise },
1455 { ATR$S_EXPDATE, ATR$C_EXPDATE, &Fat.expire },
1456 { ATR$S_BAKDATE, ATR$C_BAKDATE, &Fat.backup },
1457 { ATR$S_FPRO, ATR$C_FPRO, &Fat.prot },
1458 { ATR$S_UIC, ATR$C_UIC, &Fat.uic },
1463 struct dsc$descriptor_fib fibdsc = {sizeof (fib), (void *) &fib};
1467 unsigned long long newtime;
1468 unsigned long long revtime;
1472 struct vstring file;
1473 struct dsc$descriptor_s filedsc
1474 = {NAM$C_MAXRSS, DSC$K_DTYPE_T, DSC$K_CLASS_S, (void *) file.string};
1475 struct vstring device;
1476 struct dsc$descriptor_s devicedsc
1477 = {NAM$C_MAXRSS, DSC$K_DTYPE_T, DSC$K_CLASS_S, (void *) device.string};
1478 struct vstring timev;
1479 struct dsc$descriptor_s timedsc
1480 = {NAM$C_MAXRSS, DSC$K_DTYPE_T, DSC$K_CLASS_S, (void *) timev.string};
1481 struct vstring result;
1482 struct dsc$descriptor_s resultdsc
1483 = {NAM$C_MAXRSS, DSC$K_DTYPE_VT, DSC$K_CLASS_VS, (void *) result.string};
1485 /* Convert parameter name (a file spec) to host file form. Note that this
1486 is needed on VMS to prepare for subsequent calls to VMS RMS library
1487 routines. Note that it would not work to call __gnat_to_host_dir_spec
1488 as was done in a previous version, since this fails silently unless
1489 the feature logical DECC$EFS_CHARSET is enabled, in which case a DNF
1490 (directory not found) condition is signalled. */
1491 tryfile = (char *) __gnat_to_host_file_spec (name);
1493 /* Allocate and initialize a FAB and NAM structures. */
1497 nam.nam$l_esa = file.string;
1498 nam.nam$b_ess = NAM$C_MAXRSS;
1499 nam.nam$l_rsa = result.string;
1500 nam.nam$b_rss = NAM$C_MAXRSS;
1501 fab.fab$l_fna = tryfile;
1502 fab.fab$b_fns = strlen (tryfile);
1503 fab.fab$l_nam = &nam;
1505 /* Validate filespec syntax and device existence. */
1506 status = SYS$PARSE (&fab, 0, 0);
1507 if ((status & 1) != 1)
1508 LIB$SIGNAL (status);
1510 file.string[nam.nam$b_esl] = 0;
1512 /* Find matching filespec. */
1513 status = SYS$SEARCH (&fab, 0, 0);
1514 if ((status & 1) != 1)
1515 LIB$SIGNAL (status);
1517 file.string[nam.nam$b_esl] = 0;
1518 result.string[result.length=nam.nam$b_rsl] = 0;
1520 /* Get the device name and assign an IO channel. */
1521 strncpy (device.string, nam.nam$l_dev, nam.nam$b_dev);
1522 devicedsc.dsc$w_length = nam.nam$b_dev;
1524 status = SYS$ASSIGN (&devicedsc, &chan, 0, 0, 0);
1525 if ((status & 1) != 1)
1526 LIB$SIGNAL (status);
1528 /* Initialize the FIB and fill in the directory id field. */
1529 memset (&fib, 0, sizeof (fib));
1530 fib.fib$w_did[0] = nam.nam$w_did[0];
1531 fib.fib$w_did[1] = nam.nam$w_did[1];
1532 fib.fib$w_did[2] = nam.nam$w_did[2];
1533 fib.fib$l_acctl = 0;
1535 strcpy (file.string, (strrchr (result.string, ']') + 1));
1536 filedsc.dsc$w_length = strlen (file.string);
1537 result.string[result.length = 0] = 0;
1539 /* Open and close the file to fill in the attributes. */
1541 = SYS$QIOW (0, chan, IO$_ACCESS|IO$M_ACCESS, &iosb, 0, 0,
1542 &fibdsc, &filedsc, &result.length, &resultdsc, &atrlst, 0);
1543 if ((status & 1) != 1)
1544 LIB$SIGNAL (status);
1545 if ((iosb.status & 1) != 1)
1546 LIB$SIGNAL (iosb.status);
1548 result.string[result.length] = 0;
1549 status = SYS$QIOW (0, chan, IO$_DEACCESS, &iosb, 0, 0, &fibdsc, 0, 0, 0,
1551 if ((status & 1) != 1)
1552 LIB$SIGNAL (status);
1553 if ((iosb.status & 1) != 1)
1554 LIB$SIGNAL (iosb.status);
1559 /* Set creation time to requested time. */
1560 unix_time_to_vms (time_stamp, newtime);
1562 t = time ((time_t) 0);
1564 /* Set revision time to now in local time. */
1565 unix_time_to_vms (t, revtime);
1568 /* Reopen the file, modify the times and then close. */
1569 fib.fib$l_acctl = FIB$M_WRITE;
1571 = SYS$QIOW (0, chan, IO$_ACCESS|IO$M_ACCESS, &iosb, 0, 0,
1572 &fibdsc, &filedsc, &result.length, &resultdsc, &atrlst, 0);
1573 if ((status & 1) != 1)
1574 LIB$SIGNAL (status);
1575 if ((iosb.status & 1) != 1)
1576 LIB$SIGNAL (iosb.status);
1578 Fat.create = newtime;
1579 Fat.revise = revtime;
1581 status = SYS$QIOW (0, chan, IO$_DEACCESS, &iosb, 0, 0,
1582 &fibdsc, 0, 0, 0, &atrlst, 0);
1583 if ((status & 1) != 1)
1584 LIB$SIGNAL (status);
1585 if ((iosb.status & 1) != 1)
1586 LIB$SIGNAL (iosb.status);
1588 /* Deassign the channel and exit. */
1589 status = SYS$DASSGN (chan);
1590 if ((status & 1) != 1)
1591 LIB$SIGNAL (status);
1593 struct utimbuf utimbuf;
1596 /* Set modification time to requested time. */
1597 utimbuf.modtime = time_stamp;
1599 /* Set access time to now in local time. */
1600 t = time ((time_t) 0);
1601 utimbuf.actime = mktime (localtime (&t));
1603 utime (name, &utimbuf);
1607 /* Get the list of installed standard libraries from the
1608 HKEY_LOCAL_MACHINE\SOFTWARE\Ada Core Technologies\GNAT\Standard Libraries
1612 __gnat_get_libraries_from_registry (void)
1614 char *result = (char *) xmalloc (1);
1618 #if defined (_WIN32) && ! defined (__vxworks) && ! defined (IS_CROSS) \
1622 DWORD name_size, value_size;
1629 /* First open the key. */
1630 res = RegOpenKeyExA (HKEY_LOCAL_MACHINE, "SOFTWARE", 0, KEY_READ, ®_key);
1632 if (res == ERROR_SUCCESS)
1633 res = RegOpenKeyExA (reg_key, "Ada Core Technologies", 0,
1634 KEY_READ, ®_key);
1636 if (res == ERROR_SUCCESS)
1637 res = RegOpenKeyExA (reg_key, "GNAT", 0, KEY_READ, ®_key);
1639 if (res == ERROR_SUCCESS)
1640 res = RegOpenKeyExA (reg_key, "Standard Libraries", 0, KEY_READ, ®_key);
1642 /* If the key exists, read out all the values in it and concatenate them
1644 for (index = 0; res == ERROR_SUCCESS; index++)
1646 value_size = name_size = 256;
1647 res = RegEnumValueA (reg_key, index, name, &name_size, 0,
1648 &type, (LPBYTE)value, &value_size);
1650 if (res == ERROR_SUCCESS && type == REG_SZ)
1652 char *old_result = result;
1654 result = (char *) xmalloc (strlen (old_result) + value_size + 2);
1655 strcpy (result, old_result);
1656 strcat (result, value);
1657 strcat (result, ";");
1662 /* Remove the trailing ";". */
1664 result[strlen (result) - 1] = 0;
1671 __gnat_stat (char *name, GNAT_STRUCT_STAT *statbuf)
1674 /* Under Windows the directory name for the stat function must not be
1675 terminated by a directory separator except if just after a drive name
1676 or with UNC path without directory (only the name of the shared
1677 resource), for example: \\computer\share\ */
1679 TCHAR wname [GNAT_MAX_PATH_LEN + 2];
1682 int dirsep_count = 0;
1684 S2WSC (wname, name, GNAT_MAX_PATH_LEN + 2);
1685 name_len = _tcslen (wname);
1687 if (name_len > GNAT_MAX_PATH_LEN)
1690 last_char = wname[name_len - 1];
1692 while (name_len > 1 && (last_char == _T('\\') || last_char == _T('/')))
1694 wname[name_len - 1] = _T('\0');
1696 last_char = wname[name_len - 1];
1699 /* Count back-slashes. */
1701 for (k=0; k<name_len; k++)
1702 if (wname[k] == _T('\\') || wname[k] == _T('/'))
1705 /* Only a drive letter followed by ':', we must add a directory separator
1706 for the stat routine to work properly. */
1707 if ((name_len == 2 && wname[1] == _T(':'))
1708 || (name_len > 3 && wname[0] == _T('\\') && wname[1] == _T('\\')
1709 && dirsep_count == 3))
1710 _tcscat (wname, _T("\\"));
1712 return _tstat (wname, (struct _stat *)statbuf);
1715 return GNAT_STAT (name, statbuf);
1719 /*************************************************************************
1720 ** Check whether a file exists
1721 *************************************************************************/
1724 __gnat_file_exists_attr (char* name, struct file_attributes* attr)
1726 if (attr->exists == ATTR_UNSET) {
1728 /* On Windows do not use __gnat_stat() because of a bug in Microsoft
1729 _stat() routine. When the system time-zone is set with a negative
1730 offset the _stat() routine fails on specific files like CON: */
1731 TCHAR wname [GNAT_MAX_PATH_LEN + 2];
1732 S2WSC (wname, name, GNAT_MAX_PATH_LEN + 2);
1733 attr->exists = GetFileAttributes (wname) != INVALID_FILE_ATTRIBUTES;
1735 __gnat_stat_to_attr (-1, name, attr);
1739 return attr->exists;
1743 __gnat_file_exists (char *name)
1745 struct file_attributes attr;
1746 __gnat_reset_attributes (&attr);
1747 return __gnat_file_exists_attr (name, &attr);
1750 /**********************************************************************
1751 ** Whether name is an absolute path
1752 **********************************************************************/
1755 __gnat_is_absolute_path (char *name, int length)
1758 /* On VxWorks systems, an absolute path can be represented (depending on
1759 the host platform) as either /dir/file, or device:/dir/file, or
1760 device:drive_letter:/dir/file. */
1767 for (index = 0; index < length; index++)
1769 if (name[index] == ':' &&
1770 ((name[index + 1] == '/') ||
1771 (isalpha (name[index + 1]) && index + 2 <= length &&
1772 name[index + 2] == '/')))
1775 else if (name[index] == '/')
1780 return (length != 0) &&
1781 (*name == '/' || *name == DIR_SEPARATOR
1783 || (length > 1 && ISALPHA (name[0]) && name[1] == ':')
1790 __gnat_is_regular_file_attr (char* name, struct file_attributes* attr)
1792 if (attr->regular == ATTR_UNSET) {
1793 __gnat_stat_to_attr (-1, name, attr);
1796 return attr->regular;
1800 __gnat_is_regular_file (char *name)
1802 struct file_attributes attr;
1803 __gnat_reset_attributes (&attr);
1804 return __gnat_is_regular_file_attr (name, &attr);
1808 __gnat_is_directory_attr (char* name, struct file_attributes* attr)
1810 if (attr->directory == ATTR_UNSET) {
1811 __gnat_stat_to_attr (-1, name, attr);
1814 return attr->directory;
1818 __gnat_is_directory (char *name)
1820 struct file_attributes attr;
1821 __gnat_reset_attributes (&attr);
1822 return __gnat_is_directory_attr (name, &attr);
1825 #if defined (_WIN32) && !defined (RTX)
1827 /* Returns the same constant as GetDriveType but takes a pathname as
1831 GetDriveTypeFromPath (TCHAR *wfullpath)
1833 TCHAR wdrv[MAX_PATH];
1834 TCHAR wpath[MAX_PATH];
1835 TCHAR wfilename[MAX_PATH];
1836 TCHAR wext[MAX_PATH];
1838 _tsplitpath (wfullpath, wdrv, wpath, wfilename, wext);
1840 if (_tcslen (wdrv) != 0)
1842 /* we have a drive specified. */
1843 _tcscat (wdrv, _T("\\"));
1844 return GetDriveType (wdrv);
1848 /* No drive specified. */
1850 /* Is this a relative path, if so get current drive type. */
1851 if (wpath[0] != _T('\\') ||
1852 (_tcslen (wpath) > 2 && wpath[0] == _T('\\') && wpath[1] != _T('\\')))
1853 return GetDriveType (NULL);
1855 UINT result = GetDriveType (wpath);
1857 /* Cannot guess the drive type, is this \\.\ ? */
1859 if (result == DRIVE_NO_ROOT_DIR &&
1860 _tcslen (wpath) >= 4 && wpath[0] == _T('\\') && wpath[1] == _T('\\')
1861 && wpath[2] == _T('.') && wpath[3] == _T('\\'))
1863 if (_tcslen (wpath) == 4)
1864 _tcscat (wpath, wfilename);
1866 LPTSTR p = &wpath[4];
1867 LPTSTR b = _tcschr (p, _T('\\'));
1870 { /* logical drive \\.\c\dir\file */
1876 _tcscat (p, _T(":\\"));
1878 return GetDriveType (p);
1885 /* This MingW section contains code to work with ACL. */
1887 __gnat_check_OWNER_ACL
1889 DWORD CheckAccessDesired,
1890 GENERIC_MAPPING CheckGenericMapping)
1892 DWORD dwAccessDesired, dwAccessAllowed;
1893 PRIVILEGE_SET PrivilegeSet;
1894 DWORD dwPrivSetSize = sizeof (PRIVILEGE_SET);
1895 BOOL fAccessGranted = FALSE;
1896 HANDLE hToken = NULL;
1898 SECURITY_DESCRIPTOR* pSD = NULL;
1901 (wname, OWNER_SECURITY_INFORMATION |
1902 GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION,
1905 if ((pSD = (PSECURITY_DESCRIPTOR) HeapAlloc
1906 (GetProcessHeap (), HEAP_ZERO_MEMORY, nLength)) == NULL)
1909 /* Obtain the security descriptor. */
1911 if (!GetFileSecurity
1912 (wname, OWNER_SECURITY_INFORMATION |
1913 GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION,
1914 pSD, nLength, &nLength))
1917 if (!ImpersonateSelf (SecurityImpersonation))
1920 if (!OpenThreadToken
1921 (GetCurrentThread(), TOKEN_DUPLICATE | TOKEN_QUERY, FALSE, &hToken))
1924 /* Undoes the effect of ImpersonateSelf. */
1928 /* We want to test for write permissions. */
1930 dwAccessDesired = CheckAccessDesired;
1932 MapGenericMask (&dwAccessDesired, &CheckGenericMapping);
1935 (pSD , /* security descriptor to check */
1936 hToken, /* impersonation token */
1937 dwAccessDesired, /* requested access rights */
1938 &CheckGenericMapping, /* pointer to GENERIC_MAPPING */
1939 &PrivilegeSet, /* receives privileges used in check */
1940 &dwPrivSetSize, /* size of PrivilegeSet buffer */
1941 &dwAccessAllowed, /* receives mask of allowed access rights */
1945 CloseHandle (hToken);
1946 HeapFree (GetProcessHeap (), 0, pSD);
1947 return fAccessGranted;
1951 CloseHandle (hToken);
1952 HeapFree (GetProcessHeap (), 0, pSD);
1957 __gnat_set_OWNER_ACL
1960 DWORD AccessPermissions)
1962 PACL pOldDACL = NULL;
1963 PACL pNewDACL = NULL;
1964 PSECURITY_DESCRIPTOR pSD = NULL;
1966 TCHAR username [100];
1969 /* Get current user, he will act as the owner */
1971 if (!GetUserName (username, &unsize))
1974 if (GetNamedSecurityInfo
1977 DACL_SECURITY_INFORMATION,
1978 NULL, NULL, &pOldDACL, NULL, &pSD) != ERROR_SUCCESS)
1981 BuildExplicitAccessWithName
1982 (&ea, username, AccessPermissions, AccessMode, NO_INHERITANCE);
1984 if (AccessMode == SET_ACCESS)
1986 /* SET_ACCESS, we want to set an explicte set of permissions, do not
1987 merge with current DACL. */
1988 if (SetEntriesInAcl (1, &ea, NULL, &pNewDACL) != ERROR_SUCCESS)
1992 if (SetEntriesInAcl (1, &ea, pOldDACL, &pNewDACL) != ERROR_SUCCESS)
1995 if (SetNamedSecurityInfo
1996 (wname, SE_FILE_OBJECT,
1997 DACL_SECURITY_INFORMATION, NULL, NULL, pNewDACL, NULL) != ERROR_SUCCESS)
2001 LocalFree (pNewDACL);
2004 /* Check if it is possible to use ACL for wname, the file must not be on a
2008 __gnat_can_use_acl (TCHAR *wname)
2010 return __gnat_use_acl && GetDriveTypeFromPath (wname) != DRIVE_REMOTE;
2013 #endif /* defined (_WIN32) && !defined (RTX) */
2016 __gnat_is_readable_file_attr (char* name, struct file_attributes* attr)
2018 if (attr->readable == ATTR_UNSET) {
2019 #if defined (_WIN32) && !defined (RTX)
2020 TCHAR wname [GNAT_MAX_PATH_LEN + 2];
2021 GENERIC_MAPPING GenericMapping;
2023 S2WSC (wname, name, GNAT_MAX_PATH_LEN + 2);
2025 if (__gnat_can_use_acl (wname))
2027 ZeroMemory (&GenericMapping, sizeof (GENERIC_MAPPING));
2028 GenericMapping.GenericRead = GENERIC_READ;
2029 attr->readable = __gnat_check_OWNER_ACL (wname, FILE_READ_DATA, GenericMapping);
2032 attr->readable = GetFileAttributes (wname) != INVALID_FILE_ATTRIBUTES;
2034 __gnat_stat_to_attr (-1, name, attr);
2038 return attr->readable;
2042 __gnat_is_readable_file (char *name)
2044 struct file_attributes attr;
2045 __gnat_reset_attributes (&attr);
2046 return __gnat_is_readable_file_attr (name, &attr);
2050 __gnat_is_writable_file_attr (char* name, struct file_attributes* attr)
2052 if (attr->writable == ATTR_UNSET) {
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.GenericWrite = GENERIC_WRITE;
2064 attr->writable = __gnat_check_OWNER_ACL
2065 (wname, FILE_WRITE_DATA | FILE_APPEND_DATA, GenericMapping)
2066 && !(GetFileAttributes (wname) & FILE_ATTRIBUTE_READONLY);
2069 attr->writable = !(GetFileAttributes (wname) & FILE_ATTRIBUTE_READONLY);
2072 __gnat_stat_to_attr (-1, name, attr);
2076 return attr->writable;
2080 __gnat_is_writable_file (char *name)
2082 struct file_attributes attr;
2083 __gnat_reset_attributes (&attr);
2084 return __gnat_is_writable_file_attr (name, &attr);
2088 __gnat_is_executable_file_attr (char* name, struct file_attributes* attr)
2090 if (attr->executable == ATTR_UNSET) {
2091 #if defined (_WIN32) && !defined (RTX)
2092 TCHAR wname [GNAT_MAX_PATH_LEN + 2];
2093 GENERIC_MAPPING GenericMapping;
2095 S2WSC (wname, name, GNAT_MAX_PATH_LEN + 2);
2097 if (__gnat_can_use_acl (wname))
2099 ZeroMemory (&GenericMapping, sizeof (GENERIC_MAPPING));
2100 GenericMapping.GenericExecute = GENERIC_EXECUTE;
2102 attr->executable = __gnat_check_OWNER_ACL (wname, FILE_EXECUTE, GenericMapping);
2105 attr->executable = GetFileAttributes (wname) != INVALID_FILE_ATTRIBUTES
2106 && _tcsstr (wname, _T(".exe")) - wname == (int) (_tcslen (wname) - 4);
2108 __gnat_stat_to_attr (-1, name, attr);
2112 return attr->executable;
2116 __gnat_is_executable_file (char *name)
2118 struct file_attributes attr;
2119 __gnat_reset_attributes (&attr);
2120 return __gnat_is_executable_file_attr (name, &attr);
2124 __gnat_set_writable (char *name)
2126 #if defined (_WIN32) && !defined (RTX)
2127 TCHAR wname [GNAT_MAX_PATH_LEN + 2];
2129 S2WSC (wname, name, GNAT_MAX_PATH_LEN + 2);
2131 if (__gnat_can_use_acl (wname))
2132 __gnat_set_OWNER_ACL (wname, GRANT_ACCESS, FILE_GENERIC_WRITE);
2135 (wname, GetFileAttributes (wname) & ~FILE_ATTRIBUTE_READONLY);
2136 #elif ! defined (__vxworks) && ! defined(__nucleus__)
2137 GNAT_STRUCT_STAT statbuf;
2139 if (GNAT_STAT (name, &statbuf) == 0)
2141 statbuf.st_mode = statbuf.st_mode | S_IWUSR;
2142 chmod (name, statbuf.st_mode);
2148 __gnat_set_executable (char *name)
2150 #if defined (_WIN32) && !defined (RTX)
2151 TCHAR wname [GNAT_MAX_PATH_LEN + 2];
2153 S2WSC (wname, name, GNAT_MAX_PATH_LEN + 2);
2155 if (__gnat_can_use_acl (wname))
2156 __gnat_set_OWNER_ACL (wname, GRANT_ACCESS, FILE_GENERIC_EXECUTE);
2158 #elif ! defined (__vxworks) && ! defined(__nucleus__)
2159 GNAT_STRUCT_STAT statbuf;
2161 if (GNAT_STAT (name, &statbuf) == 0)
2163 statbuf.st_mode = statbuf.st_mode | S_IXUSR;
2164 chmod (name, statbuf.st_mode);
2170 __gnat_set_non_writable (char *name)
2172 #if defined (_WIN32) && !defined (RTX)
2173 TCHAR wname [GNAT_MAX_PATH_LEN + 2];
2175 S2WSC (wname, name, GNAT_MAX_PATH_LEN + 2);
2177 if (__gnat_can_use_acl (wname))
2178 __gnat_set_OWNER_ACL
2179 (wname, DENY_ACCESS,
2180 FILE_WRITE_DATA | FILE_APPEND_DATA |
2181 FILE_WRITE_EA | FILE_WRITE_ATTRIBUTES);
2184 (wname, GetFileAttributes (wname) | FILE_ATTRIBUTE_READONLY);
2185 #elif ! defined (__vxworks) && ! defined(__nucleus__)
2186 GNAT_STRUCT_STAT statbuf;
2188 if (GNAT_STAT (name, &statbuf) == 0)
2190 statbuf.st_mode = statbuf.st_mode & 07577;
2191 chmod (name, statbuf.st_mode);
2197 __gnat_set_readable (char *name)
2199 #if defined (_WIN32) && !defined (RTX)
2200 TCHAR wname [GNAT_MAX_PATH_LEN + 2];
2202 S2WSC (wname, name, GNAT_MAX_PATH_LEN + 2);
2204 if (__gnat_can_use_acl (wname))
2205 __gnat_set_OWNER_ACL (wname, GRANT_ACCESS, FILE_GENERIC_READ);
2207 #elif ! defined (__vxworks) && ! defined(__nucleus__)
2208 GNAT_STRUCT_STAT statbuf;
2210 if (GNAT_STAT (name, &statbuf) == 0)
2212 chmod (name, statbuf.st_mode | S_IREAD);
2218 __gnat_set_non_readable (char *name)
2220 #if defined (_WIN32) && !defined (RTX)
2221 TCHAR wname [GNAT_MAX_PATH_LEN + 2];
2223 S2WSC (wname, name, GNAT_MAX_PATH_LEN + 2);
2225 if (__gnat_can_use_acl (wname))
2226 __gnat_set_OWNER_ACL (wname, DENY_ACCESS, FILE_GENERIC_READ);
2228 #elif ! defined (__vxworks) && ! defined(__nucleus__)
2229 GNAT_STRUCT_STAT statbuf;
2231 if (GNAT_STAT (name, &statbuf) == 0)
2233 chmod (name, statbuf.st_mode & (~S_IREAD));
2239 __gnat_is_symbolic_link_attr (char* name, struct file_attributes* attr)
2241 if (attr->symbolic_link == ATTR_UNSET) {
2242 #if defined (__vxworks) || defined (__nucleus__)
2243 attr->symbolic_link = 0;
2245 #elif defined (_AIX) || defined (__APPLE__) || defined (__unix__)
2247 GNAT_STRUCT_STAT statbuf;
2248 ret = GNAT_LSTAT (name, &statbuf);
2249 attr->symbolic_link = (!ret && S_ISLNK (statbuf.st_mode));
2251 attr->symbolic_link = 0;
2254 return attr->symbolic_link;
2258 __gnat_is_symbolic_link (char *name ATTRIBUTE_UNUSED)
2260 struct file_attributes attr;
2261 __gnat_reset_attributes (&attr);
2262 return __gnat_is_symbolic_link_attr (name, &attr);
2266 #if defined (sun) && defined (__SVR4)
2267 /* Using fork on Solaris will duplicate all the threads. fork1, which
2268 duplicates only the active thread, must be used instead, or spawning
2269 subprocess from a program with tasking will lead into numerous problems. */
2274 __gnat_portable_spawn (char *args[])
2277 int finished ATTRIBUTE_UNUSED;
2278 int pid ATTRIBUTE_UNUSED;
2280 #if defined (__vxworks) || defined(__nucleus__) || defined(RTX)
2283 #elif defined (_WIN32)
2284 /* args[0] must be quotes as it could contain a full pathname with spaces */
2285 char *args_0 = args[0];
2286 args[0] = (char *)xmalloc (strlen (args_0) + 3);
2287 strcpy (args[0], "\"");
2288 strcat (args[0], args_0);
2289 strcat (args[0], "\"");
2291 status = spawnvp (P_WAIT, args_0, (const char* const*)args);
2293 /* restore previous value */
2295 args[0] = (char *)args_0;
2311 if (execv (args[0], MAYBE_TO_PTR32 (args)) != 0)
2313 return -1; /* execv is in parent context on VMS. */
2320 finished = waitpid (pid, &status, 0);
2322 if (finished != pid || WIFEXITED (status) == 0)
2325 return WEXITSTATUS (status);
2331 /* Create a copy of the given file descriptor.
2332 Return -1 if an error occurred. */
2335 __gnat_dup (int oldfd)
2337 #if defined (__vxworks) && !defined (__RTP__)
2338 /* Not supported on VxWorks 5.x, but supported on VxWorks 6.0 when using
2346 /* Make newfd be the copy of oldfd, closing newfd first if necessary.
2347 Return -1 if an error occurred. */
2350 __gnat_dup2 (int oldfd, int newfd)
2352 #if defined (__vxworks) && !defined (__RTP__)
2353 /* Not supported on VxWorks 5.x, but supported on VxWorks 6.0 when using
2357 return dup2 (oldfd, newfd);
2361 /* WIN32 code to implement a wait call that wait for any child process. */
2363 #if defined (_WIN32) && !defined (RTX)
2365 /* Synchronization code, to be thread safe. */
2369 /* For the Cert run times on native Windows we use dummy functions
2370 for locking and unlocking tasks since we do not support multiple
2371 threads on this configuration (Cert run time on native Windows). */
2373 void dummy (void) {}
2375 void (*Lock_Task) () = &dummy;
2376 void (*Unlock_Task) () = &dummy;
2380 #define Lock_Task system__soft_links__lock_task
2381 extern void (*Lock_Task) (void);
2383 #define Unlock_Task system__soft_links__unlock_task
2384 extern void (*Unlock_Task) (void);
2388 static HANDLE *HANDLES_LIST = NULL;
2389 static int *PID_LIST = NULL, plist_length = 0, plist_max_length = 0;
2392 add_handle (HANDLE h, int pid)
2395 /* -------------------- critical section -------------------- */
2398 if (plist_length == plist_max_length)
2400 plist_max_length += 1000;
2402 xrealloc (HANDLES_LIST, sizeof (HANDLE) * plist_max_length);
2404 xrealloc (PID_LIST, sizeof (int) * plist_max_length);
2407 HANDLES_LIST[plist_length] = h;
2408 PID_LIST[plist_length] = pid;
2412 /* -------------------- critical section -------------------- */
2416 __gnat_win32_remove_handle (HANDLE h, int pid)
2420 /* -------------------- critical section -------------------- */
2423 for (j = 0; j < plist_length; j++)
2425 if ((HANDLES_LIST[j] == h) || (PID_LIST[j] == pid))
2429 HANDLES_LIST[j] = HANDLES_LIST[plist_length];
2430 PID_LIST[j] = PID_LIST[plist_length];
2436 /* -------------------- critical section -------------------- */
2440 win32_no_block_spawn (char *command, char *args[], HANDLE *h, int *pid)
2444 PROCESS_INFORMATION PI;
2445 SECURITY_ATTRIBUTES SA;
2450 /* compute the total command line length */
2454 csize += strlen (args[k]) + 1;
2458 full_command = (char *) xmalloc (csize);
2461 SI.cb = sizeof (STARTUPINFO);
2462 SI.lpReserved = NULL;
2463 SI.lpReserved2 = NULL;
2464 SI.lpDesktop = NULL;
2468 SI.wShowWindow = SW_HIDE;
2470 /* Security attributes. */
2471 SA.nLength = sizeof (SECURITY_ATTRIBUTES);
2472 SA.bInheritHandle = TRUE;
2473 SA.lpSecurityDescriptor = NULL;
2475 /* Prepare the command string. */
2476 strcpy (full_command, command);
2477 strcat (full_command, " ");
2482 strcat (full_command, args[k]);
2483 strcat (full_command, " ");
2488 int wsize = csize * 2;
2489 TCHAR *wcommand = (TCHAR *) xmalloc (wsize);
2491 S2WSC (wcommand, full_command, wsize);
2493 free (full_command);
2495 result = CreateProcess
2496 (NULL, wcommand, &SA, NULL, TRUE,
2497 GetPriorityClass (GetCurrentProcess()), NULL, NULL, &SI, &PI);
2504 CloseHandle (PI.hThread);
2506 *pid = PI.dwProcessId;
2516 win32_wait (int *status)
2518 DWORD exitcode, pid;
2525 if (plist_length == 0)
2533 /* -------------------- critical section -------------------- */
2536 hl_len = plist_length;
2538 hl = (HANDLE *) xmalloc (sizeof (HANDLE) * hl_len);
2540 memmove (hl, HANDLES_LIST, sizeof (HANDLE) * hl_len);
2543 /* -------------------- critical section -------------------- */
2545 res = WaitForMultipleObjects (hl_len, hl, FALSE, INFINITE);
2546 h = hl[res - WAIT_OBJECT_0];
2548 GetExitCodeProcess (h, &exitcode);
2549 pid = PID_LIST [res - WAIT_OBJECT_0];
2550 __gnat_win32_remove_handle (h, -1);
2554 *status = (int) exitcode;
2561 __gnat_portable_no_block_spawn (char *args[])
2564 #if defined (__vxworks) || defined (__nucleus__) || defined (RTX)
2567 #elif defined (_WIN32)
2572 win32_no_block_spawn (args[0], args, &h, &pid);
2575 add_handle (h, pid);
2588 if (execv (args[0], MAYBE_TO_PTR32 (args)) != 0)
2590 return -1; /* execv is in parent context on VMS. */
2602 __gnat_portable_wait (int *process_status)
2607 #if defined (__vxworks) || defined (__nucleus__) || defined (RTX)
2608 /* Not sure what to do here, so do nothing but return zero. */
2610 #elif defined (_WIN32)
2612 pid = win32_wait (&status);
2616 pid = waitpid (-1, &status, 0);
2617 status = status & 0xffff;
2620 *process_status = status;
2625 __gnat_os_exit (int status)
2630 /* Locate a regular file, give a Path value. */
2633 __gnat_locate_regular_file (char *file_name, char *path_val)
2636 char *file_path = (char *) alloca (strlen (file_name) + 1);
2639 /* Return immediately if file_name is empty */
2641 if (*file_name == '\0')
2644 /* Remove quotes around file_name if present */
2650 strcpy (file_path, ptr);
2652 ptr = file_path + strlen (file_path) - 1;
2657 /* Handle absolute pathnames. */
2659 absolute = __gnat_is_absolute_path (file_path, strlen (file_name));
2663 if (__gnat_is_regular_file (file_path))
2664 return xstrdup (file_path);
2669 /* If file_name include directory separator(s), try it first as
2670 a path name relative to the current directory */
2671 for (ptr = file_name; *ptr && *ptr != '/' && *ptr != DIR_SEPARATOR; ptr++)
2676 if (__gnat_is_regular_file (file_name))
2677 return xstrdup (file_name);
2684 /* The result has to be smaller than path_val + file_name. */
2685 char *file_path = (char *) alloca (strlen (path_val) + strlen (file_name) + 2);
2689 /* Skip the starting quote */
2691 if (*path_val == '"')
2694 for (ptr = file_path; *path_val && *path_val != PATH_SEPARATOR; )
2695 *ptr++ = *path_val++;
2697 /* If directory is empty, it is the current directory*/
2699 if (ptr == file_path)
2706 /* Skip the ending quote */
2711 if (*ptr != '/' && *ptr != DIR_SEPARATOR)
2712 *++ptr = DIR_SEPARATOR;
2714 strcpy (++ptr, file_name);
2716 if (__gnat_is_regular_file (file_path))
2717 return xstrdup (file_path);
2722 /* Skip path separator */
2731 /* Locate an executable given a Path argument. This routine is only used by
2732 gnatbl and should not be used otherwise. Use locate_exec_on_path
2736 __gnat_locate_exec (char *exec_name, char *path_val)
2739 if (!strstr (exec_name, HOST_EXECUTABLE_SUFFIX))
2741 char *full_exec_name
2742 = (char *) alloca (strlen (exec_name) + strlen (HOST_EXECUTABLE_SUFFIX) + 1);
2744 strcpy (full_exec_name, exec_name);
2745 strcat (full_exec_name, HOST_EXECUTABLE_SUFFIX);
2746 ptr = __gnat_locate_regular_file (full_exec_name, path_val);
2749 return __gnat_locate_regular_file (exec_name, path_val);
2753 return __gnat_locate_regular_file (exec_name, path_val);
2756 /* Locate an executable using the Systems default PATH. */
2759 __gnat_locate_exec_on_path (char *exec_name)
2763 #if defined (_WIN32) && !defined (RTX)
2764 TCHAR *wpath_val = _tgetenv (_T("PATH"));
2766 /* In Win32 systems we expand the PATH as for XP environment
2767 variables are not automatically expanded. We also prepend the
2768 ".;" to the path to match normal NT path search semantics */
2770 #define EXPAND_BUFFER_SIZE 32767
2772 wapath_val = alloca (EXPAND_BUFFER_SIZE);
2774 wapath_val [0] = '.';
2775 wapath_val [1] = ';';
2777 DWORD res = ExpandEnvironmentStrings
2778 (wpath_val, &wapath_val[2], EXPAND_BUFFER_SIZE - 2);
2780 if (!res) wapath_val [0] = _T('\0');
2782 apath_val = alloca (EXPAND_BUFFER_SIZE);
2784 WS2SC (apath_val, wapath_val, EXPAND_BUFFER_SIZE);
2785 return __gnat_locate_exec (exec_name, apath_val);
2790 char *path_val = "/VAXC$PATH";
2792 char *path_val = getenv ("PATH");
2794 if (path_val == NULL) return NULL;
2795 apath_val = (char *) alloca (strlen (path_val) + 1);
2796 strcpy (apath_val, path_val);
2797 return __gnat_locate_exec (exec_name, apath_val);
2803 /* These functions are used to translate to and from VMS and Unix syntax
2804 file, directory and path specifications. */
2807 #define MAXNAMES 256
2808 #define NEW_CANONICAL_FILELIST_INCREMENT 64
2810 static char new_canonical_dirspec [MAXPATH];
2811 static char new_canonical_filespec [MAXPATH];
2812 static char new_canonical_pathspec [MAXNAMES*MAXPATH];
2813 static unsigned new_canonical_filelist_index;
2814 static unsigned new_canonical_filelist_in_use;
2815 static unsigned new_canonical_filelist_allocated;
2816 static char **new_canonical_filelist;
2817 static char new_host_pathspec [MAXNAMES*MAXPATH];
2818 static char new_host_dirspec [MAXPATH];
2819 static char new_host_filespec [MAXPATH];
2821 /* Routine is called repeatedly by decc$from_vms via
2822 __gnat_to_canonical_file_list_init until it returns 0 or the expansion
2826 wildcard_translate_unix (char *name)
2829 char buff [MAXPATH];
2831 strncpy (buff, name, MAXPATH);
2832 buff [MAXPATH - 1] = (char) 0;
2833 ver = strrchr (buff, '.');
2835 /* Chop off the version. */
2839 /* Dynamically extend the allocation by the increment. */
2840 if (new_canonical_filelist_in_use == new_canonical_filelist_allocated)
2842 new_canonical_filelist_allocated += NEW_CANONICAL_FILELIST_INCREMENT;
2843 new_canonical_filelist = (char **) xrealloc
2844 (new_canonical_filelist,
2845 new_canonical_filelist_allocated * sizeof (char *));
2848 new_canonical_filelist[new_canonical_filelist_in_use++] = xstrdup (buff);
2853 /* Translate a wildcard VMS file spec into a list of Unix file specs. First do
2854 full translation and copy the results into a list (_init), then return them
2855 one at a time (_next). If onlydirs set, only expand directory files. */
2858 __gnat_to_canonical_file_list_init (char *filespec, int onlydirs)
2861 char buff [MAXPATH];
2863 len = strlen (filespec);
2864 strncpy (buff, filespec, MAXPATH);
2866 /* Only look for directories */
2867 if (onlydirs && !strstr (&buff [len-5], "*.dir"))
2868 strncat (buff, "*.dir", MAXPATH);
2870 buff [MAXPATH - 1] = (char) 0;
2872 decc$from_vms (buff, wildcard_translate_unix, 1);
2874 /* Remove the .dir extension. */
2880 for (i = 0; i < new_canonical_filelist_in_use; i++)
2882 ext = strstr (new_canonical_filelist[i], ".dir");
2888 return new_canonical_filelist_in_use;
2891 /* Return the next filespec in the list. */
2894 __gnat_to_canonical_file_list_next ()
2896 return new_canonical_filelist[new_canonical_filelist_index++];
2899 /* Free storage used in the wildcard expansion. */
2902 __gnat_to_canonical_file_list_free ()
2906 for (i = 0; i < new_canonical_filelist_in_use; i++)
2907 free (new_canonical_filelist[i]);
2909 free (new_canonical_filelist);
2911 new_canonical_filelist_in_use = 0;
2912 new_canonical_filelist_allocated = 0;
2913 new_canonical_filelist_index = 0;
2914 new_canonical_filelist = 0;
2917 /* The functional equivalent of decc$translate_vms routine.
2918 Designed to produce the same output, but is protected against
2919 malformed paths (original version ACCVIOs in this case) and
2920 does not require VMS-specific DECC RTL */
2922 #define NAM$C_MAXRSS 1024
2925 __gnat_translate_vms (char *src)
2927 static char retbuf [NAM$C_MAXRSS+1];
2928 char *srcendpos, *pos1, *pos2, *retpos;
2929 int disp, path_present = 0;
2931 if (!src) return NULL;
2933 srcendpos = strchr (src, '\0');
2936 /* Look for the node and/or device in front of the path */
2938 pos2 = strchr (pos1, ':');
2940 if (pos2 && (pos2 < srcendpos) && (*(pos2 + 1) == ':')) {
2941 /* There is a node name. "node_name::" becomes "node_name!" */
2943 strncpy (retbuf, pos1, disp);
2944 retpos [disp] = '!';
2945 retpos = retpos + disp + 1;
2947 pos2 = strchr (pos1, ':');
2951 /* There is a device name. "dev_name:" becomes "/dev_name/" */
2954 strncpy (retpos, pos1, disp);
2955 retpos = retpos + disp;
2960 /* No explicit device; we must look ahead and prepend /sys$disk/ if
2961 the path is absolute */
2962 if ((*pos1 == '[' || *pos1 == '<') && (pos1 < srcendpos)
2963 && !strchr (".-]>", *(pos1 + 1))) {
2964 strncpy (retpos, "/sys$disk/", 10);
2968 /* Process the path part */
2969 while (*pos1 == '[' || *pos1 == '<') {
2972 if (*pos1 == ']' || *pos1 == '>') {
2973 /* Special case, [] translates to '.' */
2978 /* '[000000' means root dir. It can be present in the middle of
2979 the path due to expansion of logical devices, in which case
2981 if (!strncmp (pos1, "000000", 6) && path_present > 1 &&
2982 (*(pos1 + 6) == ']' || *(pos1 + 6) == '>' || *(pos1 + 6) == '.')) {
2984 if (*pos1 == '.') pos1++;
2986 else if (*pos1 == '.') {
2991 /* There is a qualified path */
2992 while (*pos1 && *pos1 != ']' && *pos1 != '>') {
2995 /* '.' is used to separate directories. Replace it with '/' but
2996 only if there isn't already '/' just before */
2997 if (*(retpos - 1) != '/') *(retpos++) = '/';
2999 if (pos1 + 1 < srcendpos && *pos1 == '.' && *(pos1 + 1) == '.') {
3000 /* ellipsis refers to entire subtree; replace with '**' */
3001 *(retpos++) = '*'; *(retpos++) = '*'; *(retpos++) = '/';
3006 /* When after '.' '[' '<' is equivalent to Unix ".." but there
3007 may be several in a row */
3008 if (*(pos1 - 1) == '.' || *(pos1 - 1) == '[' ||
3009 *(pos1 - 1) == '<') {
3010 while (*pos1 == '-') {
3012 *(retpos++) = '.'; *(retpos++) = '.'; *(retpos++) = '/';
3017 /* otherwise fall through to default */
3019 *(retpos++) = *(pos1++);
3026 if (pos1 < srcendpos) {
3027 /* Now add the actual file name, until the version suffix if any */
3028 if (path_present) *(retpos++) = '/';
3029 pos2 = strchr (pos1, ';');
3030 disp = pos2? (pos2 - pos1) : (srcendpos - pos1);
3031 strncpy (retpos, pos1, disp);
3033 if (pos2 && pos2 < srcendpos) {
3034 /* There is a non-empty version suffix. ";<ver>" becomes ".<ver>" */
3036 disp = srcendpos - pos2 - 1;
3037 strncpy (retpos, pos2 + 1, disp);
3048 /* Translate a VMS syntax directory specification in to Unix syntax. If
3049 PREFIXFLAG is set, append an underscore "/". If no indicators of VMS syntax
3050 found, return input string. Also translate a dirname that contains no
3051 slashes, in case it's a logical name. */
3054 __gnat_to_canonical_dir_spec (char *dirspec, int prefixflag)
3058 strcpy (new_canonical_dirspec, "");
3059 if (strlen (dirspec))
3063 if (strchr (dirspec, ']') || strchr (dirspec, ':'))
3065 strncpy (new_canonical_dirspec,
3066 __gnat_translate_vms (dirspec),
3069 else if (!strchr (dirspec, '/') && (dirspec1 = getenv (dirspec)) != 0)
3071 strncpy (new_canonical_dirspec,
3072 __gnat_translate_vms (dirspec1),
3077 strncpy (new_canonical_dirspec, dirspec, MAXPATH);
3081 len = strlen (new_canonical_dirspec);
3082 if (prefixflag && new_canonical_dirspec [len-1] != '/')
3083 strncat (new_canonical_dirspec, "/", MAXPATH);
3085 new_canonical_dirspec [MAXPATH - 1] = (char) 0;
3087 return new_canonical_dirspec;
3091 /* Translate a VMS syntax file specification into Unix syntax.
3092 If no indicators of VMS syntax found, check if it's an uppercase
3093 alphanumeric_ name and if so try it out as an environment
3094 variable (logical name). If all else fails return the
3098 __gnat_to_canonical_file_spec (char *filespec)
3102 strncpy (new_canonical_filespec, "", MAXPATH);
3104 if (strchr (filespec, ']') || strchr (filespec, ':'))
3106 char *tspec = (char *) __gnat_translate_vms (filespec);
3108 if (tspec != (char *) -1)
3109 strncpy (new_canonical_filespec, tspec, MAXPATH);
3111 else if ((strlen (filespec) == strspn (filespec,
3112 "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_"))
3113 && (filespec1 = getenv (filespec)))
3115 char *tspec = (char *) __gnat_translate_vms (filespec1);
3117 if (tspec != (char *) -1)
3118 strncpy (new_canonical_filespec, tspec, MAXPATH);
3122 strncpy (new_canonical_filespec, filespec, MAXPATH);
3125 new_canonical_filespec [MAXPATH - 1] = (char) 0;
3127 return new_canonical_filespec;
3130 /* Translate a VMS syntax path specification into Unix syntax.
3131 If no indicators of VMS syntax found, return input string. */
3134 __gnat_to_canonical_path_spec (char *pathspec)
3136 char *curr, *next, buff [MAXPATH];
3141 /* If there are /'s, assume it's a Unix path spec and return. */
3142 if (strchr (pathspec, '/'))
3145 new_canonical_pathspec[0] = 0;
3150 next = strchr (curr, ',');
3152 next = strchr (curr, 0);
3154 strncpy (buff, curr, next - curr);
3155 buff[next - curr] = 0;
3157 /* Check for wildcards and expand if present. */
3158 if (strchr (buff, '*') || strchr (buff, '%') || strstr (buff, "..."))
3162 dirs = __gnat_to_canonical_file_list_init (buff, 1);
3163 for (i = 0; i < dirs; i++)
3167 next_dir = __gnat_to_canonical_file_list_next ();
3168 strncat (new_canonical_pathspec, next_dir, MAXPATH);
3170 /* Don't append the separator after the last expansion. */
3172 strncat (new_canonical_pathspec, ":", MAXPATH);
3175 __gnat_to_canonical_file_list_free ();
3178 strncat (new_canonical_pathspec,
3179 __gnat_to_canonical_dir_spec (buff, 0), MAXPATH);
3184 strncat (new_canonical_pathspec, ":", MAXPATH);
3188 new_canonical_pathspec [MAXPATH - 1] = (char) 0;
3190 return new_canonical_pathspec;
3193 static char filename_buff [MAXPATH];
3196 translate_unix (char *name, int type)
3198 strncpy (filename_buff, name, MAXPATH);
3199 filename_buff [MAXPATH - 1] = (char) 0;
3203 /* Translate a Unix syntax path spec into a VMS style (comma separated list of
3207 to_host_path_spec (char *pathspec)
3209 char *curr, *next, buff [MAXPATH];
3214 /* Can't very well test for colons, since that's the Unix separator! */
3215 if (strchr (pathspec, ']') || strchr (pathspec, ','))
3218 new_host_pathspec[0] = 0;
3223 next = strchr (curr, ':');
3225 next = strchr (curr, 0);
3227 strncpy (buff, curr, next - curr);
3228 buff[next - curr] = 0;
3230 strncat (new_host_pathspec, __gnat_to_host_dir_spec (buff, 0), MAXPATH);
3233 strncat (new_host_pathspec, ",", MAXPATH);
3237 new_host_pathspec [MAXPATH - 1] = (char) 0;
3239 return new_host_pathspec;
3242 /* Translate a Unix syntax directory specification into VMS syntax. The
3243 PREFIXFLAG has no effect, but is kept for symmetry with
3244 to_canonical_dir_spec. If indicators of VMS syntax found, return input
3248 __gnat_to_host_dir_spec (char *dirspec, int prefixflag ATTRIBUTE_UNUSED)
3250 int len = strlen (dirspec);
3252 strncpy (new_host_dirspec, dirspec, MAXPATH);
3253 new_host_dirspec [MAXPATH - 1] = (char) 0;
3255 if (strchr (new_host_dirspec, ']') || strchr (new_host_dirspec, ':'))
3256 return new_host_dirspec;
3258 while (len > 1 && new_host_dirspec[len - 1] == '/')
3260 new_host_dirspec[len - 1] = 0;
3264 decc$to_vms (new_host_dirspec, translate_unix, 1, 2);
3265 strncpy (new_host_dirspec, filename_buff, MAXPATH);
3266 new_host_dirspec [MAXPATH - 1] = (char) 0;
3268 return new_host_dirspec;
3271 /* Translate a Unix syntax file specification into VMS syntax.
3272 If indicators of VMS syntax found, return input string. */
3275 __gnat_to_host_file_spec (char *filespec)
3277 strncpy (new_host_filespec, "", MAXPATH);
3278 if (strchr (filespec, ']') || strchr (filespec, ':'))
3280 strncpy (new_host_filespec, filespec, MAXPATH);
3284 decc$to_vms (filespec, translate_unix, 1, 1);
3285 strncpy (new_host_filespec, filename_buff, MAXPATH);
3288 new_host_filespec [MAXPATH - 1] = (char) 0;
3290 return new_host_filespec;
3294 __gnat_adjust_os_resource_limits ()
3296 SYS$ADJWSL (131072, 0);
3301 /* Dummy functions for Osint import for non-VMS systems. */
3304 __gnat_to_canonical_file_list_init
3305 (char *dirspec ATTRIBUTE_UNUSED, int onlydirs ATTRIBUTE_UNUSED)
3311 __gnat_to_canonical_file_list_next (void)
3313 static char *empty = "";
3318 __gnat_to_canonical_file_list_free (void)
3323 __gnat_to_canonical_dir_spec (char *dirspec, int prefixflag ATTRIBUTE_UNUSED)
3329 __gnat_to_canonical_file_spec (char *filespec)
3335 __gnat_to_canonical_path_spec (char *pathspec)
3341 __gnat_to_host_dir_spec (char *dirspec, int prefixflag ATTRIBUTE_UNUSED)
3347 __gnat_to_host_file_spec (char *filespec)
3353 __gnat_adjust_os_resource_limits (void)
3359 #if defined (__mips_vxworks)
3363 CACHE_USER_FLUSH (0, ENTIRE_CACHE);
3367 #if defined (IS_CROSS) \
3368 || (! ((defined (sparc) || defined (i386)) && defined (sun) \
3369 && defined (__SVR4)) \
3370 && ! (defined (linux) && (defined (i386) || defined (__x86_64__))) \
3371 && ! (defined (linux) && defined (__ia64__)) \
3372 && ! (defined (linux) && defined (powerpc)) \
3373 && ! defined (__FreeBSD__) \
3374 && ! defined (__Lynx__) \
3375 && ! defined (__hpux__) \
3376 && ! defined (__APPLE__) \
3377 && ! defined (_AIX) \
3378 && ! (defined (__alpha__) && defined (__osf__)) \
3379 && ! defined (VMS) \
3380 && ! defined (__MINGW32__) \
3381 && ! (defined (__mips) && defined (__sgi)))
3383 /* Dummy function to satisfy g-trasym.o. See the preprocessor conditional
3384 just above for a list of native platforms that provide a non-dummy
3385 version of this procedure in libaddr2line.a. */
3388 convert_addresses (const char *file_name ATTRIBUTE_UNUSED,
3389 void *addrs ATTRIBUTE_UNUSED,
3390 int n_addr ATTRIBUTE_UNUSED,
3391 void *buf ATTRIBUTE_UNUSED,
3392 int *len ATTRIBUTE_UNUSED)
3398 #if defined (_WIN32)
3399 int __gnat_argument_needs_quote = 1;
3401 int __gnat_argument_needs_quote = 0;
3404 /* This option is used to enable/disable object files handling from the
3405 binder file by the GNAT Project module. For example, this is disabled on
3406 Windows (prior to GCC 3.4) as it is already done by the mdll module.
3407 Stating with GCC 3.4 the shared libraries are not based on mdll
3408 anymore as it uses the GCC's -shared option */
3409 #if defined (_WIN32) \
3410 && ((__GNUC__ < 3) || ((__GNUC__ == 3) && (__GNUC_MINOR__ < 4)))
3411 int __gnat_prj_add_obj_files = 0;
3413 int __gnat_prj_add_obj_files = 1;
3416 /* char used as prefix/suffix for environment variables */
3417 #if defined (_WIN32)
3418 char __gnat_environment_char = '%';
3420 char __gnat_environment_char = '$';
3423 /* This functions copy the file attributes from a source file to a
3426 mode = 0 : In this mode copy only the file time stamps (last access and
3427 last modification time stamps).
3429 mode = 1 : In this mode, time stamps and read/write/execute attributes are
3432 Returns 0 if operation was successful and -1 in case of error. */
3435 __gnat_copy_attribs (char *from, char *to, int mode)
3437 #if defined (VMS) || defined (__vxworks) || defined (__nucleus__)
3440 #elif defined (_WIN32) && !defined (RTX)
3441 TCHAR wfrom [GNAT_MAX_PATH_LEN + 2];
3442 TCHAR wto [GNAT_MAX_PATH_LEN + 2];
3444 FILETIME fct, flat, flwt;
3447 S2WSC (wfrom, from, GNAT_MAX_PATH_LEN + 2);
3448 S2WSC (wto, to, GNAT_MAX_PATH_LEN + 2);
3450 /* retrieve from times */
3453 (wfrom, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
3455 if (hfrom == INVALID_HANDLE_VALUE)
3458 res = GetFileTime (hfrom, &fct, &flat, &flwt);
3460 CloseHandle (hfrom);
3465 /* retrieve from times */
3468 (wto, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
3470 if (hto == INVALID_HANDLE_VALUE)
3473 res = SetFileTime (hto, NULL, &flat, &flwt);
3480 /* Set file attributes in full mode. */
3484 DWORD attribs = GetFileAttributes (wfrom);
3486 if (attribs == INVALID_FILE_ATTRIBUTES)
3489 res = SetFileAttributes (wto, attribs);
3497 GNAT_STRUCT_STAT fbuf;
3498 struct utimbuf tbuf;
3500 if (GNAT_STAT (from, &fbuf) == -1)
3505 tbuf.actime = fbuf.st_atime;
3506 tbuf.modtime = fbuf.st_mtime;
3508 if (utime (to, &tbuf) == -1)
3515 if (chmod (to, fbuf.st_mode) == -1)
3526 __gnat_lseek (int fd, long offset, int whence)
3528 return (int) lseek (fd, offset, whence);
3531 /* This function returns the major version number of GCC being used. */
3533 get_gcc_version (void)
3538 return (int) (version_string[0] - '0');
3543 __gnat_set_close_on_exec (int fd ATTRIBUTE_UNUSED,
3544 int close_on_exec_p ATTRIBUTE_UNUSED)
3546 #if defined (F_GETFD) && defined (FD_CLOEXEC) && ! defined (__vxworks)
3547 int flags = fcntl (fd, F_GETFD, 0);
3550 if (close_on_exec_p)
3551 flags |= FD_CLOEXEC;
3553 flags &= ~FD_CLOEXEC;
3554 return fcntl (fd, F_SETFD, flags | FD_CLOEXEC);
3555 #elif defined(_WIN32)
3556 HANDLE h = (HANDLE) _get_osfhandle (fd);
3557 if (h == (HANDLE) -1)
3559 if (close_on_exec_p)
3560 return ! SetHandleInformation (h, HANDLE_FLAG_INHERIT, 0);
3561 return ! SetHandleInformation (h, HANDLE_FLAG_INHERIT,
3562 HANDLE_FLAG_INHERIT);
3564 /* TODO: Unimplemented. */
3569 /* Indicates if platforms supports automatic initialization through the
3570 constructor mechanism */
3572 __gnat_binder_supports_auto_init (void)
3581 /* Indicates that Stand-Alone Libraries are automatically initialized through
3582 the constructor mechanism */
3584 __gnat_sals_init_using_constructors (void)
3586 #if defined (__vxworks) || defined (__Lynx__) || defined (VMS)
3595 /* In RTX mode, the procedure to get the time (as file time) is different
3596 in RTSS mode and Win32 mode. In order to avoid duplicating an Ada file,
3597 we introduce an intermediate procedure to link against the corresponding
3598 one in each situation. */
3600 extern void GetTimeAsFileTime(LPFILETIME pTime);
3602 void GetTimeAsFileTime(LPFILETIME pTime)
3605 RtGetRtssTimeAsFileTime (pTime); /* RTSS interface */
3607 GetSystemTimeAsFileTime (pTime); /* w32 interface */
3612 /* Add symbol that is required to link. It would otherwise be taken from
3613 libgcc.a and it would try to use the gcc constructors that are not
3614 supported by Microsoft linker. */
3616 extern void __main (void);
3618 void __main (void) {}
3622 #if defined (linux) || defined(__GLIBC__)
3623 /* pthread affinity support */
3625 int __gnat_pthread_setaffinity_np (pthread_t th,
3627 const void *cpuset);
3630 #include <pthread.h>
3632 __gnat_pthread_setaffinity_np (pthread_t th,
3634 const cpu_set_t *cpuset)
3636 return pthread_setaffinity_np (th, cpusetsize, cpuset);
3640 __gnat_pthread_setaffinity_np (pthread_t th ATTRIBUTE_UNUSED,
3641 size_t cpusetsize ATTRIBUTE_UNUSED,
3642 const void *cpuset ATTRIBUTE_UNUSED)
3650 /* There is no function in the glibc to retrieve the LWP of the current
3651 thread. We need to do a system call in order to retrieve this
3653 #include <sys/syscall.h>
3654 void *__gnat_lwp_self (void)
3656 return (void *) syscall (__NR_gettid);