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)
196 #define DIR_SEPARATOR '\\'
201 /* Define symbols O_BINARY and O_TEXT as harmless zeroes if they are not
202 defined in the current system. On DOS-like systems these flags control
203 whether the file is opened/created in text-translation mode (CR/LF in
204 external file mapped to LF in internal file), but in Unix-like systems,
205 no text translation is required, so these flags have no effect. */
207 #if defined (__EMX__)
223 #ifndef HOST_EXECUTABLE_SUFFIX
224 #define HOST_EXECUTABLE_SUFFIX ""
227 #ifndef HOST_OBJECT_SUFFIX
228 #define HOST_OBJECT_SUFFIX ".o"
231 #ifndef PATH_SEPARATOR
232 #define PATH_SEPARATOR ':'
235 #ifndef DIR_SEPARATOR
236 #define DIR_SEPARATOR '/'
239 /* Check for cross-compilation */
240 #if defined (CROSS_COMPILE) || defined (CROSS_DIRECTORY_STRUCTURE)
242 int __gnat_is_cross_compiler = 1;
245 int __gnat_is_cross_compiler = 0;
248 char __gnat_dir_separator = DIR_SEPARATOR;
250 char __gnat_path_separator = PATH_SEPARATOR;
252 /* The GNAT_LIBRARY_TEMPLATE contains a list of expressions that define
253 the base filenames that libraries specified with -lsomelib options
254 may have. This is used by GNATMAKE to check whether an executable
255 is up-to-date or not. The syntax is
257 library_template ::= { pattern ; } pattern NUL
258 pattern ::= [ prefix ] * [ postfix ]
260 These should only specify names of static libraries as it makes
261 no sense to determine at link time if dynamic-link libraries are
262 up to date or not. Any libraries that are not found are supposed
265 * if they are needed but not present, the link
268 * otherwise they are libraries in the system paths and so
269 they are considered part of the system and not checked
272 ??? This should be part of a GNAT host-specific compiler
273 file instead of being included in all user applications
274 as well. This is only a temporary work-around for 3.11b. */
276 #ifndef GNAT_LIBRARY_TEMPLATE
277 #if defined (__EMX__)
278 #define GNAT_LIBRARY_TEMPLATE "*.a"
280 #define GNAT_LIBRARY_TEMPLATE "*.olb"
282 #define GNAT_LIBRARY_TEMPLATE "lib*.a"
286 const char *__gnat_library_template = GNAT_LIBRARY_TEMPLATE;
288 /* This variable is used in hostparm.ads to say whether the host is a VMS
291 const int __gnat_vmsp = 1;
293 const int __gnat_vmsp = 0;
297 #define GNAT_MAX_PATH_LEN MAX_PATH
300 #define GNAT_MAX_PATH_LEN 256 /* PATH_MAX */
302 #elif defined (__vxworks) || defined (__OPENNT) || defined(__nucleus__)
303 #define GNAT_MAX_PATH_LEN PATH_MAX
307 #if defined (__MINGW32__)
311 #include <sys/param.h>
315 #include <sys/param.h>
319 #define GNAT_MAX_PATH_LEN MAXPATHLEN
321 #define GNAT_MAX_PATH_LEN 256
326 /* The __gnat_max_path_len variable is used to export the maximum
327 length of a path name to Ada code. max_path_len is also provided
328 for compatibility with older GNAT versions, please do not use
331 int __gnat_max_path_len = GNAT_MAX_PATH_LEN;
332 int max_path_len = GNAT_MAX_PATH_LEN;
334 /* Control whether we can use ACL on Windows. */
336 int __gnat_use_acl = 1;
338 /* The following macro HAVE_READDIR_R should be defined if the
339 system provides the routine readdir_r. */
340 #undef HAVE_READDIR_R
342 #if defined(VMS) && defined (__LONG_POINTERS)
344 /* Return a 32 bit pointer to an array of 32 bit pointers
345 given a 64 bit pointer to an array of 64 bit pointers */
347 typedef __char_ptr32 *__char_ptr_char_ptr32 __attribute__ ((mode (SI)));
349 static __char_ptr_char_ptr32
350 to_ptr32 (char **ptr64)
353 __char_ptr_char_ptr32 short_argv;
355 for (argc=0; ptr64[argc]; argc++);
357 /* Reallocate argv with 32 bit pointers. */
358 short_argv = (__char_ptr_char_ptr32) decc$malloc
359 (sizeof (__char_ptr32) * (argc + 1));
361 for (argc=0; ptr64[argc]; argc++)
362 short_argv[argc] = (__char_ptr32) decc$strdup (ptr64[argc]);
364 short_argv[argc] = (__char_ptr32) 0;
368 #define MAYBE_TO_PTR32(argv) to_ptr32 (argv)
370 #define MAYBE_TO_PTR32(argv) argv
377 time_t res = time (NULL);
378 return (OS_Time) res;
381 /* Return the current local time as a string in the ISO 8601 format of
382 "YYYY-MM-DD HH:MM:SS.SS". The returned string is 22 + 1 (NULL) characters
386 __gnat_current_time_string
389 const char *format = "%Y-%m-%d %H:%M:%S";
390 /* Format string necessary to describe the ISO 8601 format */
392 const time_t t_val = time (NULL);
394 strftime (result, 22, format, localtime (&t_val));
395 /* Convert the local time into a string following the ISO format, copying
396 at most 22 characters into the result string. */
401 /* The sub-seconds are manually set to zero since type time_t lacks the
402 precision necessary for nanoseconds. */
416 time_t time = (time_t) *p_time;
419 /* On Windows systems, the time is sometimes rounded up to the nearest
420 even second, so if the number of seconds is odd, increment it. */
426 res = localtime (&time);
428 res = gmtime (&time);
433 *p_year = res->tm_year;
434 *p_month = res->tm_mon;
435 *p_day = res->tm_mday;
436 *p_hours = res->tm_hour;
437 *p_mins = res->tm_min;
438 *p_secs = res->tm_sec;
441 *p_year = *p_month = *p_day = *p_hours = *p_mins = *p_secs = 0;
444 /* Place the contents of the symbolic link named PATH in the buffer BUF,
445 which has size BUFSIZ. If PATH is a symbolic link, then return the number
446 of characters of its content in BUF. Otherwise, return -1.
447 For systems not supporting symbolic links, always return -1. */
450 __gnat_readlink (char *path ATTRIBUTE_UNUSED,
451 char *buf ATTRIBUTE_UNUSED,
452 size_t bufsiz ATTRIBUTE_UNUSED)
454 #if defined (MSDOS) || defined (_WIN32) || defined (__EMX__) \
455 || defined (VMS) || defined(__vxworks) || defined (__nucleus__)
458 return readlink (path, buf, bufsiz);
462 /* Creates a symbolic link named NEWPATH which contains the string OLDPATH.
463 If NEWPATH exists it will NOT be overwritten.
464 For systems not supporting symbolic links, always return -1. */
467 __gnat_symlink (char *oldpath ATTRIBUTE_UNUSED,
468 char *newpath ATTRIBUTE_UNUSED)
470 #if defined (MSDOS) || defined (_WIN32) || defined (__EMX__) \
471 || defined (VMS) || defined(__vxworks) || defined (__nucleus__)
474 return symlink (oldpath, newpath);
478 /* Try to lock a file, return 1 if success. */
480 #if defined (__vxworks) || defined (__nucleus__) || defined (MSDOS) \
481 || defined (_WIN32) || defined (__EMX__) || defined (VMS)
483 /* Version that does not use link. */
486 __gnat_try_lock (char *dir, char *file)
490 TCHAR wfull_path[GNAT_MAX_PATH_LEN];
491 TCHAR wfile[GNAT_MAX_PATH_LEN];
492 TCHAR wdir[GNAT_MAX_PATH_LEN];
494 S2WSC (wdir, dir, GNAT_MAX_PATH_LEN);
495 S2WSC (wfile, file, GNAT_MAX_PATH_LEN);
497 _stprintf (wfull_path, _T("%s%c%s"), wdir, _T(DIR_SEPARATOR), wfile);
498 fd = _topen (wfull_path, O_CREAT | O_EXCL, 0600);
502 sprintf (full_path, "%s%c%s", dir, DIR_SEPARATOR, file);
503 fd = open (full_path, O_CREAT | O_EXCL, 0600);
515 /* Version using link(), more secure over NFS. */
516 /* See TN 6913-016 for discussion ??? */
519 __gnat_try_lock (char *dir, char *file)
523 struct stat stat_result;
526 sprintf (full_path, "%s%c%s", dir, DIR_SEPARATOR, file);
527 sprintf (temp_file, "%s%cTMP-%ld-%ld",
528 dir, DIR_SEPARATOR, (long)getpid(), (long)getppid ());
530 /* Create the temporary file and write the process number. */
531 fd = open (temp_file, O_CREAT | O_WRONLY, 0600);
537 /* Link it with the new file. */
538 link (temp_file, full_path);
540 /* Count the references on the old one. If we have a count of two, then
541 the link did succeed. Remove the temporary file before returning. */
542 __gnat_stat (temp_file, &stat_result);
544 return stat_result.st_nlink == 2;
548 /* Return the maximum file name length. */
551 __gnat_get_maximum_file_name_length (void)
556 if (getenv ("GNAT$EXTENDED_FILE_SPECIFICATIONS"))
565 /* Return nonzero if file names are case sensitive. */
568 __gnat_get_file_names_case_sensitive (void)
570 #if defined (__EMX__) || defined (MSDOS) || defined (VMS) || defined (WINNT)
578 __gnat_get_default_identifier_character_set (void)
580 #if defined (__EMX__) || defined (MSDOS)
587 /* Return the current working directory. */
590 __gnat_get_current_dir (char *dir, int *length)
592 #if defined (__MINGW32__)
593 TCHAR wdir[GNAT_MAX_PATH_LEN];
595 _tgetcwd (wdir, *length);
597 WS2SC (dir, wdir, GNAT_MAX_PATH_LEN);
600 /* Force Unix style, which is what GNAT uses internally. */
601 getcwd (dir, *length, 0);
603 getcwd (dir, *length);
606 *length = strlen (dir);
608 if (dir [*length - 1] != DIR_SEPARATOR)
610 dir [*length] = DIR_SEPARATOR;
616 /* Return the suffix for object files. */
619 __gnat_get_object_suffix_ptr (int *len, const char **value)
621 *value = HOST_OBJECT_SUFFIX;
626 *len = strlen (*value);
631 /* Return the suffix for executable files. */
634 __gnat_get_executable_suffix_ptr (int *len, const char **value)
636 *value = HOST_EXECUTABLE_SUFFIX;
640 *len = strlen (*value);
645 /* Return the suffix for debuggable files. Usually this is the same as the
646 executable extension. */
649 __gnat_get_debuggable_suffix_ptr (int *len, const char **value)
652 *value = HOST_EXECUTABLE_SUFFIX;
654 /* On DOS, the extensionless COFF file is what gdb likes. */
661 *len = strlen (*value);
666 /* Returns the OS filename and corresponding encoding. */
669 __gnat_os_filename (char *filename ATTRIBUTE_UNUSED,
670 char *w_filename ATTRIBUTE_UNUSED,
671 char *os_name, int *o_length,
672 char *encoding ATTRIBUTE_UNUSED, int *e_length)
674 #if defined (_WIN32) && ! defined (__vxworks) && ! defined (IS_CROSS)
675 WS2SC (os_name, (TCHAR *)w_filename, (DWORD)o_length);
676 *o_length = strlen (os_name);
677 strcpy (encoding, "encoding=utf8");
678 *e_length = strlen (encoding);
680 strcpy (os_name, filename);
681 *o_length = strlen (filename);
689 __gnat_unlink (char *path)
691 #if defined (__MINGW32__) && ! defined (__vxworks) && ! defined (IS_CROSS)
693 TCHAR wpath[GNAT_MAX_PATH_LEN];
695 S2WSC (wpath, path, GNAT_MAX_PATH_LEN);
696 return _tunlink (wpath);
699 return unlink (path);
706 __gnat_rename (char *from, char *to)
708 #if defined (__MINGW32__) && ! defined (__vxworks) && ! defined (IS_CROSS)
710 TCHAR wfrom[GNAT_MAX_PATH_LEN], wto[GNAT_MAX_PATH_LEN];
712 S2WSC (wfrom, from, GNAT_MAX_PATH_LEN);
713 S2WSC (wto, to, GNAT_MAX_PATH_LEN);
714 return _trename (wfrom, wto);
717 return rename (from, to);
721 /* Changing directory. */
724 __gnat_chdir (char *path)
726 #if defined (__MINGW32__) && ! defined (__vxworks) && ! defined (IS_CROSS)
728 TCHAR wpath[GNAT_MAX_PATH_LEN];
730 S2WSC (wpath, path, GNAT_MAX_PATH_LEN);
731 return _tchdir (wpath);
738 /* Removing a directory. */
741 __gnat_rmdir (char *path)
743 #if defined (__MINGW32__) && ! defined (__vxworks) && ! defined (IS_CROSS)
745 TCHAR wpath[GNAT_MAX_PATH_LEN];
747 S2WSC (wpath, path, GNAT_MAX_PATH_LEN);
748 return _trmdir (wpath);
756 __gnat_fopen (char *path, char *mode, int encoding ATTRIBUTE_UNUSED)
758 #if defined (_WIN32) && ! defined (__vxworks) && ! defined (IS_CROSS)
759 TCHAR wpath[GNAT_MAX_PATH_LEN];
762 S2WS (wmode, mode, 10);
764 if (encoding == Encoding_Unspecified)
765 S2WSC (wpath, path, GNAT_MAX_PATH_LEN);
766 else if (encoding == Encoding_UTF8)
767 S2WSU (wpath, path, GNAT_MAX_PATH_LEN);
769 S2WS (wpath, path, GNAT_MAX_PATH_LEN);
771 return _tfopen (wpath, wmode);
773 return decc$fopen (path, mode);
775 return fopen (path, mode);
780 __gnat_freopen (char *path, char *mode, FILE *stream, int encoding ATTRIBUTE_UNUSED)
782 #if defined (_WIN32) && ! defined (__vxworks) && ! defined (IS_CROSS)
783 TCHAR wpath[GNAT_MAX_PATH_LEN];
786 S2WS (wmode, mode, 10);
788 if (encoding == Encoding_Unspecified)
789 S2WSC (wpath, path, GNAT_MAX_PATH_LEN);
790 else if (encoding == Encoding_UTF8)
791 S2WSU (wpath, path, GNAT_MAX_PATH_LEN);
793 S2WS (wpath, path, GNAT_MAX_PATH_LEN);
795 return _tfreopen (wpath, wmode, stream);
797 return decc$freopen (path, mode, stream);
799 return freopen (path, mode, stream);
804 __gnat_open_read (char *path, int fmode)
807 int o_fmode = O_BINARY;
813 /* Optional arguments mbc,deq,fop increase read performance. */
814 fd = open (path, O_RDONLY | o_fmode, 0444,
815 "mbc=16", "deq=64", "fop=tef");
816 #elif defined (__vxworks)
817 fd = open (path, O_RDONLY | o_fmode, 0444);
818 #elif defined (__MINGW32__)
820 TCHAR wpath[GNAT_MAX_PATH_LEN];
822 S2WSC (wpath, path, GNAT_MAX_PATH_LEN);
823 fd = _topen (wpath, O_RDONLY | o_fmode, 0444);
826 fd = open (path, O_RDONLY | o_fmode);
829 return fd < 0 ? -1 : fd;
832 #if defined (__EMX__) || defined (__MINGW32__)
833 #define PERM (S_IREAD | S_IWRITE)
835 /* Excerpt from DECC C RTL Reference Manual:
836 To create files with OpenVMS RMS default protections using the UNIX
837 system-call functions umask, mkdir, creat, and open, call mkdir, creat,
838 and open with a file-protection mode argument of 0777 in a program
839 that never specifically calls umask. These default protections include
840 correctly establishing protections based on ACLs, previous versions of
844 #define PERM (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH)
848 __gnat_open_rw (char *path, int fmode)
851 int o_fmode = O_BINARY;
857 fd = open (path, O_RDWR | o_fmode, PERM,
858 "mbc=16", "deq=64", "fop=tef");
859 #elif defined (__MINGW32__)
861 TCHAR wpath[GNAT_MAX_PATH_LEN];
863 S2WSC (wpath, path, GNAT_MAX_PATH_LEN);
864 fd = _topen (wpath, O_RDWR | o_fmode, PERM);
867 fd = open (path, O_RDWR | o_fmode, PERM);
870 return fd < 0 ? -1 : fd;
874 __gnat_open_create (char *path, int fmode)
877 int o_fmode = O_BINARY;
883 fd = open (path, O_WRONLY | O_CREAT | O_TRUNC | o_fmode, PERM,
884 "mbc=16", "deq=64", "fop=tef");
885 #elif defined (__MINGW32__)
887 TCHAR wpath[GNAT_MAX_PATH_LEN];
889 S2WSC (wpath, path, GNAT_MAX_PATH_LEN);
890 fd = _topen (wpath, O_WRONLY | O_CREAT | O_TRUNC | o_fmode, PERM);
893 fd = open (path, O_WRONLY | O_CREAT | O_TRUNC | o_fmode, PERM);
896 return fd < 0 ? -1 : fd;
900 __gnat_create_output_file (char *path)
904 fd = open (path, O_WRONLY | O_CREAT | O_TRUNC | O_TEXT, PERM,
905 "rfm=stmlf", "ctx=rec", "rat=none", "rop=nlk",
906 "shr=del,get,put,upd");
907 #elif defined (__MINGW32__)
909 TCHAR wpath[GNAT_MAX_PATH_LEN];
911 S2WSC (wpath, path, GNAT_MAX_PATH_LEN);
912 fd = _topen (wpath, O_WRONLY | O_CREAT | O_TRUNC | O_TEXT, PERM);
915 fd = open (path, O_WRONLY | O_CREAT | O_TRUNC | O_TEXT, PERM);
918 return fd < 0 ? -1 : fd;
922 __gnat_open_append (char *path, int fmode)
925 int o_fmode = O_BINARY;
931 fd = open (path, O_WRONLY | O_CREAT | O_APPEND | o_fmode, PERM,
932 "mbc=16", "deq=64", "fop=tef");
933 #elif defined (__MINGW32__)
935 TCHAR wpath[GNAT_MAX_PATH_LEN];
937 S2WSC (wpath, path, GNAT_MAX_PATH_LEN);
938 fd = _topen (wpath, O_WRONLY | O_CREAT | O_APPEND | o_fmode, PERM);
941 fd = open (path, O_WRONLY | O_CREAT | O_APPEND | o_fmode, PERM);
944 return fd < 0 ? -1 : fd;
947 /* Open a new file. Return error (-1) if the file already exists. */
950 __gnat_open_new (char *path, int fmode)
953 int o_fmode = O_BINARY;
959 fd = open (path, O_WRONLY | O_CREAT | O_EXCL | o_fmode, PERM,
960 "mbc=16", "deq=64", "fop=tef");
961 #elif defined (__MINGW32__)
963 TCHAR wpath[GNAT_MAX_PATH_LEN];
965 S2WSC (wpath, path, GNAT_MAX_PATH_LEN);
966 fd = _topen (wpath, O_WRONLY | O_CREAT | O_EXCL | o_fmode, PERM);
969 fd = open (path, O_WRONLY | O_CREAT | O_EXCL | o_fmode, PERM);
972 return fd < 0 ? -1 : fd;
975 /* Open a new temp file. Return error (-1) if the file already exists.
976 Special options for VMS allow the file to be shared between parent and child
977 processes, however they really slow down output. Used in gnatchop. */
980 __gnat_open_new_temp (char *path, int fmode)
983 int o_fmode = O_BINARY;
985 strcpy (path, "GNAT-XXXXXX");
987 #if (defined (__FreeBSD__) || defined (__NetBSD__) || defined (__OpenBSD__) \
988 || defined (linux) || defined(__GLIBC__)) && !defined (__vxworks)
989 return mkstemp (path);
990 #elif defined (__Lynx__)
992 #elif defined (__nucleus__)
995 if (mktemp (path) == NULL)
1003 fd = open (path, O_WRONLY | O_CREAT | O_EXCL | o_fmode, PERM,
1004 "rfm=stmlf", "ctx=rec", "rat=none", "shr=del,get,put,upd",
1005 "mbc=16", "deq=64", "fop=tef");
1007 fd = open (path, O_WRONLY | O_CREAT | O_EXCL | o_fmode, PERM);
1010 return fd < 0 ? -1 : fd;
1013 /* Return the number of bytes in the specified file. */
1016 __gnat_file_length (int fd)
1019 struct stat statbuf;
1021 ret = fstat (fd, &statbuf);
1022 if (ret || !S_ISREG (statbuf.st_mode))
1025 return (statbuf.st_size);
1028 /* Return the number of bytes in the specified named file. */
1031 __gnat_named_file_length (char *name)
1034 struct stat statbuf;
1036 ret = __gnat_stat (name, &statbuf);
1037 if (ret || !S_ISREG (statbuf.st_mode))
1040 return (statbuf.st_size);
1043 /* Create a temporary filename and put it in string pointed to by
1047 __gnat_tmp_name (char *tmp_filename)
1050 /* Variable used to create a series of unique names */
1051 static int counter = 0;
1053 /* RTX in RTSS mode does not support tempnam nor tmpnam so we emulate it */
1054 strcpy (tmp_filename, "c:\\WINDOWS\\Temp\\gnat-");
1055 sprintf (&tmp_filename[strlen (tmp_filename)], "%d\0", counter++);
1057 #elif defined (__MINGW32__)
1061 /* tempnam tries to create a temporary file in directory pointed to by
1062 TMP environment variable, in c:\temp if TMP is not set, and in
1063 directory specified by P_tmpdir in stdio.h if c:\temp does not
1064 exist. The filename will be created with the prefix "gnat-". */
1066 pname = (char *) tempnam ("c:\\temp", "gnat-");
1068 /* if pname is NULL, the file was not created properly, the disk is full
1069 or there is no more free temporary files */
1072 *tmp_filename = '\0';
1074 /* If pname start with a back slash and not path information it means that
1075 the filename is valid for the current working directory. */
1077 else if (pname[0] == '\\')
1079 strcpy (tmp_filename, ".\\");
1080 strcat (tmp_filename, pname+1);
1083 strcpy (tmp_filename, pname);
1088 #elif defined (linux) || defined (__FreeBSD__) || defined (__NetBSD__) \
1089 || defined (__OpenBSD__) || defined(__GLIBC__)
1090 #define MAX_SAFE_PATH 1000
1091 char *tmpdir = getenv ("TMPDIR");
1093 /* If tmpdir is longer than MAX_SAFE_PATH, revert to default value to avoid
1094 a buffer overflow. */
1095 if (tmpdir == NULL || strlen (tmpdir) > MAX_SAFE_PATH)
1096 strcpy (tmp_filename, "/tmp/gnat-XXXXXX");
1098 sprintf (tmp_filename, "%s/gnat-XXXXXX", tmpdir);
1100 close (mkstemp(tmp_filename));
1102 tmpnam (tmp_filename);
1106 /* Open directory and returns a DIR pointer. */
1108 DIR* __gnat_opendir (char *name)
1111 /* Not supported in RTX */
1115 #elif defined (__MINGW32__)
1116 TCHAR wname[GNAT_MAX_PATH_LEN];
1118 S2WSC (wname, name, GNAT_MAX_PATH_LEN);
1119 return (DIR*)_topendir (wname);
1122 return opendir (name);
1126 /* Read the next entry in a directory. The returned string points somewhere
1130 __gnat_readdir (DIR *dirp, char *buffer, int *len)
1133 /* Not supported in RTX */
1137 #elif defined (__MINGW32__)
1138 struct _tdirent *dirent = _treaddir ((_TDIR*)dirp);
1142 WS2SC (buffer, dirent->d_name, GNAT_MAX_PATH_LEN);
1143 *len = strlen (buffer);
1150 #elif defined (HAVE_READDIR_R)
1151 /* If possible, try to use the thread-safe version. */
1152 if (readdir_r (dirp, buffer) != NULL)
1154 *len = strlen (((struct dirent*) buffer)->d_name);
1155 return ((struct dirent*) buffer)->d_name;
1161 struct dirent *dirent = (struct dirent *) readdir (dirp);
1165 strcpy (buffer, dirent->d_name);
1166 *len = strlen (buffer);
1175 /* Close a directory entry. */
1177 int __gnat_closedir (DIR *dirp)
1180 /* Not supported in RTX */
1184 #elif defined (__MINGW32__)
1185 return _tclosedir ((_TDIR*)dirp);
1188 return closedir (dirp);
1192 /* Returns 1 if readdir is thread safe, 0 otherwise. */
1195 __gnat_readdir_is_thread_safe (void)
1197 #ifdef HAVE_READDIR_R
1204 #if defined (_WIN32) && !defined (RTX)
1205 /* Number of seconds between <Jan 1st 1601> and <Jan 1st 1970>. */
1206 static const unsigned long long w32_epoch_offset = 11644473600ULL;
1208 /* Returns the file modification timestamp using Win32 routines which are
1209 immune against daylight saving time change. It is in fact not possible to
1210 use fstat for this purpose as the DST modify the st_mtime field of the
1214 win32_filetime (HANDLE h)
1219 unsigned long long ull_time;
1222 /* GetFileTime returns FILETIME data which are the number of 100 nanosecs
1223 since <Jan 1st 1601>. This function must return the number of seconds
1224 since <Jan 1st 1970>. */
1226 if (GetFileTime (h, NULL, NULL, &t_write.ft_time))
1227 return (time_t) (t_write.ull_time / 10000000ULL - w32_epoch_offset);
1232 /* Return a GNAT time stamp given a file name. */
1235 __gnat_file_time_name (char *name)
1238 #if defined (__EMX__) || defined (MSDOS)
1239 int fd = open (name, O_RDONLY | O_BINARY);
1240 time_t ret = __gnat_file_time_fd (fd);
1242 return (OS_Time)ret;
1244 #elif defined (_WIN32) && !defined (RTX)
1246 TCHAR wname[GNAT_MAX_PATH_LEN];
1248 S2WSC (wname, name, GNAT_MAX_PATH_LEN);
1250 HANDLE h = CreateFile
1251 (wname, GENERIC_READ, FILE_SHARE_READ, 0,
1252 OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0);
1254 if (h != INVALID_HANDLE_VALUE)
1256 ret = win32_filetime (h);
1259 return (OS_Time) ret;
1261 struct stat statbuf;
1262 if (__gnat_stat (name, &statbuf) != 0) {
1266 /* VMS has file versioning. */
1267 return (OS_Time)statbuf.st_ctime;
1269 return (OS_Time)statbuf.st_mtime;
1275 /* Return a GNAT time stamp given a file descriptor. */
1278 __gnat_file_time_fd (int fd)
1280 /* The following workaround code is due to the fact that under EMX and
1281 DJGPP fstat attempts to convert time values to GMT rather than keep the
1282 actual OS timestamp of the file. By using the OS2/DOS functions directly
1283 the GNAT timestamp are independent of this behavior, which is desired to
1284 facilitate the distribution of GNAT compiled libraries. */
1286 #if defined (__EMX__) || defined (MSDOS)
1290 int ret = DosQueryFileInfo (fd, 1, (unsigned char *) &fs,
1291 sizeof (FILESTATUS));
1293 unsigned file_year = fs.fdateLastWrite.year;
1294 unsigned file_month = fs.fdateLastWrite.month;
1295 unsigned file_day = fs.fdateLastWrite.day;
1296 unsigned file_hour = fs.ftimeLastWrite.hours;
1297 unsigned file_min = fs.ftimeLastWrite.minutes;
1298 unsigned file_tsec = fs.ftimeLastWrite.twosecs;
1302 int ret = getftime (fd, &fs);
1304 unsigned file_year = fs.ft_year;
1305 unsigned file_month = fs.ft_month;
1306 unsigned file_day = fs.ft_day;
1307 unsigned file_hour = fs.ft_hour;
1308 unsigned file_min = fs.ft_min;
1309 unsigned file_tsec = fs.ft_tsec;
1312 /* Calculate the seconds since epoch from the time components. First count
1313 the whole days passed. The value for years returned by the DOS and OS2
1314 functions count years from 1980, so to compensate for the UNIX epoch which
1315 begins in 1970 start with 10 years worth of days and add days for each
1316 four year period since then. */
1319 int cum_days[12] = {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334};
1320 int days_passed = 3652 + (file_year / 4) * 1461;
1321 int years_since_leap = file_year % 4;
1323 if (years_since_leap == 1)
1325 else if (years_since_leap == 2)
1327 else if (years_since_leap == 3)
1328 days_passed += 1096;
1333 days_passed += cum_days[file_month - 1];
1334 if (years_since_leap == 0 && file_year != 20 && file_month > 2)
1337 days_passed += file_day - 1;
1339 /* OK - have whole days. Multiply -- then add in other parts. */
1341 tot_secs = days_passed * 86400;
1342 tot_secs += file_hour * 3600;
1343 tot_secs += file_min * 60;
1344 tot_secs += file_tsec * 2;
1345 return (OS_Time) tot_secs;
1347 #elif defined (_WIN32) && !defined (RTX)
1348 HANDLE h = (HANDLE) _get_osfhandle (fd);
1349 time_t ret = win32_filetime (h);
1350 return (OS_Time) ret;
1353 struct stat statbuf;
1355 if (fstat (fd, &statbuf) != 0) {
1356 return (OS_Time) -1;
1359 /* VMS has file versioning. */
1360 return (OS_Time) statbuf.st_ctime;
1362 return (OS_Time) statbuf.st_mtime;
1368 /* Set the file time stamp. */
1371 __gnat_set_file_time_name (char *name, time_t time_stamp)
1373 #if defined (__EMX__) || defined (MSDOS) || defined (__vxworks)
1375 /* Code to implement __gnat_set_file_time_name for these systems. */
1377 #elif defined (_WIN32) && !defined (RTX)
1381 unsigned long long ull_time;
1383 TCHAR wname[GNAT_MAX_PATH_LEN];
1385 S2WSC (wname, name, GNAT_MAX_PATH_LEN);
1387 HANDLE h = CreateFile
1388 (wname, GENERIC_WRITE, FILE_SHARE_WRITE, NULL,
1389 OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS,
1391 if (h == INVALID_HANDLE_VALUE)
1393 /* Add number of seconds between <Jan 1st 1601> and <Jan 1st 1970> */
1394 t_write.ull_time = ((unsigned long long)time_stamp + w32_epoch_offset);
1395 /* Convert to 100 nanosecond units */
1396 t_write.ull_time *= 10000000ULL;
1398 SetFileTime(h, NULL, NULL, &t_write.ft_time);
1408 unsigned long long backup, create, expire, revise;
1412 unsigned short value;
1415 unsigned system : 4;
1421 } Fat = { 0, 0, 0, 0, 0, { 0 }};
1425 { ATR$S_CREDATE, ATR$C_CREDATE, &Fat.create },
1426 { ATR$S_REVDATE, ATR$C_REVDATE, &Fat.revise },
1427 { ATR$S_EXPDATE, ATR$C_EXPDATE, &Fat.expire },
1428 { ATR$S_BAKDATE, ATR$C_BAKDATE, &Fat.backup },
1429 { ATR$S_FPRO, ATR$C_FPRO, &Fat.prot },
1430 { ATR$S_UIC, ATR$C_UIC, &Fat.uic },
1435 struct dsc$descriptor_fib fibdsc = {sizeof (fib), (void *) &fib};
1439 unsigned long long newtime;
1440 unsigned long long revtime;
1444 struct vstring file;
1445 struct dsc$descriptor_s filedsc
1446 = {NAM$C_MAXRSS, DSC$K_DTYPE_T, DSC$K_CLASS_S, (void *) file.string};
1447 struct vstring device;
1448 struct dsc$descriptor_s devicedsc
1449 = {NAM$C_MAXRSS, DSC$K_DTYPE_T, DSC$K_CLASS_S, (void *) device.string};
1450 struct vstring timev;
1451 struct dsc$descriptor_s timedsc
1452 = {NAM$C_MAXRSS, DSC$K_DTYPE_T, DSC$K_CLASS_S, (void *) timev.string};
1453 struct vstring result;
1454 struct dsc$descriptor_s resultdsc
1455 = {NAM$C_MAXRSS, DSC$K_DTYPE_VT, DSC$K_CLASS_VS, (void *) result.string};
1457 /* Convert parameter name (a file spec) to host file form. Note that this
1458 is needed on VMS to prepare for subsequent calls to VMS RMS library
1459 routines. Note that it would not work to call __gnat_to_host_dir_spec
1460 as was done in a previous version, since this fails silently unless
1461 the feature logical DECC$EFS_CHARSET is enabled, in which case a DNF
1462 (directory not found) condition is signalled. */
1463 tryfile = (char *) __gnat_to_host_file_spec (name);
1465 /* Allocate and initialize a FAB and NAM structures. */
1469 nam.nam$l_esa = file.string;
1470 nam.nam$b_ess = NAM$C_MAXRSS;
1471 nam.nam$l_rsa = result.string;
1472 nam.nam$b_rss = NAM$C_MAXRSS;
1473 fab.fab$l_fna = tryfile;
1474 fab.fab$b_fns = strlen (tryfile);
1475 fab.fab$l_nam = &nam;
1477 /* Validate filespec syntax and device existence. */
1478 status = SYS$PARSE (&fab, 0, 0);
1479 if ((status & 1) != 1)
1480 LIB$SIGNAL (status);
1482 file.string[nam.nam$b_esl] = 0;
1484 /* Find matching filespec. */
1485 status = SYS$SEARCH (&fab, 0, 0);
1486 if ((status & 1) != 1)
1487 LIB$SIGNAL (status);
1489 file.string[nam.nam$b_esl] = 0;
1490 result.string[result.length=nam.nam$b_rsl] = 0;
1492 /* Get the device name and assign an IO channel. */
1493 strncpy (device.string, nam.nam$l_dev, nam.nam$b_dev);
1494 devicedsc.dsc$w_length = nam.nam$b_dev;
1496 status = SYS$ASSIGN (&devicedsc, &chan, 0, 0, 0);
1497 if ((status & 1) != 1)
1498 LIB$SIGNAL (status);
1500 /* Initialize the FIB and fill in the directory id field. */
1501 memset (&fib, 0, sizeof (fib));
1502 fib.fib$w_did[0] = nam.nam$w_did[0];
1503 fib.fib$w_did[1] = nam.nam$w_did[1];
1504 fib.fib$w_did[2] = nam.nam$w_did[2];
1505 fib.fib$l_acctl = 0;
1507 strcpy (file.string, (strrchr (result.string, ']') + 1));
1508 filedsc.dsc$w_length = strlen (file.string);
1509 result.string[result.length = 0] = 0;
1511 /* Open and close the file to fill in the attributes. */
1513 = SYS$QIOW (0, chan, IO$_ACCESS|IO$M_ACCESS, &iosb, 0, 0,
1514 &fibdsc, &filedsc, &result.length, &resultdsc, &atrlst, 0);
1515 if ((status & 1) != 1)
1516 LIB$SIGNAL (status);
1517 if ((iosb.status & 1) != 1)
1518 LIB$SIGNAL (iosb.status);
1520 result.string[result.length] = 0;
1521 status = SYS$QIOW (0, chan, IO$_DEACCESS, &iosb, 0, 0, &fibdsc, 0, 0, 0,
1523 if ((status & 1) != 1)
1524 LIB$SIGNAL (status);
1525 if ((iosb.status & 1) != 1)
1526 LIB$SIGNAL (iosb.status);
1531 /* Set creation time to requested time. */
1532 unix_time_to_vms (time_stamp, newtime);
1534 t = time ((time_t) 0);
1536 /* Set revision time to now in local time. */
1537 unix_time_to_vms (t, revtime);
1540 /* Reopen the file, modify the times and then close. */
1541 fib.fib$l_acctl = FIB$M_WRITE;
1543 = SYS$QIOW (0, chan, IO$_ACCESS|IO$M_ACCESS, &iosb, 0, 0,
1544 &fibdsc, &filedsc, &result.length, &resultdsc, &atrlst, 0);
1545 if ((status & 1) != 1)
1546 LIB$SIGNAL (status);
1547 if ((iosb.status & 1) != 1)
1548 LIB$SIGNAL (iosb.status);
1550 Fat.create = newtime;
1551 Fat.revise = revtime;
1553 status = SYS$QIOW (0, chan, IO$_DEACCESS, &iosb, 0, 0,
1554 &fibdsc, 0, 0, 0, &atrlst, 0);
1555 if ((status & 1) != 1)
1556 LIB$SIGNAL (status);
1557 if ((iosb.status & 1) != 1)
1558 LIB$SIGNAL (iosb.status);
1560 /* Deassign the channel and exit. */
1561 status = SYS$DASSGN (chan);
1562 if ((status & 1) != 1)
1563 LIB$SIGNAL (status);
1565 struct utimbuf utimbuf;
1568 /* Set modification time to requested time. */
1569 utimbuf.modtime = time_stamp;
1571 /* Set access time to now in local time. */
1572 t = time ((time_t) 0);
1573 utimbuf.actime = mktime (localtime (&t));
1575 utime (name, &utimbuf);
1579 /* Get the list of installed standard libraries from the
1580 HKEY_LOCAL_MACHINE\SOFTWARE\Ada Core Technologies\GNAT\Standard Libraries
1584 __gnat_get_libraries_from_registry (void)
1586 char *result = (char *) xmalloc (1);
1590 #if defined (_WIN32) && ! defined (__vxworks) && ! defined (IS_CROSS) \
1594 DWORD name_size, value_size;
1601 /* First open the key. */
1602 res = RegOpenKeyExA (HKEY_LOCAL_MACHINE, "SOFTWARE", 0, KEY_READ, ®_key);
1604 if (res == ERROR_SUCCESS)
1605 res = RegOpenKeyExA (reg_key, "Ada Core Technologies", 0,
1606 KEY_READ, ®_key);
1608 if (res == ERROR_SUCCESS)
1609 res = RegOpenKeyExA (reg_key, "GNAT", 0, KEY_READ, ®_key);
1611 if (res == ERROR_SUCCESS)
1612 res = RegOpenKeyExA (reg_key, "Standard Libraries", 0, KEY_READ, ®_key);
1614 /* If the key exists, read out all the values in it and concatenate them
1616 for (index = 0; res == ERROR_SUCCESS; index++)
1618 value_size = name_size = 256;
1619 res = RegEnumValueA (reg_key, index, name, &name_size, 0,
1620 &type, (LPBYTE)value, &value_size);
1622 if (res == ERROR_SUCCESS && type == REG_SZ)
1624 char *old_result = result;
1626 result = (char *) xmalloc (strlen (old_result) + value_size + 2);
1627 strcpy (result, old_result);
1628 strcat (result, value);
1629 strcat (result, ";");
1634 /* Remove the trailing ";". */
1636 result[strlen (result) - 1] = 0;
1643 __gnat_stat (char *name, struct stat *statbuf)
1646 /* Under Windows the directory name for the stat function must not be
1647 terminated by a directory separator except if just after a drive name. */
1648 TCHAR wname [GNAT_MAX_PATH_LEN + 2];
1652 S2WSC (wname, name, GNAT_MAX_PATH_LEN + 2);
1653 name_len = _tcslen (wname);
1655 if (name_len > GNAT_MAX_PATH_LEN)
1658 last_char = wname[name_len - 1];
1660 while (name_len > 1 && (last_char == _T('\\') || last_char == _T('/')))
1662 wname[name_len - 1] = _T('\0');
1664 last_char = wname[name_len - 1];
1667 /* Only a drive letter followed by ':', we must add a directory separator
1668 for the stat routine to work properly. */
1669 if (name_len == 2 && wname[1] == _T(':'))
1670 _tcscat (wname, _T("\\"));
1672 return _tstat (wname, (struct _stat *)statbuf);
1675 return stat (name, statbuf);
1680 __gnat_file_exists (char *name)
1683 /* On Windows do not use __gnat_stat() because a bug in Microsoft
1684 _stat() routine. When the system time-zone is set with a negative
1685 offset the _stat() routine fails on specific files like CON: */
1686 TCHAR wname [GNAT_MAX_PATH_LEN + 2];
1688 S2WSC (wname, name, GNAT_MAX_PATH_LEN + 2);
1689 return GetFileAttributes (wname) != INVALID_FILE_ATTRIBUTES;
1691 struct stat statbuf;
1693 return !__gnat_stat (name, &statbuf);
1698 __gnat_is_absolute_path (char *name, int length)
1701 /* On VxWorks systems, an absolute path can be represented (depending on
1702 the host platform) as either /dir/file, or device:/dir/file, or
1703 device:drive_letter:/dir/file. */
1710 for (index = 0; index < length; index++)
1712 if (name[index] == ':' &&
1713 ((name[index + 1] == '/') ||
1714 (isalpha (name[index + 1]) && index + 2 <= length &&
1715 name[index + 2] == '/')))
1718 else if (name[index] == '/')
1723 return (length != 0) &&
1724 (*name == '/' || *name == DIR_SEPARATOR
1725 #if defined (__EMX__) || defined (MSDOS) || defined (WINNT)
1726 || (length > 1 && ISALPHA (name[0]) && name[1] == ':')
1733 __gnat_is_regular_file (char *name)
1736 struct stat statbuf;
1738 ret = __gnat_stat (name, &statbuf);
1739 return (!ret && S_ISREG (statbuf.st_mode));
1743 __gnat_is_directory (char *name)
1746 struct stat statbuf;
1748 ret = __gnat_stat (name, &statbuf);
1749 return (!ret && S_ISDIR (statbuf.st_mode));
1752 #if defined (_WIN32) && !defined (RTX)
1754 /* Returns the same constant as GetDriveType but takes a pathname as
1758 GetDriveTypeFromPath (TCHAR *wfullpath)
1760 TCHAR wdrv[MAX_PATH];
1761 TCHAR wpath[MAX_PATH];
1762 TCHAR wfilename[MAX_PATH];
1763 TCHAR wext[MAX_PATH];
1765 _tsplitpath (wfullpath, wdrv, wpath, wfilename, wext);
1767 if (_tcslen (wdrv) != 0)
1769 /* we have a drive specified. */
1770 _tcscat (wdrv, _T("\\"));
1771 return GetDriveType (wdrv);
1775 /* No drive specified. */
1777 /* Is this a relative path, if so get current drive type. */
1778 if (wpath[0] != _T('\\') ||
1779 (_tcslen (wpath) > 2 && wpath[0] == _T('\\') && wpath[1] != _T('\\')))
1780 return GetDriveType (NULL);
1782 UINT result = GetDriveType (wpath);
1784 /* Cannot guess the drive type, is this \\.\ ? */
1786 if (result == DRIVE_NO_ROOT_DIR &&
1787 _tcslen (wpath) >= 4 && wpath[0] == _T('\\') && wpath[1] == _T('\\')
1788 && wpath[2] == _T('.') && wpath[3] == _T('\\'))
1790 if (_tcslen (wpath) == 4)
1791 _tcscat (wpath, wfilename);
1793 LPTSTR p = &wpath[4];
1794 LPTSTR b = _tcschr (p, _T('\\'));
1797 { /* logical drive \\.\c\dir\file */
1803 _tcscat (p, _T(":\\"));
1805 return GetDriveType (p);
1812 /* This MingW section contains code to work with ACL. */
1814 __gnat_check_OWNER_ACL
1816 DWORD CheckAccessDesired,
1817 GENERIC_MAPPING CheckGenericMapping)
1819 DWORD dwAccessDesired, dwAccessAllowed;
1820 PRIVILEGE_SET PrivilegeSet;
1821 DWORD dwPrivSetSize = sizeof (PRIVILEGE_SET);
1822 BOOL fAccessGranted = FALSE;
1825 SECURITY_DESCRIPTOR* pSD = NULL;
1828 (wname, OWNER_SECURITY_INFORMATION |
1829 GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION,
1832 if ((pSD = (PSECURITY_DESCRIPTOR) HeapAlloc
1833 (GetProcessHeap (), HEAP_ZERO_MEMORY, nLength)) == NULL)
1836 /* Obtain the security descriptor. */
1838 if (!GetFileSecurity
1839 (wname, OWNER_SECURITY_INFORMATION |
1840 GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION,
1841 pSD, nLength, &nLength))
1844 if (!ImpersonateSelf (SecurityImpersonation))
1847 if (!OpenThreadToken
1848 (GetCurrentThread(), TOKEN_DUPLICATE | TOKEN_QUERY, FALSE, &hToken))
1851 /* Undoes the effect of ImpersonateSelf. */
1855 /* We want to test for write permissions. */
1857 dwAccessDesired = CheckAccessDesired;
1859 MapGenericMask (&dwAccessDesired, &CheckGenericMapping);
1862 (pSD , /* security descriptor to check */
1863 hToken, /* impersonation token */
1864 dwAccessDesired, /* requested access rights */
1865 &CheckGenericMapping, /* pointer to GENERIC_MAPPING */
1866 &PrivilegeSet, /* receives privileges used in check */
1867 &dwPrivSetSize, /* size of PrivilegeSet buffer */
1868 &dwAccessAllowed, /* receives mask of allowed access rights */
1872 return fAccessGranted;
1876 __gnat_set_OWNER_ACL
1879 DWORD AccessPermissions)
1881 ACL* pOldDACL = NULL;
1882 ACL* pNewDACL = NULL;
1883 SECURITY_DESCRIPTOR* pSD = NULL;
1885 TCHAR username [100];
1888 /* Get current user, he will act as the owner */
1890 if (!GetUserName (username, &unsize))
1893 if (GetNamedSecurityInfo
1896 DACL_SECURITY_INFORMATION,
1897 NULL, NULL, &pOldDACL, NULL, &pSD) != ERROR_SUCCESS)
1900 BuildExplicitAccessWithName
1901 (&ea, username, AccessPermissions, AccessMode, NO_INHERITANCE);
1903 if (AccessMode == SET_ACCESS)
1905 /* SET_ACCESS, we want to set an explicte set of permissions, do not
1906 merge with current DACL. */
1907 if (SetEntriesInAcl (1, &ea, NULL, &pNewDACL) != ERROR_SUCCESS)
1911 if (SetEntriesInAcl (1, &ea, pOldDACL, &pNewDACL) != ERROR_SUCCESS)
1914 if (SetNamedSecurityInfo
1915 (wname, SE_FILE_OBJECT,
1916 DACL_SECURITY_INFORMATION, NULL, NULL, pNewDACL, NULL) != ERROR_SUCCESS)
1920 LocalFree (pNewDACL);
1923 /* Check if it is possible to use ACL for wname, the file must not be on a
1927 __gnat_can_use_acl (TCHAR *wname)
1929 return __gnat_use_acl && GetDriveTypeFromPath (wname) != DRIVE_REMOTE;
1932 #endif /* defined (_WIN32) && !defined (RTX) */
1935 __gnat_is_readable_file (char *name)
1937 #if defined (_WIN32) && !defined (RTX)
1938 TCHAR wname [GNAT_MAX_PATH_LEN + 2];
1939 GENERIC_MAPPING GenericMapping;
1941 S2WSC (wname, name, GNAT_MAX_PATH_LEN + 2);
1943 if (__gnat_can_use_acl (wname))
1945 ZeroMemory (&GenericMapping, sizeof (GENERIC_MAPPING));
1946 GenericMapping.GenericRead = GENERIC_READ;
1948 return __gnat_check_OWNER_ACL (wname, FILE_READ_DATA, GenericMapping);
1956 struct stat statbuf;
1958 ret = stat (name, &statbuf);
1959 mode = statbuf.st_mode & S_IRUSR;
1960 return (!ret && mode);
1965 __gnat_is_writable_file (char *name)
1967 #if defined (_WIN32) && !defined (RTX)
1968 TCHAR wname [GNAT_MAX_PATH_LEN + 2];
1969 GENERIC_MAPPING GenericMapping;
1971 S2WSC (wname, name, GNAT_MAX_PATH_LEN + 2);
1973 if (__gnat_can_use_acl (wname))
1975 ZeroMemory (&GenericMapping, sizeof (GENERIC_MAPPING));
1976 GenericMapping.GenericWrite = GENERIC_WRITE;
1978 return __gnat_check_OWNER_ACL
1979 (wname, FILE_WRITE_DATA | FILE_APPEND_DATA, GenericMapping)
1980 && !(GetFileAttributes (wname) & FILE_ATTRIBUTE_READONLY);
1983 return !(GetFileAttributes (wname) & FILE_ATTRIBUTE_READONLY);
1988 struct stat statbuf;
1990 ret = stat (name, &statbuf);
1991 mode = statbuf.st_mode & S_IWUSR;
1992 return (!ret && mode);
1997 __gnat_is_executable_file (char *name)
1999 #if defined (_WIN32) && !defined (RTX)
2000 TCHAR wname [GNAT_MAX_PATH_LEN + 2];
2001 GENERIC_MAPPING GenericMapping;
2003 S2WSC (wname, name, GNAT_MAX_PATH_LEN + 2);
2005 if (__gnat_can_use_acl (wname))
2007 ZeroMemory (&GenericMapping, sizeof (GENERIC_MAPPING));
2008 GenericMapping.GenericExecute = GENERIC_EXECUTE;
2010 return __gnat_check_OWNER_ACL (wname, FILE_EXECUTE, GenericMapping);
2013 return GetFileAttributes (wname) != INVALID_FILE_ATTRIBUTES
2014 && _tcsstr (wname, _T(".exe")) - wname == (int) (_tcslen (wname) - 4);
2019 struct stat statbuf;
2021 ret = stat (name, &statbuf);
2022 mode = statbuf.st_mode & S_IXUSR;
2023 return (!ret && mode);
2028 __gnat_set_writable (char *name)
2030 #if defined (_WIN32) && !defined (RTX)
2031 TCHAR wname [GNAT_MAX_PATH_LEN + 2];
2033 S2WSC (wname, name, GNAT_MAX_PATH_LEN + 2);
2035 if (__gnat_can_use_acl (wname))
2036 __gnat_set_OWNER_ACL (wname, GRANT_ACCESS, FILE_GENERIC_WRITE);
2039 (wname, GetFileAttributes (wname) & ~FILE_ATTRIBUTE_READONLY);
2040 #elif ! defined (__vxworks) && ! defined(__nucleus__)
2041 struct stat statbuf;
2043 if (stat (name, &statbuf) == 0)
2045 statbuf.st_mode = statbuf.st_mode | S_IWUSR;
2046 chmod (name, statbuf.st_mode);
2052 __gnat_set_executable (char *name)
2054 #if defined (_WIN32) && !defined (RTX)
2055 TCHAR wname [GNAT_MAX_PATH_LEN + 2];
2057 S2WSC (wname, name, GNAT_MAX_PATH_LEN + 2);
2059 if (__gnat_can_use_acl (wname))
2060 __gnat_set_OWNER_ACL (wname, GRANT_ACCESS, FILE_GENERIC_EXECUTE);
2062 #elif ! defined (__vxworks) && ! defined(__nucleus__)
2063 struct stat statbuf;
2065 if (stat (name, &statbuf) == 0)
2067 statbuf.st_mode = statbuf.st_mode | S_IXUSR;
2068 chmod (name, statbuf.st_mode);
2074 __gnat_set_non_writable (char *name)
2076 #if defined (_WIN32) && !defined (RTX)
2077 TCHAR wname [GNAT_MAX_PATH_LEN + 2];
2079 S2WSC (wname, name, GNAT_MAX_PATH_LEN + 2);
2081 if (__gnat_can_use_acl (wname))
2082 __gnat_set_OWNER_ACL
2083 (wname, DENY_ACCESS,
2084 FILE_WRITE_DATA | FILE_APPEND_DATA |
2085 FILE_WRITE_EA | FILE_WRITE_ATTRIBUTES);
2088 (wname, GetFileAttributes (wname) | FILE_ATTRIBUTE_READONLY);
2089 #elif ! defined (__vxworks) && ! defined(__nucleus__)
2090 struct stat statbuf;
2092 if (stat (name, &statbuf) == 0)
2094 statbuf.st_mode = statbuf.st_mode & 07577;
2095 chmod (name, statbuf.st_mode);
2101 __gnat_set_readable (char *name)
2103 #if defined (_WIN32) && !defined (RTX)
2104 TCHAR wname [GNAT_MAX_PATH_LEN + 2];
2106 S2WSC (wname, name, GNAT_MAX_PATH_LEN + 2);
2108 if (__gnat_can_use_acl (wname))
2109 __gnat_set_OWNER_ACL (wname, GRANT_ACCESS, FILE_GENERIC_READ);
2111 #elif ! defined (__vxworks) && ! defined(__nucleus__)
2112 struct stat statbuf;
2114 if (stat (name, &statbuf) == 0)
2116 chmod (name, statbuf.st_mode | S_IREAD);
2122 __gnat_set_non_readable (char *name)
2124 #if defined (_WIN32) && !defined (RTX)
2125 TCHAR wname [GNAT_MAX_PATH_LEN + 2];
2127 S2WSC (wname, name, GNAT_MAX_PATH_LEN + 2);
2129 if (__gnat_can_use_acl (wname))
2130 __gnat_set_OWNER_ACL (wname, DENY_ACCESS, FILE_GENERIC_READ);
2132 #elif ! defined (__vxworks) && ! defined(__nucleus__)
2133 struct stat statbuf;
2135 if (stat (name, &statbuf) == 0)
2137 chmod (name, statbuf.st_mode & (~S_IREAD));
2143 __gnat_is_symbolic_link (char *name ATTRIBUTE_UNUSED)
2145 #if defined (__vxworks) || defined (__nucleus__)
2148 #elif defined (_AIX) || defined (__APPLE__) || defined (__unix__)
2150 struct stat statbuf;
2152 ret = lstat (name, &statbuf);
2153 return (!ret && S_ISLNK (statbuf.st_mode));
2160 #if defined (sun) && defined (__SVR4)
2161 /* Using fork on Solaris will duplicate all the threads. fork1, which
2162 duplicates only the active thread, must be used instead, or spawning
2163 subprocess from a program with tasking will lead into numerous problems. */
2168 __gnat_portable_spawn (char *args[])
2171 int finished ATTRIBUTE_UNUSED;
2172 int pid ATTRIBUTE_UNUSED;
2174 #if defined (__vxworks) || defined(__nucleus__) || defined(RTX)
2177 #elif defined (MSDOS) || defined (_WIN32)
2178 /* args[0] must be quotes as it could contain a full pathname with spaces */
2179 char *args_0 = args[0];
2180 args[0] = (char *)xmalloc (strlen (args_0) + 3);
2181 strcpy (args[0], "\"");
2182 strcat (args[0], args_0);
2183 strcat (args[0], "\"");
2185 status = spawnvp (P_WAIT, args_0, (const char* const*)args);
2187 /* restore previous value */
2189 args[0] = (char *)args_0;
2199 pid = spawnvp (P_NOWAIT, args[0], args);
2211 if (execv (args[0], MAYBE_TO_PTR32 (args)) != 0)
2213 return -1; /* execv is in parent context on VMS. */
2221 finished = waitpid (pid, &status, 0);
2223 if (finished != pid || WIFEXITED (status) == 0)
2226 return WEXITSTATUS (status);
2232 /* Create a copy of the given file descriptor.
2233 Return -1 if an error occurred. */
2236 __gnat_dup (int oldfd)
2238 #if defined (__vxworks) && !defined (__RTP__)
2239 /* Not supported on VxWorks 5.x, but supported on VxWorks 6.0 when using
2247 /* Make newfd be the copy of oldfd, closing newfd first if necessary.
2248 Return -1 if an error occurred. */
2251 __gnat_dup2 (int oldfd, int newfd)
2253 #if defined (__vxworks) && !defined (__RTP__)
2254 /* Not supported on VxWorks 5.x, but supported on VxWorks 6.0 when using
2258 return dup2 (oldfd, newfd);
2262 /* WIN32 code to implement a wait call that wait for any child process. */
2264 #if defined (_WIN32) && !defined (RTX)
2266 /* Synchronization code, to be thread safe. */
2270 /* For the Cert run times on native Windows we use dummy functions
2271 for locking and unlocking tasks since we do not support multiple
2272 threads on this configuration (Cert run time on native Windows). */
2274 void dummy (void) {}
2276 void (*Lock_Task) () = &dummy;
2277 void (*Unlock_Task) () = &dummy;
2281 #define Lock_Task system__soft_links__lock_task
2282 extern void (*Lock_Task) (void);
2284 #define Unlock_Task system__soft_links__unlock_task
2285 extern void (*Unlock_Task) (void);
2289 typedef struct _process_list
2292 struct _process_list *next;
2295 static Process_List *PLIST = NULL;
2297 static int plist_length = 0;
2300 add_handle (HANDLE h)
2304 pl = (Process_List *) xmalloc (sizeof (Process_List));
2306 /* -------------------- critical section -------------------- */
2315 /* -------------------- critical section -------------------- */
2319 remove_handle (HANDLE h)
2322 Process_List *prev = NULL;
2324 /* -------------------- critical section -------------------- */
2335 prev->next = pl->next;
2349 /* -------------------- critical section -------------------- */
2353 win32_no_block_spawn (char *command, char *args[])
2357 PROCESS_INFORMATION PI;
2358 SECURITY_ATTRIBUTES SA;
2363 /* compute the total command line length */
2367 csize += strlen (args[k]) + 1;
2371 full_command = (char *) xmalloc (csize);
2374 SI.cb = sizeof (STARTUPINFO);
2375 SI.lpReserved = NULL;
2376 SI.lpReserved2 = NULL;
2377 SI.lpDesktop = NULL;
2381 SI.wShowWindow = SW_HIDE;
2383 /* Security attributes. */
2384 SA.nLength = sizeof (SECURITY_ATTRIBUTES);
2385 SA.bInheritHandle = TRUE;
2386 SA.lpSecurityDescriptor = NULL;
2388 /* Prepare the command string. */
2389 strcpy (full_command, command);
2390 strcat (full_command, " ");
2395 strcat (full_command, args[k]);
2396 strcat (full_command, " ");
2401 int wsize = csize * 2;
2402 TCHAR *wcommand = (TCHAR *) xmalloc (wsize);
2404 S2WSC (wcommand, full_command, wsize);
2406 free (full_command);
2408 result = CreateProcess
2409 (NULL, wcommand, &SA, NULL, TRUE,
2410 GetPriorityClass (GetCurrentProcess()), NULL, NULL, &SI, &PI);
2417 add_handle (PI.hProcess);
2418 CloseHandle (PI.hThread);
2419 return (int) PI.hProcess;
2426 win32_wait (int *status)
2436 if (plist_length == 0)
2444 /* -------------------- critical section -------------------- */
2447 hl_len = plist_length;
2449 hl = (HANDLE *) xmalloc (sizeof (HANDLE) * hl_len);
2459 /* -------------------- critical section -------------------- */
2461 res = WaitForMultipleObjects (hl_len, hl, FALSE, INFINITE);
2462 h = hl[res - WAIT_OBJECT_0];
2467 GetExitCodeProcess (h, &exitcode);
2470 *status = (int) exitcode;
2477 __gnat_portable_no_block_spawn (char *args[])
2481 #if defined (__vxworks) || defined (__nucleus__) || defined (RTX)
2484 #elif defined (__EMX__) || defined (MSDOS)
2486 /* ??? For PC machines I (Franco) don't know the system calls to implement
2487 this routine. So I'll fake it as follows. This routine will behave
2488 exactly like the blocking portable_spawn and will systematically return
2489 a pid of 0 unless the spawned task did not complete successfully, in
2490 which case we return a pid of -1. To synchronize with this the
2491 portable_wait below systematically returns a pid of 0 and reports that
2492 the subprocess terminated successfully. */
2494 if (spawnvp (P_WAIT, args[0], args) != 0)
2497 #elif defined (_WIN32)
2499 pid = win32_no_block_spawn (args[0], args);
2508 if (execv (args[0], MAYBE_TO_PTR32 (args)) != 0)
2510 return -1; /* execv is in parent context on VMS. */
2522 __gnat_portable_wait (int *process_status)
2527 #if defined (__vxworks) || defined (__nucleus__) || defined (RTX)
2528 /* Not sure what to do here, so do same as __EMX__ case, i.e., nothing but
2531 #elif defined (_WIN32)
2533 pid = win32_wait (&status);
2535 #elif defined (__EMX__) || defined (MSDOS)
2536 /* ??? See corresponding comment in portable_no_block_spawn. */
2540 pid = waitpid (-1, &status, 0);
2541 status = status & 0xffff;
2544 *process_status = status;
2549 __gnat_os_exit (int status)
2554 /* Locate a regular file, give a Path value. */
2557 __gnat_locate_regular_file (char *file_name, char *path_val)
2560 char *file_path = (char *) alloca (strlen (file_name) + 1);
2563 /* Return immediately if file_name is empty */
2565 if (*file_name == '\0')
2568 /* Remove quotes around file_name if present */
2574 strcpy (file_path, ptr);
2576 ptr = file_path + strlen (file_path) - 1;
2581 /* Handle absolute pathnames. */
2583 absolute = __gnat_is_absolute_path (file_path, strlen (file_name));
2587 if (__gnat_is_regular_file (file_path))
2588 return xstrdup (file_path);
2593 /* If file_name include directory separator(s), try it first as
2594 a path name relative to the current directory */
2595 for (ptr = file_name; *ptr && *ptr != '/' && *ptr != DIR_SEPARATOR; ptr++)
2600 if (__gnat_is_regular_file (file_name))
2601 return xstrdup (file_name);
2608 /* The result has to be smaller than path_val + file_name. */
2609 char *file_path = (char *) alloca (strlen (path_val) + strlen (file_name) + 2);
2613 for (; *path_val == PATH_SEPARATOR; path_val++)
2619 /* Skip the starting quote */
2621 if (*path_val == '"')
2624 for (ptr = file_path; *path_val && *path_val != PATH_SEPARATOR; )
2625 *ptr++ = *path_val++;
2629 /* Skip the ending quote */
2634 if (*ptr != '/' && *ptr != DIR_SEPARATOR)
2635 *++ptr = DIR_SEPARATOR;
2637 strcpy (++ptr, file_name);
2639 if (__gnat_is_regular_file (file_path))
2640 return xstrdup (file_path);
2647 /* Locate an executable given a Path argument. This routine is only used by
2648 gnatbl and should not be used otherwise. Use locate_exec_on_path
2652 __gnat_locate_exec (char *exec_name, char *path_val)
2655 if (!strstr (exec_name, HOST_EXECUTABLE_SUFFIX))
2657 char *full_exec_name
2658 = (char *) alloca (strlen (exec_name) + strlen (HOST_EXECUTABLE_SUFFIX) + 1);
2660 strcpy (full_exec_name, exec_name);
2661 strcat (full_exec_name, HOST_EXECUTABLE_SUFFIX);
2662 ptr = __gnat_locate_regular_file (full_exec_name, path_val);
2665 return __gnat_locate_regular_file (exec_name, path_val);
2669 return __gnat_locate_regular_file (exec_name, path_val);
2672 /* Locate an executable using the Systems default PATH. */
2675 __gnat_locate_exec_on_path (char *exec_name)
2679 #if defined (_WIN32) && !defined (RTX)
2680 TCHAR *wpath_val = _tgetenv (_T("PATH"));
2682 /* In Win32 systems we expand the PATH as for XP environment
2683 variables are not automatically expanded. We also prepend the
2684 ".;" to the path to match normal NT path search semantics */
2686 #define EXPAND_BUFFER_SIZE 32767
2688 wapath_val = alloca (EXPAND_BUFFER_SIZE);
2690 wapath_val [0] = '.';
2691 wapath_val [1] = ';';
2693 DWORD res = ExpandEnvironmentStrings
2694 (wpath_val, &wapath_val[2], EXPAND_BUFFER_SIZE - 2);
2696 if (!res) wapath_val [0] = _T('\0');
2698 apath_val = alloca (EXPAND_BUFFER_SIZE);
2700 WS2SC (apath_val, wapath_val, EXPAND_BUFFER_SIZE);
2701 return __gnat_locate_exec (exec_name, apath_val);
2706 char *path_val = "/VAXC$PATH";
2708 char *path_val = getenv ("PATH");
2710 if (path_val == NULL) return NULL;
2711 apath_val = (char *) alloca (strlen (path_val) + 1);
2712 strcpy (apath_val, path_val);
2713 return __gnat_locate_exec (exec_name, apath_val);
2719 /* These functions are used to translate to and from VMS and Unix syntax
2720 file, directory and path specifications. */
2723 #define MAXNAMES 256
2724 #define NEW_CANONICAL_FILELIST_INCREMENT 64
2726 static char new_canonical_dirspec [MAXPATH];
2727 static char new_canonical_filespec [MAXPATH];
2728 static char new_canonical_pathspec [MAXNAMES*MAXPATH];
2729 static unsigned new_canonical_filelist_index;
2730 static unsigned new_canonical_filelist_in_use;
2731 static unsigned new_canonical_filelist_allocated;
2732 static char **new_canonical_filelist;
2733 static char new_host_pathspec [MAXNAMES*MAXPATH];
2734 static char new_host_dirspec [MAXPATH];
2735 static char new_host_filespec [MAXPATH];
2737 /* Routine is called repeatedly by decc$from_vms via
2738 __gnat_to_canonical_file_list_init until it returns 0 or the expansion
2742 wildcard_translate_unix (char *name)
2745 char buff [MAXPATH];
2747 strncpy (buff, name, MAXPATH);
2748 buff [MAXPATH - 1] = (char) 0;
2749 ver = strrchr (buff, '.');
2751 /* Chop off the version. */
2755 /* Dynamically extend the allocation by the increment. */
2756 if (new_canonical_filelist_in_use == new_canonical_filelist_allocated)
2758 new_canonical_filelist_allocated += NEW_CANONICAL_FILELIST_INCREMENT;
2759 new_canonical_filelist = (char **) xrealloc
2760 (new_canonical_filelist,
2761 new_canonical_filelist_allocated * sizeof (char *));
2764 new_canonical_filelist[new_canonical_filelist_in_use++] = xstrdup (buff);
2769 /* Translate a wildcard VMS file spec into a list of Unix file specs. First do
2770 full translation and copy the results into a list (_init), then return them
2771 one at a time (_next). If onlydirs set, only expand directory files. */
2774 __gnat_to_canonical_file_list_init (char *filespec, int onlydirs)
2777 char buff [MAXPATH];
2779 len = strlen (filespec);
2780 strncpy (buff, filespec, MAXPATH);
2782 /* Only look for directories */
2783 if (onlydirs && !strstr (&buff [len-5], "*.dir"))
2784 strncat (buff, "*.dir", MAXPATH);
2786 buff [MAXPATH - 1] = (char) 0;
2788 decc$from_vms (buff, wildcard_translate_unix, 1);
2790 /* Remove the .dir extension. */
2796 for (i = 0; i < new_canonical_filelist_in_use; i++)
2798 ext = strstr (new_canonical_filelist[i], ".dir");
2804 return new_canonical_filelist_in_use;
2807 /* Return the next filespec in the list. */
2810 __gnat_to_canonical_file_list_next ()
2812 return new_canonical_filelist[new_canonical_filelist_index++];
2815 /* Free storage used in the wildcard expansion. */
2818 __gnat_to_canonical_file_list_free ()
2822 for (i = 0; i < new_canonical_filelist_in_use; i++)
2823 free (new_canonical_filelist[i]);
2825 free (new_canonical_filelist);
2827 new_canonical_filelist_in_use = 0;
2828 new_canonical_filelist_allocated = 0;
2829 new_canonical_filelist_index = 0;
2830 new_canonical_filelist = 0;
2833 /* The functional equivalent of decc$translate_vms routine.
2834 Designed to produce the same output, but is protected against
2835 malformed paths (original version ACCVIOs in this case) and
2836 does not require VMS-specific DECC RTL */
2838 #define NAM$C_MAXRSS 1024
2841 __gnat_translate_vms (char *src)
2843 static char retbuf [NAM$C_MAXRSS+1];
2844 char *srcendpos, *pos1, *pos2, *retpos;
2845 int disp, path_present = 0;
2847 if (!src) return NULL;
2849 srcendpos = strchr (src, '\0');
2852 /* Look for the node and/or device in front of the path */
2854 pos2 = strchr (pos1, ':');
2856 if (pos2 && (pos2 < srcendpos) && (*(pos2 + 1) == ':')) {
2857 /* There is a node name. "node_name::" becomes "node_name!" */
2859 strncpy (retbuf, pos1, disp);
2860 retpos [disp] = '!';
2861 retpos = retpos + disp + 1;
2863 pos2 = strchr (pos1, ':');
2867 /* There is a device name. "dev_name:" becomes "/dev_name/" */
2870 strncpy (retpos, pos1, disp);
2871 retpos = retpos + disp;
2876 /* No explicit device; we must look ahead and prepend /sys$disk/ if
2877 the path is absolute */
2878 if ((*pos1 == '[' || *pos1 == '<') && (pos1 < srcendpos)
2879 && !strchr (".-]>", *(pos1 + 1))) {
2880 strncpy (retpos, "/sys$disk/", 10);
2884 /* Process the path part */
2885 while (*pos1 == '[' || *pos1 == '<') {
2888 if (*pos1 == ']' || *pos1 == '>') {
2889 /* Special case, [] translates to '.' */
2894 /* '[000000' means root dir. It can be present in the middle of
2895 the path due to expansion of logical devices, in which case
2897 if (!strncmp (pos1, "000000", 6) && path_present > 1 &&
2898 (*(pos1 + 6) == ']' || *(pos1 + 6) == '>' || *(pos1 + 6) == '.')) {
2900 if (*pos1 == '.') pos1++;
2902 else if (*pos1 == '.') {
2907 /* There is a qualified path */
2908 while (*pos1 && *pos1 != ']' && *pos1 != '>') {
2911 /* '.' is used to separate directories. Replace it with '/' but
2912 only if there isn't already '/' just before */
2913 if (*(retpos - 1) != '/') *(retpos++) = '/';
2915 if (pos1 + 1 < srcendpos && *pos1 == '.' && *(pos1 + 1) == '.') {
2916 /* ellipsis refers to entire subtree; replace with '**' */
2917 *(retpos++) = '*'; *(retpos++) = '*'; *(retpos++) = '/';
2922 /* When after '.' '[' '<' is equivalent to Unix ".." but there
2923 may be several in a row */
2924 if (*(pos1 - 1) == '.' || *(pos1 - 1) == '[' ||
2925 *(pos1 - 1) == '<') {
2926 while (*pos1 == '-') {
2928 *(retpos++) = '.'; *(retpos++) = '.'; *(retpos++) = '/';
2933 /* otherwise fall through to default */
2935 *(retpos++) = *(pos1++);
2942 if (pos1 < srcendpos) {
2943 /* Now add the actual file name, until the version suffix if any */
2944 if (path_present) *(retpos++) = '/';
2945 pos2 = strchr (pos1, ';');
2946 disp = pos2? (pos2 - pos1) : (srcendpos - pos1);
2947 strncpy (retpos, pos1, disp);
2949 if (pos2 && pos2 < srcendpos) {
2950 /* There is a non-empty version suffix. ";<ver>" becomes ".<ver>" */
2952 disp = srcendpos - pos2 - 1;
2953 strncpy (retpos, pos2 + 1, disp);
2964 /* Translate a VMS syntax directory specification in to Unix syntax. If
2965 PREFIXFLAG is set, append an underscore "/". If no indicators of VMS syntax
2966 found, return input string. Also translate a dirname that contains no
2967 slashes, in case it's a logical name. */
2970 __gnat_to_canonical_dir_spec (char *dirspec, int prefixflag)
2974 strcpy (new_canonical_dirspec, "");
2975 if (strlen (dirspec))
2979 if (strchr (dirspec, ']') || strchr (dirspec, ':'))
2981 strncpy (new_canonical_dirspec,
2982 __gnat_translate_vms (dirspec),
2985 else if (!strchr (dirspec, '/') && (dirspec1 = getenv (dirspec)) != 0)
2987 strncpy (new_canonical_dirspec,
2988 __gnat_translate_vms (dirspec1),
2993 strncpy (new_canonical_dirspec, dirspec, MAXPATH);
2997 len = strlen (new_canonical_dirspec);
2998 if (prefixflag && new_canonical_dirspec [len-1] != '/')
2999 strncat (new_canonical_dirspec, "/", MAXPATH);
3001 new_canonical_dirspec [MAXPATH - 1] = (char) 0;
3003 return new_canonical_dirspec;
3007 /* Translate a VMS syntax file specification into Unix syntax.
3008 If no indicators of VMS syntax found, check if it's an uppercase
3009 alphanumeric_ name and if so try it out as an environment
3010 variable (logical name). If all else fails return the
3014 __gnat_to_canonical_file_spec (char *filespec)
3018 strncpy (new_canonical_filespec, "", MAXPATH);
3020 if (strchr (filespec, ']') || strchr (filespec, ':'))
3022 char *tspec = (char *) __gnat_translate_vms (filespec);
3024 if (tspec != (char *) -1)
3025 strncpy (new_canonical_filespec, tspec, MAXPATH);
3027 else if ((strlen (filespec) == strspn (filespec,
3028 "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_"))
3029 && (filespec1 = getenv (filespec)))
3031 char *tspec = (char *) __gnat_translate_vms (filespec1);
3033 if (tspec != (char *) -1)
3034 strncpy (new_canonical_filespec, tspec, MAXPATH);
3038 strncpy (new_canonical_filespec, filespec, MAXPATH);
3041 new_canonical_filespec [MAXPATH - 1] = (char) 0;
3043 return new_canonical_filespec;
3046 /* Translate a VMS syntax path specification into Unix syntax.
3047 If no indicators of VMS syntax found, return input string. */
3050 __gnat_to_canonical_path_spec (char *pathspec)
3052 char *curr, *next, buff [MAXPATH];
3057 /* If there are /'s, assume it's a Unix path spec and return. */
3058 if (strchr (pathspec, '/'))
3061 new_canonical_pathspec[0] = 0;
3066 next = strchr (curr, ',');
3068 next = strchr (curr, 0);
3070 strncpy (buff, curr, next - curr);
3071 buff[next - curr] = 0;
3073 /* Check for wildcards and expand if present. */
3074 if (strchr (buff, '*') || strchr (buff, '%') || strstr (buff, "..."))
3078 dirs = __gnat_to_canonical_file_list_init (buff, 1);
3079 for (i = 0; i < dirs; i++)
3083 next_dir = __gnat_to_canonical_file_list_next ();
3084 strncat (new_canonical_pathspec, next_dir, MAXPATH);
3086 /* Don't append the separator after the last expansion. */
3088 strncat (new_canonical_pathspec, ":", MAXPATH);
3091 __gnat_to_canonical_file_list_free ();
3094 strncat (new_canonical_pathspec,
3095 __gnat_to_canonical_dir_spec (buff, 0), MAXPATH);
3100 strncat (new_canonical_pathspec, ":", MAXPATH);
3104 new_canonical_pathspec [MAXPATH - 1] = (char) 0;
3106 return new_canonical_pathspec;
3109 static char filename_buff [MAXPATH];
3112 translate_unix (char *name, int type)
3114 strncpy (filename_buff, name, MAXPATH);
3115 filename_buff [MAXPATH - 1] = (char) 0;
3119 /* Translate a Unix syntax path spec into a VMS style (comma separated list of
3123 to_host_path_spec (char *pathspec)
3125 char *curr, *next, buff [MAXPATH];
3130 /* Can't very well test for colons, since that's the Unix separator! */
3131 if (strchr (pathspec, ']') || strchr (pathspec, ','))
3134 new_host_pathspec[0] = 0;
3139 next = strchr (curr, ':');
3141 next = strchr (curr, 0);
3143 strncpy (buff, curr, next - curr);
3144 buff[next - curr] = 0;
3146 strncat (new_host_pathspec, __gnat_to_host_dir_spec (buff, 0), MAXPATH);
3149 strncat (new_host_pathspec, ",", MAXPATH);
3153 new_host_pathspec [MAXPATH - 1] = (char) 0;
3155 return new_host_pathspec;
3158 /* Translate a Unix syntax directory specification into VMS syntax. The
3159 PREFIXFLAG has no effect, but is kept for symmetry with
3160 to_canonical_dir_spec. If indicators of VMS syntax found, return input
3164 __gnat_to_host_dir_spec (char *dirspec, int prefixflag ATTRIBUTE_UNUSED)
3166 int len = strlen (dirspec);
3168 strncpy (new_host_dirspec, dirspec, MAXPATH);
3169 new_host_dirspec [MAXPATH - 1] = (char) 0;
3171 if (strchr (new_host_dirspec, ']') || strchr (new_host_dirspec, ':'))
3172 return new_host_dirspec;
3174 while (len > 1 && new_host_dirspec[len - 1] == '/')
3176 new_host_dirspec[len - 1] = 0;
3180 decc$to_vms (new_host_dirspec, translate_unix, 1, 2);
3181 strncpy (new_host_dirspec, filename_buff, MAXPATH);
3182 new_host_dirspec [MAXPATH - 1] = (char) 0;
3184 return new_host_dirspec;
3187 /* Translate a Unix syntax file specification into VMS syntax.
3188 If indicators of VMS syntax found, return input string. */
3191 __gnat_to_host_file_spec (char *filespec)
3193 strncpy (new_host_filespec, "", MAXPATH);
3194 if (strchr (filespec, ']') || strchr (filespec, ':'))
3196 strncpy (new_host_filespec, filespec, MAXPATH);
3200 decc$to_vms (filespec, translate_unix, 1, 1);
3201 strncpy (new_host_filespec, filename_buff, MAXPATH);
3204 new_host_filespec [MAXPATH - 1] = (char) 0;
3206 return new_host_filespec;
3210 __gnat_adjust_os_resource_limits ()
3212 SYS$ADJWSL (131072, 0);
3217 /* Dummy functions for Osint import for non-VMS systems. */
3220 __gnat_to_canonical_file_list_init
3221 (char *dirspec ATTRIBUTE_UNUSED, int onlydirs ATTRIBUTE_UNUSED)
3227 __gnat_to_canonical_file_list_next (void)
3233 __gnat_to_canonical_file_list_free (void)
3238 __gnat_to_canonical_dir_spec (char *dirspec, int prefixflag ATTRIBUTE_UNUSED)
3244 __gnat_to_canonical_file_spec (char *filespec)
3250 __gnat_to_canonical_path_spec (char *pathspec)
3256 __gnat_to_host_dir_spec (char *dirspec, int prefixflag ATTRIBUTE_UNUSED)
3262 __gnat_to_host_file_spec (char *filespec)
3268 __gnat_adjust_os_resource_limits (void)
3274 /* For EMX, we cannot include dummy in libgcc, since it is too difficult
3275 to coordinate this with the EMX distribution. Consequently, we put the
3276 definition of dummy which is used for exception handling, here. */
3278 #if defined (__EMX__)
3282 #if defined (__mips_vxworks)
3286 CACHE_USER_FLUSH (0, ENTIRE_CACHE);
3290 #if defined (IS_CROSS) \
3291 || (! ((defined (sparc) || defined (i386)) && defined (sun) \
3292 && defined (__SVR4)) \
3293 && ! (defined (linux) && (defined (i386) || defined (__x86_64__))) \
3294 && ! (defined (linux) && defined (__ia64__)) \
3295 && ! (defined (linux) && defined (powerpc)) \
3296 && ! defined (__FreeBSD__) \
3297 && ! defined (__hpux__) \
3298 && ! defined (__APPLE__) \
3299 && ! defined (_AIX) \
3300 && ! (defined (__alpha__) && defined (__osf__)) \
3301 && ! defined (VMS) \
3302 && ! defined (__MINGW32__) \
3303 && ! (defined (__mips) && defined (__sgi)))
3305 /* Dummy function to satisfy g-trasym.o. See the preprocessor conditional
3306 just above for a list of native platforms that provide a non-dummy
3307 version of this procedure in libaddr2line.a. */
3310 convert_addresses (const char *file_name ATTRIBUTE_UNUSED,
3311 void *addrs ATTRIBUTE_UNUSED,
3312 int n_addr ATTRIBUTE_UNUSED,
3313 void *buf ATTRIBUTE_UNUSED,
3314 int *len ATTRIBUTE_UNUSED)
3320 #if defined (_WIN32)
3321 int __gnat_argument_needs_quote = 1;
3323 int __gnat_argument_needs_quote = 0;
3326 /* This option is used to enable/disable object files handling from the
3327 binder file by the GNAT Project module. For example, this is disabled on
3328 Windows (prior to GCC 3.4) as it is already done by the mdll module.
3329 Stating with GCC 3.4 the shared libraries are not based on mdll
3330 anymore as it uses the GCC's -shared option */
3331 #if defined (_WIN32) \
3332 && ((__GNUC__ < 3) || ((__GNUC__ == 3) && (__GNUC_MINOR__ < 4)))
3333 int __gnat_prj_add_obj_files = 0;
3335 int __gnat_prj_add_obj_files = 1;
3338 /* char used as prefix/suffix for environment variables */
3339 #if defined (_WIN32)
3340 char __gnat_environment_char = '%';
3342 char __gnat_environment_char = '$';
3345 /* This functions copy the file attributes from a source file to a
3348 mode = 0 : In this mode copy only the file time stamps (last access and
3349 last modification time stamps).
3351 mode = 1 : In this mode, time stamps and read/write/execute attributes are
3354 Returns 0 if operation was successful and -1 in case of error. */
3357 __gnat_copy_attribs (char *from, char *to, int mode)
3359 #if defined (VMS) || defined (__vxworks) || defined (__nucleus__)
3363 struct utimbuf tbuf;
3365 if (stat (from, &fbuf) == -1)
3370 tbuf.actime = fbuf.st_atime;
3371 tbuf.modtime = fbuf.st_mtime;
3373 if (utime (to, &tbuf) == -1)
3380 if (chmod (to, fbuf.st_mode) == -1)
3391 __gnat_lseek (int fd, long offset, int whence)
3393 return (int) lseek (fd, offset, whence);
3396 /* This function returns the major version number of GCC being used. */
3398 get_gcc_version (void)
3403 return (int) (version_string[0] - '0');
3408 __gnat_set_close_on_exec (int fd ATTRIBUTE_UNUSED,
3409 int close_on_exec_p ATTRIBUTE_UNUSED)
3411 #if defined (F_GETFD) && defined (FD_CLOEXEC) && ! defined (__vxworks)
3412 int flags = fcntl (fd, F_GETFD, 0);
3415 if (close_on_exec_p)
3416 flags |= FD_CLOEXEC;
3418 flags &= ~FD_CLOEXEC;
3419 return fcntl (fd, F_SETFD, flags | FD_CLOEXEC);
3420 #elif defined(_WIN32)
3421 HANDLE h = (HANDLE) _get_osfhandle (fd);
3422 if (h == (HANDLE) -1)
3424 if (close_on_exec_p)
3425 return ! SetHandleInformation (h, HANDLE_FLAG_INHERIT, 0);
3426 return ! SetHandleInformation (h, HANDLE_FLAG_INHERIT,
3427 HANDLE_FLAG_INHERIT);
3429 /* TODO: Unimplemented. */
3434 /* Indicates if platforms supports automatic initialization through the
3435 constructor mechanism */
3437 __gnat_binder_supports_auto_init ()
3446 /* Indicates that Stand-Alone Libraries are automatically initialized through
3447 the constructor mechanism */
3449 __gnat_sals_init_using_constructors ()
3451 #if defined (__vxworks) || defined (__Lynx__) || defined (VMS)
3460 /* In RTX mode, the procedure to get the time (as file time) is different
3461 in RTSS mode and Win32 mode. In order to avoid duplicating an Ada file,
3462 we introduce an intermediate procedure to link against the corresponding
3463 one in each situation. */
3465 extern void GetTimeAsFileTime(LPFILETIME pTime);
3467 void GetTimeAsFileTime(LPFILETIME pTime)
3470 RtGetRtssTimeAsFileTime (pTime); /* RTSS interface */
3472 GetSystemTimeAsFileTime (pTime); /* w32 interface */
3477 /* Add symbol that is required to link. It would otherwise be taken from
3478 libgcc.a and it would try to use the gcc constructors that are not
3479 supported by Microsoft linker. */
3481 extern void __main (void);
3483 void __main (void) {}
3487 #if defined (linux) || defined(__GLIBC__)
3488 /* pthread affinity support */
3490 int __gnat_pthread_setaffinity_np (pthread_t th,
3492 const void *cpuset);
3495 #include <pthread.h>
3497 __gnat_pthread_setaffinity_np (pthread_t th,
3499 const cpu_set_t *cpuset)
3501 return pthread_setaffinity_np (th, cpusetsize, cpuset);
3505 __gnat_pthread_setaffinity_np (pthread_t th ATTRIBUTE_UNUSED,
3506 size_t cpusetsize ATTRIBUTE_UNUSED,
3507 const void *cpuset ATTRIBUTE_UNUSED)
3515 /* There is no function in the glibc to retrieve the LWP of the current
3516 thread. We need to do a system call in order to retrieve this
3518 #include <sys/syscall.h>
3519 void *__gnat_lwp_self (void)
3521 return (void *) syscall (__NR_gettid);