1 /****************************************************************************
3 * GNAT COMPILER COMPONENTS *
7 * C Implementation File *
9 * Copyright (C) 1992-2008, 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 2, or (at your option) any later ver- *
14 * sion. GNAT is distributed in the hope that it will be useful, but WITH- *
15 * OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY *
16 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License *
17 * for more details. You should have received a copy of the GNU General *
18 * Public License distributed with GNAT; see file COPYING. If not, write *
19 * to the Free Software Foundation, 51 Franklin Street, Fifth Floor, *
20 * Boston, MA 02110-1301, USA. *
22 * As a special exception, if you link this file with other files to *
23 * produce an executable, this file does not by itself cause the resulting *
24 * executable to be covered by the GNU General Public License. This except- *
25 * ion does not however invalidate any other reasons why the executable *
26 * file might be covered by the GNU Public License. *
28 * GNAT was originally developed by the GNAT team at New York University. *
29 * Extensive contributions were provided by Ada Core Technologies Inc. *
31 ****************************************************************************/
33 /* This file contains those routines named by Import pragmas in
34 packages in the GNAT hierarchy (especially GNAT.OS_Lib) and in
35 package Osint. Many of the subprograms in OS_Lib import standard
36 library calls directly. This file contains all other routines. */
40 /* No need to redefine exit here. */
43 /* We want to use the POSIX variants of include files. */
47 #if defined (__mips_vxworks)
49 #endif /* __mips_vxworks */
55 #define HOST_EXECUTABLE_SUFFIX ".exe"
56 #define HOST_OBJECT_SUFFIX ".obj"
70 /* We don't have libiberty, so use malloc. */
71 #define xmalloc(S) malloc (S)
72 #define xrealloc(V,S) realloc (V,S)
82 #include <sys/utime.h>
84 #elif defined (__MINGW32__)
87 #include <sys/utime.h>
89 /* For isalpha-like tests in the compiler, we're expected to resort to
90 safe-ctype.h/ISALPHA. This isn't available for the runtime library
91 build, so we fallback on ctype.h/isalpha there. */
95 #define ISALPHA isalpha
98 #elif defined (__Lynx__)
100 /* Lynx utime.h only defines the entities of interest to us if
101 defined (VMOS_DEV), so ... */
110 /* wait.h processing */
113 #include <sys/wait.h>
115 #elif defined (__vxworks) && defined (__RTP__)
117 #elif defined (__Lynx__)
118 /* ??? We really need wait.h and it includes resource.h on Lynx. GCC
119 has a resource.h header as well, included instead of the lynx
120 version in our setup, causing lots of errors. We don't really need
121 the lynx contents of this file, so just workaround the issue by
122 preventing the inclusion of the GCC header from doing anything. */
123 #define GCC_RESOURCE_H
124 #include <sys/wait.h>
125 #elif defined (__nucleus__)
126 /* No wait() or waitpid() calls available */
129 #include <sys/wait.h>
132 #if defined (__EMX__) || defined (MSDOS) || defined (_WIN32)
135 /* Header files and definitions for __gnat_set_file_time_name. */
137 #define __NEW_STARLET 1
139 #include <vms/atrdef.h>
140 #include <vms/fibdef.h>
141 #include <vms/stsdef.h>
142 #include <vms/iodef.h>
144 #include <vms/descrip.h>
148 /* Use native 64-bit arithmetic. */
149 #define unix_time_to_vms(X,Y) \
150 { unsigned long long reftime, tmptime = (X); \
151 $DESCRIPTOR (unixtime,"1-JAN-1970 0:00:00.00"); \
152 SYS$BINTIM (&unixtime, &reftime); \
153 Y = tmptime * 10000000 + reftime; }
155 /* descrip.h doesn't have everything ... */
156 typedef struct fibdef* __fibdef_ptr32 __attribute__ (( mode (SI) ));
157 struct dsc$descriptor_fib
159 unsigned int fib$l_len;
160 __fibdef_ptr32 fib$l_addr;
163 /* I/O Status Block. */
166 unsigned short status, count;
170 static char *tryfile;
172 /* Variable length string. */
176 char string[NAM$C_MAXRSS+1];
183 #if defined (__EMX__) || defined (MSDOS) || defined (_WIN32)
193 #define DIR_SEPARATOR '\\'
198 /* Define symbols O_BINARY and O_TEXT as harmless zeroes if they are not
199 defined in the current system. On DOS-like systems these flags control
200 whether the file is opened/created in text-translation mode (CR/LF in
201 external file mapped to LF in internal file), but in Unix-like systems,
202 no text translation is required, so these flags have no effect. */
204 #if defined (__EMX__)
220 #ifndef HOST_EXECUTABLE_SUFFIX
221 #define HOST_EXECUTABLE_SUFFIX ""
224 #ifndef HOST_OBJECT_SUFFIX
225 #define HOST_OBJECT_SUFFIX ".o"
228 #ifndef PATH_SEPARATOR
229 #define PATH_SEPARATOR ':'
232 #ifndef DIR_SEPARATOR
233 #define DIR_SEPARATOR '/'
236 /* Check for cross-compilation */
237 #ifdef CROSS_DIRECTORY_STRUCTURE
238 int __gnat_is_cross_compiler = 1;
240 int __gnat_is_cross_compiler = 0;
243 char __gnat_dir_separator = DIR_SEPARATOR;
245 char __gnat_path_separator = PATH_SEPARATOR;
247 /* The GNAT_LIBRARY_TEMPLATE contains a list of expressions that define
248 the base filenames that libraries specified with -lsomelib options
249 may have. This is used by GNATMAKE to check whether an executable
250 is up-to-date or not. The syntax is
252 library_template ::= { pattern ; } pattern NUL
253 pattern ::= [ prefix ] * [ postfix ]
255 These should only specify names of static libraries as it makes
256 no sense to determine at link time if dynamic-link libraries are
257 up to date or not. Any libraries that are not found are supposed
260 * if they are needed but not present, the link
263 * otherwise they are libraries in the system paths and so
264 they are considered part of the system and not checked
267 ??? This should be part of a GNAT host-specific compiler
268 file instead of being included in all user applications
269 as well. This is only a temporary work-around for 3.11b. */
271 #ifndef GNAT_LIBRARY_TEMPLATE
272 #if defined (__EMX__)
273 #define GNAT_LIBRARY_TEMPLATE "*.a"
275 #define GNAT_LIBRARY_TEMPLATE "*.olb"
277 #define GNAT_LIBRARY_TEMPLATE "lib*.a"
281 const char *__gnat_library_template = GNAT_LIBRARY_TEMPLATE;
283 /* This variable is used in hostparm.ads to say whether the host is a VMS
286 const int __gnat_vmsp = 1;
288 const int __gnat_vmsp = 0;
292 #define GNAT_MAX_PATH_LEN MAX_PATH
295 #define GNAT_MAX_PATH_LEN 256 /* PATH_MAX */
297 #elif defined (__vxworks) || defined (__OPENNT) || defined(__nucleus__)
298 #define GNAT_MAX_PATH_LEN PATH_MAX
302 #if defined (__MINGW32__)
306 #include <sys/param.h>
310 #include <sys/param.h>
314 #define GNAT_MAX_PATH_LEN MAXPATHLEN
316 #define GNAT_MAX_PATH_LEN 256
321 /* The __gnat_max_path_len variable is used to export the maximum
322 length of a path name to Ada code. max_path_len is also provided
323 for compatibility with older GNAT versions, please do not use
326 int __gnat_max_path_len = GNAT_MAX_PATH_LEN;
327 int max_path_len = GNAT_MAX_PATH_LEN;
329 /* The following macro HAVE_READDIR_R should be defined if the
330 system provides the routine readdir_r. */
331 #undef HAVE_READDIR_R
333 #if defined(VMS) && defined (__LONG_POINTERS)
335 /* Return a 32 bit pointer to an array of 32 bit pointers
336 given a 64 bit pointer to an array of 64 bit pointers */
338 typedef __char_ptr32 *__char_ptr_char_ptr32 __attribute__ ((mode (SI)));
340 static __char_ptr_char_ptr32
341 to_ptr32 (char **ptr64)
344 __char_ptr_char_ptr32 short_argv;
346 for (argc=0; ptr64[argc]; argc++);
348 /* Reallocate argv with 32 bit pointers. */
349 short_argv = (__char_ptr_char_ptr32) decc$malloc
350 (sizeof (__char_ptr32) * (argc + 1));
352 for (argc=0; ptr64[argc]; argc++)
353 short_argv[argc] = (__char_ptr32) decc$strdup (ptr64[argc]);
355 short_argv[argc] = (__char_ptr32) 0;
359 #define MAYBE_TO_PTR32(argv) to_ptr32 (argv)
361 #define MAYBE_TO_PTR32(argv) argv
368 time_t res = time (NULL);
369 return (OS_Time) res;
372 /* Return the current local time as a string in the ISO 8601 format of
373 "YYYY-MM-DD HH:MM:SS.SS". The returned string is 22 + 1 (NULL) characters
377 __gnat_current_time_string
380 const char *format = "%Y-%m-%d %H:%M:%S";
381 /* Format string necessary to describe the ISO 8601 format */
383 const time_t t_val = time (NULL);
385 strftime (result, 22, format, localtime (&t_val));
386 /* Convert the local time into a string following the ISO format, copying
387 at most 22 characters into the result string. */
392 /* The sub-seconds are manually set to zero since type time_t lacks the
393 precision necessary for nanoseconds. */
407 time_t time = (time_t) *p_time;
410 /* On Windows systems, the time is sometimes rounded up to the nearest
411 even second, so if the number of seconds is odd, increment it. */
417 res = localtime (&time);
419 res = gmtime (&time);
424 *p_year = res->tm_year;
425 *p_month = res->tm_mon;
426 *p_day = res->tm_mday;
427 *p_hours = res->tm_hour;
428 *p_mins = res->tm_min;
429 *p_secs = res->tm_sec;
432 *p_year = *p_month = *p_day = *p_hours = *p_mins = *p_secs = 0;
435 /* Place the contents of the symbolic link named PATH in the buffer BUF,
436 which has size BUFSIZ. If PATH is a symbolic link, then return the number
437 of characters of its content in BUF. Otherwise, return -1.
438 For systems not supporting symbolic links, always return -1. */
441 __gnat_readlink (char *path ATTRIBUTE_UNUSED,
442 char *buf ATTRIBUTE_UNUSED,
443 size_t bufsiz ATTRIBUTE_UNUSED)
445 #if defined (MSDOS) || defined (_WIN32) || defined (__EMX__) \
446 || defined (VMS) || defined(__vxworks) || defined (__nucleus__)
449 return readlink (path, buf, bufsiz);
453 /* Creates a symbolic link named NEWPATH which contains the string OLDPATH.
454 If NEWPATH exists it will NOT be overwritten.
455 For systems not supporting symbolic links, always return -1. */
458 __gnat_symlink (char *oldpath ATTRIBUTE_UNUSED,
459 char *newpath ATTRIBUTE_UNUSED)
461 #if defined (MSDOS) || defined (_WIN32) || defined (__EMX__) \
462 || defined (VMS) || defined(__vxworks) || defined (__nucleus__)
465 return symlink (oldpath, newpath);
469 /* Try to lock a file, return 1 if success. */
471 #if defined (__vxworks) || defined (__nucleus__) || defined (MSDOS) \
474 /* Version that does not use link. */
477 __gnat_try_lock (char *dir, char *file)
481 TCHAR wfull_path[GNAT_MAX_PATH_LEN];
482 TCHAR wfile[GNAT_MAX_PATH_LEN];
483 TCHAR wdir[GNAT_MAX_PATH_LEN];
485 S2WSU (wdir, dir, GNAT_MAX_PATH_LEN);
486 S2WSU (wfile, file, GNAT_MAX_PATH_LEN);
488 _stprintf (wfull_path, _T("%s%c%s"), wdir, _T(DIR_SEPARATOR), wfile);
489 fd = _topen (wfull_path, O_CREAT | O_EXCL, 0600);
493 sprintf (full_path, "%s%c%s", dir, DIR_SEPARATOR, file);
494 fd = open (full_path, O_CREAT | O_EXCL, 0600);
504 #elif defined (__EMX__) || defined (VMS)
506 /* More cases that do not use link; identical code, to solve too long
510 __gnat_try_lock (char *dir, char *file)
515 sprintf (full_path, "%s%c%s", dir, DIR_SEPARATOR, file);
516 fd = open (full_path, O_CREAT | O_EXCL, 0600);
527 /* Version using link(), more secure over NFS. */
528 /* See TN 6913-016 for discussion ??? */
531 __gnat_try_lock (char *dir, char *file)
535 struct stat stat_result;
538 sprintf (full_path, "%s%c%s", dir, DIR_SEPARATOR, file);
539 sprintf (temp_file, "%s%cTMP-%ld-%ld",
540 dir, DIR_SEPARATOR, (long)getpid(), (long)getppid ());
542 /* Create the temporary file and write the process number. */
543 fd = open (temp_file, O_CREAT | O_WRONLY, 0600);
549 /* Link it with the new file. */
550 link (temp_file, full_path);
552 /* Count the references on the old one. If we have a count of two, then
553 the link did succeed. Remove the temporary file before returning. */
554 __gnat_stat (temp_file, &stat_result);
556 return stat_result.st_nlink == 2;
560 /* Return the maximum file name length. */
563 __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 #if defined (__EMX__) || defined (MSDOS) || defined (VMS) || defined (WINNT)
590 __gnat_get_default_identifier_character_set (void)
592 #if defined (__EMX__) || defined (MSDOS)
599 /* Return the current working directory. */
602 __gnat_get_current_dir (char *dir, int *length)
604 #if defined (__MINGW32__)
605 TCHAR wdir[GNAT_MAX_PATH_LEN];
607 _tgetcwd (wdir, *length);
609 WS2SU (dir, wdir, GNAT_MAX_PATH_LEN);
612 /* Force Unix style, which is what GNAT uses internally. */
613 getcwd (dir, *length, 0);
615 getcwd (dir, *length);
618 *length = strlen (dir);
620 if (dir [*length - 1] != DIR_SEPARATOR)
622 dir [*length] = DIR_SEPARATOR;
628 /* Return the suffix for object files. */
631 __gnat_get_object_suffix_ptr (int *len, const char **value)
633 *value = HOST_OBJECT_SUFFIX;
638 *len = strlen (*value);
643 /* Return the suffix for executable files. */
646 __gnat_get_executable_suffix_ptr (int *len, const char **value)
648 *value = HOST_EXECUTABLE_SUFFIX;
652 *len = strlen (*value);
657 /* Return the suffix for debuggable files. Usually this is the same as the
658 executable extension. */
661 __gnat_get_debuggable_suffix_ptr (int *len, const char **value)
664 *value = HOST_EXECUTABLE_SUFFIX;
666 /* On DOS, the extensionless COFF file is what gdb likes. */
673 *len = strlen (*value);
678 /* Returns the OS filename and corresponding encoding. */
681 __gnat_os_filename (char *filename, char *w_filename ATTRIBUTE_UNUSED,
682 char *os_name, int *o_length,
683 char *encoding ATTRIBUTE_UNUSED, int *e_length)
685 #if defined (_WIN32) && ! defined (__vxworks) && ! defined (CROSS_DIRECTORY_STRUCTURE)
686 WS2SU (os_name, (TCHAR *)w_filename, o_length);
687 *o_length = strlen (os_name);
688 strcpy (encoding, "encoding=utf8");
689 *e_length = strlen (encoding);
691 strcpy (os_name, filename);
692 *o_length = strlen (filename);
698 __gnat_fopen (char *path, char *mode, int encoding ATTRIBUTE_UNUSED)
700 #if defined (_WIN32) && ! defined (__vxworks) && ! defined (CROSS_DIRECTORY_STRUCTURE)
701 TCHAR wpath[GNAT_MAX_PATH_LEN];
704 S2WS (wmode, mode, 10);
706 if (encoding == Encoding_UTF8)
707 S2WSU (wpath, path, GNAT_MAX_PATH_LEN);
709 S2WS (wpath, path, GNAT_MAX_PATH_LEN);
711 return _tfopen (wpath, wmode);
713 return decc$fopen (path, mode);
715 return fopen (path, mode);
720 __gnat_freopen (char *path, char *mode, FILE *stream, int encoding ATTRIBUTE_UNUSED)
722 #if defined (_WIN32) && ! defined (__vxworks) && ! defined (CROSS_DIRECTORY_STRUCTURE)
723 TCHAR wpath[GNAT_MAX_PATH_LEN];
726 S2WS (wmode, mode, 10);
728 if (encoding == Encoding_UTF8)
729 S2WSU (wpath, path, GNAT_MAX_PATH_LEN);
731 S2WS (wpath, path, GNAT_MAX_PATH_LEN);
733 return _tfreopen (wpath, wmode, stream);
735 return decc$freopen (path, mode, stream);
737 return freopen (path, mode, stream);
742 __gnat_open_read (char *path, int fmode)
745 int o_fmode = O_BINARY;
751 /* Optional arguments mbc,deq,fop increase read performance. */
752 fd = open (path, O_RDONLY | o_fmode, 0444,
753 "mbc=16", "deq=64", "fop=tef");
754 #elif defined (__vxworks)
755 fd = open (path, O_RDONLY | o_fmode, 0444);
756 #elif defined (__MINGW32__)
758 TCHAR wpath[GNAT_MAX_PATH_LEN];
760 S2WSU (wpath, path, GNAT_MAX_PATH_LEN);
761 fd = _topen (wpath, O_RDONLY | o_fmode, 0444);
764 fd = open (path, O_RDONLY | o_fmode);
767 return fd < 0 ? -1 : fd;
770 #if defined (__EMX__) || defined (__MINGW32__)
771 #define PERM (S_IREAD | S_IWRITE)
773 /* Excerpt from DECC C RTL Reference Manual:
774 To create files with OpenVMS RMS default protections using the UNIX
775 system-call functions umask, mkdir, creat, and open, call mkdir, creat,
776 and open with a file-protection mode argument of 0777 in a program
777 that never specifically calls umask. These default protections include
778 correctly establishing protections based on ACLs, previous versions of
782 #define PERM (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH)
786 __gnat_open_rw (char *path, int fmode)
789 int o_fmode = O_BINARY;
795 fd = open (path, O_RDWR | o_fmode, PERM,
796 "mbc=16", "deq=64", "fop=tef");
797 #elif defined (__MINGW32__)
799 TCHAR wpath[GNAT_MAX_PATH_LEN];
801 S2WSU (wpath, path, GNAT_MAX_PATH_LEN);
802 fd = _topen (wpath, O_RDWR | o_fmode, PERM);
805 fd = open (path, O_RDWR | o_fmode, PERM);
808 return fd < 0 ? -1 : fd;
812 __gnat_open_create (char *path, int fmode)
815 int o_fmode = O_BINARY;
821 fd = open (path, O_WRONLY | O_CREAT | O_TRUNC | o_fmode, PERM,
822 "mbc=16", "deq=64", "fop=tef");
823 #elif defined (__MINGW32__)
825 TCHAR wpath[GNAT_MAX_PATH_LEN];
827 S2WSU (wpath, path, GNAT_MAX_PATH_LEN);
828 fd = _topen (wpath, O_WRONLY | O_CREAT | O_TRUNC | o_fmode, PERM);
831 fd = open (path, O_WRONLY | O_CREAT | O_TRUNC | o_fmode, PERM);
834 return fd < 0 ? -1 : fd;
838 __gnat_create_output_file (char *path)
842 fd = open (path, O_WRONLY | O_CREAT | O_TRUNC | O_TEXT, PERM,
843 "rfm=stmlf", "ctx=rec", "rat=none", "rop=nlk",
844 "shr=del,get,put,upd");
845 #elif defined (__MINGW32__)
847 TCHAR wpath[GNAT_MAX_PATH_LEN];
849 S2WSU (wpath, path, GNAT_MAX_PATH_LEN);
850 fd = _topen (wpath, O_WRONLY | O_CREAT | O_TRUNC | O_TEXT, PERM);
853 fd = open (path, O_WRONLY | O_CREAT | O_TRUNC | O_TEXT, PERM);
856 return fd < 0 ? -1 : fd;
860 __gnat_open_append (char *path, int fmode)
863 int o_fmode = O_BINARY;
869 fd = open (path, O_WRONLY | O_CREAT | O_APPEND | o_fmode, PERM,
870 "mbc=16", "deq=64", "fop=tef");
871 #elif defined (__MINGW32__)
873 TCHAR wpath[GNAT_MAX_PATH_LEN];
875 S2WSU (wpath, path, GNAT_MAX_PATH_LEN);
876 fd = _topen (wpath, O_WRONLY | O_CREAT | O_APPEND | o_fmode, PERM);
879 fd = open (path, O_WRONLY | O_CREAT | O_APPEND | o_fmode, PERM);
882 return fd < 0 ? -1 : fd;
885 /* Open a new file. Return error (-1) if the file already exists. */
888 __gnat_open_new (char *path, int fmode)
891 int o_fmode = O_BINARY;
897 fd = open (path, O_WRONLY | O_CREAT | O_EXCL | o_fmode, PERM,
898 "mbc=16", "deq=64", "fop=tef");
899 #elif defined (__MINGW32__)
901 TCHAR wpath[GNAT_MAX_PATH_LEN];
903 S2WSU (wpath, path, GNAT_MAX_PATH_LEN);
904 fd = _topen (wpath, O_WRONLY | O_CREAT | O_EXCL | o_fmode, PERM);
907 fd = open (path, O_WRONLY | O_CREAT | O_EXCL | o_fmode, PERM);
910 return fd < 0 ? -1 : fd;
913 /* Open a new temp file. Return error (-1) if the file already exists.
914 Special options for VMS allow the file to be shared between parent and child
915 processes, however they really slow down output. Used in gnatchop. */
918 __gnat_open_new_temp (char *path, int fmode)
921 int o_fmode = O_BINARY;
923 strcpy (path, "GNAT-XXXXXX");
925 #if (defined (__FreeBSD__) || defined (__NetBSD__) || defined (__OpenBSD__) \
926 || defined (linux) || defined(__GLIBC__)) && !defined (__vxworks)
927 return mkstemp (path);
928 #elif defined (__Lynx__)
930 #elif defined (__nucleus__)
933 if (mktemp (path) == NULL)
941 fd = open (path, O_WRONLY | O_CREAT | O_EXCL | o_fmode, PERM,
942 "rfm=stmlf", "ctx=rec", "rat=none", "shr=del,get,put,upd",
943 "mbc=16", "deq=64", "fop=tef");
945 fd = open (path, O_WRONLY | O_CREAT | O_EXCL | o_fmode, PERM);
948 return fd < 0 ? -1 : fd;
951 /* Return the number of bytes in the specified file. */
954 __gnat_file_length (int fd)
959 ret = fstat (fd, &statbuf);
960 if (ret || !S_ISREG (statbuf.st_mode))
963 return (statbuf.st_size);
966 /* Return the number of bytes in the specified named file. */
969 __gnat_named_file_length (char *name)
974 ret = __gnat_stat (name, &statbuf);
975 if (ret || !S_ISREG (statbuf.st_mode))
978 return (statbuf.st_size);
981 /* Create a temporary filename and put it in string pointed to by
985 __gnat_tmp_name (char *tmp_filename)
988 /* Variable used to create a series of unique names */
989 static int counter = 0;
991 /* RTX in RTSS mode does not support tempnam nor tmpnam so we emulate it */
992 strcpy (tmp_filename, "c:\\WINDOWS\\Temp\\gnat-");
993 sprintf (&tmp_filename[strlen (tmp_filename)], "%d\0", counter++);
995 #elif defined (__MINGW32__)
999 /* tempnam tries to create a temporary file in directory pointed to by
1000 TMP environment variable, in c:\temp if TMP is not set, and in
1001 directory specified by P_tmpdir in stdio.h if c:\temp does not
1002 exist. The filename will be created with the prefix "gnat-". */
1004 pname = (char *) tempnam ("c:\\temp", "gnat-");
1006 /* if pname is NULL, the file was not created properly, the disk is full
1007 or there is no more free temporary files */
1010 *tmp_filename = '\0';
1012 /* If pname start with a back slash and not path information it means that
1013 the filename is valid for the current working directory. */
1015 else if (pname[0] == '\\')
1017 strcpy (tmp_filename, ".\\");
1018 strcat (tmp_filename, pname+1);
1021 strcpy (tmp_filename, pname);
1026 #elif defined (linux) || defined (__FreeBSD__) || defined (__NetBSD__) \
1027 || defined (__OpenBSD__) || defined(__GLIBC__)
1028 #define MAX_SAFE_PATH 1000
1029 char *tmpdir = getenv ("TMPDIR");
1031 /* If tmpdir is longer than MAX_SAFE_PATH, revert to default value to avoid
1032 a buffer overflow. */
1033 if (tmpdir == NULL || strlen (tmpdir) > MAX_SAFE_PATH)
1034 strcpy (tmp_filename, "/tmp/gnat-XXXXXX");
1036 sprintf (tmp_filename, "%s/gnat-XXXXXX", tmpdir);
1038 close (mkstemp(tmp_filename));
1040 tmpnam (tmp_filename);
1044 /* Open directory and returns a DIR pointer. */
1046 DIR* __gnat_opendir (char *name)
1049 /* Not supported in RTX */
1053 #elif defined (__MINGW32__)
1054 TCHAR wname[GNAT_MAX_PATH_LEN];
1056 S2WSU (wname, name, GNAT_MAX_PATH_LEN);
1057 return (DIR*)_topendir (wname);
1060 return opendir (name);
1064 /* Read the next entry in a directory. The returned string points somewhere
1068 __gnat_readdir (DIR *dirp, char *buffer, int *len)
1071 /* Not supported in RTX */
1075 #elif defined (__MINGW32__)
1076 struct _tdirent *dirent = _treaddir ((_TDIR*)dirp);
1080 WS2SU (buffer, dirent->d_name, GNAT_MAX_PATH_LEN);
1081 *len = strlen (buffer);
1088 #elif defined (HAVE_READDIR_R)
1089 /* If possible, try to use the thread-safe version. */
1090 if (readdir_r (dirp, buffer) != NULL)
1092 *len = strlen (((struct dirent*) buffer)->d_name);
1093 return ((struct dirent*) buffer)->d_name;
1099 struct dirent *dirent = (struct dirent *) readdir (dirp);
1103 strcpy (buffer, dirent->d_name);
1104 *len = strlen (buffer);
1113 /* Close a directory entry. */
1115 int __gnat_closedir (DIR *dirp)
1118 /* Not supported in RTX */
1122 #elif defined (__MINGW32__)
1123 return _tclosedir ((_TDIR*)dirp);
1126 return closedir (dirp);
1130 /* Returns 1 if readdir is thread safe, 0 otherwise. */
1133 __gnat_readdir_is_thread_safe (void)
1135 #ifdef HAVE_READDIR_R
1142 #if defined (_WIN32) && !defined (RTX)
1143 /* Number of seconds between <Jan 1st 1601> and <Jan 1st 1970>. */
1144 static const unsigned long long w32_epoch_offset = 11644473600ULL;
1146 /* Returns the file modification timestamp using Win32 routines which are
1147 immune against daylight saving time change. It is in fact not possible to
1148 use fstat for this purpose as the DST modify the st_mtime field of the
1152 win32_filetime (HANDLE h)
1157 unsigned long long ull_time;
1160 /* GetFileTime returns FILETIME data which are the number of 100 nanosecs
1161 since <Jan 1st 1601>. This function must return the number of seconds
1162 since <Jan 1st 1970>. */
1164 if (GetFileTime (h, NULL, NULL, &t_write.ft_time))
1165 return (time_t) (t_write.ull_time / 10000000ULL - w32_epoch_offset);
1170 /* Return a GNAT time stamp given a file name. */
1173 __gnat_file_time_name (char *name)
1176 #if defined (__EMX__) || defined (MSDOS)
1177 int fd = open (name, O_RDONLY | O_BINARY);
1178 time_t ret = __gnat_file_time_fd (fd);
1180 return (OS_Time)ret;
1182 #elif defined (_WIN32) && !defined (RTX)
1184 TCHAR wname[GNAT_MAX_PATH_LEN];
1186 S2WSU (wname, name, GNAT_MAX_PATH_LEN);
1188 HANDLE h = CreateFile
1189 (wname, GENERIC_READ, FILE_SHARE_READ, 0,
1190 OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0);
1192 if (h != INVALID_HANDLE_VALUE)
1194 ret = win32_filetime (h);
1197 return (OS_Time) ret;
1199 struct stat statbuf;
1200 if (__gnat_stat (name, &statbuf) != 0) {
1204 /* VMS has file versioning. */
1205 return (OS_Time)statbuf.st_ctime;
1207 return (OS_Time)statbuf.st_mtime;
1213 /* Return a GNAT time stamp given a file descriptor. */
1216 __gnat_file_time_fd (int fd)
1218 /* The following workaround code is due to the fact that under EMX and
1219 DJGPP fstat attempts to convert time values to GMT rather than keep the
1220 actual OS timestamp of the file. By using the OS2/DOS functions directly
1221 the GNAT timestamp are independent of this behavior, which is desired to
1222 facilitate the distribution of GNAT compiled libraries. */
1224 #if defined (__EMX__) || defined (MSDOS)
1228 int ret = DosQueryFileInfo (fd, 1, (unsigned char *) &fs,
1229 sizeof (FILESTATUS));
1231 unsigned file_year = fs.fdateLastWrite.year;
1232 unsigned file_month = fs.fdateLastWrite.month;
1233 unsigned file_day = fs.fdateLastWrite.day;
1234 unsigned file_hour = fs.ftimeLastWrite.hours;
1235 unsigned file_min = fs.ftimeLastWrite.minutes;
1236 unsigned file_tsec = fs.ftimeLastWrite.twosecs;
1240 int ret = getftime (fd, &fs);
1242 unsigned file_year = fs.ft_year;
1243 unsigned file_month = fs.ft_month;
1244 unsigned file_day = fs.ft_day;
1245 unsigned file_hour = fs.ft_hour;
1246 unsigned file_min = fs.ft_min;
1247 unsigned file_tsec = fs.ft_tsec;
1250 /* Calculate the seconds since epoch from the time components. First count
1251 the whole days passed. The value for years returned by the DOS and OS2
1252 functions count years from 1980, so to compensate for the UNIX epoch which
1253 begins in 1970 start with 10 years worth of days and add days for each
1254 four year period since then. */
1257 int cum_days[12] = {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334};
1258 int days_passed = 3652 + (file_year / 4) * 1461;
1259 int years_since_leap = file_year % 4;
1261 if (years_since_leap == 1)
1263 else if (years_since_leap == 2)
1265 else if (years_since_leap == 3)
1266 days_passed += 1096;
1271 days_passed += cum_days[file_month - 1];
1272 if (years_since_leap == 0 && file_year != 20 && file_month > 2)
1275 days_passed += file_day - 1;
1277 /* OK - have whole days. Multiply -- then add in other parts. */
1279 tot_secs = days_passed * 86400;
1280 tot_secs += file_hour * 3600;
1281 tot_secs += file_min * 60;
1282 tot_secs += file_tsec * 2;
1283 return (OS_Time) tot_secs;
1285 #elif defined (_WIN32) && !defined (RTX)
1286 HANDLE h = (HANDLE) _get_osfhandle (fd);
1287 time_t ret = win32_filetime (h);
1288 return (OS_Time) ret;
1291 struct stat statbuf;
1293 if (fstat (fd, &statbuf) != 0) {
1294 return (OS_Time) -1;
1297 /* VMS has file versioning. */
1298 return (OS_Time) statbuf.st_ctime;
1300 return (OS_Time) statbuf.st_mtime;
1306 /* Set the file time stamp. */
1309 __gnat_set_file_time_name (char *name, time_t time_stamp)
1311 #if defined (__EMX__) || defined (MSDOS) || defined (__vxworks)
1313 /* Code to implement __gnat_set_file_time_name for these systems. */
1315 #elif defined (_WIN32) && !defined (RTX)
1319 unsigned long long ull_time;
1321 TCHAR wname[GNAT_MAX_PATH_LEN];
1323 S2WSU (wname, name, GNAT_MAX_PATH_LEN);
1325 HANDLE h = CreateFile
1326 (wname, GENERIC_WRITE, FILE_SHARE_WRITE, NULL,
1327 OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS,
1329 if (h == INVALID_HANDLE_VALUE)
1331 /* Add number of seconds between <Jan 1st 1601> and <Jan 1st 1970> */
1332 t_write.ull_time = ((unsigned long long)time_stamp + w32_epoch_offset);
1333 /* Convert to 100 nanosecond units */
1334 t_write.ull_time *= 10000000ULL;
1336 SetFileTime(h, NULL, NULL, &t_write.ft_time);
1346 unsigned long long backup, create, expire, revise;
1350 unsigned short value;
1353 unsigned system : 4;
1359 } Fat = { 0, 0, 0, 0, 0, { 0 }};
1363 { ATR$S_CREDATE, ATR$C_CREDATE, &Fat.create },
1364 { ATR$S_REVDATE, ATR$C_REVDATE, &Fat.revise },
1365 { ATR$S_EXPDATE, ATR$C_EXPDATE, &Fat.expire },
1366 { ATR$S_BAKDATE, ATR$C_BAKDATE, &Fat.backup },
1367 { ATR$S_FPRO, ATR$C_FPRO, &Fat.prot },
1368 { ATR$S_UIC, ATR$C_UIC, &Fat.uic },
1373 struct dsc$descriptor_fib fibdsc = {sizeof (fib), (void *) &fib};
1377 unsigned long long newtime;
1378 unsigned long long revtime;
1382 struct vstring file;
1383 struct dsc$descriptor_s filedsc
1384 = {NAM$C_MAXRSS, DSC$K_DTYPE_T, DSC$K_CLASS_S, (void *) file.string};
1385 struct vstring device;
1386 struct dsc$descriptor_s devicedsc
1387 = {NAM$C_MAXRSS, DSC$K_DTYPE_T, DSC$K_CLASS_S, (void *) device.string};
1388 struct vstring timev;
1389 struct dsc$descriptor_s timedsc
1390 = {NAM$C_MAXRSS, DSC$K_DTYPE_T, DSC$K_CLASS_S, (void *) timev.string};
1391 struct vstring result;
1392 struct dsc$descriptor_s resultdsc
1393 = {NAM$C_MAXRSS, DSC$K_DTYPE_VT, DSC$K_CLASS_VS, (void *) result.string};
1395 /* Convert parameter name (a file spec) to host file form. Note that this
1396 is needed on VMS to prepare for subsequent calls to VMS RMS library
1397 routines. Note that it would not work to call __gnat_to_host_dir_spec
1398 as was done in a previous version, since this fails silently unless
1399 the feature logical DECC$EFS_CHARSET is enabled, in which case a DNF
1400 (directory not found) condition is signalled. */
1401 tryfile = (char *) __gnat_to_host_file_spec (name);
1403 /* Allocate and initialize a FAB and NAM structures. */
1407 nam.nam$l_esa = file.string;
1408 nam.nam$b_ess = NAM$C_MAXRSS;
1409 nam.nam$l_rsa = result.string;
1410 nam.nam$b_rss = NAM$C_MAXRSS;
1411 fab.fab$l_fna = tryfile;
1412 fab.fab$b_fns = strlen (tryfile);
1413 fab.fab$l_nam = &nam;
1415 /* Validate filespec syntax and device existence. */
1416 status = SYS$PARSE (&fab, 0, 0);
1417 if ((status & 1) != 1)
1418 LIB$SIGNAL (status);
1420 file.string[nam.nam$b_esl] = 0;
1422 /* Find matching filespec. */
1423 status = SYS$SEARCH (&fab, 0, 0);
1424 if ((status & 1) != 1)
1425 LIB$SIGNAL (status);
1427 file.string[nam.nam$b_esl] = 0;
1428 result.string[result.length=nam.nam$b_rsl] = 0;
1430 /* Get the device name and assign an IO channel. */
1431 strncpy (device.string, nam.nam$l_dev, nam.nam$b_dev);
1432 devicedsc.dsc$w_length = nam.nam$b_dev;
1434 status = SYS$ASSIGN (&devicedsc, &chan, 0, 0, 0);
1435 if ((status & 1) != 1)
1436 LIB$SIGNAL (status);
1438 /* Initialize the FIB and fill in the directory id field. */
1439 memset (&fib, 0, sizeof (fib));
1440 fib.fib$w_did[0] = nam.nam$w_did[0];
1441 fib.fib$w_did[1] = nam.nam$w_did[1];
1442 fib.fib$w_did[2] = nam.nam$w_did[2];
1443 fib.fib$l_acctl = 0;
1445 strcpy (file.string, (strrchr (result.string, ']') + 1));
1446 filedsc.dsc$w_length = strlen (file.string);
1447 result.string[result.length = 0] = 0;
1449 /* Open and close the file to fill in the attributes. */
1451 = SYS$QIOW (0, chan, IO$_ACCESS|IO$M_ACCESS, &iosb, 0, 0,
1452 &fibdsc, &filedsc, &result.length, &resultdsc, &atrlst, 0);
1453 if ((status & 1) != 1)
1454 LIB$SIGNAL (status);
1455 if ((iosb.status & 1) != 1)
1456 LIB$SIGNAL (iosb.status);
1458 result.string[result.length] = 0;
1459 status = SYS$QIOW (0, chan, IO$_DEACCESS, &iosb, 0, 0, &fibdsc, 0, 0, 0,
1461 if ((status & 1) != 1)
1462 LIB$SIGNAL (status);
1463 if ((iosb.status & 1) != 1)
1464 LIB$SIGNAL (iosb.status);
1469 /* Set creation time to requested time. */
1470 unix_time_to_vms (time_stamp, newtime);
1472 t = time ((time_t) 0);
1474 /* Set revision time to now in local time. */
1475 unix_time_to_vms (t, revtime);
1478 /* Reopen the file, modify the times and then close. */
1479 fib.fib$l_acctl = FIB$M_WRITE;
1481 = SYS$QIOW (0, chan, IO$_ACCESS|IO$M_ACCESS, &iosb, 0, 0,
1482 &fibdsc, &filedsc, &result.length, &resultdsc, &atrlst, 0);
1483 if ((status & 1) != 1)
1484 LIB$SIGNAL (status);
1485 if ((iosb.status & 1) != 1)
1486 LIB$SIGNAL (iosb.status);
1488 Fat.create = newtime;
1489 Fat.revise = revtime;
1491 status = SYS$QIOW (0, chan, IO$_DEACCESS, &iosb, 0, 0,
1492 &fibdsc, 0, 0, 0, &atrlst, 0);
1493 if ((status & 1) != 1)
1494 LIB$SIGNAL (status);
1495 if ((iosb.status & 1) != 1)
1496 LIB$SIGNAL (iosb.status);
1498 /* Deassign the channel and exit. */
1499 status = SYS$DASSGN (chan);
1500 if ((status & 1) != 1)
1501 LIB$SIGNAL (status);
1503 struct utimbuf utimbuf;
1506 /* Set modification time to requested time. */
1507 utimbuf.modtime = time_stamp;
1509 /* Set access time to now in local time. */
1510 t = time ((time_t) 0);
1511 utimbuf.actime = mktime (localtime (&t));
1513 utime (name, &utimbuf);
1517 /* Get the list of installed standard libraries from the
1518 HKEY_LOCAL_MACHINE\SOFTWARE\Ada Core Technologies\GNAT\Standard Libraries
1522 __gnat_get_libraries_from_registry (void)
1524 char *result = (char *) "";
1526 #if defined (_WIN32) && ! defined (__vxworks) && ! defined (CROSS_DIRECTORY_STRUCTURE) && ! defined (RTX)
1529 DWORD name_size, value_size;
1536 /* First open the key. */
1537 res = RegOpenKeyExA (HKEY_LOCAL_MACHINE, "SOFTWARE", 0, KEY_READ, ®_key);
1539 if (res == ERROR_SUCCESS)
1540 res = RegOpenKeyExA (reg_key, "Ada Core Technologies", 0,
1541 KEY_READ, ®_key);
1543 if (res == ERROR_SUCCESS)
1544 res = RegOpenKeyExA (reg_key, "GNAT", 0, KEY_READ, ®_key);
1546 if (res == ERROR_SUCCESS)
1547 res = RegOpenKeyExA (reg_key, "Standard Libraries", 0, KEY_READ, ®_key);
1549 /* If the key exists, read out all the values in it and concatenate them
1551 for (index = 0; res == ERROR_SUCCESS; index++)
1553 value_size = name_size = 256;
1554 res = RegEnumValueA (reg_key, index, (TCHAR*)name, &name_size, 0,
1555 &type, (LPBYTE)value, &value_size);
1557 if (res == ERROR_SUCCESS && type == REG_SZ)
1559 char *old_result = result;
1561 result = (char *) xmalloc (strlen (old_result) + value_size + 2);
1562 strcpy (result, old_result);
1563 strcat (result, value);
1564 strcat (result, ";");
1568 /* Remove the trailing ";". */
1570 result[strlen (result) - 1] = 0;
1577 __gnat_stat (char *name, struct stat *statbuf)
1580 /* Under Windows the directory name for the stat function must not be
1581 terminated by a directory separator except if just after a drive name. */
1582 TCHAR wname [GNAT_MAX_PATH_LEN + 2];
1586 S2WSU (wname, name, GNAT_MAX_PATH_LEN + 2);
1587 name_len = _tcslen (wname);
1589 if (name_len > GNAT_MAX_PATH_LEN)
1592 last_char = wname[name_len - 1];
1594 while (name_len > 1 && (last_char == _T('\\') || last_char == _T('/')))
1596 wname[name_len - 1] = _T('\0');
1598 last_char = wname[name_len - 1];
1601 /* Only a drive letter followed by ':', we must add a directory separator
1602 for the stat routine to work properly. */
1603 if (name_len == 2 && wname[1] == _T(':'))
1604 _tcscat (wname, _T("\\"));
1606 return _tstat (wname, statbuf);
1609 return stat (name, statbuf);
1614 __gnat_file_exists (char *name)
1617 /* On Windows do not use __gnat_stat() because a bug in Microsoft
1618 _stat() routine. When the system time-zone is set with a negative
1619 offset the _stat() routine fails on specific files like CON: */
1620 TCHAR wname [GNAT_MAX_PATH_LEN + 2];
1622 S2WSU (wname, name, GNAT_MAX_PATH_LEN + 2);
1623 return GetFileAttributes (wname) != INVALID_FILE_ATTRIBUTES;
1625 struct stat statbuf;
1627 return !__gnat_stat (name, &statbuf);
1632 __gnat_is_absolute_path (char *name, int length)
1635 /* On VxWorks systems, an absolute path can be represented (depending on
1636 the host platform) as either /dir/file, or device:/dir/file, or
1637 device:drive_letter:/dir/file. */
1644 for (index = 0; index < length; index++)
1646 if (name[index] == ':' &&
1647 ((name[index + 1] == '/') ||
1648 (isalpha (name[index + 1]) && index + 2 <= length &&
1649 name[index + 2] == '/')))
1652 else if (name[index] == '/')
1657 return (length != 0) &&
1658 (*name == '/' || *name == DIR_SEPARATOR
1659 #if defined (__EMX__) || defined (MSDOS) || defined (WINNT)
1660 || (length > 1 && ISALPHA (name[0]) && name[1] == ':')
1667 __gnat_is_regular_file (char *name)
1670 struct stat statbuf;
1672 ret = __gnat_stat (name, &statbuf);
1673 return (!ret && S_ISREG (statbuf.st_mode));
1677 __gnat_is_directory (char *name)
1680 struct stat statbuf;
1682 ret = __gnat_stat (name, &statbuf);
1683 return (!ret && S_ISDIR (statbuf.st_mode));
1686 #if defined (_WIN32) && !defined (RTX)
1687 /* This MingW section contains code to work with ACL. */
1689 __gnat_check_OWNER_ACL
1691 DWORD CheckAccessDesired,
1692 GENERIC_MAPPING CheckGenericMapping)
1694 TCHAR wname [GNAT_MAX_PATH_LEN + 2];
1695 DWORD dwAccessDesired, dwAccessAllowed;
1696 PRIVILEGE_SET PrivilegeSet;
1697 DWORD dwPrivSetSize = sizeof (PRIVILEGE_SET);
1698 BOOL fAccessGranted = FALSE;
1701 SECURITY_DESCRIPTOR* pSD = NULL;
1703 S2WSU (wname, name, GNAT_MAX_PATH_LEN + 2);
1706 (wname, OWNER_SECURITY_INFORMATION |
1707 GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION,
1710 if ((pSD = (PSECURITY_DESCRIPTOR) HeapAlloc
1711 (GetProcessHeap (), HEAP_ZERO_MEMORY, nLength)) == NULL)
1714 /* Obtain the security descriptor. */
1716 if (!GetFileSecurity
1717 (wname, OWNER_SECURITY_INFORMATION |
1718 GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION,
1719 pSD, nLength, &nLength))
1722 if (!ImpersonateSelf (SecurityImpersonation))
1725 if (!OpenThreadToken
1726 (GetCurrentThread(), TOKEN_DUPLICATE | TOKEN_QUERY, FALSE, &hToken))
1729 /* Undoes the effect of ImpersonateSelf. */
1733 /* We want to test for write permissions. */
1735 dwAccessDesired = CheckAccessDesired;
1737 MapGenericMask (&dwAccessDesired, &CheckGenericMapping);
1740 (pSD , /* security descriptor to check */
1741 hToken, /* impersonation token */
1742 dwAccessDesired, /* requested access rights */
1743 &CheckGenericMapping, /* pointer to GENERIC_MAPPING */
1744 &PrivilegeSet, /* receives privileges used in check */
1745 &dwPrivSetSize, /* size of PrivilegeSet buffer */
1746 &dwAccessAllowed, /* receives mask of allowed access rights */
1750 return fAccessGranted;
1754 __gnat_set_OWNER_ACL
1757 DWORD AccessPermissions)
1759 ACL* pOldDACL = NULL;
1760 ACL* pNewDACL = NULL;
1761 SECURITY_DESCRIPTOR* pSD = NULL;
1763 TCHAR username [100];
1766 TCHAR wname [GNAT_MAX_PATH_LEN + 2];
1768 S2WSU (wname, name, GNAT_MAX_PATH_LEN + 2);
1770 HANDLE file = CreateFile
1771 (wname, READ_CONTROL | WRITE_DAC, 0, NULL,
1772 OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
1774 if (file == INVALID_HANDLE_VALUE)
1777 /* Get current user, he will act as the owner */
1779 if (!GetUserName (username, &unsize))
1785 DACL_SECURITY_INFORMATION,
1786 NULL, NULL, &pOldDACL, NULL, &pSD) != ERROR_SUCCESS)
1789 ZeroMemory (&ea, sizeof (EXPLICIT_ACCESS));
1791 ea.grfAccessMode = AccessMode;
1792 ea.grfAccessPermissions = AccessPermissions;
1793 ea.grfInheritance = CONTAINER_INHERIT_ACE | OBJECT_INHERIT_ACE;
1794 ea.Trustee.TrusteeForm = TRUSTEE_IS_NAME;
1795 ea.Trustee.TrusteeType = TRUSTEE_IS_USER;
1796 ea.Trustee.ptstrName = username;
1798 if (AccessMode == SET_ACCESS)
1800 /* SET_ACCESS, we want to set an explicte set of permissions, do not
1801 merge with current DACL. */
1802 if (SetEntriesInAcl (1, &ea, NULL, &pNewDACL) != ERROR_SUCCESS)
1806 if (SetEntriesInAcl (1, &ea, pOldDACL, &pNewDACL) != ERROR_SUCCESS)
1810 (file, SE_FILE_OBJECT,
1811 DACL_SECURITY_INFORMATION, NULL, NULL, pNewDACL, NULL) != ERROR_SUCCESS)
1815 LocalFree (pNewDACL);
1818 #endif /* defined (_WIN32) && !defined (RTX) */
1821 __gnat_is_readable_file (char *name)
1823 #if defined (_WIN32) && !defined (RTX)
1824 GENERIC_MAPPING GenericMapping;
1825 ZeroMemory (&GenericMapping, sizeof (GENERIC_MAPPING));
1826 GenericMapping.GenericRead = GENERIC_READ;
1828 return __gnat_check_OWNER_ACL (name, FILE_READ_DATA, GenericMapping);
1832 struct stat statbuf;
1834 ret = __gnat_stat (name, &statbuf);
1835 mode = statbuf.st_mode & S_IRUSR;
1836 return (!ret && mode);
1841 __gnat_is_writable_file (char *name)
1843 #if defined (_WIN32) && !defined (RTX)
1844 GENERIC_MAPPING GenericMapping;
1845 ZeroMemory (&GenericMapping, sizeof (GENERIC_MAPPING));
1846 GenericMapping.GenericWrite = GENERIC_WRITE;
1848 return __gnat_check_OWNER_ACL
1849 (name, FILE_WRITE_DATA | FILE_APPEND_DATA, GenericMapping);
1853 struct stat statbuf;
1855 ret = __gnat_stat (name, &statbuf);
1856 mode = statbuf.st_mode & S_IWUSR;
1857 return (!ret && mode);
1862 __gnat_is_executable_file (char *name)
1864 #if defined (_WIN32) && !defined (RTX)
1865 GENERIC_MAPPING GenericMapping;
1866 ZeroMemory (&GenericMapping, sizeof (GENERIC_MAPPING));
1867 GenericMapping.GenericExecute = GENERIC_EXECUTE;
1869 return __gnat_check_OWNER_ACL (name, FILE_EXECUTE, GenericMapping);
1873 struct stat statbuf;
1875 ret = __gnat_stat (name, &statbuf);
1876 mode = statbuf.st_mode & S_IXUSR;
1877 return (!ret && mode);
1882 __gnat_set_writable (char *name)
1884 #if defined (_WIN32) && !defined (RTX)
1885 __gnat_set_OWNER_ACL (name, GRANT_ACCESS, GENERIC_WRITE);
1886 #elif ! defined (__vxworks) && ! defined(__nucleus__)
1887 struct stat statbuf;
1889 if (stat (name, &statbuf) == 0)
1891 statbuf.st_mode = statbuf.st_mode | S_IWUSR;
1892 chmod (name, statbuf.st_mode);
1898 __gnat_set_executable (char *name)
1900 #if defined (_WIN32) && !defined (RTX)
1901 __gnat_set_OWNER_ACL (name, GRANT_ACCESS, GENERIC_EXECUTE);
1902 #elif ! defined (__vxworks) && ! defined(__nucleus__)
1903 struct stat statbuf;
1905 if (stat (name, &statbuf) == 0)
1907 statbuf.st_mode = statbuf.st_mode | S_IXUSR;
1908 chmod (name, statbuf.st_mode);
1914 __gnat_set_readonly (char *name)
1916 #if defined (_WIN32) && !defined (RTX)
1917 __gnat_set_OWNER_ACL (name, SET_ACCESS, GENERIC_READ);
1918 #elif ! defined (__vxworks) && ! defined(__nucleus__)
1919 struct stat statbuf;
1921 if (stat (name, &statbuf) == 0)
1923 statbuf.st_mode = statbuf.st_mode & 07577;
1924 chmod (name, statbuf.st_mode);
1930 __gnat_is_symbolic_link (char *name ATTRIBUTE_UNUSED)
1932 #if defined (__vxworks) || defined (__nucleus__)
1935 #elif defined (_AIX) || defined (__APPLE__) || defined (__unix__)
1937 struct stat statbuf;
1939 ret = lstat (name, &statbuf);
1940 return (!ret && S_ISLNK (statbuf.st_mode));
1947 #if defined (sun) && defined (__SVR4)
1948 /* Using fork on Solaris will duplicate all the threads. fork1, which
1949 duplicates only the active thread, must be used instead, or spawning
1950 subprocess from a program with tasking will lead into numerous problems. */
1955 __gnat_portable_spawn (char *args[])
1958 int finished ATTRIBUTE_UNUSED;
1959 int pid ATTRIBUTE_UNUSED;
1961 #if defined (__vxworks) || defined(__nucleus__) || defined(RTX)
1964 #elif defined (MSDOS) || defined (_WIN32)
1965 /* args[0] must be quotes as it could contain a full pathname with spaces */
1966 char *args_0 = args[0];
1967 args[0] = (char *)xmalloc (strlen (args_0) + 3);
1968 strcpy (args[0], "\"");
1969 strcat (args[0], args_0);
1970 strcat (args[0], "\"");
1972 status = spawnvp (P_WAIT, args_0, (const char* const*)args);
1974 /* restore previous value */
1976 args[0] = (char *)args_0;
1986 pid = spawnvp (P_NOWAIT, args[0], args);
1998 if (execv (args[0], MAYBE_TO_PTR32 (args)) != 0)
2000 return -1; /* execv is in parent context on VMS. */
2008 finished = waitpid (pid, &status, 0);
2010 if (finished != pid || WIFEXITED (status) == 0)
2013 return WEXITSTATUS (status);
2019 /* Create a copy of the given file descriptor.
2020 Return -1 if an error occurred. */
2023 __gnat_dup (int oldfd)
2025 #if defined (__vxworks) && !defined (__RTP__)
2026 /* Not supported on VxWorks 5.x, but supported on VxWorks 6.0 when using
2034 /* Make newfd be the copy of oldfd, closing newfd first if necessary.
2035 Return -1 if an error occurred. */
2038 __gnat_dup2 (int oldfd, int newfd)
2040 #if defined (__vxworks) && !defined (__RTP__)
2041 /* Not supported on VxWorks 5.x, but supported on VxWorks 6.0 when using
2045 return dup2 (oldfd, newfd);
2049 /* WIN32 code to implement a wait call that wait for any child process. */
2051 #if defined (_WIN32) && !defined (RTX)
2053 /* Synchronization code, to be thread safe. */
2055 static CRITICAL_SECTION plist_cs;
2058 __gnat_plist_init (void)
2060 InitializeCriticalSection (&plist_cs);
2066 EnterCriticalSection (&plist_cs);
2072 LeaveCriticalSection (&plist_cs);
2075 typedef struct _process_list
2078 struct _process_list *next;
2081 static Process_List *PLIST = NULL;
2083 static int plist_length = 0;
2086 add_handle (HANDLE h)
2090 pl = (Process_List *) xmalloc (sizeof (Process_List));
2094 /* -------------------- critical section -------------------- */
2099 /* -------------------- critical section -------------------- */
2105 remove_handle (HANDLE h)
2108 Process_List *prev = NULL;
2112 /* -------------------- critical section -------------------- */
2121 prev->next = pl->next;
2133 /* -------------------- critical section -------------------- */
2139 win32_no_block_spawn (char *command, char *args[])
2143 PROCESS_INFORMATION PI;
2144 SECURITY_ATTRIBUTES SA;
2149 /* compute the total command line length */
2153 csize += strlen (args[k]) + 1;
2157 full_command = (char *) xmalloc (csize);
2160 SI.cb = sizeof (STARTUPINFO);
2161 SI.lpReserved = NULL;
2162 SI.lpReserved2 = NULL;
2163 SI.lpDesktop = NULL;
2167 SI.wShowWindow = SW_HIDE;
2169 /* Security attributes. */
2170 SA.nLength = sizeof (SECURITY_ATTRIBUTES);
2171 SA.bInheritHandle = TRUE;
2172 SA.lpSecurityDescriptor = NULL;
2174 /* Prepare the command string. */
2175 strcpy (full_command, command);
2176 strcat (full_command, " ");
2181 strcat (full_command, args[k]);
2182 strcat (full_command, " ");
2187 int wsize = csize * 2;
2188 TCHAR *wcommand = (TCHAR *) xmalloc (wsize);
2190 S2WSU (wcommand, full_command, wsize);
2192 free (full_command);
2194 result = CreateProcess
2195 (NULL, wcommand, &SA, NULL, TRUE,
2196 GetPriorityClass (GetCurrentProcess()), NULL, NULL, &SI, &PI);
2203 add_handle (PI.hProcess);
2204 CloseHandle (PI.hThread);
2205 return (int) PI.hProcess;
2212 win32_wait (int *status)
2221 if (plist_length == 0)
2227 hl = (HANDLE *) xmalloc (sizeof (HANDLE) * plist_length);
2232 /* -------------------- critical section -------------------- */
2239 /* -------------------- critical section -------------------- */
2243 res = WaitForMultipleObjects (plist_length, hl, FALSE, INFINITE);
2244 h = hl[res - WAIT_OBJECT_0];
2249 GetExitCodeProcess (h, &exitcode);
2252 *status = (int) exitcode;
2259 __gnat_portable_no_block_spawn (char *args[])
2263 #if defined (__vxworks) || defined (__nucleus__) || defined (RTX)
2266 #elif defined (__EMX__) || defined (MSDOS)
2268 /* ??? For PC machines I (Franco) don't know the system calls to implement
2269 this routine. So I'll fake it as follows. This routine will behave
2270 exactly like the blocking portable_spawn and will systematically return
2271 a pid of 0 unless the spawned task did not complete successfully, in
2272 which case we return a pid of -1. To synchronize with this the
2273 portable_wait below systematically returns a pid of 0 and reports that
2274 the subprocess terminated successfully. */
2276 if (spawnvp (P_WAIT, args[0], args) != 0)
2279 #elif defined (_WIN32)
2281 pid = win32_no_block_spawn (args[0], args);
2290 if (execv (args[0], MAYBE_TO_PTR32 (args)) != 0)
2292 return -1; /* execv is in parent context on VMS. */
2304 __gnat_portable_wait (int *process_status)
2309 #if defined (__vxworks) || defined (__nucleus__) || defined (RTX)
2310 /* Not sure what to do here, so do same as __EMX__ case, i.e., nothing but
2313 #elif defined (_WIN32)
2315 pid = win32_wait (&status);
2317 #elif defined (__EMX__) || defined (MSDOS)
2318 /* ??? See corresponding comment in portable_no_block_spawn. */
2322 pid = waitpid (-1, &status, 0);
2323 status = status & 0xffff;
2326 *process_status = status;
2331 __gnat_os_exit (int status)
2336 /* Locate a regular file, give a Path value. */
2339 __gnat_locate_regular_file (char *file_name, char *path_val)
2342 char *file_path = (char *) alloca (strlen (file_name) + 1);
2345 /* Return immediately if file_name is empty */
2347 if (*file_name == '\0')
2350 /* Remove quotes around file_name if present */
2356 strcpy (file_path, ptr);
2358 ptr = file_path + strlen (file_path) - 1;
2363 /* Handle absolute pathnames. */
2365 absolute = __gnat_is_absolute_path (file_path, strlen (file_name));
2369 if (__gnat_is_regular_file (file_path))
2370 return xstrdup (file_path);
2375 /* If file_name include directory separator(s), try it first as
2376 a path name relative to the current directory */
2377 for (ptr = file_name; *ptr && *ptr != '/' && *ptr != DIR_SEPARATOR; ptr++)
2382 if (__gnat_is_regular_file (file_name))
2383 return xstrdup (file_name);
2390 /* The result has to be smaller than path_val + file_name. */
2391 char *file_path = (char *) alloca (strlen (path_val) + strlen (file_name) + 2);
2395 for (; *path_val == PATH_SEPARATOR; path_val++)
2401 /* Skip the starting quote */
2403 if (*path_val == '"')
2406 for (ptr = file_path; *path_val && *path_val != PATH_SEPARATOR; )
2407 *ptr++ = *path_val++;
2411 /* Skip the ending quote */
2416 if (*ptr != '/' && *ptr != DIR_SEPARATOR)
2417 *++ptr = DIR_SEPARATOR;
2419 strcpy (++ptr, file_name);
2421 if (__gnat_is_regular_file (file_path))
2422 return xstrdup (file_path);
2429 /* Locate an executable given a Path argument. This routine is only used by
2430 gnatbl and should not be used otherwise. Use locate_exec_on_path
2434 __gnat_locate_exec (char *exec_name, char *path_val)
2437 if (!strstr (exec_name, HOST_EXECUTABLE_SUFFIX))
2439 char *full_exec_name
2440 = (char *) alloca (strlen (exec_name) + strlen (HOST_EXECUTABLE_SUFFIX) + 1);
2442 strcpy (full_exec_name, exec_name);
2443 strcat (full_exec_name, HOST_EXECUTABLE_SUFFIX);
2444 ptr = __gnat_locate_regular_file (full_exec_name, path_val);
2447 return __gnat_locate_regular_file (exec_name, path_val);
2451 return __gnat_locate_regular_file (exec_name, path_val);
2454 /* Locate an executable using the Systems default PATH. */
2457 __gnat_locate_exec_on_path (char *exec_name)
2461 #if defined (_WIN32) && !defined (RTX)
2462 TCHAR *wpath_val = _tgetenv (_T("PATH"));
2464 /* In Win32 systems we expand the PATH as for XP environment
2465 variables are not automatically expanded. We also prepend the
2466 ".;" to the path to match normal NT path search semantics */
2468 #define EXPAND_BUFFER_SIZE 32767
2470 wapath_val = alloca (EXPAND_BUFFER_SIZE);
2472 wapath_val [0] = '.';
2473 wapath_val [1] = ';';
2475 DWORD res = ExpandEnvironmentStrings
2476 (wpath_val, &wapath_val[2], EXPAND_BUFFER_SIZE - 2);
2478 if (!res) wapath_val [0] = _T('\0');
2480 apath_val = alloca (EXPAND_BUFFER_SIZE);
2482 WS2SU (apath_val, wapath_val, EXPAND_BUFFER_SIZE);
2483 return __gnat_locate_exec (exec_name, apath_val);
2488 char *path_val = "/VAXC$PATH";
2490 char *path_val = getenv ("PATH");
2492 if (path_val == NULL) return NULL;
2493 apath_val = (char *) alloca (strlen (path_val) + 1);
2494 strcpy (apath_val, path_val);
2495 return __gnat_locate_exec (exec_name, apath_val);
2501 /* These functions are used to translate to and from VMS and Unix syntax
2502 file, directory and path specifications. */
2505 #define MAXNAMES 256
2506 #define NEW_CANONICAL_FILELIST_INCREMENT 64
2508 static char new_canonical_dirspec [MAXPATH];
2509 static char new_canonical_filespec [MAXPATH];
2510 static char new_canonical_pathspec [MAXNAMES*MAXPATH];
2511 static unsigned new_canonical_filelist_index;
2512 static unsigned new_canonical_filelist_in_use;
2513 static unsigned new_canonical_filelist_allocated;
2514 static char **new_canonical_filelist;
2515 static char new_host_pathspec [MAXNAMES*MAXPATH];
2516 static char new_host_dirspec [MAXPATH];
2517 static char new_host_filespec [MAXPATH];
2519 /* Routine is called repeatedly by decc$from_vms via
2520 __gnat_to_canonical_file_list_init until it returns 0 or the expansion
2524 wildcard_translate_unix (char *name)
2527 char buff [MAXPATH];
2529 strncpy (buff, name, MAXPATH);
2530 buff [MAXPATH - 1] = (char) 0;
2531 ver = strrchr (buff, '.');
2533 /* Chop off the version. */
2537 /* Dynamically extend the allocation by the increment. */
2538 if (new_canonical_filelist_in_use == new_canonical_filelist_allocated)
2540 new_canonical_filelist_allocated += NEW_CANONICAL_FILELIST_INCREMENT;
2541 new_canonical_filelist = (char **) xrealloc
2542 (new_canonical_filelist,
2543 new_canonical_filelist_allocated * sizeof (char *));
2546 new_canonical_filelist[new_canonical_filelist_in_use++] = xstrdup (buff);
2551 /* Translate a wildcard VMS file spec into a list of Unix file specs. First do
2552 full translation and copy the results into a list (_init), then return them
2553 one at a time (_next). If onlydirs set, only expand directory files. */
2556 __gnat_to_canonical_file_list_init (char *filespec, int onlydirs)
2559 char buff [MAXPATH];
2561 len = strlen (filespec);
2562 strncpy (buff, filespec, MAXPATH);
2564 /* Only look for directories */
2565 if (onlydirs && !strstr (&buff [len-5], "*.dir"))
2566 strncat (buff, "*.dir", MAXPATH);
2568 buff [MAXPATH - 1] = (char) 0;
2570 decc$from_vms (buff, wildcard_translate_unix, 1);
2572 /* Remove the .dir extension. */
2578 for (i = 0; i < new_canonical_filelist_in_use; i++)
2580 ext = strstr (new_canonical_filelist[i], ".dir");
2586 return new_canonical_filelist_in_use;
2589 /* Return the next filespec in the list. */
2592 __gnat_to_canonical_file_list_next ()
2594 return new_canonical_filelist[new_canonical_filelist_index++];
2597 /* Free storage used in the wildcard expansion. */
2600 __gnat_to_canonical_file_list_free ()
2604 for (i = 0; i < new_canonical_filelist_in_use; i++)
2605 free (new_canonical_filelist[i]);
2607 free (new_canonical_filelist);
2609 new_canonical_filelist_in_use = 0;
2610 new_canonical_filelist_allocated = 0;
2611 new_canonical_filelist_index = 0;
2612 new_canonical_filelist = 0;
2615 /* The functional equivalent of decc$translate_vms routine.
2616 Designed to produce the same output, but is protected against
2617 malformed paths (original version ACCVIOs in this case) and
2618 does not require VMS-specific DECC RTL */
2620 #define NAM$C_MAXRSS 1024
2623 __gnat_translate_vms (char *src)
2625 static char retbuf [NAM$C_MAXRSS+1];
2626 char *srcendpos, *pos1, *pos2, *retpos;
2627 int disp, path_present = 0;
2629 if (!src) return NULL;
2631 srcendpos = strchr (src, '\0');
2634 /* Look for the node and/or device in front of the path */
2636 pos2 = strchr (pos1, ':');
2638 if (pos2 && (pos2 < srcendpos) && (*(pos2 + 1) == ':')) {
2639 /* There is a node name. "node_name::" becomes "node_name!" */
2641 strncpy (retbuf, pos1, disp);
2642 retpos [disp] = '!';
2643 retpos = retpos + disp + 1;
2645 pos2 = strchr (pos1, ':');
2649 /* There is a device name. "dev_name:" becomes "/dev_name/" */
2652 strncpy (retpos, pos1, disp);
2653 retpos = retpos + disp;
2658 /* No explicit device; we must look ahead and prepend /sys$disk/ if
2659 the path is absolute */
2660 if ((*pos1 == '[' || *pos1 == '<') && (pos1 < srcendpos)
2661 && !strchr (".-]>", *(pos1 + 1))) {
2662 strncpy (retpos, "/sys$disk/", 10);
2666 /* Process the path part */
2667 while (*pos1 == '[' || *pos1 == '<') {
2670 if (*pos1 == ']' || *pos1 == '>') {
2671 /* Special case, [] translates to '.' */
2676 /* '[000000' means root dir. It can be present in the middle of
2677 the path due to expansion of logical devices, in which case
2679 if (!strncmp (pos1, "000000", 6) && path_present > 1 &&
2680 (*(pos1 + 6) == ']' || *(pos1 + 6) == '>' || *(pos1 + 6) == '.')) {
2682 if (*pos1 == '.') pos1++;
2684 else if (*pos1 == '.') {
2689 /* There is a qualified path */
2690 while (*pos1 && *pos1 != ']' && *pos1 != '>') {
2693 /* '.' is used to separate directories. Replace it with '/' but
2694 only if there isn't already '/' just before */
2695 if (*(retpos - 1) != '/') *(retpos++) = '/';
2697 if (pos1 + 1 < srcendpos && *pos1 == '.' && *(pos1 + 1) == '.') {
2698 /* ellipsis refers to entire subtree; replace with '**' */
2699 *(retpos++) = '*'; *(retpos++) = '*'; *(retpos++) = '/';
2704 /* When after '.' '[' '<' is equivalent to Unix ".." but there
2705 may be several in a row */
2706 if (*(pos1 - 1) == '.' || *(pos1 - 1) == '[' ||
2707 *(pos1 - 1) == '<') {
2708 while (*pos1 == '-') {
2710 *(retpos++) = '.'; *(retpos++) = '.'; *(retpos++) = '/';
2715 /* otherwise fall through to default */
2717 *(retpos++) = *(pos1++);
2724 if (pos1 < srcendpos) {
2725 /* Now add the actual file name, until the version suffix if any */
2726 if (path_present) *(retpos++) = '/';
2727 pos2 = strchr (pos1, ';');
2728 disp = pos2? (pos2 - pos1) : (srcendpos - pos1);
2729 strncpy (retpos, pos1, disp);
2731 if (pos2 && pos2 < srcendpos) {
2732 /* There is a non-empty version suffix. ";<ver>" becomes ".<ver>" */
2734 disp = srcendpos - pos2 - 1;
2735 strncpy (retpos, pos2 + 1, disp);
2746 /* Translate a VMS syntax directory specification in to Unix syntax. If
2747 PREFIXFLAG is set, append an underscore "/". If no indicators of VMS syntax
2748 found, return input string. Also translate a dirname that contains no
2749 slashes, in case it's a logical name. */
2752 __gnat_to_canonical_dir_spec (char *dirspec, int prefixflag)
2756 strcpy (new_canonical_dirspec, "");
2757 if (strlen (dirspec))
2761 if (strchr (dirspec, ']') || strchr (dirspec, ':'))
2763 strncpy (new_canonical_dirspec,
2764 __gnat_translate_vms (dirspec),
2767 else if (!strchr (dirspec, '/') && (dirspec1 = getenv (dirspec)) != 0)
2769 strncpy (new_canonical_dirspec,
2770 __gnat_translate_vms (dirspec1),
2775 strncpy (new_canonical_dirspec, dirspec, MAXPATH);
2779 len = strlen (new_canonical_dirspec);
2780 if (prefixflag && new_canonical_dirspec [len-1] != '/')
2781 strncat (new_canonical_dirspec, "/", MAXPATH);
2783 new_canonical_dirspec [MAXPATH - 1] = (char) 0;
2785 return new_canonical_dirspec;
2789 /* Translate a VMS syntax file specification into Unix syntax.
2790 If no indicators of VMS syntax found, check if it's an uppercase
2791 alphanumeric_ name and if so try it out as an environment
2792 variable (logical name). If all else fails return the
2796 __gnat_to_canonical_file_spec (char *filespec)
2800 strncpy (new_canonical_filespec, "", MAXPATH);
2802 if (strchr (filespec, ']') || strchr (filespec, ':'))
2804 char *tspec = (char *) __gnat_translate_vms (filespec);
2806 if (tspec != (char *) -1)
2807 strncpy (new_canonical_filespec, tspec, MAXPATH);
2809 else if ((strlen (filespec) == strspn (filespec,
2810 "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_"))
2811 && (filespec1 = getenv (filespec)))
2813 char *tspec = (char *) __gnat_translate_vms (filespec1);
2815 if (tspec != (char *) -1)
2816 strncpy (new_canonical_filespec, tspec, MAXPATH);
2820 strncpy (new_canonical_filespec, filespec, MAXPATH);
2823 new_canonical_filespec [MAXPATH - 1] = (char) 0;
2825 return new_canonical_filespec;
2828 /* Translate a VMS syntax path specification into Unix syntax.
2829 If no indicators of VMS syntax found, return input string. */
2832 __gnat_to_canonical_path_spec (char *pathspec)
2834 char *curr, *next, buff [MAXPATH];
2839 /* If there are /'s, assume it's a Unix path spec and return. */
2840 if (strchr (pathspec, '/'))
2843 new_canonical_pathspec[0] = 0;
2848 next = strchr (curr, ',');
2850 next = strchr (curr, 0);
2852 strncpy (buff, curr, next - curr);
2853 buff[next - curr] = 0;
2855 /* Check for wildcards and expand if present. */
2856 if (strchr (buff, '*') || strchr (buff, '%') || strstr (buff, "..."))
2860 dirs = __gnat_to_canonical_file_list_init (buff, 1);
2861 for (i = 0; i < dirs; i++)
2865 next_dir = __gnat_to_canonical_file_list_next ();
2866 strncat (new_canonical_pathspec, next_dir, MAXPATH);
2868 /* Don't append the separator after the last expansion. */
2870 strncat (new_canonical_pathspec, ":", MAXPATH);
2873 __gnat_to_canonical_file_list_free ();
2876 strncat (new_canonical_pathspec,
2877 __gnat_to_canonical_dir_spec (buff, 0), MAXPATH);
2882 strncat (new_canonical_pathspec, ":", MAXPATH);
2886 new_canonical_pathspec [MAXPATH - 1] = (char) 0;
2888 return new_canonical_pathspec;
2891 static char filename_buff [MAXPATH];
2894 translate_unix (char *name, int type)
2896 strncpy (filename_buff, name, MAXPATH);
2897 filename_buff [MAXPATH - 1] = (char) 0;
2901 /* Translate a Unix syntax path spec into a VMS style (comma separated list of
2905 to_host_path_spec (char *pathspec)
2907 char *curr, *next, buff [MAXPATH];
2912 /* Can't very well test for colons, since that's the Unix separator! */
2913 if (strchr (pathspec, ']') || strchr (pathspec, ','))
2916 new_host_pathspec[0] = 0;
2921 next = strchr (curr, ':');
2923 next = strchr (curr, 0);
2925 strncpy (buff, curr, next - curr);
2926 buff[next - curr] = 0;
2928 strncat (new_host_pathspec, __gnat_to_host_dir_spec (buff, 0), MAXPATH);
2931 strncat (new_host_pathspec, ",", MAXPATH);
2935 new_host_pathspec [MAXPATH - 1] = (char) 0;
2937 return new_host_pathspec;
2940 /* Translate a Unix syntax directory specification into VMS syntax. The
2941 PREFIXFLAG has no effect, but is kept for symmetry with
2942 to_canonical_dir_spec. If indicators of VMS syntax found, return input
2946 __gnat_to_host_dir_spec (char *dirspec, int prefixflag ATTRIBUTE_UNUSED)
2948 int len = strlen (dirspec);
2950 strncpy (new_host_dirspec, dirspec, MAXPATH);
2951 new_host_dirspec [MAXPATH - 1] = (char) 0;
2953 if (strchr (new_host_dirspec, ']') || strchr (new_host_dirspec, ':'))
2954 return new_host_dirspec;
2956 while (len > 1 && new_host_dirspec[len - 1] == '/')
2958 new_host_dirspec[len - 1] = 0;
2962 decc$to_vms (new_host_dirspec, translate_unix, 1, 2);
2963 strncpy (new_host_dirspec, filename_buff, MAXPATH);
2964 new_host_dirspec [MAXPATH - 1] = (char) 0;
2966 return new_host_dirspec;
2969 /* Translate a Unix syntax file specification into VMS syntax.
2970 If indicators of VMS syntax found, return input string. */
2973 __gnat_to_host_file_spec (char *filespec)
2975 strncpy (new_host_filespec, "", MAXPATH);
2976 if (strchr (filespec, ']') || strchr (filespec, ':'))
2978 strncpy (new_host_filespec, filespec, MAXPATH);
2982 decc$to_vms (filespec, translate_unix, 1, 1);
2983 strncpy (new_host_filespec, filename_buff, MAXPATH);
2986 new_host_filespec [MAXPATH - 1] = (char) 0;
2988 return new_host_filespec;
2992 __gnat_adjust_os_resource_limits ()
2994 SYS$ADJWSL (131072, 0);
2999 /* Dummy functions for Osint import for non-VMS systems. */
3002 __gnat_to_canonical_file_list_init
3003 (char *dirspec ATTRIBUTE_UNUSED, int onlydirs ATTRIBUTE_UNUSED)
3009 __gnat_to_canonical_file_list_next (void)
3015 __gnat_to_canonical_file_list_free (void)
3020 __gnat_to_canonical_dir_spec (char *dirspec, int prefixflag ATTRIBUTE_UNUSED)
3026 __gnat_to_canonical_file_spec (char *filespec)
3032 __gnat_to_canonical_path_spec (char *pathspec)
3038 __gnat_to_host_dir_spec (char *dirspec, int prefixflag ATTRIBUTE_UNUSED)
3044 __gnat_to_host_file_spec (char *filespec)
3050 __gnat_adjust_os_resource_limits (void)
3056 /* For EMX, we cannot include dummy in libgcc, since it is too difficult
3057 to coordinate this with the EMX distribution. Consequently, we put the
3058 definition of dummy which is used for exception handling, here. */
3060 #if defined (__EMX__)
3064 #if defined (__mips_vxworks)
3068 CACHE_USER_FLUSH (0, ENTIRE_CACHE);
3072 #if defined (CROSS_DIRECTORY_STRUCTURE) \
3073 || (! ((defined (sparc) || defined (i386)) && defined (sun) \
3074 && defined (__SVR4)) \
3075 && ! (defined (linux) && (defined (i386) || defined (__x86_64__))) \
3076 && ! (defined (linux) && defined (__ia64__)) \
3077 && ! (defined (linux) && defined (powerpc)) \
3078 && ! defined (__FreeBSD__) \
3079 && ! defined (__hpux__) \
3080 && ! defined (__APPLE__) \
3081 && ! defined (_AIX) \
3082 && ! (defined (__alpha__) && defined (__osf__)) \
3083 && ! defined (VMS) \
3084 && ! defined (__MINGW32__) \
3085 && ! (defined (__mips) && defined (__sgi)))
3087 /* Dummy function to satisfy g-trasym.o. See the preprocessor conditional
3088 just above for a list of native platforms that provide a non-dummy
3089 version of this procedure in libaddr2line.a. */
3092 convert_addresses (const char *file_name ATTRIBUTE_UNUSED,
3093 void *addrs ATTRIBUTE_UNUSED,
3094 int n_addr ATTRIBUTE_UNUSED,
3095 void *buf ATTRIBUTE_UNUSED,
3096 int *len ATTRIBUTE_UNUSED)
3102 #if defined (_WIN32)
3103 int __gnat_argument_needs_quote = 1;
3105 int __gnat_argument_needs_quote = 0;
3108 /* This option is used to enable/disable object files handling from the
3109 binder file by the GNAT Project module. For example, this is disabled on
3110 Windows (prior to GCC 3.4) as it is already done by the mdll module.
3111 Stating with GCC 3.4 the shared libraries are not based on mdll
3112 anymore as it uses the GCC's -shared option */
3113 #if defined (_WIN32) \
3114 && ((__GNUC__ < 3) || ((__GNUC__ == 3) && (__GNUC_MINOR__ < 4)))
3115 int __gnat_prj_add_obj_files = 0;
3117 int __gnat_prj_add_obj_files = 1;
3120 /* char used as prefix/suffix for environment variables */
3121 #if defined (_WIN32)
3122 char __gnat_environment_char = '%';
3124 char __gnat_environment_char = '$';
3127 /* This functions copy the file attributes from a source file to a
3130 mode = 0 : In this mode copy only the file time stamps (last access and
3131 last modification time stamps).
3133 mode = 1 : In this mode, time stamps and read/write/execute attributes are
3136 Returns 0 if operation was successful and -1 in case of error. */
3139 __gnat_copy_attribs (char *from, char *to, int mode)
3141 #if defined (VMS) || defined (__vxworks) || defined (__nucleus__)
3145 struct utimbuf tbuf;
3147 if (stat (from, &fbuf) == -1)
3152 tbuf.actime = fbuf.st_atime;
3153 tbuf.modtime = fbuf.st_mtime;
3155 if (utime (to, &tbuf) == -1)
3162 if (chmod (to, fbuf.st_mode) == -1)
3173 __gnat_lseek (int fd, long offset, int whence)
3175 return (int) lseek (fd, offset, whence);
3178 /* This function returns the major version number of GCC being used. */
3180 get_gcc_version (void)
3185 return (int) (version_string[0] - '0');
3190 __gnat_set_close_on_exec (int fd ATTRIBUTE_UNUSED,
3191 int close_on_exec_p ATTRIBUTE_UNUSED)
3193 #if defined (F_GETFD) && defined (FD_CLOEXEC) && ! defined (__vxworks)
3194 int flags = fcntl (fd, F_GETFD, 0);
3197 if (close_on_exec_p)
3198 flags |= FD_CLOEXEC;
3200 flags &= ~FD_CLOEXEC;
3201 return fcntl (fd, F_SETFD, flags | FD_CLOEXEC);
3204 /* For the Windows case, we should use SetHandleInformation to remove
3205 the HANDLE_INHERIT property from fd. This is not implemented yet,
3206 but for our purposes (support of GNAT.Expect) this does not matter,
3207 as by default handles are *not* inherited. */
3211 /* Indicates if platforms supports automatic initialization through the
3212 constructor mechanism */
3214 __gnat_binder_supports_auto_init ()
3223 /* Indicates that Stand-Alone Libraries are automatically initialized through
3224 the constructor mechanism */
3226 __gnat_sals_init_using_constructors ()
3228 #if defined (__vxworks) || defined (__Lynx__) || defined (VMS)
3237 /* In RTX mode, the procedure to get the time (as file time) is different
3238 in RTSS mode and Win32 mode. In order to avoid duplicating an Ada file,
3239 we introduce an intermediate procedure to link against the corresponding
3240 one in each situation. */
3242 extern void GetTimeAsFileTime(LPFILETIME pTime);
3244 void GetTimeAsFileTime(LPFILETIME pTime)
3247 RtGetRtssTimeAsFileTime (pTime); /* RTSS interface */
3249 GetSystemTimeAsFileTime (pTime); /* w32 interface */
3254 /* Add symbol that is required to link. It would otherwise be taken from
3255 libgcc.a and it would try to use the gcc constructors that are not
3256 supported by Microsoft linker. */
3258 extern void __main (void);
3260 void __main (void) {}
3264 #if defined (linux) || defined(__GLIBC__)
3265 /* pthread affinity support */
3267 int __gnat_pthread_setaffinity_np (pthread_t th,
3269 const void *cpuset);
3272 #include <pthread.h>
3274 __gnat_pthread_setaffinity_np (pthread_t th,
3276 const cpu_set_t *cpuset)
3278 return pthread_setaffinity_np (th, cpusetsize, cpuset);
3282 __gnat_pthread_setaffinity_np (pthread_t th ATTRIBUTE_UNUSED,
3283 size_t cpusetsize ATTRIBUTE_UNUSED,
3284 const void *cpuset ATTRIBUTE_UNUSED)