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 DWORD dwAccessDesired, dwAccessAllowed;
1695 PRIVILEGE_SET PrivilegeSet;
1696 DWORD dwPrivSetSize = sizeof (PRIVILEGE_SET);
1697 BOOL fAccessGranted = FALSE;
1700 SECURITY_DESCRIPTOR* pSD = NULL;
1703 (wname, OWNER_SECURITY_INFORMATION |
1704 GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION,
1707 if ((pSD = (PSECURITY_DESCRIPTOR) HeapAlloc
1708 (GetProcessHeap (), HEAP_ZERO_MEMORY, nLength)) == NULL)
1711 /* Obtain the security descriptor. */
1713 if (!GetFileSecurity
1714 (wname, OWNER_SECURITY_INFORMATION |
1715 GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION,
1716 pSD, nLength, &nLength))
1719 if (!ImpersonateSelf (SecurityImpersonation))
1722 if (!OpenThreadToken
1723 (GetCurrentThread(), TOKEN_DUPLICATE | TOKEN_QUERY, FALSE, &hToken))
1726 /* Undoes the effect of ImpersonateSelf. */
1730 /* We want to test for write permissions. */
1732 dwAccessDesired = CheckAccessDesired;
1734 MapGenericMask (&dwAccessDesired, &CheckGenericMapping);
1737 (pSD , /* security descriptor to check */
1738 hToken, /* impersonation token */
1739 dwAccessDesired, /* requested access rights */
1740 &CheckGenericMapping, /* pointer to GENERIC_MAPPING */
1741 &PrivilegeSet, /* receives privileges used in check */
1742 &dwPrivSetSize, /* size of PrivilegeSet buffer */
1743 &dwAccessAllowed, /* receives mask of allowed access rights */
1747 return fAccessGranted;
1751 __gnat_set_OWNER_ACL
1754 DWORD AccessPermissions)
1756 ACL* pOldDACL = NULL;
1757 ACL* pNewDACL = NULL;
1758 SECURITY_DESCRIPTOR* pSD = NULL;
1760 TCHAR username [100];
1763 /* Get current user, he will act as the owner */
1765 if (!GetUserName (username, &unsize))
1768 if (GetNamedSecurityInfo
1771 DACL_SECURITY_INFORMATION,
1772 NULL, NULL, &pOldDACL, NULL, &pSD) != ERROR_SUCCESS)
1775 BuildExplicitAccessWithName
1776 (&ea, username, AccessPermissions, AccessMode, NO_INHERITANCE);
1778 if (AccessMode == SET_ACCESS)
1780 /* SET_ACCESS, we want to set an explicte set of permissions, do not
1781 merge with current DACL. */
1782 if (SetEntriesInAcl (1, &ea, NULL, &pNewDACL) != ERROR_SUCCESS)
1786 if (SetEntriesInAcl (1, &ea, pOldDACL, &pNewDACL) != ERROR_SUCCESS)
1789 if (SetNamedSecurityInfo
1790 (wname, SE_FILE_OBJECT,
1791 DACL_SECURITY_INFORMATION, NULL, NULL, pNewDACL, NULL) != ERROR_SUCCESS)
1795 LocalFree (pNewDACL);
1797 #endif /* defined (_WIN32) && !defined (RTX) */
1800 __gnat_is_readable_file (char *name)
1802 #if defined (_WIN32) && !defined (RTX)
1803 TCHAR wname [GNAT_MAX_PATH_LEN + 2];
1804 GENERIC_MAPPING GenericMapping;
1806 S2WSU (wname, name, GNAT_MAX_PATH_LEN + 2);
1808 ZeroMemory (&GenericMapping, sizeof (GENERIC_MAPPING));
1809 GenericMapping.GenericRead = GENERIC_READ;
1811 return __gnat_check_OWNER_ACL (wname, FILE_READ_DATA, GenericMapping);
1815 struct stat statbuf;
1817 ret = stat (name, &statbuf);
1818 mode = statbuf.st_mode & S_IRUSR;
1819 return (!ret && mode);
1824 __gnat_is_writable_file (char *name)
1826 #if defined (_WIN32) && !defined (RTX)
1827 TCHAR wname [GNAT_MAX_PATH_LEN + 2];
1828 GENERIC_MAPPING GenericMapping;
1830 S2WSU (wname, name, GNAT_MAX_PATH_LEN + 2);
1832 ZeroMemory (&GenericMapping, sizeof (GENERIC_MAPPING));
1833 GenericMapping.GenericWrite = GENERIC_WRITE;
1835 return __gnat_check_OWNER_ACL
1836 (wname, FILE_WRITE_DATA | FILE_APPEND_DATA, GenericMapping)
1837 && !(GetFileAttributes (wname) & FILE_ATTRIBUTE_READONLY);
1841 struct stat statbuf;
1843 ret = stat (name, &statbuf);
1844 mode = statbuf.st_mode & S_IWUSR;
1845 return (!ret && mode);
1850 __gnat_is_executable_file (char *name)
1852 #if defined (_WIN32) && !defined (RTX)
1853 TCHAR wname [GNAT_MAX_PATH_LEN + 2];
1854 GENERIC_MAPPING GenericMapping;
1856 S2WSU (wname, name, GNAT_MAX_PATH_LEN + 2);
1858 ZeroMemory (&GenericMapping, sizeof (GENERIC_MAPPING));
1859 GenericMapping.GenericExecute = GENERIC_EXECUTE;
1861 return __gnat_check_OWNER_ACL (wname, FILE_EXECUTE, GenericMapping);
1865 struct stat statbuf;
1867 ret = stat (name, &statbuf);
1868 mode = statbuf.st_mode & S_IXUSR;
1869 return (!ret && mode);
1874 __gnat_set_writable (char *name)
1876 #if defined (_WIN32) && !defined (RTX)
1877 TCHAR wname [GNAT_MAX_PATH_LEN + 2];
1879 S2WSU (wname, name, GNAT_MAX_PATH_LEN + 2);
1881 __gnat_set_OWNER_ACL (wname, GRANT_ACCESS, FILE_GENERIC_WRITE);
1883 (wname, GetFileAttributes (wname) & ~FILE_ATTRIBUTE_READONLY);
1884 #elif ! defined (__vxworks) && ! defined(__nucleus__)
1885 struct stat statbuf;
1887 if (stat (name, &statbuf) == 0)
1889 statbuf.st_mode = statbuf.st_mode | S_IWUSR;
1890 chmod (name, statbuf.st_mode);
1896 __gnat_set_executable (char *name)
1898 #if defined (_WIN32) && !defined (RTX)
1899 TCHAR wname [GNAT_MAX_PATH_LEN + 2];
1901 S2WSU (wname, name, GNAT_MAX_PATH_LEN + 2);
1903 __gnat_set_OWNER_ACL (wname, GRANT_ACCESS, FILE_GENERIC_EXECUTE);
1904 #elif ! defined (__vxworks) && ! defined(__nucleus__)
1905 struct stat statbuf;
1907 if (stat (name, &statbuf) == 0)
1909 statbuf.st_mode = statbuf.st_mode | S_IXUSR;
1910 chmod (name, statbuf.st_mode);
1916 __gnat_set_non_writable (char *name)
1918 #if defined (_WIN32) && !defined (RTX)
1919 TCHAR wname [GNAT_MAX_PATH_LEN + 2];
1921 S2WSU (wname, name, GNAT_MAX_PATH_LEN + 2);
1923 __gnat_set_OWNER_ACL
1924 (wname, DENY_ACCESS,
1925 FILE_WRITE_DATA | FILE_APPEND_DATA |
1926 FILE_WRITE_PROPERTIES | FILE_WRITE_ATTRIBUTES);
1928 (wname, GetFileAttributes (wname) | FILE_ATTRIBUTE_READONLY);
1929 #elif ! defined (__vxworks) && ! defined(__nucleus__)
1930 struct stat statbuf;
1932 if (stat (name, &statbuf) == 0)
1934 statbuf.st_mode = statbuf.st_mode & 07577;
1935 chmod (name, statbuf.st_mode);
1941 __gnat_set_readable (char *name)
1943 #if defined (_WIN32) && !defined (RTX)
1944 TCHAR wname [GNAT_MAX_PATH_LEN + 2];
1946 S2WSU (wname, name, GNAT_MAX_PATH_LEN + 2);
1948 __gnat_set_OWNER_ACL (wname, GRANT_ACCESS, FILE_GENERIC_READ);
1949 #elif ! defined (__vxworks) && ! defined(__nucleus__)
1950 struct stat statbuf;
1952 if (stat (name, &statbuf) == 0)
1954 chmod (name, statbuf.st_mode | S_IREAD);
1960 __gnat_set_non_readable (char *name)
1962 #if defined (_WIN32) && !defined (RTX)
1963 TCHAR wname [GNAT_MAX_PATH_LEN + 2];
1965 S2WSU (wname, name, GNAT_MAX_PATH_LEN + 2);
1967 __gnat_set_OWNER_ACL (wname, DENY_ACCESS, FILE_GENERIC_READ);
1968 #elif ! defined (__vxworks) && ! defined(__nucleus__)
1969 struct stat statbuf;
1971 if (stat (name, &statbuf) == 0)
1973 chmod (name, statbuf.st_mode & (~S_IREAD));
1979 __gnat_is_symbolic_link (char *name ATTRIBUTE_UNUSED)
1981 #if defined (__vxworks) || defined (__nucleus__)
1984 #elif defined (_AIX) || defined (__APPLE__) || defined (__unix__)
1986 struct stat statbuf;
1988 ret = lstat (name, &statbuf);
1989 return (!ret && S_ISLNK (statbuf.st_mode));
1996 #if defined (sun) && defined (__SVR4)
1997 /* Using fork on Solaris will duplicate all the threads. fork1, which
1998 duplicates only the active thread, must be used instead, or spawning
1999 subprocess from a program with tasking will lead into numerous problems. */
2004 __gnat_portable_spawn (char *args[])
2007 int finished ATTRIBUTE_UNUSED;
2008 int pid ATTRIBUTE_UNUSED;
2010 #if defined (__vxworks) || defined(__nucleus__) || defined(RTX)
2013 #elif defined (MSDOS) || defined (_WIN32)
2014 /* args[0] must be quotes as it could contain a full pathname with spaces */
2015 char *args_0 = args[0];
2016 args[0] = (char *)xmalloc (strlen (args_0) + 3);
2017 strcpy (args[0], "\"");
2018 strcat (args[0], args_0);
2019 strcat (args[0], "\"");
2021 status = spawnvp (P_WAIT, args_0, (const char* const*)args);
2023 /* restore previous value */
2025 args[0] = (char *)args_0;
2035 pid = spawnvp (P_NOWAIT, args[0], args);
2047 if (execv (args[0], MAYBE_TO_PTR32 (args)) != 0)
2049 return -1; /* execv is in parent context on VMS. */
2057 finished = waitpid (pid, &status, 0);
2059 if (finished != pid || WIFEXITED (status) == 0)
2062 return WEXITSTATUS (status);
2068 /* Create a copy of the given file descriptor.
2069 Return -1 if an error occurred. */
2072 __gnat_dup (int oldfd)
2074 #if defined (__vxworks) && !defined (__RTP__)
2075 /* Not supported on VxWorks 5.x, but supported on VxWorks 6.0 when using
2083 /* Make newfd be the copy of oldfd, closing newfd first if necessary.
2084 Return -1 if an error occurred. */
2087 __gnat_dup2 (int oldfd, int newfd)
2089 #if defined (__vxworks) && !defined (__RTP__)
2090 /* Not supported on VxWorks 5.x, but supported on VxWorks 6.0 when using
2094 return dup2 (oldfd, newfd);
2098 /* WIN32 code to implement a wait call that wait for any child process. */
2100 #if defined (_WIN32) && !defined (RTX)
2102 /* Synchronization code, to be thread safe. */
2104 static CRITICAL_SECTION plist_cs;
2107 __gnat_plist_init (void)
2109 InitializeCriticalSection (&plist_cs);
2115 EnterCriticalSection (&plist_cs);
2121 LeaveCriticalSection (&plist_cs);
2124 typedef struct _process_list
2127 struct _process_list *next;
2130 static Process_List *PLIST = NULL;
2132 static int plist_length = 0;
2135 add_handle (HANDLE h)
2139 pl = (Process_List *) xmalloc (sizeof (Process_List));
2143 /* -------------------- critical section -------------------- */
2148 /* -------------------- critical section -------------------- */
2154 remove_handle (HANDLE h)
2157 Process_List *prev = NULL;
2161 /* -------------------- critical section -------------------- */
2170 prev->next = pl->next;
2182 /* -------------------- critical section -------------------- */
2188 win32_no_block_spawn (char *command, char *args[])
2192 PROCESS_INFORMATION PI;
2193 SECURITY_ATTRIBUTES SA;
2198 /* compute the total command line length */
2202 csize += strlen (args[k]) + 1;
2206 full_command = (char *) xmalloc (csize);
2209 SI.cb = sizeof (STARTUPINFO);
2210 SI.lpReserved = NULL;
2211 SI.lpReserved2 = NULL;
2212 SI.lpDesktop = NULL;
2216 SI.wShowWindow = SW_HIDE;
2218 /* Security attributes. */
2219 SA.nLength = sizeof (SECURITY_ATTRIBUTES);
2220 SA.bInheritHandle = TRUE;
2221 SA.lpSecurityDescriptor = NULL;
2223 /* Prepare the command string. */
2224 strcpy (full_command, command);
2225 strcat (full_command, " ");
2230 strcat (full_command, args[k]);
2231 strcat (full_command, " ");
2236 int wsize = csize * 2;
2237 TCHAR *wcommand = (TCHAR *) xmalloc (wsize);
2239 S2WSU (wcommand, full_command, wsize);
2241 free (full_command);
2243 result = CreateProcess
2244 (NULL, wcommand, &SA, NULL, TRUE,
2245 GetPriorityClass (GetCurrentProcess()), NULL, NULL, &SI, &PI);
2252 add_handle (PI.hProcess);
2253 CloseHandle (PI.hThread);
2254 return (int) PI.hProcess;
2261 win32_wait (int *status)
2270 if (plist_length == 0)
2276 hl = (HANDLE *) xmalloc (sizeof (HANDLE) * plist_length);
2281 /* -------------------- critical section -------------------- */
2288 /* -------------------- critical section -------------------- */
2292 res = WaitForMultipleObjects (plist_length, hl, FALSE, INFINITE);
2293 h = hl[res - WAIT_OBJECT_0];
2298 GetExitCodeProcess (h, &exitcode);
2301 *status = (int) exitcode;
2308 __gnat_portable_no_block_spawn (char *args[])
2312 #if defined (__vxworks) || defined (__nucleus__) || defined (RTX)
2315 #elif defined (__EMX__) || defined (MSDOS)
2317 /* ??? For PC machines I (Franco) don't know the system calls to implement
2318 this routine. So I'll fake it as follows. This routine will behave
2319 exactly like the blocking portable_spawn and will systematically return
2320 a pid of 0 unless the spawned task did not complete successfully, in
2321 which case we return a pid of -1. To synchronize with this the
2322 portable_wait below systematically returns a pid of 0 and reports that
2323 the subprocess terminated successfully. */
2325 if (spawnvp (P_WAIT, args[0], args) != 0)
2328 #elif defined (_WIN32)
2330 pid = win32_no_block_spawn (args[0], args);
2339 if (execv (args[0], MAYBE_TO_PTR32 (args)) != 0)
2341 return -1; /* execv is in parent context on VMS. */
2353 __gnat_portable_wait (int *process_status)
2358 #if defined (__vxworks) || defined (__nucleus__) || defined (RTX)
2359 /* Not sure what to do here, so do same as __EMX__ case, i.e., nothing but
2362 #elif defined (_WIN32)
2364 pid = win32_wait (&status);
2366 #elif defined (__EMX__) || defined (MSDOS)
2367 /* ??? See corresponding comment in portable_no_block_spawn. */
2371 pid = waitpid (-1, &status, 0);
2372 status = status & 0xffff;
2375 *process_status = status;
2380 __gnat_os_exit (int status)
2385 /* Locate a regular file, give a Path value. */
2388 __gnat_locate_regular_file (char *file_name, char *path_val)
2391 char *file_path = (char *) alloca (strlen (file_name) + 1);
2394 /* Return immediately if file_name is empty */
2396 if (*file_name == '\0')
2399 /* Remove quotes around file_name if present */
2405 strcpy (file_path, ptr);
2407 ptr = file_path + strlen (file_path) - 1;
2412 /* Handle absolute pathnames. */
2414 absolute = __gnat_is_absolute_path (file_path, strlen (file_name));
2418 if (__gnat_is_regular_file (file_path))
2419 return xstrdup (file_path);
2424 /* If file_name include directory separator(s), try it first as
2425 a path name relative to the current directory */
2426 for (ptr = file_name; *ptr && *ptr != '/' && *ptr != DIR_SEPARATOR; ptr++)
2431 if (__gnat_is_regular_file (file_name))
2432 return xstrdup (file_name);
2439 /* The result has to be smaller than path_val + file_name. */
2440 char *file_path = (char *) alloca (strlen (path_val) + strlen (file_name) + 2);
2444 for (; *path_val == PATH_SEPARATOR; path_val++)
2450 /* Skip the starting quote */
2452 if (*path_val == '"')
2455 for (ptr = file_path; *path_val && *path_val != PATH_SEPARATOR; )
2456 *ptr++ = *path_val++;
2460 /* Skip the ending quote */
2465 if (*ptr != '/' && *ptr != DIR_SEPARATOR)
2466 *++ptr = DIR_SEPARATOR;
2468 strcpy (++ptr, file_name);
2470 if (__gnat_is_regular_file (file_path))
2471 return xstrdup (file_path);
2478 /* Locate an executable given a Path argument. This routine is only used by
2479 gnatbl and should not be used otherwise. Use locate_exec_on_path
2483 __gnat_locate_exec (char *exec_name, char *path_val)
2486 if (!strstr (exec_name, HOST_EXECUTABLE_SUFFIX))
2488 char *full_exec_name
2489 = (char *) alloca (strlen (exec_name) + strlen (HOST_EXECUTABLE_SUFFIX) + 1);
2491 strcpy (full_exec_name, exec_name);
2492 strcat (full_exec_name, HOST_EXECUTABLE_SUFFIX);
2493 ptr = __gnat_locate_regular_file (full_exec_name, path_val);
2496 return __gnat_locate_regular_file (exec_name, path_val);
2500 return __gnat_locate_regular_file (exec_name, path_val);
2503 /* Locate an executable using the Systems default PATH. */
2506 __gnat_locate_exec_on_path (char *exec_name)
2510 #if defined (_WIN32) && !defined (RTX)
2511 TCHAR *wpath_val = _tgetenv (_T("PATH"));
2513 /* In Win32 systems we expand the PATH as for XP environment
2514 variables are not automatically expanded. We also prepend the
2515 ".;" to the path to match normal NT path search semantics */
2517 #define EXPAND_BUFFER_SIZE 32767
2519 wapath_val = alloca (EXPAND_BUFFER_SIZE);
2521 wapath_val [0] = '.';
2522 wapath_val [1] = ';';
2524 DWORD res = ExpandEnvironmentStrings
2525 (wpath_val, &wapath_val[2], EXPAND_BUFFER_SIZE - 2);
2527 if (!res) wapath_val [0] = _T('\0');
2529 apath_val = alloca (EXPAND_BUFFER_SIZE);
2531 WS2SU (apath_val, wapath_val, EXPAND_BUFFER_SIZE);
2532 return __gnat_locate_exec (exec_name, apath_val);
2537 char *path_val = "/VAXC$PATH";
2539 char *path_val = getenv ("PATH");
2541 if (path_val == NULL) return NULL;
2542 apath_val = (char *) alloca (strlen (path_val) + 1);
2543 strcpy (apath_val, path_val);
2544 return __gnat_locate_exec (exec_name, apath_val);
2550 /* These functions are used to translate to and from VMS and Unix syntax
2551 file, directory and path specifications. */
2554 #define MAXNAMES 256
2555 #define NEW_CANONICAL_FILELIST_INCREMENT 64
2557 static char new_canonical_dirspec [MAXPATH];
2558 static char new_canonical_filespec [MAXPATH];
2559 static char new_canonical_pathspec [MAXNAMES*MAXPATH];
2560 static unsigned new_canonical_filelist_index;
2561 static unsigned new_canonical_filelist_in_use;
2562 static unsigned new_canonical_filelist_allocated;
2563 static char **new_canonical_filelist;
2564 static char new_host_pathspec [MAXNAMES*MAXPATH];
2565 static char new_host_dirspec [MAXPATH];
2566 static char new_host_filespec [MAXPATH];
2568 /* Routine is called repeatedly by decc$from_vms via
2569 __gnat_to_canonical_file_list_init until it returns 0 or the expansion
2573 wildcard_translate_unix (char *name)
2576 char buff [MAXPATH];
2578 strncpy (buff, name, MAXPATH);
2579 buff [MAXPATH - 1] = (char) 0;
2580 ver = strrchr (buff, '.');
2582 /* Chop off the version. */
2586 /* Dynamically extend the allocation by the increment. */
2587 if (new_canonical_filelist_in_use == new_canonical_filelist_allocated)
2589 new_canonical_filelist_allocated += NEW_CANONICAL_FILELIST_INCREMENT;
2590 new_canonical_filelist = (char **) xrealloc
2591 (new_canonical_filelist,
2592 new_canonical_filelist_allocated * sizeof (char *));
2595 new_canonical_filelist[new_canonical_filelist_in_use++] = xstrdup (buff);
2600 /* Translate a wildcard VMS file spec into a list of Unix file specs. First do
2601 full translation and copy the results into a list (_init), then return them
2602 one at a time (_next). If onlydirs set, only expand directory files. */
2605 __gnat_to_canonical_file_list_init (char *filespec, int onlydirs)
2608 char buff [MAXPATH];
2610 len = strlen (filespec);
2611 strncpy (buff, filespec, MAXPATH);
2613 /* Only look for directories */
2614 if (onlydirs && !strstr (&buff [len-5], "*.dir"))
2615 strncat (buff, "*.dir", MAXPATH);
2617 buff [MAXPATH - 1] = (char) 0;
2619 decc$from_vms (buff, wildcard_translate_unix, 1);
2621 /* Remove the .dir extension. */
2627 for (i = 0; i < new_canonical_filelist_in_use; i++)
2629 ext = strstr (new_canonical_filelist[i], ".dir");
2635 return new_canonical_filelist_in_use;
2638 /* Return the next filespec in the list. */
2641 __gnat_to_canonical_file_list_next ()
2643 return new_canonical_filelist[new_canonical_filelist_index++];
2646 /* Free storage used in the wildcard expansion. */
2649 __gnat_to_canonical_file_list_free ()
2653 for (i = 0; i < new_canonical_filelist_in_use; i++)
2654 free (new_canonical_filelist[i]);
2656 free (new_canonical_filelist);
2658 new_canonical_filelist_in_use = 0;
2659 new_canonical_filelist_allocated = 0;
2660 new_canonical_filelist_index = 0;
2661 new_canonical_filelist = 0;
2664 /* The functional equivalent of decc$translate_vms routine.
2665 Designed to produce the same output, but is protected against
2666 malformed paths (original version ACCVIOs in this case) and
2667 does not require VMS-specific DECC RTL */
2669 #define NAM$C_MAXRSS 1024
2672 __gnat_translate_vms (char *src)
2674 static char retbuf [NAM$C_MAXRSS+1];
2675 char *srcendpos, *pos1, *pos2, *retpos;
2676 int disp, path_present = 0;
2678 if (!src) return NULL;
2680 srcendpos = strchr (src, '\0');
2683 /* Look for the node and/or device in front of the path */
2685 pos2 = strchr (pos1, ':');
2687 if (pos2 && (pos2 < srcendpos) && (*(pos2 + 1) == ':')) {
2688 /* There is a node name. "node_name::" becomes "node_name!" */
2690 strncpy (retbuf, pos1, disp);
2691 retpos [disp] = '!';
2692 retpos = retpos + disp + 1;
2694 pos2 = strchr (pos1, ':');
2698 /* There is a device name. "dev_name:" becomes "/dev_name/" */
2701 strncpy (retpos, pos1, disp);
2702 retpos = retpos + disp;
2707 /* No explicit device; we must look ahead and prepend /sys$disk/ if
2708 the path is absolute */
2709 if ((*pos1 == '[' || *pos1 == '<') && (pos1 < srcendpos)
2710 && !strchr (".-]>", *(pos1 + 1))) {
2711 strncpy (retpos, "/sys$disk/", 10);
2715 /* Process the path part */
2716 while (*pos1 == '[' || *pos1 == '<') {
2719 if (*pos1 == ']' || *pos1 == '>') {
2720 /* Special case, [] translates to '.' */
2725 /* '[000000' means root dir. It can be present in the middle of
2726 the path due to expansion of logical devices, in which case
2728 if (!strncmp (pos1, "000000", 6) && path_present > 1 &&
2729 (*(pos1 + 6) == ']' || *(pos1 + 6) == '>' || *(pos1 + 6) == '.')) {
2731 if (*pos1 == '.') pos1++;
2733 else if (*pos1 == '.') {
2738 /* There is a qualified path */
2739 while (*pos1 && *pos1 != ']' && *pos1 != '>') {
2742 /* '.' is used to separate directories. Replace it with '/' but
2743 only if there isn't already '/' just before */
2744 if (*(retpos - 1) != '/') *(retpos++) = '/';
2746 if (pos1 + 1 < srcendpos && *pos1 == '.' && *(pos1 + 1) == '.') {
2747 /* ellipsis refers to entire subtree; replace with '**' */
2748 *(retpos++) = '*'; *(retpos++) = '*'; *(retpos++) = '/';
2753 /* When after '.' '[' '<' is equivalent to Unix ".." but there
2754 may be several in a row */
2755 if (*(pos1 - 1) == '.' || *(pos1 - 1) == '[' ||
2756 *(pos1 - 1) == '<') {
2757 while (*pos1 == '-') {
2759 *(retpos++) = '.'; *(retpos++) = '.'; *(retpos++) = '/';
2764 /* otherwise fall through to default */
2766 *(retpos++) = *(pos1++);
2773 if (pos1 < srcendpos) {
2774 /* Now add the actual file name, until the version suffix if any */
2775 if (path_present) *(retpos++) = '/';
2776 pos2 = strchr (pos1, ';');
2777 disp = pos2? (pos2 - pos1) : (srcendpos - pos1);
2778 strncpy (retpos, pos1, disp);
2780 if (pos2 && pos2 < srcendpos) {
2781 /* There is a non-empty version suffix. ";<ver>" becomes ".<ver>" */
2783 disp = srcendpos - pos2 - 1;
2784 strncpy (retpos, pos2 + 1, disp);
2795 /* Translate a VMS syntax directory specification in to Unix syntax. If
2796 PREFIXFLAG is set, append an underscore "/". If no indicators of VMS syntax
2797 found, return input string. Also translate a dirname that contains no
2798 slashes, in case it's a logical name. */
2801 __gnat_to_canonical_dir_spec (char *dirspec, int prefixflag)
2805 strcpy (new_canonical_dirspec, "");
2806 if (strlen (dirspec))
2810 if (strchr (dirspec, ']') || strchr (dirspec, ':'))
2812 strncpy (new_canonical_dirspec,
2813 __gnat_translate_vms (dirspec),
2816 else if (!strchr (dirspec, '/') && (dirspec1 = getenv (dirspec)) != 0)
2818 strncpy (new_canonical_dirspec,
2819 __gnat_translate_vms (dirspec1),
2824 strncpy (new_canonical_dirspec, dirspec, MAXPATH);
2828 len = strlen (new_canonical_dirspec);
2829 if (prefixflag && new_canonical_dirspec [len-1] != '/')
2830 strncat (new_canonical_dirspec, "/", MAXPATH);
2832 new_canonical_dirspec [MAXPATH - 1] = (char) 0;
2834 return new_canonical_dirspec;
2838 /* Translate a VMS syntax file specification into Unix syntax.
2839 If no indicators of VMS syntax found, check if it's an uppercase
2840 alphanumeric_ name and if so try it out as an environment
2841 variable (logical name). If all else fails return the
2845 __gnat_to_canonical_file_spec (char *filespec)
2849 strncpy (new_canonical_filespec, "", MAXPATH);
2851 if (strchr (filespec, ']') || strchr (filespec, ':'))
2853 char *tspec = (char *) __gnat_translate_vms (filespec);
2855 if (tspec != (char *) -1)
2856 strncpy (new_canonical_filespec, tspec, MAXPATH);
2858 else if ((strlen (filespec) == strspn (filespec,
2859 "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_"))
2860 && (filespec1 = getenv (filespec)))
2862 char *tspec = (char *) __gnat_translate_vms (filespec1);
2864 if (tspec != (char *) -1)
2865 strncpy (new_canonical_filespec, tspec, MAXPATH);
2869 strncpy (new_canonical_filespec, filespec, MAXPATH);
2872 new_canonical_filespec [MAXPATH - 1] = (char) 0;
2874 return new_canonical_filespec;
2877 /* Translate a VMS syntax path specification into Unix syntax.
2878 If no indicators of VMS syntax found, return input string. */
2881 __gnat_to_canonical_path_spec (char *pathspec)
2883 char *curr, *next, buff [MAXPATH];
2888 /* If there are /'s, assume it's a Unix path spec and return. */
2889 if (strchr (pathspec, '/'))
2892 new_canonical_pathspec[0] = 0;
2897 next = strchr (curr, ',');
2899 next = strchr (curr, 0);
2901 strncpy (buff, curr, next - curr);
2902 buff[next - curr] = 0;
2904 /* Check for wildcards and expand if present. */
2905 if (strchr (buff, '*') || strchr (buff, '%') || strstr (buff, "..."))
2909 dirs = __gnat_to_canonical_file_list_init (buff, 1);
2910 for (i = 0; i < dirs; i++)
2914 next_dir = __gnat_to_canonical_file_list_next ();
2915 strncat (new_canonical_pathspec, next_dir, MAXPATH);
2917 /* Don't append the separator after the last expansion. */
2919 strncat (new_canonical_pathspec, ":", MAXPATH);
2922 __gnat_to_canonical_file_list_free ();
2925 strncat (new_canonical_pathspec,
2926 __gnat_to_canonical_dir_spec (buff, 0), MAXPATH);
2931 strncat (new_canonical_pathspec, ":", MAXPATH);
2935 new_canonical_pathspec [MAXPATH - 1] = (char) 0;
2937 return new_canonical_pathspec;
2940 static char filename_buff [MAXPATH];
2943 translate_unix (char *name, int type)
2945 strncpy (filename_buff, name, MAXPATH);
2946 filename_buff [MAXPATH - 1] = (char) 0;
2950 /* Translate a Unix syntax path spec into a VMS style (comma separated list of
2954 to_host_path_spec (char *pathspec)
2956 char *curr, *next, buff [MAXPATH];
2961 /* Can't very well test for colons, since that's the Unix separator! */
2962 if (strchr (pathspec, ']') || strchr (pathspec, ','))
2965 new_host_pathspec[0] = 0;
2970 next = strchr (curr, ':');
2972 next = strchr (curr, 0);
2974 strncpy (buff, curr, next - curr);
2975 buff[next - curr] = 0;
2977 strncat (new_host_pathspec, __gnat_to_host_dir_spec (buff, 0), MAXPATH);
2980 strncat (new_host_pathspec, ",", MAXPATH);
2984 new_host_pathspec [MAXPATH - 1] = (char) 0;
2986 return new_host_pathspec;
2989 /* Translate a Unix syntax directory specification into VMS syntax. The
2990 PREFIXFLAG has no effect, but is kept for symmetry with
2991 to_canonical_dir_spec. If indicators of VMS syntax found, return input
2995 __gnat_to_host_dir_spec (char *dirspec, int prefixflag ATTRIBUTE_UNUSED)
2997 int len = strlen (dirspec);
2999 strncpy (new_host_dirspec, dirspec, MAXPATH);
3000 new_host_dirspec [MAXPATH - 1] = (char) 0;
3002 if (strchr (new_host_dirspec, ']') || strchr (new_host_dirspec, ':'))
3003 return new_host_dirspec;
3005 while (len > 1 && new_host_dirspec[len - 1] == '/')
3007 new_host_dirspec[len - 1] = 0;
3011 decc$to_vms (new_host_dirspec, translate_unix, 1, 2);
3012 strncpy (new_host_dirspec, filename_buff, MAXPATH);
3013 new_host_dirspec [MAXPATH - 1] = (char) 0;
3015 return new_host_dirspec;
3018 /* Translate a Unix syntax file specification into VMS syntax.
3019 If indicators of VMS syntax found, return input string. */
3022 __gnat_to_host_file_spec (char *filespec)
3024 strncpy (new_host_filespec, "", MAXPATH);
3025 if (strchr (filespec, ']') || strchr (filespec, ':'))
3027 strncpy (new_host_filespec, filespec, MAXPATH);
3031 decc$to_vms (filespec, translate_unix, 1, 1);
3032 strncpy (new_host_filespec, filename_buff, MAXPATH);
3035 new_host_filespec [MAXPATH - 1] = (char) 0;
3037 return new_host_filespec;
3041 __gnat_adjust_os_resource_limits ()
3043 SYS$ADJWSL (131072, 0);
3048 /* Dummy functions for Osint import for non-VMS systems. */
3051 __gnat_to_canonical_file_list_init
3052 (char *dirspec ATTRIBUTE_UNUSED, int onlydirs ATTRIBUTE_UNUSED)
3058 __gnat_to_canonical_file_list_next (void)
3064 __gnat_to_canonical_file_list_free (void)
3069 __gnat_to_canonical_dir_spec (char *dirspec, int prefixflag ATTRIBUTE_UNUSED)
3075 __gnat_to_canonical_file_spec (char *filespec)
3081 __gnat_to_canonical_path_spec (char *pathspec)
3087 __gnat_to_host_dir_spec (char *dirspec, int prefixflag ATTRIBUTE_UNUSED)
3093 __gnat_to_host_file_spec (char *filespec)
3099 __gnat_adjust_os_resource_limits (void)
3105 /* For EMX, we cannot include dummy in libgcc, since it is too difficult
3106 to coordinate this with the EMX distribution. Consequently, we put the
3107 definition of dummy which is used for exception handling, here. */
3109 #if defined (__EMX__)
3113 #if defined (__mips_vxworks)
3117 CACHE_USER_FLUSH (0, ENTIRE_CACHE);
3121 #if defined (CROSS_DIRECTORY_STRUCTURE) \
3122 || (! ((defined (sparc) || defined (i386)) && defined (sun) \
3123 && defined (__SVR4)) \
3124 && ! (defined (linux) && (defined (i386) || defined (__x86_64__))) \
3125 && ! (defined (linux) && defined (__ia64__)) \
3126 && ! (defined (linux) && defined (powerpc)) \
3127 && ! defined (__FreeBSD__) \
3128 && ! defined (__hpux__) \
3129 && ! defined (__APPLE__) \
3130 && ! defined (_AIX) \
3131 && ! (defined (__alpha__) && defined (__osf__)) \
3132 && ! defined (VMS) \
3133 && ! defined (__MINGW32__) \
3134 && ! (defined (__mips) && defined (__sgi)))
3136 /* Dummy function to satisfy g-trasym.o. See the preprocessor conditional
3137 just above for a list of native platforms that provide a non-dummy
3138 version of this procedure in libaddr2line.a. */
3141 convert_addresses (const char *file_name ATTRIBUTE_UNUSED,
3142 void *addrs ATTRIBUTE_UNUSED,
3143 int n_addr ATTRIBUTE_UNUSED,
3144 void *buf ATTRIBUTE_UNUSED,
3145 int *len ATTRIBUTE_UNUSED)
3151 #if defined (_WIN32)
3152 int __gnat_argument_needs_quote = 1;
3154 int __gnat_argument_needs_quote = 0;
3157 /* This option is used to enable/disable object files handling from the
3158 binder file by the GNAT Project module. For example, this is disabled on
3159 Windows (prior to GCC 3.4) as it is already done by the mdll module.
3160 Stating with GCC 3.4 the shared libraries are not based on mdll
3161 anymore as it uses the GCC's -shared option */
3162 #if defined (_WIN32) \
3163 && ((__GNUC__ < 3) || ((__GNUC__ == 3) && (__GNUC_MINOR__ < 4)))
3164 int __gnat_prj_add_obj_files = 0;
3166 int __gnat_prj_add_obj_files = 1;
3169 /* char used as prefix/suffix for environment variables */
3170 #if defined (_WIN32)
3171 char __gnat_environment_char = '%';
3173 char __gnat_environment_char = '$';
3176 /* This functions copy the file attributes from a source file to a
3179 mode = 0 : In this mode copy only the file time stamps (last access and
3180 last modification time stamps).
3182 mode = 1 : In this mode, time stamps and read/write/execute attributes are
3185 Returns 0 if operation was successful and -1 in case of error. */
3188 __gnat_copy_attribs (char *from, char *to, int mode)
3190 #if defined (VMS) || defined (__vxworks) || defined (__nucleus__)
3194 struct utimbuf tbuf;
3196 if (stat (from, &fbuf) == -1)
3201 tbuf.actime = fbuf.st_atime;
3202 tbuf.modtime = fbuf.st_mtime;
3204 if (utime (to, &tbuf) == -1)
3211 if (chmod (to, fbuf.st_mode) == -1)
3222 __gnat_lseek (int fd, long offset, int whence)
3224 return (int) lseek (fd, offset, whence);
3227 /* This function returns the major version number of GCC being used. */
3229 get_gcc_version (void)
3234 return (int) (version_string[0] - '0');
3239 __gnat_set_close_on_exec (int fd ATTRIBUTE_UNUSED,
3240 int close_on_exec_p ATTRIBUTE_UNUSED)
3242 #if defined (F_GETFD) && defined (FD_CLOEXEC) && ! defined (__vxworks)
3243 int flags = fcntl (fd, F_GETFD, 0);
3246 if (close_on_exec_p)
3247 flags |= FD_CLOEXEC;
3249 flags &= ~FD_CLOEXEC;
3250 return fcntl (fd, F_SETFD, flags | FD_CLOEXEC);
3251 #elif defined(_WIN32)
3252 HANDLE h = (HANDLE) _get_osfhandle (fd);
3253 if (h == (HANDLE) -1)
3255 if (close_on_exec_p)
3256 return ! SetHandleInformation (h, HANDLE_FLAG_INHERIT, 0);
3257 return ! SetHandleInformation (h, HANDLE_FLAG_INHERIT,
3258 HANDLE_FLAG_INHERIT);
3260 /* TODO: Unimplemented. */
3265 /* Indicates if platforms supports automatic initialization through the
3266 constructor mechanism */
3268 __gnat_binder_supports_auto_init ()
3277 /* Indicates that Stand-Alone Libraries are automatically initialized through
3278 the constructor mechanism */
3280 __gnat_sals_init_using_constructors ()
3282 #if defined (__vxworks) || defined (__Lynx__) || defined (VMS)
3291 /* In RTX mode, the procedure to get the time (as file time) is different
3292 in RTSS mode and Win32 mode. In order to avoid duplicating an Ada file,
3293 we introduce an intermediate procedure to link against the corresponding
3294 one in each situation. */
3296 extern void GetTimeAsFileTime(LPFILETIME pTime);
3298 void GetTimeAsFileTime(LPFILETIME pTime)
3301 RtGetRtssTimeAsFileTime (pTime); /* RTSS interface */
3303 GetSystemTimeAsFileTime (pTime); /* w32 interface */
3308 /* Add symbol that is required to link. It would otherwise be taken from
3309 libgcc.a and it would try to use the gcc constructors that are not
3310 supported by Microsoft linker. */
3312 extern void __main (void);
3314 void __main (void) {}
3318 #if defined (linux) || defined(__GLIBC__)
3319 /* pthread affinity support */
3321 int __gnat_pthread_setaffinity_np (pthread_t th,
3323 const void *cpuset);
3326 #include <pthread.h>
3328 __gnat_pthread_setaffinity_np (pthread_t th,
3330 const cpu_set_t *cpuset)
3332 return pthread_setaffinity_np (th, cpusetsize, cpuset);
3336 __gnat_pthread_setaffinity_np (pthread_t th ATTRIBUTE_UNUSED,
3337 size_t cpusetsize ATTRIBUTE_UNUSED,
3338 const void *cpuset ATTRIBUTE_UNUSED)