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. */
2106 /* For the Cert run times on native Windows we use dummy functions
2107 for locking and unlocking tasks since we do not support multiple
2108 threads on this configuration (Cert run time on native Windows). */
2110 void dummy (void) {}
2112 void (*Lock_Task) () = &dummy;
2113 void (*Unlock_Task) () = &dummy;
2117 #define Lock_Task system__soft_links__lock_task
2118 extern void (*Lock_Task) (void);
2120 #define Unlock_Task system__soft_links__unlock_task
2121 extern void (*Unlock_Task) (void);
2125 typedef struct _process_list
2128 struct _process_list *next;
2131 static Process_List *PLIST = NULL;
2133 static int plist_length = 0;
2136 add_handle (HANDLE h)
2140 pl = (Process_List *) xmalloc (sizeof (Process_List));
2142 /* -------------------- critical section -------------------- */
2151 /* -------------------- critical section -------------------- */
2155 remove_handle (HANDLE h)
2158 Process_List *prev = NULL;
2160 /* -------------------- critical section -------------------- */
2171 prev->next = pl->next;
2185 /* -------------------- critical section -------------------- */
2189 win32_no_block_spawn (char *command, char *args[])
2193 PROCESS_INFORMATION PI;
2194 SECURITY_ATTRIBUTES SA;
2199 /* compute the total command line length */
2203 csize += strlen (args[k]) + 1;
2207 full_command = (char *) xmalloc (csize);
2210 SI.cb = sizeof (STARTUPINFO);
2211 SI.lpReserved = NULL;
2212 SI.lpReserved2 = NULL;
2213 SI.lpDesktop = NULL;
2217 SI.wShowWindow = SW_HIDE;
2219 /* Security attributes. */
2220 SA.nLength = sizeof (SECURITY_ATTRIBUTES);
2221 SA.bInheritHandle = TRUE;
2222 SA.lpSecurityDescriptor = NULL;
2224 /* Prepare the command string. */
2225 strcpy (full_command, command);
2226 strcat (full_command, " ");
2231 strcat (full_command, args[k]);
2232 strcat (full_command, " ");
2237 int wsize = csize * 2;
2238 TCHAR *wcommand = (TCHAR *) xmalloc (wsize);
2240 S2WSU (wcommand, full_command, wsize);
2242 free (full_command);
2244 result = CreateProcess
2245 (NULL, wcommand, &SA, NULL, TRUE,
2246 GetPriorityClass (GetCurrentProcess()), NULL, NULL, &SI, &PI);
2253 add_handle (PI.hProcess);
2254 CloseHandle (PI.hThread);
2255 return (int) PI.hProcess;
2262 win32_wait (int *status)
2272 if (plist_length == 0)
2280 /* -------------------- critical section -------------------- */
2283 hl_len = plist_length;
2285 hl = (HANDLE *) xmalloc (sizeof (HANDLE) * hl_len);
2295 /* -------------------- critical section -------------------- */
2297 res = WaitForMultipleObjects (hl_len, hl, FALSE, INFINITE);
2298 h = hl[res - WAIT_OBJECT_0];
2303 GetExitCodeProcess (h, &exitcode);
2306 *status = (int) exitcode;
2313 __gnat_portable_no_block_spawn (char *args[])
2317 #if defined (__vxworks) || defined (__nucleus__) || defined (RTX)
2320 #elif defined (__EMX__) || defined (MSDOS)
2322 /* ??? For PC machines I (Franco) don't know the system calls to implement
2323 this routine. So I'll fake it as follows. This routine will behave
2324 exactly like the blocking portable_spawn and will systematically return
2325 a pid of 0 unless the spawned task did not complete successfully, in
2326 which case we return a pid of -1. To synchronize with this the
2327 portable_wait below systematically returns a pid of 0 and reports that
2328 the subprocess terminated successfully. */
2330 if (spawnvp (P_WAIT, args[0], args) != 0)
2333 #elif defined (_WIN32)
2335 pid = win32_no_block_spawn (args[0], args);
2344 if (execv (args[0], MAYBE_TO_PTR32 (args)) != 0)
2346 return -1; /* execv is in parent context on VMS. */
2358 __gnat_portable_wait (int *process_status)
2363 #if defined (__vxworks) || defined (__nucleus__) || defined (RTX)
2364 /* Not sure what to do here, so do same as __EMX__ case, i.e., nothing but
2367 #elif defined (_WIN32)
2369 pid = win32_wait (&status);
2371 #elif defined (__EMX__) || defined (MSDOS)
2372 /* ??? See corresponding comment in portable_no_block_spawn. */
2376 pid = waitpid (-1, &status, 0);
2377 status = status & 0xffff;
2380 *process_status = status;
2385 __gnat_os_exit (int status)
2390 /* Locate a regular file, give a Path value. */
2393 __gnat_locate_regular_file (char *file_name, char *path_val)
2396 char *file_path = (char *) alloca (strlen (file_name) + 1);
2399 /* Return immediately if file_name is empty */
2401 if (*file_name == '\0')
2404 /* Remove quotes around file_name if present */
2410 strcpy (file_path, ptr);
2412 ptr = file_path + strlen (file_path) - 1;
2417 /* Handle absolute pathnames. */
2419 absolute = __gnat_is_absolute_path (file_path, strlen (file_name));
2423 if (__gnat_is_regular_file (file_path))
2424 return xstrdup (file_path);
2429 /* If file_name include directory separator(s), try it first as
2430 a path name relative to the current directory */
2431 for (ptr = file_name; *ptr && *ptr != '/' && *ptr != DIR_SEPARATOR; ptr++)
2436 if (__gnat_is_regular_file (file_name))
2437 return xstrdup (file_name);
2444 /* The result has to be smaller than path_val + file_name. */
2445 char *file_path = (char *) alloca (strlen (path_val) + strlen (file_name) + 2);
2449 for (; *path_val == PATH_SEPARATOR; path_val++)
2455 /* Skip the starting quote */
2457 if (*path_val == '"')
2460 for (ptr = file_path; *path_val && *path_val != PATH_SEPARATOR; )
2461 *ptr++ = *path_val++;
2465 /* Skip the ending quote */
2470 if (*ptr != '/' && *ptr != DIR_SEPARATOR)
2471 *++ptr = DIR_SEPARATOR;
2473 strcpy (++ptr, file_name);
2475 if (__gnat_is_regular_file (file_path))
2476 return xstrdup (file_path);
2483 /* Locate an executable given a Path argument. This routine is only used by
2484 gnatbl and should not be used otherwise. Use locate_exec_on_path
2488 __gnat_locate_exec (char *exec_name, char *path_val)
2491 if (!strstr (exec_name, HOST_EXECUTABLE_SUFFIX))
2493 char *full_exec_name
2494 = (char *) alloca (strlen (exec_name) + strlen (HOST_EXECUTABLE_SUFFIX) + 1);
2496 strcpy (full_exec_name, exec_name);
2497 strcat (full_exec_name, HOST_EXECUTABLE_SUFFIX);
2498 ptr = __gnat_locate_regular_file (full_exec_name, path_val);
2501 return __gnat_locate_regular_file (exec_name, path_val);
2505 return __gnat_locate_regular_file (exec_name, path_val);
2508 /* Locate an executable using the Systems default PATH. */
2511 __gnat_locate_exec_on_path (char *exec_name)
2515 #if defined (_WIN32) && !defined (RTX)
2516 TCHAR *wpath_val = _tgetenv (_T("PATH"));
2518 /* In Win32 systems we expand the PATH as for XP environment
2519 variables are not automatically expanded. We also prepend the
2520 ".;" to the path to match normal NT path search semantics */
2522 #define EXPAND_BUFFER_SIZE 32767
2524 wapath_val = alloca (EXPAND_BUFFER_SIZE);
2526 wapath_val [0] = '.';
2527 wapath_val [1] = ';';
2529 DWORD res = ExpandEnvironmentStrings
2530 (wpath_val, &wapath_val[2], EXPAND_BUFFER_SIZE - 2);
2532 if (!res) wapath_val [0] = _T('\0');
2534 apath_val = alloca (EXPAND_BUFFER_SIZE);
2536 WS2SU (apath_val, wapath_val, EXPAND_BUFFER_SIZE);
2537 return __gnat_locate_exec (exec_name, apath_val);
2542 char *path_val = "/VAXC$PATH";
2544 char *path_val = getenv ("PATH");
2546 if (path_val == NULL) return NULL;
2547 apath_val = (char *) alloca (strlen (path_val) + 1);
2548 strcpy (apath_val, path_val);
2549 return __gnat_locate_exec (exec_name, apath_val);
2555 /* These functions are used to translate to and from VMS and Unix syntax
2556 file, directory and path specifications. */
2559 #define MAXNAMES 256
2560 #define NEW_CANONICAL_FILELIST_INCREMENT 64
2562 static char new_canonical_dirspec [MAXPATH];
2563 static char new_canonical_filespec [MAXPATH];
2564 static char new_canonical_pathspec [MAXNAMES*MAXPATH];
2565 static unsigned new_canonical_filelist_index;
2566 static unsigned new_canonical_filelist_in_use;
2567 static unsigned new_canonical_filelist_allocated;
2568 static char **new_canonical_filelist;
2569 static char new_host_pathspec [MAXNAMES*MAXPATH];
2570 static char new_host_dirspec [MAXPATH];
2571 static char new_host_filespec [MAXPATH];
2573 /* Routine is called repeatedly by decc$from_vms via
2574 __gnat_to_canonical_file_list_init until it returns 0 or the expansion
2578 wildcard_translate_unix (char *name)
2581 char buff [MAXPATH];
2583 strncpy (buff, name, MAXPATH);
2584 buff [MAXPATH - 1] = (char) 0;
2585 ver = strrchr (buff, '.');
2587 /* Chop off the version. */
2591 /* Dynamically extend the allocation by the increment. */
2592 if (new_canonical_filelist_in_use == new_canonical_filelist_allocated)
2594 new_canonical_filelist_allocated += NEW_CANONICAL_FILELIST_INCREMENT;
2595 new_canonical_filelist = (char **) xrealloc
2596 (new_canonical_filelist,
2597 new_canonical_filelist_allocated * sizeof (char *));
2600 new_canonical_filelist[new_canonical_filelist_in_use++] = xstrdup (buff);
2605 /* Translate a wildcard VMS file spec into a list of Unix file specs. First do
2606 full translation and copy the results into a list (_init), then return them
2607 one at a time (_next). If onlydirs set, only expand directory files. */
2610 __gnat_to_canonical_file_list_init (char *filespec, int onlydirs)
2613 char buff [MAXPATH];
2615 len = strlen (filespec);
2616 strncpy (buff, filespec, MAXPATH);
2618 /* Only look for directories */
2619 if (onlydirs && !strstr (&buff [len-5], "*.dir"))
2620 strncat (buff, "*.dir", MAXPATH);
2622 buff [MAXPATH - 1] = (char) 0;
2624 decc$from_vms (buff, wildcard_translate_unix, 1);
2626 /* Remove the .dir extension. */
2632 for (i = 0; i < new_canonical_filelist_in_use; i++)
2634 ext = strstr (new_canonical_filelist[i], ".dir");
2640 return new_canonical_filelist_in_use;
2643 /* Return the next filespec in the list. */
2646 __gnat_to_canonical_file_list_next ()
2648 return new_canonical_filelist[new_canonical_filelist_index++];
2651 /* Free storage used in the wildcard expansion. */
2654 __gnat_to_canonical_file_list_free ()
2658 for (i = 0; i < new_canonical_filelist_in_use; i++)
2659 free (new_canonical_filelist[i]);
2661 free (new_canonical_filelist);
2663 new_canonical_filelist_in_use = 0;
2664 new_canonical_filelist_allocated = 0;
2665 new_canonical_filelist_index = 0;
2666 new_canonical_filelist = 0;
2669 /* The functional equivalent of decc$translate_vms routine.
2670 Designed to produce the same output, but is protected against
2671 malformed paths (original version ACCVIOs in this case) and
2672 does not require VMS-specific DECC RTL */
2674 #define NAM$C_MAXRSS 1024
2677 __gnat_translate_vms (char *src)
2679 static char retbuf [NAM$C_MAXRSS+1];
2680 char *srcendpos, *pos1, *pos2, *retpos;
2681 int disp, path_present = 0;
2683 if (!src) return NULL;
2685 srcendpos = strchr (src, '\0');
2688 /* Look for the node and/or device in front of the path */
2690 pos2 = strchr (pos1, ':');
2692 if (pos2 && (pos2 < srcendpos) && (*(pos2 + 1) == ':')) {
2693 /* There is a node name. "node_name::" becomes "node_name!" */
2695 strncpy (retbuf, pos1, disp);
2696 retpos [disp] = '!';
2697 retpos = retpos + disp + 1;
2699 pos2 = strchr (pos1, ':');
2703 /* There is a device name. "dev_name:" becomes "/dev_name/" */
2706 strncpy (retpos, pos1, disp);
2707 retpos = retpos + disp;
2712 /* No explicit device; we must look ahead and prepend /sys$disk/ if
2713 the path is absolute */
2714 if ((*pos1 == '[' || *pos1 == '<') && (pos1 < srcendpos)
2715 && !strchr (".-]>", *(pos1 + 1))) {
2716 strncpy (retpos, "/sys$disk/", 10);
2720 /* Process the path part */
2721 while (*pos1 == '[' || *pos1 == '<') {
2724 if (*pos1 == ']' || *pos1 == '>') {
2725 /* Special case, [] translates to '.' */
2730 /* '[000000' means root dir. It can be present in the middle of
2731 the path due to expansion of logical devices, in which case
2733 if (!strncmp (pos1, "000000", 6) && path_present > 1 &&
2734 (*(pos1 + 6) == ']' || *(pos1 + 6) == '>' || *(pos1 + 6) == '.')) {
2736 if (*pos1 == '.') pos1++;
2738 else if (*pos1 == '.') {
2743 /* There is a qualified path */
2744 while (*pos1 && *pos1 != ']' && *pos1 != '>') {
2747 /* '.' is used to separate directories. Replace it with '/' but
2748 only if there isn't already '/' just before */
2749 if (*(retpos - 1) != '/') *(retpos++) = '/';
2751 if (pos1 + 1 < srcendpos && *pos1 == '.' && *(pos1 + 1) == '.') {
2752 /* ellipsis refers to entire subtree; replace with '**' */
2753 *(retpos++) = '*'; *(retpos++) = '*'; *(retpos++) = '/';
2758 /* When after '.' '[' '<' is equivalent to Unix ".." but there
2759 may be several in a row */
2760 if (*(pos1 - 1) == '.' || *(pos1 - 1) == '[' ||
2761 *(pos1 - 1) == '<') {
2762 while (*pos1 == '-') {
2764 *(retpos++) = '.'; *(retpos++) = '.'; *(retpos++) = '/';
2769 /* otherwise fall through to default */
2771 *(retpos++) = *(pos1++);
2778 if (pos1 < srcendpos) {
2779 /* Now add the actual file name, until the version suffix if any */
2780 if (path_present) *(retpos++) = '/';
2781 pos2 = strchr (pos1, ';');
2782 disp = pos2? (pos2 - pos1) : (srcendpos - pos1);
2783 strncpy (retpos, pos1, disp);
2785 if (pos2 && pos2 < srcendpos) {
2786 /* There is a non-empty version suffix. ";<ver>" becomes ".<ver>" */
2788 disp = srcendpos - pos2 - 1;
2789 strncpy (retpos, pos2 + 1, disp);
2800 /* Translate a VMS syntax directory specification in to Unix syntax. If
2801 PREFIXFLAG is set, append an underscore "/". If no indicators of VMS syntax
2802 found, return input string. Also translate a dirname that contains no
2803 slashes, in case it's a logical name. */
2806 __gnat_to_canonical_dir_spec (char *dirspec, int prefixflag)
2810 strcpy (new_canonical_dirspec, "");
2811 if (strlen (dirspec))
2815 if (strchr (dirspec, ']') || strchr (dirspec, ':'))
2817 strncpy (new_canonical_dirspec,
2818 __gnat_translate_vms (dirspec),
2821 else if (!strchr (dirspec, '/') && (dirspec1 = getenv (dirspec)) != 0)
2823 strncpy (new_canonical_dirspec,
2824 __gnat_translate_vms (dirspec1),
2829 strncpy (new_canonical_dirspec, dirspec, MAXPATH);
2833 len = strlen (new_canonical_dirspec);
2834 if (prefixflag && new_canonical_dirspec [len-1] != '/')
2835 strncat (new_canonical_dirspec, "/", MAXPATH);
2837 new_canonical_dirspec [MAXPATH - 1] = (char) 0;
2839 return new_canonical_dirspec;
2843 /* Translate a VMS syntax file specification into Unix syntax.
2844 If no indicators of VMS syntax found, check if it's an uppercase
2845 alphanumeric_ name and if so try it out as an environment
2846 variable (logical name). If all else fails return the
2850 __gnat_to_canonical_file_spec (char *filespec)
2854 strncpy (new_canonical_filespec, "", MAXPATH);
2856 if (strchr (filespec, ']') || strchr (filespec, ':'))
2858 char *tspec = (char *) __gnat_translate_vms (filespec);
2860 if (tspec != (char *) -1)
2861 strncpy (new_canonical_filespec, tspec, MAXPATH);
2863 else if ((strlen (filespec) == strspn (filespec,
2864 "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_"))
2865 && (filespec1 = getenv (filespec)))
2867 char *tspec = (char *) __gnat_translate_vms (filespec1);
2869 if (tspec != (char *) -1)
2870 strncpy (new_canonical_filespec, tspec, MAXPATH);
2874 strncpy (new_canonical_filespec, filespec, MAXPATH);
2877 new_canonical_filespec [MAXPATH - 1] = (char) 0;
2879 return new_canonical_filespec;
2882 /* Translate a VMS syntax path specification into Unix syntax.
2883 If no indicators of VMS syntax found, return input string. */
2886 __gnat_to_canonical_path_spec (char *pathspec)
2888 char *curr, *next, buff [MAXPATH];
2893 /* If there are /'s, assume it's a Unix path spec and return. */
2894 if (strchr (pathspec, '/'))
2897 new_canonical_pathspec[0] = 0;
2902 next = strchr (curr, ',');
2904 next = strchr (curr, 0);
2906 strncpy (buff, curr, next - curr);
2907 buff[next - curr] = 0;
2909 /* Check for wildcards and expand if present. */
2910 if (strchr (buff, '*') || strchr (buff, '%') || strstr (buff, "..."))
2914 dirs = __gnat_to_canonical_file_list_init (buff, 1);
2915 for (i = 0; i < dirs; i++)
2919 next_dir = __gnat_to_canonical_file_list_next ();
2920 strncat (new_canonical_pathspec, next_dir, MAXPATH);
2922 /* Don't append the separator after the last expansion. */
2924 strncat (new_canonical_pathspec, ":", MAXPATH);
2927 __gnat_to_canonical_file_list_free ();
2930 strncat (new_canonical_pathspec,
2931 __gnat_to_canonical_dir_spec (buff, 0), MAXPATH);
2936 strncat (new_canonical_pathspec, ":", MAXPATH);
2940 new_canonical_pathspec [MAXPATH - 1] = (char) 0;
2942 return new_canonical_pathspec;
2945 static char filename_buff [MAXPATH];
2948 translate_unix (char *name, int type)
2950 strncpy (filename_buff, name, MAXPATH);
2951 filename_buff [MAXPATH - 1] = (char) 0;
2955 /* Translate a Unix syntax path spec into a VMS style (comma separated list of
2959 to_host_path_spec (char *pathspec)
2961 char *curr, *next, buff [MAXPATH];
2966 /* Can't very well test for colons, since that's the Unix separator! */
2967 if (strchr (pathspec, ']') || strchr (pathspec, ','))
2970 new_host_pathspec[0] = 0;
2975 next = strchr (curr, ':');
2977 next = strchr (curr, 0);
2979 strncpy (buff, curr, next - curr);
2980 buff[next - curr] = 0;
2982 strncat (new_host_pathspec, __gnat_to_host_dir_spec (buff, 0), MAXPATH);
2985 strncat (new_host_pathspec, ",", MAXPATH);
2989 new_host_pathspec [MAXPATH - 1] = (char) 0;
2991 return new_host_pathspec;
2994 /* Translate a Unix syntax directory specification into VMS syntax. The
2995 PREFIXFLAG has no effect, but is kept for symmetry with
2996 to_canonical_dir_spec. If indicators of VMS syntax found, return input
3000 __gnat_to_host_dir_spec (char *dirspec, int prefixflag ATTRIBUTE_UNUSED)
3002 int len = strlen (dirspec);
3004 strncpy (new_host_dirspec, dirspec, MAXPATH);
3005 new_host_dirspec [MAXPATH - 1] = (char) 0;
3007 if (strchr (new_host_dirspec, ']') || strchr (new_host_dirspec, ':'))
3008 return new_host_dirspec;
3010 while (len > 1 && new_host_dirspec[len - 1] == '/')
3012 new_host_dirspec[len - 1] = 0;
3016 decc$to_vms (new_host_dirspec, translate_unix, 1, 2);
3017 strncpy (new_host_dirspec, filename_buff, MAXPATH);
3018 new_host_dirspec [MAXPATH - 1] = (char) 0;
3020 return new_host_dirspec;
3023 /* Translate a Unix syntax file specification into VMS syntax.
3024 If indicators of VMS syntax found, return input string. */
3027 __gnat_to_host_file_spec (char *filespec)
3029 strncpy (new_host_filespec, "", MAXPATH);
3030 if (strchr (filespec, ']') || strchr (filespec, ':'))
3032 strncpy (new_host_filespec, filespec, MAXPATH);
3036 decc$to_vms (filespec, translate_unix, 1, 1);
3037 strncpy (new_host_filespec, filename_buff, MAXPATH);
3040 new_host_filespec [MAXPATH - 1] = (char) 0;
3042 return new_host_filespec;
3046 __gnat_adjust_os_resource_limits ()
3048 SYS$ADJWSL (131072, 0);
3053 /* Dummy functions for Osint import for non-VMS systems. */
3056 __gnat_to_canonical_file_list_init
3057 (char *dirspec ATTRIBUTE_UNUSED, int onlydirs ATTRIBUTE_UNUSED)
3063 __gnat_to_canonical_file_list_next (void)
3069 __gnat_to_canonical_file_list_free (void)
3074 __gnat_to_canonical_dir_spec (char *dirspec, int prefixflag ATTRIBUTE_UNUSED)
3080 __gnat_to_canonical_file_spec (char *filespec)
3086 __gnat_to_canonical_path_spec (char *pathspec)
3092 __gnat_to_host_dir_spec (char *dirspec, int prefixflag ATTRIBUTE_UNUSED)
3098 __gnat_to_host_file_spec (char *filespec)
3104 __gnat_adjust_os_resource_limits (void)
3110 /* For EMX, we cannot include dummy in libgcc, since it is too difficult
3111 to coordinate this with the EMX distribution. Consequently, we put the
3112 definition of dummy which is used for exception handling, here. */
3114 #if defined (__EMX__)
3118 #if defined (__mips_vxworks)
3122 CACHE_USER_FLUSH (0, ENTIRE_CACHE);
3126 #if defined (CROSS_DIRECTORY_STRUCTURE) \
3127 || (! ((defined (sparc) || defined (i386)) && defined (sun) \
3128 && defined (__SVR4)) \
3129 && ! (defined (linux) && (defined (i386) || defined (__x86_64__))) \
3130 && ! (defined (linux) && defined (__ia64__)) \
3131 && ! (defined (linux) && defined (powerpc)) \
3132 && ! defined (__FreeBSD__) \
3133 && ! defined (__hpux__) \
3134 && ! defined (__APPLE__) \
3135 && ! defined (_AIX) \
3136 && ! (defined (__alpha__) && defined (__osf__)) \
3137 && ! defined (VMS) \
3138 && ! defined (__MINGW32__) \
3139 && ! (defined (__mips) && defined (__sgi)))
3141 /* Dummy function to satisfy g-trasym.o. See the preprocessor conditional
3142 just above for a list of native platforms that provide a non-dummy
3143 version of this procedure in libaddr2line.a. */
3146 convert_addresses (const char *file_name ATTRIBUTE_UNUSED,
3147 void *addrs ATTRIBUTE_UNUSED,
3148 int n_addr ATTRIBUTE_UNUSED,
3149 void *buf ATTRIBUTE_UNUSED,
3150 int *len ATTRIBUTE_UNUSED)
3156 #if defined (_WIN32)
3157 int __gnat_argument_needs_quote = 1;
3159 int __gnat_argument_needs_quote = 0;
3162 /* This option is used to enable/disable object files handling from the
3163 binder file by the GNAT Project module. For example, this is disabled on
3164 Windows (prior to GCC 3.4) as it is already done by the mdll module.
3165 Stating with GCC 3.4 the shared libraries are not based on mdll
3166 anymore as it uses the GCC's -shared option */
3167 #if defined (_WIN32) \
3168 && ((__GNUC__ < 3) || ((__GNUC__ == 3) && (__GNUC_MINOR__ < 4)))
3169 int __gnat_prj_add_obj_files = 0;
3171 int __gnat_prj_add_obj_files = 1;
3174 /* char used as prefix/suffix for environment variables */
3175 #if defined (_WIN32)
3176 char __gnat_environment_char = '%';
3178 char __gnat_environment_char = '$';
3181 /* This functions copy the file attributes from a source file to a
3184 mode = 0 : In this mode copy only the file time stamps (last access and
3185 last modification time stamps).
3187 mode = 1 : In this mode, time stamps and read/write/execute attributes are
3190 Returns 0 if operation was successful and -1 in case of error. */
3193 __gnat_copy_attribs (char *from, char *to, int mode)
3195 #if defined (VMS) || defined (__vxworks) || defined (__nucleus__)
3199 struct utimbuf tbuf;
3201 if (stat (from, &fbuf) == -1)
3206 tbuf.actime = fbuf.st_atime;
3207 tbuf.modtime = fbuf.st_mtime;
3209 if (utime (to, &tbuf) == -1)
3216 if (chmod (to, fbuf.st_mode) == -1)
3227 __gnat_lseek (int fd, long offset, int whence)
3229 return (int) lseek (fd, offset, whence);
3232 /* This function returns the major version number of GCC being used. */
3234 get_gcc_version (void)
3239 return (int) (version_string[0] - '0');
3244 __gnat_set_close_on_exec (int fd ATTRIBUTE_UNUSED,
3245 int close_on_exec_p ATTRIBUTE_UNUSED)
3247 #if defined (F_GETFD) && defined (FD_CLOEXEC) && ! defined (__vxworks)
3248 int flags = fcntl (fd, F_GETFD, 0);
3251 if (close_on_exec_p)
3252 flags |= FD_CLOEXEC;
3254 flags &= ~FD_CLOEXEC;
3255 return fcntl (fd, F_SETFD, flags | FD_CLOEXEC);
3256 #elif defined(_WIN32)
3257 HANDLE h = (HANDLE) _get_osfhandle (fd);
3258 if (h == (HANDLE) -1)
3260 if (close_on_exec_p)
3261 return ! SetHandleInformation (h, HANDLE_FLAG_INHERIT, 0);
3262 return ! SetHandleInformation (h, HANDLE_FLAG_INHERIT,
3263 HANDLE_FLAG_INHERIT);
3265 /* TODO: Unimplemented. */
3270 /* Indicates if platforms supports automatic initialization through the
3271 constructor mechanism */
3273 __gnat_binder_supports_auto_init ()
3282 /* Indicates that Stand-Alone Libraries are automatically initialized through
3283 the constructor mechanism */
3285 __gnat_sals_init_using_constructors ()
3287 #if defined (__vxworks) || defined (__Lynx__) || defined (VMS)
3296 /* In RTX mode, the procedure to get the time (as file time) is different
3297 in RTSS mode and Win32 mode. In order to avoid duplicating an Ada file,
3298 we introduce an intermediate procedure to link against the corresponding
3299 one in each situation. */
3301 extern void GetTimeAsFileTime(LPFILETIME pTime);
3303 void GetTimeAsFileTime(LPFILETIME pTime)
3306 RtGetRtssTimeAsFileTime (pTime); /* RTSS interface */
3308 GetSystemTimeAsFileTime (pTime); /* w32 interface */
3313 /* Add symbol that is required to link. It would otherwise be taken from
3314 libgcc.a and it would try to use the gcc constructors that are not
3315 supported by Microsoft linker. */
3317 extern void __main (void);
3319 void __main (void) {}
3323 #if defined (linux) || defined(__GLIBC__)
3324 /* pthread affinity support */
3326 int __gnat_pthread_setaffinity_np (pthread_t th,
3328 const void *cpuset);
3331 #include <pthread.h>
3333 __gnat_pthread_setaffinity_np (pthread_t th,
3335 const cpu_set_t *cpuset)
3337 return pthread_setaffinity_np (th, cpusetsize, cpuset);
3341 __gnat_pthread_setaffinity_np (pthread_t th ATTRIBUTE_UNUSED,
3342 size_t cpusetsize ATTRIBUTE_UNUSED,
3343 const void *cpuset ATTRIBUTE_UNUSED)