1 /****************************************************************************
3 * GNAT COMPILER COMPONENTS *
7 * C Implementation File *
9 * Copyright (C) 1992-2014, Free Software Foundation, Inc. *
11 * GNAT is free software; you can redistribute it and/or modify it under *
12 * terms of the GNU General Public License as published by the Free Soft- *
13 * ware Foundation; either version 3, or (at your option) any later ver- *
14 * sion. GNAT is distributed in the hope that it will be useful, but WITH- *
15 * OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY *
16 * or FITNESS FOR A PARTICULAR PURPOSE. *
18 * As a special exception under Section 7 of GPL version 3, you are granted *
19 * additional permissions described in the GCC Runtime Library Exception, *
20 * version 3.1, as published by the Free Software Foundation. *
22 * You should have received a copy of the GNU General Public License and *
23 * a copy of the GCC Runtime Library Exception along with this program; *
24 * see the files COPYING3 and COPYING.RUNTIME respectively. If not, see *
25 * <http://www.gnu.org/licenses/>. *
27 * GNAT was originally developed by the GNAT team at New York University. *
28 * Extensive contributions were provided by Ada Core Technologies Inc. *
30 ****************************************************************************/
32 /* This file contains those routines named by Import pragmas in
33 packages in the GNAT hierarchy (especially GNAT.OS_Lib) and in
34 package Osint. Many of the subprograms in OS_Lib import standard
35 library calls directly. This file contains all other routines. */
37 /* Ensure accesses to errno are thread safe. */
43 /* No need to redefine exit here. */
46 /* We want to use the POSIX variants of include files. */
50 #if defined (__mips_vxworks)
52 #endif /* __mips_vxworks */
54 /* If SMP, access vxCpuConfiguredGet */
55 #ifdef _WRS_CONFIG_SMP
57 #endif /* _WRS_CONFIG_SMP */
59 /* We need to know the VxWorks version because some file operations
60 (such as chmod) are only available on VxWorks 6. */
65 #if defined (__APPLE__)
69 #if defined (__hpux__)
70 #include <sys/param.h>
71 #include <sys/pstat.h>
76 #define HOST_EXECUTABLE_SUFFIX ".exe"
77 #define HOST_OBJECT_SUFFIX ".obj"
81 #define __BSD_VISIBLE 1
94 #if defined (__vxworks) || defined (__ANDROID__)
95 /* S_IREAD and S_IWRITE are not defined in VxWorks or Android */
97 #define S_IREAD (S_IRUSR | S_IRGRP | S_IROTH)
101 #define S_IWRITE (S_IWUSR)
105 /* We don't have libiberty, so use malloc. */
106 #define xmalloc(S) malloc (S)
107 #define xrealloc(V,S) realloc (V,S)
118 #if defined (__MINGW32__)
126 /* Current code page to use, set in initialize.c. */
127 UINT CurrentCodePage
;
130 #include <sys/utime.h>
132 /* For isalpha-like tests in the compiler, we're expected to resort to
133 safe-ctype.h/ISALPHA. This isn't available for the runtime library
134 build, so we fallback on ctype.h/isalpha there. */
138 #define ISALPHA isalpha
141 #elif defined (__Lynx__)
143 /* Lynx utime.h only defines the entities of interest to us if
144 defined (VMOS_DEV), so ... */
153 /* wait.h processing */
156 # include <sys/wait.h>
158 #elif defined (__vxworks) && defined (__RTP__)
160 #elif defined (__Lynx__)
161 /* ??? We really need wait.h and it includes resource.h on Lynx. GCC
162 has a resource.h header as well, included instead of the lynx
163 version in our setup, causing lots of errors. We don't really need
164 the lynx contents of this file, so just workaround the issue by
165 preventing the inclusion of the GCC header from doing anything. */
166 # define GCC_RESOURCE_H
167 # include <sys/wait.h>
168 #elif defined (__nucleus__) || defined (__PikeOS__)
169 /* No wait() or waitpid() calls available. */
172 #include <sys/wait.h>
178 /* Header files and definitions for __gnat_set_file_time_name. */
180 #define __NEW_STARLET 1
182 #include <vms/atrdef.h>
183 #include <vms/fibdef.h>
184 #include <vms/stsdef.h>
185 #include <vms/iodef.h>
187 #include <vms/descrip.h>
191 /* Use native 64-bit arithmetic. */
192 #define unix_time_to_vms(X,Y) \
194 unsigned long long reftime, tmptime = (X); \
195 $DESCRIPTOR (unixtime,"1-JAN-1970 0:00:00.00"); \
196 SYS$BINTIM (&unixtime, &reftime); \
197 Y = tmptime * 10000000 + reftime; \
200 /* descrip.h doesn't have everything ... */
201 typedef struct fibdef
* __fibdef_ptr32
__attribute__ (( mode (SI
) ));
202 struct dsc$descriptor_fib
204 unsigned int fib$l_len
;
205 __fibdef_ptr32 fib$l_addr
;
208 /* I/O Status Block. */
211 unsigned short status
, count
;
215 static char *tryfile
;
217 /* Variable length string. */
221 char string
[NAM$C_MAXRSS
+1];
224 #define SYI$_ACTIVECPU_CNT 0x111e
225 extern int LIB$
GETSYI (int *, unsigned int *);
226 extern unsigned int LIB$
CALLG_64 (unsigned long long argument_list
[],
227 int (*user_procedure
)(void));
244 #define DIR_SEPARATOR '\\'
249 /* Define symbols O_BINARY and O_TEXT as harmless zeroes if they are not
250 defined in the current system. On DOS-like systems these flags control
251 whether the file is opened/created in text-translation mode (CR/LF in
252 external file mapped to LF in internal file), but in Unix-like systems,
253 no text translation is required, so these flags have no effect. */
263 #ifndef HOST_EXECUTABLE_SUFFIX
264 #define HOST_EXECUTABLE_SUFFIX ""
267 #ifndef HOST_OBJECT_SUFFIX
268 #define HOST_OBJECT_SUFFIX ".o"
271 #ifndef PATH_SEPARATOR
272 #define PATH_SEPARATOR ':'
275 #ifndef DIR_SEPARATOR
276 #define DIR_SEPARATOR '/'
279 /* Check for cross-compilation. */
280 #if defined (CROSS_COMPILE) || defined (CROSS_DIRECTORY_STRUCTURE)
282 int __gnat_is_cross_compiler
= 1;
285 int __gnat_is_cross_compiler
= 0;
288 char __gnat_dir_separator
= DIR_SEPARATOR
;
290 char __gnat_path_separator
= PATH_SEPARATOR
;
292 /* The GNAT_LIBRARY_TEMPLATE contains a list of expressions that define
293 the base filenames that libraries specified with -lsomelib options
294 may have. This is used by GNATMAKE to check whether an executable
295 is up-to-date or not. The syntax is
297 library_template ::= { pattern ; } pattern NUL
298 pattern ::= [ prefix ] * [ postfix ]
300 These should only specify names of static libraries as it makes
301 no sense to determine at link time if dynamic-link libraries are
302 up to date or not. Any libraries that are not found are supposed
305 * if they are needed but not present, the link
308 * otherwise they are libraries in the system paths and so
309 they are considered part of the system and not checked
312 ??? This should be part of a GNAT host-specific compiler
313 file instead of being included in all user applications
314 as well. This is only a temporary work-around for 3.11b. */
316 #ifndef GNAT_LIBRARY_TEMPLATE
318 #define GNAT_LIBRARY_TEMPLATE "*.olb"
320 #define GNAT_LIBRARY_TEMPLATE "lib*.a"
324 const char *__gnat_library_template
= GNAT_LIBRARY_TEMPLATE
;
326 /* This variable is used in hostparm.ads to say whether the host is a VMS
335 #define GNAT_MAX_PATH_LEN 256 /* PATH_MAX */
337 #elif defined (__vxworks) || defined (__OPENNT) || defined(__nucleus__)
338 #define GNAT_MAX_PATH_LEN PATH_MAX
342 #if defined (__MINGW32__)
346 #include <sys/param.h>
350 #include <sys/param.h>
354 #define GNAT_MAX_PATH_LEN MAXPATHLEN
356 #define GNAT_MAX_PATH_LEN 256
361 /* Used for runtime check that Ada constant File_Attributes_Size is no
362 less than the actual size of struct file_attributes (see Osint
364 int __gnat_size_of_file_attributes
= sizeof (struct file_attributes
);
366 void __gnat_stat_to_attr (int fd
, char* name
, struct file_attributes
* attr
);
368 /* The __gnat_max_path_len variable is used to export the maximum
369 length of a path name to Ada code. max_path_len is also provided
370 for compatibility with older GNAT versions, please do not use
373 int __gnat_max_path_len
= GNAT_MAX_PATH_LEN
;
374 int max_path_len
= GNAT_MAX_PATH_LEN
;
376 /* Control whether we can use ACL on Windows. */
378 int __gnat_use_acl
= 1;
380 /* The following macro HAVE_READDIR_R should be defined if the
381 system provides the routine readdir_r. */
382 #undef HAVE_READDIR_R
384 #if defined(VMS) && defined (__LONG_POINTERS)
386 /* Return a 32 bit pointer to an array of 32 bit pointers
387 given a 64 bit pointer to an array of 64 bit pointers */
389 typedef __char_ptr32
*__char_ptr_char_ptr32
__attribute__ ((mode (SI
)));
391 static __char_ptr_char_ptr32
392 to_ptr32 (char **ptr64
)
395 __char_ptr_char_ptr32 short_argv
;
397 for (argc
= 0; ptr64
[argc
]; argc
++)
400 /* Reallocate argv with 32 bit pointers. */
401 short_argv
= (__char_ptr_char_ptr32
) decc$malloc
402 (sizeof (__char_ptr32
) * (argc
+ 1));
404 for (argc
= 0; ptr64
[argc
]; argc
++)
405 short_argv
[argc
] = (__char_ptr32
) decc$
strdup (ptr64
[argc
]);
407 short_argv
[argc
] = (__char_ptr32
) 0;
411 #define MAYBE_TO_PTR32(argv) to_ptr32 (argv)
413 #define MAYBE_TO_PTR32(argv) argv
416 static const char ATTR_UNSET
= 127;
418 /* Reset the file attributes as if no system call had been performed */
421 __gnat_reset_attributes (struct file_attributes
* attr
)
423 attr
->exists
= ATTR_UNSET
;
424 attr
->error
= EINVAL
;
426 attr
->writable
= ATTR_UNSET
;
427 attr
->readable
= ATTR_UNSET
;
428 attr
->executable
= ATTR_UNSET
;
430 attr
->regular
= ATTR_UNSET
;
431 attr
->symbolic_link
= ATTR_UNSET
;
432 attr
->directory
= ATTR_UNSET
;
434 attr
->timestamp
= (OS_Time
)-2;
435 attr
->file_length
= -1;
439 __gnat_error_attributes (struct file_attributes
*attr
) {
444 __gnat_current_time (void)
446 time_t res
= time (NULL
);
447 return (OS_Time
) res
;
450 /* Return the current local time as a string in the ISO 8601 format of
451 "YYYY-MM-DD HH:MM:SS.SS". The returned string is 22 + 1 (NULL) characters
455 __gnat_current_time_string (char *result
)
457 const char *format
= "%Y-%m-%d %H:%M:%S";
458 /* Format string necessary to describe the ISO 8601 format */
460 const time_t t_val
= time (NULL
);
462 strftime (result
, 22, format
, localtime (&t_val
));
463 /* Convert the local time into a string following the ISO format, copying
464 at most 22 characters into the result string. */
469 /* The sub-seconds are manually set to zero since type time_t lacks the
470 precision necessary for nanoseconds. */
474 __gnat_to_gm_time (OS_Time
*p_time
, int *p_year
, int *p_month
, int *p_day
,
475 int *p_hours
, int *p_mins
, int *p_secs
)
478 time_t time
= (time_t) *p_time
;
481 /* On Windows systems, the time is sometimes rounded up to the nearest
482 even second, so if the number of seconds is odd, increment it. */
488 res
= localtime (&time
);
490 res
= gmtime (&time
);
495 *p_year
= res
->tm_year
;
496 *p_month
= res
->tm_mon
;
497 *p_day
= res
->tm_mday
;
498 *p_hours
= res
->tm_hour
;
499 *p_mins
= res
->tm_min
;
500 *p_secs
= res
->tm_sec
;
503 *p_year
= *p_month
= *p_day
= *p_hours
= *p_mins
= *p_secs
= 0;
506 /* Place the contents of the symbolic link named PATH in the buffer BUF,
507 which has size BUFSIZ. If PATH is a symbolic link, then return the number
508 of characters of its content in BUF. Otherwise, return -1.
509 For systems not supporting symbolic links, always return -1. */
512 __gnat_readlink (char *path ATTRIBUTE_UNUSED
,
513 char *buf ATTRIBUTE_UNUSED
,
514 size_t bufsiz ATTRIBUTE_UNUSED
)
516 #if defined (_WIN32) || defined (VMS) \
517 || defined(__vxworks) || defined (__nucleus__) || defined (__PikeOS__)
520 return readlink (path
, buf
, bufsiz
);
524 /* Creates a symbolic link named NEWPATH which contains the string OLDPATH.
525 If NEWPATH exists it will NOT be overwritten.
526 For systems not supporting symbolic links, always return -1. */
529 __gnat_symlink (char *oldpath ATTRIBUTE_UNUSED
,
530 char *newpath ATTRIBUTE_UNUSED
)
532 #if defined (_WIN32) || defined (VMS) \
533 || defined(__vxworks) || defined (__nucleus__) || defined (__PikeOS__)
536 return symlink (oldpath
, newpath
);
540 /* Try to lock a file, return 1 if success. */
542 #if defined (__vxworks) || defined (__nucleus__) \
543 || defined (_WIN32) || defined (VMS) || defined (__PikeOS__)
545 /* Version that does not use link. */
548 __gnat_try_lock (char *dir
, char *file
)
552 TCHAR wfull_path
[GNAT_MAX_PATH_LEN
];
553 TCHAR wfile
[GNAT_MAX_PATH_LEN
];
554 TCHAR wdir
[GNAT_MAX_PATH_LEN
];
556 S2WSC (wdir
, dir
, GNAT_MAX_PATH_LEN
);
557 S2WSC (wfile
, file
, GNAT_MAX_PATH_LEN
);
559 _stprintf (wfull_path
, _T("%s%c%s"), wdir
, _T(DIR_SEPARATOR
), wfile
);
560 fd
= _topen (wfull_path
, O_CREAT
| O_EXCL
, 0600);
564 sprintf (full_path
, "%s%c%s", dir
, DIR_SEPARATOR
, file
);
565 fd
= open (full_path
, O_CREAT
| O_EXCL
, 0600);
577 /* Version using link(), more secure over NFS. */
578 /* See TN 6913-016 for discussion ??? */
581 __gnat_try_lock (char *dir
, char *file
)
585 GNAT_STRUCT_STAT stat_result
;
588 sprintf (full_path
, "%s%c%s", dir
, DIR_SEPARATOR
, file
);
589 sprintf (temp_file
, "%s%cTMP-%ld-%ld",
590 dir
, DIR_SEPARATOR
, (long)getpid(), (long)getppid ());
592 /* Create the temporary file and write the process number. */
593 fd
= open (temp_file
, O_CREAT
| O_WRONLY
, 0600);
599 /* Link it with the new file. */
600 link (temp_file
, full_path
);
602 /* Count the references on the old one. If we have a count of two, then
603 the link did succeed. Remove the temporary file before returning. */
604 __gnat_stat (temp_file
, &stat_result
);
606 return stat_result
.st_nlink
== 2;
610 /* Return the maximum file name length. */
613 __gnat_get_maximum_file_name_length (void)
616 if (getenv ("GNAT$EXTENDED_FILE_SPECIFICATIONS"))
625 /* Return nonzero if file names are case sensitive. */
627 static int file_names_case_sensitive_cache
= -1;
630 __gnat_get_file_names_case_sensitive (void)
632 if (file_names_case_sensitive_cache
== -1)
634 const char *sensitive
= getenv ("GNAT_FILE_NAME_CASE_SENSITIVE");
636 if (sensitive
!= NULL
637 && (sensitive
[0] == '0' || sensitive
[0] == '1')
638 && sensitive
[1] == '\0')
639 file_names_case_sensitive_cache
= sensitive
[0] - '0';
641 #if defined (VMS) || defined (WINNT) || defined (__APPLE__)
642 file_names_case_sensitive_cache
= 0;
644 file_names_case_sensitive_cache
= 1;
647 return file_names_case_sensitive_cache
;
650 /* Return nonzero if environment variables are case sensitive. */
653 __gnat_get_env_vars_case_sensitive (void)
655 #if defined (VMS) || defined (WINNT)
663 __gnat_get_default_identifier_character_set (void)
668 /* Return the current working directory. */
671 __gnat_get_current_dir (char *dir
, int *length
)
673 #if defined (__MINGW32__)
674 TCHAR wdir
[GNAT_MAX_PATH_LEN
];
676 _tgetcwd (wdir
, *length
);
678 WS2SC (dir
, wdir
, GNAT_MAX_PATH_LEN
);
681 /* Force Unix style, which is what GNAT uses internally. */
682 getcwd (dir
, *length
, 0);
684 getcwd (dir
, *length
);
687 *length
= strlen (dir
);
689 if (dir
[*length
- 1] != DIR_SEPARATOR
)
691 dir
[*length
] = DIR_SEPARATOR
;
697 /* Return the suffix for object files. */
700 __gnat_get_object_suffix_ptr (int *len
, const char **value
)
702 *value
= HOST_OBJECT_SUFFIX
;
707 *len
= strlen (*value
);
712 /* Return the suffix for executable files. */
715 __gnat_get_executable_suffix_ptr (int *len
, const char **value
)
717 *value
= HOST_EXECUTABLE_SUFFIX
;
721 *len
= strlen (*value
);
726 /* Return the suffix for debuggable files. Usually this is the same as the
727 executable extension. */
730 __gnat_get_debuggable_suffix_ptr (int *len
, const char **value
)
732 *value
= HOST_EXECUTABLE_SUFFIX
;
737 *len
= strlen (*value
);
742 /* Returns the OS filename and corresponding encoding. */
745 __gnat_os_filename (char *filename ATTRIBUTE_UNUSED
,
746 char *w_filename ATTRIBUTE_UNUSED
,
747 char *os_name
, int *o_length
,
748 char *encoding ATTRIBUTE_UNUSED
, int *e_length
)
750 #if defined (_WIN32) && ! defined (__vxworks) && ! defined (IS_CROSS)
751 WS2SC (os_name
, (TCHAR
*)w_filename
, (DWORD
)*o_length
);
752 *o_length
= strlen (os_name
);
753 strcpy (encoding
, "encoding=utf8");
754 *e_length
= strlen (encoding
);
756 strcpy (os_name
, filename
);
757 *o_length
= strlen (filename
);
765 __gnat_unlink (char *path
)
767 #if defined (__MINGW32__) && ! defined (__vxworks) && ! defined (IS_CROSS)
769 TCHAR wpath
[GNAT_MAX_PATH_LEN
];
771 S2WSC (wpath
, path
, GNAT_MAX_PATH_LEN
);
772 return _tunlink (wpath
);
775 return unlink (path
);
782 __gnat_rename (char *from
, char *to
)
784 #if defined (__MINGW32__) && ! defined (__vxworks) && ! defined (IS_CROSS)
786 TCHAR wfrom
[GNAT_MAX_PATH_LEN
], wto
[GNAT_MAX_PATH_LEN
];
788 S2WSC (wfrom
, from
, GNAT_MAX_PATH_LEN
);
789 S2WSC (wto
, to
, GNAT_MAX_PATH_LEN
);
790 return _trename (wfrom
, wto
);
793 return rename (from
, to
);
797 /* Changing directory. */
800 __gnat_chdir (char *path
)
802 #if defined (__MINGW32__) && ! defined (__vxworks) && ! defined (IS_CROSS)
804 TCHAR wpath
[GNAT_MAX_PATH_LEN
];
806 S2WSC (wpath
, path
, GNAT_MAX_PATH_LEN
);
807 return _tchdir (wpath
);
814 /* Removing a directory. */
817 __gnat_rmdir (char *path
)
819 #if defined (__MINGW32__) && ! defined (__vxworks) && ! defined (IS_CROSS)
821 TCHAR wpath
[GNAT_MAX_PATH_LEN
];
823 S2WSC (wpath
, path
, GNAT_MAX_PATH_LEN
);
824 return _trmdir (wpath
);
826 #elif defined (VTHREADS)
827 /* rmdir not available */
835 __gnat_fopen (char *path
, char *mode
, int encoding ATTRIBUTE_UNUSED
,
836 char *vms_form ATTRIBUTE_UNUSED
)
838 #if defined (_WIN32) && ! defined (__vxworks) && ! defined (IS_CROSS)
839 TCHAR wpath
[GNAT_MAX_PATH_LEN
];
842 S2WS (wmode
, mode
, 10);
844 if (encoding
== Encoding_Unspecified
)
845 S2WSC (wpath
, path
, GNAT_MAX_PATH_LEN
);
846 else if (encoding
== Encoding_UTF8
)
847 S2WSU (wpath
, path
, GNAT_MAX_PATH_LEN
);
849 S2WS (wpath
, path
, GNAT_MAX_PATH_LEN
);
851 return _tfopen (wpath
, wmode
);
854 return decc$
fopen (path
, mode
);
857 char *local_form
= (char *) alloca (strlen (vms_form
) + 1);
858 /* Allocate an argument list of guaranteed ample length. */
859 unsigned long long *arg_list
=
860 (unsigned long long *) alloca (strlen (vms_form
) + 3);
864 arg_list
[1] = (unsigned long long) path
;
865 arg_list
[2] = (unsigned long long) mode
;
866 strcpy (local_form
, vms_form
);
868 /* Given a string such as "\"rfm=udf\",\"rat=cr\""
869 Split it into an argument list as "rfm=udf","rat=cr". */
871 for (i
= 0; *ptrb
; i
++)
873 ptrb
= strchr (ptrb
, '"');
874 ptre
= strchr (ptrb
+ 1, '"');
876 arg_list
[i
+ 3] = (unsigned long long) (ptrb
+ 1);
879 arg_list
[0] = i
+ 2;
880 /* CALLG_64 returns int , fortunately (FILE *) on VMS is a
881 always a 32bit pointer. */
882 return LIB$
CALLG_64 (arg_list
, &decc$fopen
);
885 return GNAT_FOPEN (path
, mode
);
890 __gnat_freopen (char *path
,
893 int encoding ATTRIBUTE_UNUSED
,
894 char *vms_form ATTRIBUTE_UNUSED
)
896 #if defined (_WIN32) && ! defined (__vxworks) && ! defined (IS_CROSS)
897 TCHAR wpath
[GNAT_MAX_PATH_LEN
];
900 S2WS (wmode
, mode
, 10);
902 if (encoding
== Encoding_Unspecified
)
903 S2WSC (wpath
, path
, GNAT_MAX_PATH_LEN
);
904 else if (encoding
== Encoding_UTF8
)
905 S2WSU (wpath
, path
, GNAT_MAX_PATH_LEN
);
907 S2WS (wpath
, path
, GNAT_MAX_PATH_LEN
);
909 return _tfreopen (wpath
, wmode
, stream
);
912 return decc$
freopen (path
, mode
, stream
);
915 char *local_form
= (char *) alloca (strlen (vms_form
) + 1);
916 /* Allocate an argument list of guaranteed ample length. */
917 unsigned long long *arg_list
=
918 (unsigned long long *) alloca (strlen (vms_form
) + 4);
922 arg_list
[1] = (unsigned long long) path
;
923 arg_list
[2] = (unsigned long long) mode
;
924 arg_list
[3] = (unsigned long long) stream
;
925 strcpy (local_form
, vms_form
);
927 /* Given a string such as "\"rfm=udf\",\"rat=cr\""
928 Split it into an argument list as "rfm=udf","rat=cr". */
930 for (i
= 0; *ptrb
; i
++)
932 ptrb
= strchr (ptrb
, '"');
933 ptre
= strchr (ptrb
+ 1, '"');
935 arg_list
[i
+ 4] = (unsigned long long) (ptrb
+ 1);
938 arg_list
[0] = i
+ 3;
939 /* CALLG_64 returns int , fortunately (FILE *) on VMS is a
940 always a 32bit pointer. */
941 return LIB$
CALLG_64 (arg_list
, &decc$freopen
);
944 return freopen (path
, mode
, stream
);
949 __gnat_open_read (char *path
, int fmode
)
952 int o_fmode
= O_BINARY
;
958 /* Optional arguments mbc,deq,fop increase read performance. */
959 fd
= open (path
, O_RDONLY
| o_fmode
, 0444,
960 "mbc=16", "deq=64", "fop=tef");
961 #elif defined (__vxworks)
962 fd
= open (path
, O_RDONLY
| o_fmode
, 0444);
963 #elif defined (__MINGW32__)
965 TCHAR wpath
[GNAT_MAX_PATH_LEN
];
967 S2WSC (wpath
, path
, GNAT_MAX_PATH_LEN
);
968 fd
= _topen (wpath
, O_RDONLY
| o_fmode
, 0444);
971 fd
= open (path
, O_RDONLY
| o_fmode
);
974 return fd
< 0 ? -1 : fd
;
977 #if defined (__MINGW32__)
978 #define PERM (S_IREAD | S_IWRITE)
980 /* Excerpt from DECC C RTL Reference Manual:
981 To create files with OpenVMS RMS default protections using the UNIX
982 system-call functions umask, mkdir, creat, and open, call mkdir, creat,
983 and open with a file-protection mode argument of 0777 in a program
984 that never specifically calls umask. These default protections include
985 correctly establishing protections based on ACLs, previous versions of
989 #define PERM (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH)
993 __gnat_open_rw (char *path
, int fmode
)
996 int o_fmode
= O_BINARY
;
1002 fd
= open (path
, O_RDWR
| o_fmode
, PERM
,
1003 "mbc=16", "deq=64", "fop=tef");
1004 #elif defined (__MINGW32__)
1006 TCHAR wpath
[GNAT_MAX_PATH_LEN
];
1008 S2WSC (wpath
, path
, GNAT_MAX_PATH_LEN
);
1009 fd
= _topen (wpath
, O_RDWR
| o_fmode
, PERM
);
1012 fd
= open (path
, O_RDWR
| o_fmode
, PERM
);
1015 return fd
< 0 ? -1 : fd
;
1019 __gnat_open_create (char *path
, int fmode
)
1022 int o_fmode
= O_BINARY
;
1028 fd
= open (path
, O_WRONLY
| O_CREAT
| O_TRUNC
| o_fmode
, PERM
,
1029 "mbc=16", "deq=64", "fop=tef");
1030 #elif defined (__MINGW32__)
1032 TCHAR wpath
[GNAT_MAX_PATH_LEN
];
1034 S2WSC (wpath
, path
, GNAT_MAX_PATH_LEN
);
1035 fd
= _topen (wpath
, O_WRONLY
| O_CREAT
| O_TRUNC
| o_fmode
, PERM
);
1038 fd
= open (path
, O_WRONLY
| O_CREAT
| O_TRUNC
| o_fmode
, PERM
);
1041 return fd
< 0 ? -1 : fd
;
1045 __gnat_create_output_file (char *path
)
1049 fd
= open (path
, O_WRONLY
| O_CREAT
| O_TRUNC
| O_TEXT
, PERM
,
1050 "rfm=stmlf", "ctx=rec", "rat=none", "rop=nlk",
1051 "shr=del,get,put,upd");
1052 #elif defined (__MINGW32__)
1054 TCHAR wpath
[GNAT_MAX_PATH_LEN
];
1056 S2WSC (wpath
, path
, GNAT_MAX_PATH_LEN
);
1057 fd
= _topen (wpath
, O_WRONLY
| O_CREAT
| O_TRUNC
| O_TEXT
, PERM
);
1060 fd
= open (path
, O_WRONLY
| O_CREAT
| O_TRUNC
| O_TEXT
, PERM
);
1063 return fd
< 0 ? -1 : fd
;
1067 __gnat_create_output_file_new (char *path
)
1071 fd
= open (path
, O_WRONLY
| O_CREAT
| O_TRUNC
| O_TEXT
| O_EXCL
, PERM
,
1072 "rfm=stmlf", "ctx=rec", "rat=none", "rop=nlk",
1073 "shr=del,get,put,upd");
1074 #elif defined (__MINGW32__)
1076 TCHAR wpath
[GNAT_MAX_PATH_LEN
];
1078 S2WSC (wpath
, path
, GNAT_MAX_PATH_LEN
);
1079 fd
= _topen (wpath
, O_WRONLY
| O_CREAT
| O_TRUNC
| O_TEXT
| O_EXCL
, PERM
);
1082 fd
= open (path
, O_WRONLY
| O_CREAT
| O_TRUNC
| O_TEXT
| O_EXCL
, PERM
);
1085 return fd
< 0 ? -1 : fd
;
1089 __gnat_open_append (char *path
, int fmode
)
1092 int o_fmode
= O_BINARY
;
1098 fd
= open (path
, O_WRONLY
| O_CREAT
| O_APPEND
| o_fmode
, PERM
,
1099 "mbc=16", "deq=64", "fop=tef");
1100 #elif defined (__MINGW32__)
1102 TCHAR wpath
[GNAT_MAX_PATH_LEN
];
1104 S2WSC (wpath
, path
, GNAT_MAX_PATH_LEN
);
1105 fd
= _topen (wpath
, O_WRONLY
| O_CREAT
| O_APPEND
| o_fmode
, PERM
);
1108 fd
= open (path
, O_WRONLY
| O_CREAT
| O_APPEND
| o_fmode
, PERM
);
1111 return fd
< 0 ? -1 : fd
;
1114 /* Open a new file. Return error (-1) if the file already exists. */
1117 __gnat_open_new (char *path
, int fmode
)
1120 int o_fmode
= O_BINARY
;
1126 fd
= open (path
, O_WRONLY
| O_CREAT
| O_EXCL
| o_fmode
, PERM
,
1127 "mbc=16", "deq=64", "fop=tef");
1128 #elif defined (__MINGW32__)
1130 TCHAR wpath
[GNAT_MAX_PATH_LEN
];
1132 S2WSC (wpath
, path
, GNAT_MAX_PATH_LEN
);
1133 fd
= _topen (wpath
, O_WRONLY
| O_CREAT
| O_EXCL
| o_fmode
, PERM
);
1136 fd
= open (path
, O_WRONLY
| O_CREAT
| O_EXCL
| o_fmode
, PERM
);
1139 return fd
< 0 ? -1 : fd
;
1142 /* Open a new temp file. Return error (-1) if the file already exists.
1143 Special options for VMS allow the file to be shared between parent and child
1144 processes, however they really slow down output. Used in gnatchop. */
1147 __gnat_open_new_temp (char *path
, int fmode
)
1150 int o_fmode
= O_BINARY
;
1152 strcpy (path
, "GNAT-XXXXXX");
1154 #if (defined (__FreeBSD__) || defined (__NetBSD__) || defined (__OpenBSD__) \
1155 || defined (linux) || defined(__GLIBC__)) && !defined (__vxworks)
1156 return mkstemp (path
);
1157 #elif defined (__Lynx__)
1159 #elif defined (__nucleus__)
1162 if (mktemp (path
) == NULL
)
1170 /* Passing rfm=stmlf for binary files seems questionable since it results
1171 in having an extraneous line feed added after every call to CRTL write,
1172 so pass rfm=udf (aka undefined) instead. */
1173 fd
= open (path
, O_WRONLY
| O_CREAT
| O_EXCL
| o_fmode
, PERM
,
1174 fmode
? "rfm=stmlf" : "rfm=udf", "ctx=rec", "rat=none",
1175 "shr=del,get,put,upd", "mbc=16", "deq=64", "fop=tef");
1177 fd
= open (path
, O_WRONLY
| O_CREAT
| O_EXCL
| o_fmode
, PERM
);
1180 return fd
< 0 ? -1 : fd
;
1183 /****************************************************************
1184 ** Perform a call to GNAT_STAT or GNAT_FSTAT, and extract as much information
1185 ** as possible from it, storing the result in a cache for later reuse
1186 ****************************************************************/
1189 __gnat_stat_to_attr (int fd
, char* name
, struct file_attributes
* attr
)
1191 GNAT_STRUCT_STAT statbuf
;
1195 /* GNAT_FSTAT returns -1 and sets errno for failure */
1196 ret
= GNAT_FSTAT (fd
, &statbuf
);
1197 error
= ret
? errno
: 0;
1200 /* __gnat_stat returns errno value directly */
1201 error
= __gnat_stat (name
, &statbuf
);
1202 ret
= error
? -1 : 0;
1206 * A missing file is reported as an attr structure with error == 0 and
1210 if (error
== 0 || error
== ENOENT
)
1213 attr
->error
= error
;
1215 attr
->regular
= (!ret
&& S_ISREG (statbuf
.st_mode
));
1216 attr
->directory
= (!ret
&& S_ISDIR (statbuf
.st_mode
));
1219 attr
->file_length
= 0;
1221 /* st_size may be 32 bits, or 64 bits which is converted to long. We
1222 don't return a useful value for files larger than 2 gigabytes in
1224 attr
->file_length
= statbuf
.st_size
; /* all systems */
1226 attr
->exists
= !ret
;
1228 #if !defined (_WIN32) || defined (RTX)
1229 /* on Windows requires extra system call, see __gnat_is_readable_file_attr */
1230 attr
->readable
= (!ret
&& (statbuf
.st_mode
& S_IRUSR
));
1231 attr
->writable
= (!ret
&& (statbuf
.st_mode
& S_IWUSR
));
1232 attr
->executable
= (!ret
&& (statbuf
.st_mode
& S_IXUSR
));
1236 attr
->timestamp
= (OS_Time
)-1;
1239 /* VMS has file versioning. */
1240 attr
->timestamp
= (OS_Time
)statbuf
.st_ctime
;
1242 attr
->timestamp
= (OS_Time
)statbuf
.st_mtime
;
1247 /****************************************************************
1248 ** Return the number of bytes in the specified file
1249 ****************************************************************/
1252 __gnat_file_length_attr (int fd
, char* name
, struct file_attributes
* attr
)
1254 if (attr
->file_length
== -1) {
1255 __gnat_stat_to_attr (fd
, name
, attr
);
1258 return attr
->file_length
;
1262 __gnat_file_length (int fd
)
1264 struct file_attributes attr
;
1265 __gnat_reset_attributes (&attr
);
1266 return __gnat_file_length_attr (fd
, NULL
, &attr
);
1270 __gnat_named_file_length (char *name
)
1272 struct file_attributes attr
;
1273 __gnat_reset_attributes (&attr
);
1274 return __gnat_file_length_attr (-1, name
, &attr
);
1277 /* Create a temporary filename and put it in string pointed to by
1281 __gnat_tmp_name (char *tmp_filename
)
1284 /* Variable used to create a series of unique names */
1285 static int counter
= 0;
1287 /* RTX in RTSS mode does not support tempnam nor tmpnam so we emulate it */
1288 strcpy (tmp_filename
, "c:\\WINDOWS\\Temp\\gnat-");
1289 sprintf (&tmp_filename
[strlen (tmp_filename
)], "%d\0", counter
++);
1291 #elif defined (__MINGW32__)
1296 /* tempnam tries to create a temporary file in directory pointed to by
1297 TMP environment variable, in c:\temp if TMP is not set, and in
1298 directory specified by P_tmpdir in stdio.h if c:\temp does not
1299 exist. The filename will be created with the prefix "gnat-". */
1301 sprintf (prefix
, "gnat-%d-", (int)getpid());
1302 pname
= (char *) _tempnam ("c:\\temp", prefix
);
1304 /* if pname is NULL, the file was not created properly, the disk is full
1305 or there is no more free temporary files */
1308 *tmp_filename
= '\0';
1310 /* If pname start with a back slash and not path information it means that
1311 the filename is valid for the current working directory. */
1313 else if (pname
[0] == '\\')
1315 strcpy (tmp_filename
, ".\\");
1316 strcat (tmp_filename
, pname
+1);
1319 strcpy (tmp_filename
, pname
);
1324 #elif defined (linux) || defined (__FreeBSD__) || defined (__NetBSD__) \
1325 || defined (__OpenBSD__) || defined(__GLIBC__)
1326 #define MAX_SAFE_PATH 1000
1327 char *tmpdir
= getenv ("TMPDIR");
1329 /* If tmpdir is longer than MAX_SAFE_PATH, revert to default value to avoid
1330 a buffer overflow. */
1331 if (tmpdir
== NULL
|| strlen (tmpdir
) > MAX_SAFE_PATH
)
1332 strcpy (tmp_filename
, "/tmp/gnat-XXXXXX");
1334 sprintf (tmp_filename
, "%s/gnat-XXXXXX", tmpdir
);
1336 close (mkstemp(tmp_filename
));
1337 #elif defined (__vxworks) && !(defined (__RTP__) || defined (VTHREADS))
1341 static ushort_t seed
= 0; /* used to generate unique name */
1343 /* generate unique name */
1344 strcpy (tmp_filename
, "tmp");
1346 /* fill up the name buffer from the last position */
1348 pos
= tmp_filename
+ strlen (tmp_filename
) + index
;
1352 for (t
= seed
; 0 <= --index
; t
>>= 3)
1353 *--pos
= '0' + (t
& 07);
1355 tmpnam (tmp_filename
);
1359 /* Open directory and returns a DIR pointer. */
1361 DIR* __gnat_opendir (char *name
)
1364 /* Not supported in RTX */
1368 #elif defined (__MINGW32__)
1369 TCHAR wname
[GNAT_MAX_PATH_LEN
];
1371 S2WSC (wname
, name
, GNAT_MAX_PATH_LEN
);
1372 return (DIR*)_topendir (wname
);
1375 return opendir (name
);
1379 /* Read the next entry in a directory. The returned string points somewhere
1383 __gnat_readdir (DIR *dirp
, char *buffer
, int *len
)
1386 /* Not supported in RTX */
1390 #elif defined (__MINGW32__)
1391 struct _tdirent
*dirent
= _treaddir ((_TDIR
*)dirp
);
1395 WS2SC (buffer
, dirent
->d_name
, GNAT_MAX_PATH_LEN
);
1396 *len
= strlen (buffer
);
1403 #elif defined (HAVE_READDIR_R)
1404 /* If possible, try to use the thread-safe version. */
1405 if (readdir_r (dirp
, buffer
) != NULL
)
1407 *len
= strlen (((struct dirent
*) buffer
)->d_name
);
1408 return ((struct dirent
*) buffer
)->d_name
;
1414 struct dirent
*dirent
= (struct dirent
*) readdir (dirp
);
1418 strcpy (buffer
, dirent
->d_name
);
1419 *len
= strlen (buffer
);
1428 /* Close a directory entry. */
1430 int __gnat_closedir (DIR *dirp
)
1433 /* Not supported in RTX */
1437 #elif defined (__MINGW32__)
1438 return _tclosedir ((_TDIR
*)dirp
);
1441 return closedir (dirp
);
1445 /* Returns 1 if readdir is thread safe, 0 otherwise. */
1448 __gnat_readdir_is_thread_safe (void)
1450 #ifdef HAVE_READDIR_R
1457 #if defined (_WIN32) && !defined (RTX)
1458 /* Number of seconds between <Jan 1st 1601> and <Jan 1st 1970>. */
1459 static const unsigned long long w32_epoch_offset
= 11644473600ULL;
1461 /* Returns the file modification timestamp using Win32 routines which are
1462 immune against daylight saving time change. It is in fact not possible to
1463 use fstat for this purpose as the DST modify the st_mtime field of the
1467 win32_filetime (HANDLE h
)
1472 unsigned long long ull_time
;
1475 /* GetFileTime returns FILETIME data which are the number of 100 nanosecs
1476 since <Jan 1st 1601>. This function must return the number of seconds
1477 since <Jan 1st 1970>. */
1479 if (GetFileTime (h
, NULL
, NULL
, &t_write
.ft_time
))
1480 return (time_t) (t_write
.ull_time
/ 10000000ULL - w32_epoch_offset
);
1484 /* As above but starting from a FILETIME. */
1486 f2t (const FILETIME
*ft
, time_t *t
)
1491 unsigned long long ull_time
;
1494 t_write
.ft_time
= *ft
;
1495 *t
= (time_t) (t_write
.ull_time
/ 10000000ULL - w32_epoch_offset
);
1499 /* Return a GNAT time stamp given a file name. */
1502 __gnat_file_time_name_attr (char* name
, struct file_attributes
* attr
)
1504 if (attr
->timestamp
== (OS_Time
)-2) {
1505 #if defined (_WIN32) && !defined (RTX)
1507 WIN32_FILE_ATTRIBUTE_DATA fad
;
1509 TCHAR wname
[GNAT_MAX_PATH_LEN
];
1510 S2WSC (wname
, name
, GNAT_MAX_PATH_LEN
);
1512 if ((res
= GetFileAttributesEx (wname
, GetFileExInfoStandard
, &fad
)))
1513 f2t (&fad
.ftLastWriteTime
, &ret
);
1514 attr
->timestamp
= (OS_Time
) ret
;
1516 __gnat_stat_to_attr (-1, name
, attr
);
1519 return attr
->timestamp
;
1523 __gnat_file_time_name (char *name
)
1525 struct file_attributes attr
;
1526 __gnat_reset_attributes (&attr
);
1527 return __gnat_file_time_name_attr (name
, &attr
);
1530 /* Return a GNAT time stamp given a file descriptor. */
1533 __gnat_file_time_fd_attr (int fd
, struct file_attributes
* attr
)
1535 if (attr
->timestamp
== (OS_Time
)-2) {
1536 #if defined (_WIN32) && !defined (RTX)
1537 HANDLE h
= (HANDLE
) _get_osfhandle (fd
);
1538 time_t ret
= win32_filetime (h
);
1539 attr
->timestamp
= (OS_Time
) ret
;
1542 __gnat_stat_to_attr (fd
, NULL
, attr
);
1546 return attr
->timestamp
;
1550 __gnat_file_time_fd (int fd
)
1552 struct file_attributes attr
;
1553 __gnat_reset_attributes (&attr
);
1554 return __gnat_file_time_fd_attr (fd
, &attr
);
1557 /* Set the file time stamp. */
1560 __gnat_set_file_time_name (char *name
, time_t time_stamp
)
1562 #if defined (__vxworks)
1564 /* Code to implement __gnat_set_file_time_name for these systems. */
1566 #elif defined (_WIN32) && !defined (RTX)
1570 unsigned long long ull_time
;
1572 TCHAR wname
[GNAT_MAX_PATH_LEN
];
1574 S2WSC (wname
, name
, GNAT_MAX_PATH_LEN
);
1576 HANDLE h
= CreateFile
1577 (wname
, GENERIC_WRITE
, FILE_SHARE_WRITE
, NULL
,
1578 OPEN_EXISTING
, FILE_FLAG_BACKUP_SEMANTICS
,
1580 if (h
== INVALID_HANDLE_VALUE
)
1582 /* Add number of seconds between <Jan 1st 1601> and <Jan 1st 1970> */
1583 t_write
.ull_time
= ((unsigned long long)time_stamp
+ w32_epoch_offset
);
1584 /* Convert to 100 nanosecond units */
1585 t_write
.ull_time
*= 10000000ULL;
1587 SetFileTime(h
, NULL
, NULL
, &t_write
.ft_time
);
1597 unsigned long long backup
, create
, expire
, revise
;
1601 unsigned short value
;
1604 unsigned system
: 4;
1610 } Fat
= { 0, 0, 0, 0, 0, { 0 }};
1614 { ATR$S_CREDATE
, ATR$C_CREDATE
, &Fat
.create
},
1615 { ATR$S_REVDATE
, ATR$C_REVDATE
, &Fat
.revise
},
1616 { ATR$S_EXPDATE
, ATR$C_EXPDATE
, &Fat
.expire
},
1617 { ATR$S_BAKDATE
, ATR$C_BAKDATE
, &Fat
.backup
},
1618 { ATR$S_FPRO
, ATR$C_FPRO
, &Fat
.prot
},
1619 { ATR$S_UIC
, ATR$C_UIC
, &Fat
.uic
},
1624 struct dsc$descriptor_fib fibdsc
= {sizeof (fib
), (void *) &fib
};
1628 unsigned long long newtime
;
1629 unsigned long long revtime
;
1633 struct vstring file
;
1634 struct dsc$descriptor_s filedsc
1635 = {NAM$C_MAXRSS
, DSC$K_DTYPE_T
, DSC$K_CLASS_S
, (void *) file
.string
};
1636 struct vstring device
;
1637 struct dsc$descriptor_s devicedsc
1638 = {NAM$C_MAXRSS
, DSC$K_DTYPE_T
, DSC$K_CLASS_S
, (void *) device
.string
};
1639 struct vstring timev
;
1640 struct dsc$descriptor_s timedsc
1641 = {NAM$C_MAXRSS
, DSC$K_DTYPE_T
, DSC$K_CLASS_S
, (void *) timev
.string
};
1642 struct vstring result
;
1643 struct dsc$descriptor_s resultdsc
1644 = {NAM$C_MAXRSS
, DSC$K_DTYPE_VT
, DSC$K_CLASS_VS
, (void *) result
.string
};
1646 /* Convert parameter name (a file spec) to host file form. Note that this
1647 is needed on VMS to prepare for subsequent calls to VMS RMS library
1648 routines. Note that it would not work to call __gnat_to_host_dir_spec
1649 as was done in a previous version, since this fails silently unless
1650 the feature logical DECC$EFS_CHARSET is enabled, in which case a DNF
1651 (directory not found) condition is signalled. */
1652 tryfile
= (char *) __gnat_to_host_file_spec (name
);
1654 /* Allocate and initialize a FAB and NAM structures. */
1658 nam
.nam$l_esa
= file
.string
;
1659 nam
.nam$b_ess
= NAM$C_MAXRSS
;
1660 nam
.nam$l_rsa
= result
.string
;
1661 nam
.nam$b_rss
= NAM$C_MAXRSS
;
1662 fab
.fab$l_fna
= tryfile
;
1663 fab
.fab$b_fns
= strlen (tryfile
);
1664 fab
.fab$l_nam
= &nam
;
1666 /* Validate filespec syntax and device existence. */
1667 status
= SYS$
PARSE (&fab
, 0, 0);
1668 if ((status
& 1) != 1)
1669 LIB$
SIGNAL (status
);
1671 file
.string
[nam
.nam$b_esl
] = 0;
1673 /* Find matching filespec. */
1674 status
= SYS$
SEARCH (&fab
, 0, 0);
1675 if ((status
& 1) != 1)
1676 LIB$
SIGNAL (status
);
1678 file
.string
[nam
.nam$b_esl
] = 0;
1679 result
.string
[result
.length
=nam
.nam$b_rsl
] = 0;
1681 /* Get the device name and assign an IO channel. */
1682 strncpy (device
.string
, nam
.nam$l_dev
, nam
.nam$b_dev
);
1683 devicedsc
.dsc$w_length
= nam
.nam$b_dev
;
1685 status
= SYS$
ASSIGN (&devicedsc
, &chan
, 0, 0, 0);
1686 if ((status
& 1) != 1)
1687 LIB$
SIGNAL (status
);
1689 /* Initialize the FIB and fill in the directory id field. */
1690 memset (&fib
, 0, sizeof (fib
));
1691 fib
.fib$w_did
[0] = nam
.nam$w_did
[0];
1692 fib
.fib$w_did
[1] = nam
.nam$w_did
[1];
1693 fib
.fib$w_did
[2] = nam
.nam$w_did
[2];
1694 fib
.fib$l_acctl
= 0;
1696 strcpy (file
.string
, (strrchr (result
.string
, ']') + 1));
1697 filedsc
.dsc$w_length
= strlen (file
.string
);
1698 result
.string
[result
.length
= 0] = 0;
1700 /* Open and close the file to fill in the attributes. */
1702 = SYS$
QIOW (0, chan
, IO$_ACCESS
|IO$M_ACCESS
, &iosb
, 0, 0,
1703 &fibdsc
, &filedsc
, &result
.length
, &resultdsc
, &atrlst
, 0);
1704 if ((status
& 1) != 1)
1705 LIB$
SIGNAL (status
);
1706 if ((iosb
.status
& 1) != 1)
1707 LIB$
SIGNAL (iosb
.status
);
1709 result
.string
[result
.length
] = 0;
1710 status
= SYS$
QIOW (0, chan
, IO$_DEACCESS
, &iosb
, 0, 0, &fibdsc
, 0, 0, 0,
1712 if ((status
& 1) != 1)
1713 LIB$
SIGNAL (status
);
1714 if ((iosb
.status
& 1) != 1)
1715 LIB$
SIGNAL (iosb
.status
);
1720 /* Set creation time to requested time. */
1721 unix_time_to_vms (time_stamp
, newtime
);
1723 t
= time ((time_t) 0);
1725 /* Set revision time to now in local time. */
1726 unix_time_to_vms (t
, revtime
);
1729 /* Reopen the file, modify the times and then close. */
1730 fib
.fib$l_acctl
= FIB$M_WRITE
;
1732 = SYS$
QIOW (0, chan
, IO$_ACCESS
|IO$M_ACCESS
, &iosb
, 0, 0,
1733 &fibdsc
, &filedsc
, &result
.length
, &resultdsc
, &atrlst
, 0);
1734 if ((status
& 1) != 1)
1735 LIB$
SIGNAL (status
);
1736 if ((iosb
.status
& 1) != 1)
1737 LIB$
SIGNAL (iosb
.status
);
1739 Fat
.create
= newtime
;
1740 Fat
.revise
= revtime
;
1742 status
= SYS$
QIOW (0, chan
, IO$_DEACCESS
, &iosb
, 0, 0,
1743 &fibdsc
, 0, 0, 0, &atrlst
, 0);
1744 if ((status
& 1) != 1)
1745 LIB$
SIGNAL (status
);
1746 if ((iosb
.status
& 1) != 1)
1747 LIB$
SIGNAL (iosb
.status
);
1749 /* Deassign the channel and exit. */
1750 status
= SYS$
DASSGN (chan
);
1751 if ((status
& 1) != 1)
1752 LIB$
SIGNAL (status
);
1754 struct utimbuf utimbuf
;
1757 /* Set modification time to requested time. */
1758 utimbuf
.modtime
= time_stamp
;
1760 /* Set access time to now in local time. */
1761 t
= time ((time_t) 0);
1762 utimbuf
.actime
= mktime (localtime (&t
));
1764 utime (name
, &utimbuf
);
1768 /* Get the list of installed standard libraries from the
1769 HKEY_LOCAL_MACHINE\SOFTWARE\Ada Core Technologies\GNAT\Standard Libraries
1773 __gnat_get_libraries_from_registry (void)
1775 char *result
= (char *) xmalloc (1);
1779 #if defined (_WIN32) && ! defined (__vxworks) && ! defined (IS_CROSS) \
1783 DWORD name_size
, value_size
;
1790 /* First open the key. */
1791 res
= RegOpenKeyExA (HKEY_LOCAL_MACHINE
, "SOFTWARE", 0, KEY_READ
, ®_key
);
1793 if (res
== ERROR_SUCCESS
)
1794 res
= RegOpenKeyExA (reg_key
, "Ada Core Technologies", 0,
1795 KEY_READ
, ®_key
);
1797 if (res
== ERROR_SUCCESS
)
1798 res
= RegOpenKeyExA (reg_key
, "GNAT", 0, KEY_READ
, ®_key
);
1800 if (res
== ERROR_SUCCESS
)
1801 res
= RegOpenKeyExA (reg_key
, "Standard Libraries", 0, KEY_READ
, ®_key
);
1803 /* If the key exists, read out all the values in it and concatenate them
1805 for (index
= 0; res
== ERROR_SUCCESS
; index
++)
1807 value_size
= name_size
= 256;
1808 res
= RegEnumValueA (reg_key
, index
, name
, &name_size
, 0,
1809 &type
, (LPBYTE
)value
, &value_size
);
1811 if (res
== ERROR_SUCCESS
&& type
== REG_SZ
)
1813 char *old_result
= result
;
1815 result
= (char *) xmalloc (strlen (old_result
) + value_size
+ 2);
1816 strcpy (result
, old_result
);
1817 strcat (result
, value
);
1818 strcat (result
, ";");
1823 /* Remove the trailing ";". */
1825 result
[strlen (result
) - 1] = 0;
1831 /* Query information for the given file NAME and return it in STATBUF.
1832 * Returns 0 for success, or errno value for failure.
1835 __gnat_stat (char *name
, GNAT_STRUCT_STAT
*statbuf
)
1838 WIN32_FILE_ATTRIBUTE_DATA fad
;
1839 TCHAR wname
[GNAT_MAX_PATH_LEN
+ 2];
1844 S2WSC (wname
, name
, GNAT_MAX_PATH_LEN
+ 2);
1845 name_len
= _tcslen (wname
);
1847 if (name_len
> GNAT_MAX_PATH_LEN
)
1850 ZeroMemory (statbuf
, sizeof(GNAT_STRUCT_STAT
));
1852 res
= GetFileAttributesEx (wname
, GetFileExInfoStandard
, &fad
);
1855 error
= GetLastError();
1857 /* Check file existence using GetFileAttributes() which does not fail on
1858 special Windows files like con:, aux:, nul: etc... */
1860 if (GetFileAttributes(wname
) != INVALID_FILE_ATTRIBUTES
) {
1861 /* Just pretend that it is a regular and readable file */
1862 statbuf
->st_mode
= S_IFREG
| S_IREAD
| S_IWRITE
;
1867 case ERROR_ACCESS_DENIED
:
1868 case ERROR_SHARING_VIOLATION
:
1869 case ERROR_LOCK_VIOLATION
:
1870 case ERROR_SHARING_BUFFER_EXCEEDED
:
1872 case ERROR_BUFFER_OVERFLOW
:
1873 return ENAMETOOLONG
;
1874 case ERROR_NOT_ENOUGH_MEMORY
:
1881 f2t (&fad
.ftCreationTime
, &statbuf
->st_ctime
);
1882 f2t (&fad
.ftLastWriteTime
, &statbuf
->st_mtime
);
1883 f2t (&fad
.ftLastAccessTime
, &statbuf
->st_atime
);
1885 statbuf
->st_size
= (off_t
)fad
.nFileSizeLow
;
1887 /* We do not have the S_IEXEC attribute, but this is not used on GNAT. */
1888 statbuf
->st_mode
= S_IREAD
;
1890 if (fad
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
)
1891 statbuf
->st_mode
|= S_IFDIR
;
1893 statbuf
->st_mode
|= S_IFREG
;
1895 if (!(fad
.dwFileAttributes
& FILE_ATTRIBUTE_READONLY
))
1896 statbuf
->st_mode
|= S_IWRITE
;
1901 return GNAT_STAT (name
, statbuf
) == 0 ? 0 : errno
;
1905 /*************************************************************************
1906 ** Check whether a file exists
1907 *************************************************************************/
1910 __gnat_file_exists_attr (char* name
, struct file_attributes
* attr
)
1912 if (attr
->exists
== ATTR_UNSET
)
1913 __gnat_stat_to_attr (-1, name
, attr
);
1915 return attr
->exists
;
1919 __gnat_file_exists (char *name
)
1921 struct file_attributes attr
;
1922 __gnat_reset_attributes (&attr
);
1923 return __gnat_file_exists_attr (name
, &attr
);
1926 /**********************************************************************
1927 ** Whether name is an absolute path
1928 **********************************************************************/
1931 __gnat_is_absolute_path (char *name
, int length
)
1934 /* On VxWorks systems, an absolute path can be represented (depending on
1935 the host platform) as either /dir/file, or device:/dir/file, or
1936 device:drive_letter:/dir/file. */
1943 for (index
= 0; index
< length
; index
++)
1945 if (name
[index
] == ':' &&
1946 ((name
[index
+ 1] == '/') ||
1947 (isalpha (name
[index
+ 1]) && index
+ 2 <= length
&&
1948 name
[index
+ 2] == '/')))
1951 else if (name
[index
] == '/')
1956 return (length
!= 0) &&
1957 (*name
== '/' || *name
== DIR_SEPARATOR
1959 || (length
> 1 && ISALPHA (name
[0]) && name
[1] == ':')
1966 __gnat_is_regular_file_attr (char* name
, struct file_attributes
* attr
)
1968 if (attr
->regular
== ATTR_UNSET
)
1969 __gnat_stat_to_attr (-1, name
, attr
);
1971 return attr
->regular
;
1975 __gnat_is_regular_file (char *name
)
1977 struct file_attributes attr
;
1979 __gnat_reset_attributes (&attr
);
1980 return __gnat_is_regular_file_attr (name
, &attr
);
1984 __gnat_is_directory_attr (char* name
, struct file_attributes
* attr
)
1986 if (attr
->directory
== ATTR_UNSET
)
1987 __gnat_stat_to_attr (-1, name
, attr
);
1989 return attr
->directory
;
1993 __gnat_is_directory (char *name
)
1995 struct file_attributes attr
;
1997 __gnat_reset_attributes (&attr
);
1998 return __gnat_is_directory_attr (name
, &attr
);
2001 #if defined (_WIN32) && !defined (RTX)
2003 /* Returns the same constant as GetDriveType but takes a pathname as
2007 GetDriveTypeFromPath (TCHAR
*wfullpath
)
2009 TCHAR wdrv
[MAX_PATH
];
2010 TCHAR wpath
[MAX_PATH
];
2011 TCHAR wfilename
[MAX_PATH
];
2012 TCHAR wext
[MAX_PATH
];
2014 _tsplitpath (wfullpath
, wdrv
, wpath
, wfilename
, wext
);
2016 if (_tcslen (wdrv
) != 0)
2018 /* we have a drive specified. */
2019 _tcscat (wdrv
, _T("\\"));
2020 return GetDriveType (wdrv
);
2024 /* No drive specified. */
2026 /* Is this a relative path, if so get current drive type. */
2027 if (wpath
[0] != _T('\\') ||
2028 (_tcslen (wpath
) > 2 && wpath
[0] == _T('\\')
2029 && wpath
[1] != _T('\\')))
2030 return GetDriveType (NULL
);
2032 UINT result
= GetDriveType (wpath
);
2034 /* Cannot guess the drive type, is this \\.\ ? */
2036 if (result
== DRIVE_NO_ROOT_DIR
&&
2037 _tcslen (wpath
) >= 4 && wpath
[0] == _T('\\') && wpath
[1] == _T('\\')
2038 && wpath
[2] == _T('.') && wpath
[3] == _T('\\'))
2040 if (_tcslen (wpath
) == 4)
2041 _tcscat (wpath
, wfilename
);
2043 LPTSTR p
= &wpath
[4];
2044 LPTSTR b
= _tcschr (p
, _T('\\'));
2048 /* logical drive \\.\c\dir\file */
2054 _tcscat (p
, _T(":\\"));
2056 return GetDriveType (p
);
2063 /* This MingW section contains code to work with ACL. */
2065 __gnat_check_OWNER_ACL (TCHAR
*wname
,
2066 DWORD CheckAccessDesired
,
2067 GENERIC_MAPPING CheckGenericMapping
)
2069 DWORD dwAccessDesired
, dwAccessAllowed
;
2070 PRIVILEGE_SET PrivilegeSet
;
2071 DWORD dwPrivSetSize
= sizeof (PRIVILEGE_SET
);
2072 BOOL fAccessGranted
= FALSE
;
2073 HANDLE hToken
= NULL
;
2075 SECURITY_DESCRIPTOR
* pSD
= NULL
;
2078 (wname
, OWNER_SECURITY_INFORMATION
|
2079 GROUP_SECURITY_INFORMATION
| DACL_SECURITY_INFORMATION
,
2082 if ((pSD
= (SECURITY_DESCRIPTOR
*) HeapAlloc
2083 (GetProcessHeap (), HEAP_ZERO_MEMORY
, nLength
)) == NULL
)
2086 /* Obtain the security descriptor. */
2088 if (!GetFileSecurity
2089 (wname
, OWNER_SECURITY_INFORMATION
|
2090 GROUP_SECURITY_INFORMATION
| DACL_SECURITY_INFORMATION
,
2091 pSD
, nLength
, &nLength
))
2094 if (!ImpersonateSelf (SecurityImpersonation
))
2097 if (!OpenThreadToken
2098 (GetCurrentThread(), TOKEN_DUPLICATE
| TOKEN_QUERY
, FALSE
, &hToken
))
2101 /* Undoes the effect of ImpersonateSelf. */
2105 /* We want to test for write permissions. */
2107 dwAccessDesired
= CheckAccessDesired
;
2109 MapGenericMask (&dwAccessDesired
, &CheckGenericMapping
);
2112 (pSD
, /* security descriptor to check */
2113 hToken
, /* impersonation token */
2114 dwAccessDesired
, /* requested access rights */
2115 &CheckGenericMapping
, /* pointer to GENERIC_MAPPING */
2116 &PrivilegeSet
, /* receives privileges used in check */
2117 &dwPrivSetSize
, /* size of PrivilegeSet buffer */
2118 &dwAccessAllowed
, /* receives mask of allowed access rights */
2122 CloseHandle (hToken
);
2123 HeapFree (GetProcessHeap (), 0, pSD
);
2124 return fAccessGranted
;
2128 CloseHandle (hToken
);
2129 HeapFree (GetProcessHeap (), 0, pSD
);
2134 __gnat_set_OWNER_ACL (TCHAR
*wname
,
2136 DWORD AccessPermissions
)
2138 PACL pOldDACL
= NULL
;
2139 PACL pNewDACL
= NULL
;
2140 PSECURITY_DESCRIPTOR pSD
= NULL
;
2142 TCHAR username
[100];
2145 /* Get current user, he will act as the owner */
2147 if (!GetUserName (username
, &unsize
))
2150 if (GetNamedSecurityInfo
2153 DACL_SECURITY_INFORMATION
,
2154 NULL
, NULL
, &pOldDACL
, NULL
, &pSD
) != ERROR_SUCCESS
)
2157 BuildExplicitAccessWithName
2158 (&ea
, username
, AccessPermissions
, (ACCESS_MODE
) AccessMode
, NO_INHERITANCE
);
2160 if (AccessMode
== SET_ACCESS
)
2162 /* SET_ACCESS, we want to set an explicte set of permissions, do not
2163 merge with current DACL. */
2164 if (SetEntriesInAcl (1, &ea
, NULL
, &pNewDACL
) != ERROR_SUCCESS
)
2168 if (SetEntriesInAcl (1, &ea
, pOldDACL
, &pNewDACL
) != ERROR_SUCCESS
)
2171 if (SetNamedSecurityInfo
2172 (wname
, SE_FILE_OBJECT
,
2173 DACL_SECURITY_INFORMATION
, NULL
, NULL
, pNewDACL
, NULL
) != ERROR_SUCCESS
)
2177 LocalFree (pNewDACL
);
2180 /* Check if it is possible to use ACL for wname, the file must not be on a
2184 __gnat_can_use_acl (TCHAR
*wname
)
2186 return __gnat_use_acl
&& GetDriveTypeFromPath (wname
) != DRIVE_REMOTE
;
2189 #endif /* defined (_WIN32) && !defined (RTX) */
2192 __gnat_is_readable_file_attr (char* name
, struct file_attributes
* attr
)
2194 if (attr
->readable
== ATTR_UNSET
)
2196 #if defined (_WIN32) && !defined (RTX)
2197 TCHAR wname
[GNAT_MAX_PATH_LEN
+ 2];
2198 GENERIC_MAPPING GenericMapping
;
2200 S2WSC (wname
, name
, GNAT_MAX_PATH_LEN
+ 2);
2202 if (__gnat_can_use_acl (wname
))
2204 ZeroMemory (&GenericMapping
, sizeof (GENERIC_MAPPING
));
2205 GenericMapping
.GenericRead
= GENERIC_READ
;
2207 __gnat_check_OWNER_ACL (wname
, FILE_READ_DATA
, GenericMapping
);
2210 attr
->readable
= GetFileAttributes (wname
) != INVALID_FILE_ATTRIBUTES
;
2212 __gnat_stat_to_attr (-1, name
, attr
);
2216 return attr
->readable
;
2220 __gnat_is_readable_file (char *name
)
2222 struct file_attributes attr
;
2224 __gnat_reset_attributes (&attr
);
2225 return __gnat_is_readable_file_attr (name
, &attr
);
2229 __gnat_is_writable_file_attr (char* name
, struct file_attributes
* attr
)
2231 if (attr
->writable
== ATTR_UNSET
)
2233 #if defined (_WIN32) && !defined (RTX)
2234 TCHAR wname
[GNAT_MAX_PATH_LEN
+ 2];
2235 GENERIC_MAPPING GenericMapping
;
2237 S2WSC (wname
, name
, GNAT_MAX_PATH_LEN
+ 2);
2239 if (__gnat_can_use_acl (wname
))
2241 ZeroMemory (&GenericMapping
, sizeof (GENERIC_MAPPING
));
2242 GenericMapping
.GenericWrite
= GENERIC_WRITE
;
2244 attr
->writable
= __gnat_check_OWNER_ACL
2245 (wname
, FILE_WRITE_DATA
| FILE_APPEND_DATA
, GenericMapping
)
2246 && !(GetFileAttributes (wname
) & FILE_ATTRIBUTE_READONLY
);
2250 !(GetFileAttributes (wname
) & FILE_ATTRIBUTE_READONLY
);
2253 __gnat_stat_to_attr (-1, name
, attr
);
2257 return attr
->writable
;
2261 __gnat_is_writable_file (char *name
)
2263 struct file_attributes attr
;
2265 __gnat_reset_attributes (&attr
);
2266 return __gnat_is_writable_file_attr (name
, &attr
);
2270 __gnat_is_executable_file_attr (char* name
, struct file_attributes
* attr
)
2272 if (attr
->executable
== ATTR_UNSET
)
2274 #if defined (_WIN32) && !defined (RTX)
2275 TCHAR wname
[GNAT_MAX_PATH_LEN
+ 2];
2276 GENERIC_MAPPING GenericMapping
;
2278 S2WSC (wname
, name
, GNAT_MAX_PATH_LEN
+ 2);
2280 if (__gnat_can_use_acl (wname
))
2282 ZeroMemory (&GenericMapping
, sizeof (GENERIC_MAPPING
));
2283 GenericMapping
.GenericExecute
= GENERIC_EXECUTE
;
2286 __gnat_check_OWNER_ACL (wname
, FILE_EXECUTE
, GenericMapping
);
2290 TCHAR
*l
, *last
= _tcsstr(wname
, _T(".exe"));
2292 /* look for last .exe */
2294 while ((l
= _tcsstr(last
+1, _T(".exe"))))
2298 GetFileAttributes (wname
) != INVALID_FILE_ATTRIBUTES
2299 && (last
- wname
) == (int) (_tcslen (wname
) - 4);
2302 __gnat_stat_to_attr (-1, name
, attr
);
2306 return attr
->regular
&& attr
->executable
;
2310 __gnat_is_executable_file (char *name
)
2312 struct file_attributes attr
;
2314 __gnat_reset_attributes (&attr
);
2315 return __gnat_is_executable_file_attr (name
, &attr
);
2319 __gnat_set_writable (char *name
)
2321 #if defined (_WIN32) && !defined (RTX)
2322 TCHAR wname
[GNAT_MAX_PATH_LEN
+ 2];
2324 S2WSC (wname
, name
, GNAT_MAX_PATH_LEN
+ 2);
2326 if (__gnat_can_use_acl (wname
))
2327 __gnat_set_OWNER_ACL (wname
, GRANT_ACCESS
, FILE_GENERIC_WRITE
);
2330 (wname
, GetFileAttributes (wname
) & ~FILE_ATTRIBUTE_READONLY
);
2331 #elif ! (defined (__vxworks) && _WRS_VXWORKS_MAJOR < 6) && \
2332 ! defined(__nucleus__)
2333 GNAT_STRUCT_STAT statbuf
;
2335 if (GNAT_STAT (name
, &statbuf
) == 0)
2337 statbuf
.st_mode
= statbuf
.st_mode
| S_IWUSR
;
2338 chmod (name
, statbuf
.st_mode
);
2343 /* must match definition in s-os_lib.ads */
2349 __gnat_set_executable (char *name
, int mode
)
2351 #if defined (_WIN32) && !defined (RTX)
2352 TCHAR wname
[GNAT_MAX_PATH_LEN
+ 2];
2354 S2WSC (wname
, name
, GNAT_MAX_PATH_LEN
+ 2);
2356 if (__gnat_can_use_acl (wname
))
2357 __gnat_set_OWNER_ACL (wname
, GRANT_ACCESS
, FILE_GENERIC_EXECUTE
);
2359 #elif ! (defined (__vxworks) && _WRS_VXWORKS_MAJOR < 6) && \
2360 ! defined(__nucleus__)
2361 GNAT_STRUCT_STAT statbuf
;
2363 if (GNAT_STAT (name
, &statbuf
) == 0)
2366 statbuf
.st_mode
= statbuf
.st_mode
| S_IXUSR
;
2368 statbuf
.st_mode
= statbuf
.st_mode
| S_IXGRP
;
2369 if (mode
& S_OTHERS
)
2370 statbuf
.st_mode
= statbuf
.st_mode
| S_IXOTH
;
2371 chmod (name
, statbuf
.st_mode
);
2377 __gnat_set_non_writable (char *name
)
2379 #if defined (_WIN32) && !defined (RTX)
2380 TCHAR wname
[GNAT_MAX_PATH_LEN
+ 2];
2382 S2WSC (wname
, name
, GNAT_MAX_PATH_LEN
+ 2);
2384 if (__gnat_can_use_acl (wname
))
2385 __gnat_set_OWNER_ACL
2386 (wname
, DENY_ACCESS
,
2387 FILE_WRITE_DATA
| FILE_APPEND_DATA
|
2388 FILE_WRITE_EA
| FILE_WRITE_ATTRIBUTES
);
2391 (wname
, GetFileAttributes (wname
) | FILE_ATTRIBUTE_READONLY
);
2392 #elif ! (defined (__vxworks) && _WRS_VXWORKS_MAJOR < 6) && \
2393 ! defined(__nucleus__)
2394 GNAT_STRUCT_STAT statbuf
;
2396 if (GNAT_STAT (name
, &statbuf
) == 0)
2398 statbuf
.st_mode
= statbuf
.st_mode
& 07577;
2399 chmod (name
, statbuf
.st_mode
);
2405 __gnat_set_readable (char *name
)
2407 #if defined (_WIN32) && !defined (RTX)
2408 TCHAR wname
[GNAT_MAX_PATH_LEN
+ 2];
2410 S2WSC (wname
, name
, GNAT_MAX_PATH_LEN
+ 2);
2412 if (__gnat_can_use_acl (wname
))
2413 __gnat_set_OWNER_ACL (wname
, GRANT_ACCESS
, FILE_GENERIC_READ
);
2415 #elif ! (defined (__vxworks) && _WRS_VXWORKS_MAJOR < 6) && \
2416 ! defined(__nucleus__)
2417 GNAT_STRUCT_STAT statbuf
;
2419 if (GNAT_STAT (name
, &statbuf
) == 0)
2421 chmod (name
, statbuf
.st_mode
| S_IREAD
);
2427 __gnat_set_non_readable (char *name
)
2429 #if defined (_WIN32) && !defined (RTX)
2430 TCHAR wname
[GNAT_MAX_PATH_LEN
+ 2];
2432 S2WSC (wname
, name
, GNAT_MAX_PATH_LEN
+ 2);
2434 if (__gnat_can_use_acl (wname
))
2435 __gnat_set_OWNER_ACL (wname
, DENY_ACCESS
, FILE_GENERIC_READ
);
2437 #elif ! (defined (__vxworks) && _WRS_VXWORKS_MAJOR < 6) && \
2438 ! defined(__nucleus__)
2439 GNAT_STRUCT_STAT statbuf
;
2441 if (GNAT_STAT (name
, &statbuf
) == 0)
2443 chmod (name
, statbuf
.st_mode
& (~S_IREAD
));
2449 __gnat_is_symbolic_link_attr (char* name ATTRIBUTE_UNUSED
,
2450 struct file_attributes
* attr
)
2452 if (attr
->symbolic_link
== ATTR_UNSET
)
2454 #if defined (__vxworks) || defined (__nucleus__)
2455 attr
->symbolic_link
= 0;
2457 #elif defined (_AIX) || defined (__APPLE__) || defined (__unix__)
2459 GNAT_STRUCT_STAT statbuf
;
2460 ret
= GNAT_LSTAT (name
, &statbuf
);
2461 attr
->symbolic_link
= (!ret
&& S_ISLNK (statbuf
.st_mode
));
2463 attr
->symbolic_link
= 0;
2466 return attr
->symbolic_link
;
2470 __gnat_is_symbolic_link (char *name ATTRIBUTE_UNUSED
)
2472 struct file_attributes attr
;
2474 __gnat_reset_attributes (&attr
);
2475 return __gnat_is_symbolic_link_attr (name
, &attr
);
2478 #if defined (sun) && defined (__SVR4)
2479 /* Using fork on Solaris will duplicate all the threads. fork1, which
2480 duplicates only the active thread, must be used instead, or spawning
2481 subprocess from a program with tasking will lead into numerous problems. */
2486 __gnat_portable_spawn (char *args
[] ATTRIBUTE_UNUSED
)
2488 int status ATTRIBUTE_UNUSED
= 0;
2489 int finished ATTRIBUTE_UNUSED
;
2490 int pid ATTRIBUTE_UNUSED
;
2492 #if defined (__vxworks) || defined(__nucleus__) || defined(RTX) \
2493 || defined(__PikeOS__)
2496 #elif defined (_WIN32)
2497 /* args[0] must be quotes as it could contain a full pathname with spaces */
2498 char *args_0
= args
[0];
2499 args
[0] = (char *)xmalloc (strlen (args_0
) + 3);
2500 strcpy (args
[0], "\"");
2501 strcat (args
[0], args_0
);
2502 strcat (args
[0], "\"");
2504 status
= spawnvp (P_WAIT
, args_0
, (char* const*)args
);
2506 /* restore previous value */
2508 args
[0] = (char *)args_0
;
2524 if (execv (args
[0], MAYBE_TO_PTR32 (args
)) != 0)
2526 return -1; /* execv is in parent context on VMS. */
2533 finished
= waitpid (pid
, &status
, 0);
2535 if (finished
!= pid
|| WIFEXITED (status
) == 0)
2538 return WEXITSTATUS (status
);
2544 /* Create a copy of the given file descriptor.
2545 Return -1 if an error occurred. */
2548 __gnat_dup (int oldfd
)
2550 #if defined (__vxworks) && !defined (__RTP__)
2551 /* Not supported on VxWorks 5.x, but supported on VxWorks 6.0 when using
2559 /* Make newfd be the copy of oldfd, closing newfd first if necessary.
2560 Return -1 if an error occurred. */
2563 __gnat_dup2 (int oldfd ATTRIBUTE_UNUSED
, int newfd ATTRIBUTE_UNUSED
)
2565 #if defined (__vxworks) && !defined (__RTP__)
2566 /* Not supported on VxWorks 5.x, but supported on VxWorks 6.0 when using
2569 #elif defined (__PikeOS__)
2570 /* Not supported. */
2572 #elif defined (_WIN32)
2573 /* Special case when oldfd and newfd are identical and are the standard
2574 input, output or error as this makes Windows XP hangs. Note that we
2575 do that only for standard file descriptors that are known to be valid. */
2576 if (oldfd
== newfd
&& newfd
>= 0 && newfd
<= 2)
2579 return dup2 (oldfd
, newfd
);
2581 return dup2 (oldfd
, newfd
);
2586 __gnat_number_of_cpus (void)
2590 #if defined (linux) || defined (sun) || defined (AIX) || defined (__APPLE__)
2591 cores
= (int) sysconf (_SC_NPROCESSORS_ONLN
);
2593 #elif defined (__hpux__)
2594 struct pst_dynamic psd
;
2595 if (pstat_getdynamic (&psd
, sizeof (psd
), 1, 0) != -1)
2596 cores
= (int) psd
.psd_proc_cnt
;
2598 #elif defined (_WIN32)
2599 SYSTEM_INFO sysinfo
;
2600 GetSystemInfo (&sysinfo
);
2601 cores
= (int) sysinfo
.dwNumberOfProcessors
;
2604 int code
= SYI$_ACTIVECPU_CNT
;
2608 status
= LIB$
GETSYI (&code
, &res
);
2609 if ((status
& 1) != 0)
2612 #elif defined (_WRS_CONFIG_SMP)
2613 unsigned int vxCpuConfiguredGet (void);
2615 cores
= vxCpuConfiguredGet ();
2622 /* WIN32 code to implement a wait call that wait for any child process. */
2624 #if defined (_WIN32) && !defined (RTX)
2626 /* Synchronization code, to be thread safe. */
2630 /* For the Cert run times on native Windows we use dummy functions
2631 for locking and unlocking tasks since we do not support multiple
2632 threads on this configuration (Cert run time on native Windows). */
2634 static void dummy (void)
2638 void (*Lock_Task
) () = &dummy
;
2639 void (*Unlock_Task
) () = &dummy
;
2643 #define Lock_Task system__soft_links__lock_task
2644 extern void (*Lock_Task
) (void);
2646 #define Unlock_Task system__soft_links__unlock_task
2647 extern void (*Unlock_Task
) (void);
2651 static HANDLE
*HANDLES_LIST
= NULL
;
2652 static int *PID_LIST
= NULL
, plist_length
= 0, plist_max_length
= 0;
2655 add_handle (HANDLE h
, int pid
)
2658 /* -------------------- critical section -------------------- */
2661 if (plist_length
== plist_max_length
)
2663 plist_max_length
+= 1000;
2665 (void **) xrealloc (HANDLES_LIST
, sizeof (HANDLE
) * plist_max_length
);
2667 (int *) xrealloc (PID_LIST
, sizeof (int) * plist_max_length
);
2670 HANDLES_LIST
[plist_length
] = h
;
2671 PID_LIST
[plist_length
] = pid
;
2675 /* -------------------- critical section -------------------- */
2679 __gnat_win32_remove_handle (HANDLE h
, int pid
)
2683 /* -------------------- critical section -------------------- */
2686 for (j
= 0; j
< plist_length
; j
++)
2688 if ((HANDLES_LIST
[j
] == h
) || (PID_LIST
[j
] == pid
))
2692 HANDLES_LIST
[j
] = HANDLES_LIST
[plist_length
];
2693 PID_LIST
[j
] = PID_LIST
[plist_length
];
2699 /* -------------------- critical section -------------------- */
2703 win32_no_block_spawn (char *command
, char *args
[], HANDLE
*h
, int *pid
)
2707 PROCESS_INFORMATION PI
;
2708 SECURITY_ATTRIBUTES SA
;
2713 /* compute the total command line length */
2717 csize
+= strlen (args
[k
]) + 1;
2721 full_command
= (char *) xmalloc (csize
);
2724 SI
.cb
= sizeof (STARTUPINFO
);
2725 SI
.lpReserved
= NULL
;
2726 SI
.lpReserved2
= NULL
;
2727 SI
.lpDesktop
= NULL
;
2731 SI
.wShowWindow
= SW_HIDE
;
2733 /* Security attributes. */
2734 SA
.nLength
= sizeof (SECURITY_ATTRIBUTES
);
2735 SA
.bInheritHandle
= TRUE
;
2736 SA
.lpSecurityDescriptor
= NULL
;
2738 /* Prepare the command string. */
2739 strcpy (full_command
, command
);
2740 strcat (full_command
, " ");
2745 strcat (full_command
, args
[k
]);
2746 strcat (full_command
, " ");
2751 int wsize
= csize
* 2;
2752 TCHAR
*wcommand
= (TCHAR
*) xmalloc (wsize
);
2754 S2WSC (wcommand
, full_command
, wsize
);
2756 free (full_command
);
2758 result
= CreateProcess
2759 (NULL
, wcommand
, &SA
, NULL
, TRUE
,
2760 GetPriorityClass (GetCurrentProcess()), NULL
, NULL
, &SI
, &PI
);
2767 CloseHandle (PI
.hThread
);
2769 *pid
= PI
.dwProcessId
;
2779 win32_wait (int *status
)
2781 DWORD exitcode
, pid
;
2788 if (plist_length
== 0)
2796 /* -------------------- critical section -------------------- */
2799 hl_len
= plist_length
;
2801 hl
= (HANDLE
*) xmalloc (sizeof (HANDLE
) * hl_len
);
2803 memmove (hl
, HANDLES_LIST
, sizeof (HANDLE
) * hl_len
);
2806 /* -------------------- critical section -------------------- */
2808 res
= WaitForMultipleObjects (hl_len
, hl
, FALSE
, INFINITE
);
2809 h
= hl
[res
- WAIT_OBJECT_0
];
2811 GetExitCodeProcess (h
, &exitcode
);
2812 pid
= PID_LIST
[res
- WAIT_OBJECT_0
];
2813 __gnat_win32_remove_handle (h
, -1);
2817 *status
= (int) exitcode
;
2824 __gnat_portable_no_block_spawn (char *args
[] ATTRIBUTE_UNUSED
)
2827 #if defined (__vxworks) || defined (__nucleus__) || defined (RTX) \
2828 || defined (__PikeOS__)
2829 /* Not supported. */
2832 #elif defined (_WIN32)
2837 win32_no_block_spawn (args
[0], args
, &h
, &pid
);
2840 add_handle (h
, pid
);
2853 if (execv (args
[0], MAYBE_TO_PTR32 (args
)) != 0)
2855 return -1; /* execv is in parent context on VMS. */
2867 __gnat_portable_wait (int *process_status
)
2872 #if defined (__vxworks) || defined (__nucleus__) || defined (RTX) \
2873 || defined (__PikeOS__)
2874 /* Not sure what to do here, so do nothing but return zero. */
2876 #elif defined (_WIN32)
2878 pid
= win32_wait (&status
);
2882 pid
= waitpid (-1, &status
, 0);
2883 status
= status
& 0xffff;
2886 *process_status
= status
;
2891 __gnat_os_exit (int status
)
2896 /* Locate file on path, that matches a predicate */
2899 __gnat_locate_file_with_predicate (char *file_name
, char *path_val
,
2900 int (*predicate
)(char *))
2903 char *file_path
= (char *) alloca (strlen (file_name
) + 1);
2906 /* Return immediately if file_name is empty */
2908 if (*file_name
== '\0')
2911 /* Remove quotes around file_name if present */
2917 strcpy (file_path
, ptr
);
2919 ptr
= file_path
+ strlen (file_path
) - 1;
2924 /* Handle absolute pathnames. */
2926 absolute
= __gnat_is_absolute_path (file_path
, strlen (file_name
));
2930 if (predicate (file_path
))
2931 return xstrdup (file_path
);
2936 /* If file_name include directory separator(s), try it first as
2937 a path name relative to the current directory */
2938 for (ptr
= file_name
; *ptr
&& *ptr
!= '/' && *ptr
!= DIR_SEPARATOR
; ptr
++)
2943 if (predicate (file_name
))
2944 return xstrdup (file_name
);
2951 /* The result has to be smaller than path_val + file_name. */
2953 (char *) alloca (strlen (path_val
) + strlen (file_name
) + 2);
2957 /* Skip the starting quote */
2959 if (*path_val
== '"')
2962 for (ptr
= file_path
; *path_val
&& *path_val
!= PATH_SEPARATOR
; )
2963 *ptr
++ = *path_val
++;
2965 /* If directory is empty, it is the current directory*/
2967 if (ptr
== file_path
)
2974 /* Skip the ending quote */
2979 if (*ptr
!= '/' && *ptr
!= DIR_SEPARATOR
)
2980 *++ptr
= DIR_SEPARATOR
;
2982 strcpy (++ptr
, file_name
);
2984 if (predicate (file_path
))
2985 return xstrdup (file_path
);
2990 /* Skip path separator */
2999 /* Locate an executable file, give a Path value. */
3002 __gnat_locate_executable_file (char *file_name
, char *path_val
)
3004 return __gnat_locate_file_with_predicate
3005 (file_name
, path_val
, &__gnat_is_executable_file
);
3008 /* Locate a regular file, give a Path value. */
3011 __gnat_locate_regular_file (char *file_name
, char *path_val
)
3013 return __gnat_locate_file_with_predicate
3014 (file_name
, path_val
, &__gnat_is_regular_file
);
3017 /* Locate an executable given a Path argument. This routine is only used by
3018 gnatbl and should not be used otherwise. Use locate_exec_on_path
3022 __gnat_locate_exec (char *exec_name
, char *path_val
)
3025 if (!strstr (exec_name
, HOST_EXECUTABLE_SUFFIX
))
3027 char *full_exec_name
=
3029 (strlen (exec_name
) + strlen (HOST_EXECUTABLE_SUFFIX
) + 1);
3031 strcpy (full_exec_name
, exec_name
);
3032 strcat (full_exec_name
, HOST_EXECUTABLE_SUFFIX
);
3033 ptr
= __gnat_locate_executable_file (full_exec_name
, path_val
);
3036 return __gnat_locate_executable_file (exec_name
, path_val
);
3040 return __gnat_locate_executable_file (exec_name
, path_val
);
3043 /* Locate an executable using the Systems default PATH. */
3046 __gnat_locate_exec_on_path (char *exec_name
)
3050 #if defined (_WIN32) && !defined (RTX)
3051 TCHAR
*wpath_val
= _tgetenv (_T("PATH"));
3053 /* In Win32 systems we expand the PATH as for XP environment
3054 variables are not automatically expanded. We also prepend the
3055 ".;" to the path to match normal NT path search semantics */
3057 #define EXPAND_BUFFER_SIZE 32767
3059 wapath_val
= (TCHAR
*) alloca (EXPAND_BUFFER_SIZE
);
3061 wapath_val
[0] = '.';
3062 wapath_val
[1] = ';';
3064 DWORD res
= ExpandEnvironmentStrings
3065 (wpath_val
, &wapath_val
[2], EXPAND_BUFFER_SIZE
- 2);
3067 if (!res
) wapath_val
[0] = _T('\0');
3069 apath_val
= (char *) alloca (EXPAND_BUFFER_SIZE
);
3071 WS2SC (apath_val
, wapath_val
, EXPAND_BUFFER_SIZE
);
3072 return __gnat_locate_exec (exec_name
, apath_val
);
3077 char *path_val
= "/VAXC$PATH";
3079 char *path_val
= getenv ("PATH");
3081 if (path_val
== NULL
) return NULL
;
3082 apath_val
= (char *) alloca (strlen (path_val
) + 1);
3083 strcpy (apath_val
, path_val
);
3084 return __gnat_locate_exec (exec_name
, apath_val
);
3090 /* These functions are used to translate to and from VMS and Unix syntax
3091 file, directory and path specifications. */
3094 #define MAXNAMES 256
3095 #define NEW_CANONICAL_FILELIST_INCREMENT 64
3097 static char new_canonical_dirspec
[MAXPATH
];
3098 static char new_canonical_filespec
[MAXPATH
];
3099 static char new_canonical_pathspec
[MAXNAMES
*MAXPATH
];
3100 static unsigned new_canonical_filelist_index
;
3101 static unsigned new_canonical_filelist_in_use
;
3102 static unsigned new_canonical_filelist_allocated
;
3103 static char **new_canonical_filelist
;
3104 static char new_host_pathspec
[MAXNAMES
*MAXPATH
];
3105 static char new_host_dirspec
[MAXPATH
];
3106 static char new_host_filespec
[MAXPATH
];
3108 /* Routine is called repeatedly by decc$from_vms via
3109 __gnat_to_canonical_file_list_init until it returns 0 or the expansion
3113 wildcard_translate_unix (char *name
)
3116 char buff
[MAXPATH
];
3118 strncpy (buff
, name
, MAXPATH
);
3119 buff
[MAXPATH
- 1] = (char) 0;
3120 ver
= strrchr (buff
, '.');
3122 /* Chop off the version. */
3126 /* Dynamically extend the allocation by the increment. */
3127 if (new_canonical_filelist_in_use
== new_canonical_filelist_allocated
)
3129 new_canonical_filelist_allocated
+= NEW_CANONICAL_FILELIST_INCREMENT
;
3130 new_canonical_filelist
= (char **) xrealloc
3131 (new_canonical_filelist
,
3132 new_canonical_filelist_allocated
* sizeof (char *));
3135 new_canonical_filelist
[new_canonical_filelist_in_use
++] = xstrdup (buff
);
3140 /* Translate a wildcard VMS file spec into a list of Unix file specs. First do
3141 full translation and copy the results into a list (_init), then return them
3142 one at a time (_next). If onlydirs set, only expand directory files. */
3145 __gnat_to_canonical_file_list_init (char *filespec
, int onlydirs
)
3148 char buff
[MAXPATH
];
3150 len
= strlen (filespec
);
3151 strncpy (buff
, filespec
, MAXPATH
);
3153 /* Only look for directories */
3154 if (onlydirs
&& !strstr (&buff
[len
-5], "*.dir"))
3155 strncat (buff
, "*.dir", MAXPATH
);
3157 buff
[MAXPATH
- 1] = (char) 0;
3159 decc$
from_vms (buff
, wildcard_translate_unix
, 1);
3161 /* Remove the .dir extension. */
3167 for (i
= 0; i
< new_canonical_filelist_in_use
; i
++)
3169 ext
= strstr (new_canonical_filelist
[i
], ".dir");
3175 return new_canonical_filelist_in_use
;
3178 /* Return the next filespec in the list. */
3181 __gnat_to_canonical_file_list_next (void)
3183 return new_canonical_filelist
[new_canonical_filelist_index
++];
3186 /* Free storage used in the wildcard expansion. */
3189 __gnat_to_canonical_file_list_free (void)
3193 for (i
= 0; i
< new_canonical_filelist_in_use
; i
++)
3194 free (new_canonical_filelist
[i
]);
3196 free (new_canonical_filelist
);
3198 new_canonical_filelist_in_use
= 0;
3199 new_canonical_filelist_allocated
= 0;
3200 new_canonical_filelist_index
= 0;
3201 new_canonical_filelist
= 0;
3204 /* The functional equivalent of decc$translate_vms routine.
3205 Designed to produce the same output, but is protected against
3206 malformed paths (original version ACCVIOs in this case) and
3207 does not require VMS-specific DECC RTL. */
3209 #define NAM$C_MAXRSS 1024
3212 __gnat_translate_vms (char *src
)
3214 static char retbuf
[NAM$C_MAXRSS
+ 1];
3215 char *srcendpos
, *pos1
, *pos2
, *retpos
;
3216 int disp
, path_present
= 0;
3221 srcendpos
= strchr (src
, '\0');
3224 /* Look for the node and/or device in front of the path. */
3226 pos2
= strchr (pos1
, ':');
3228 if (pos2
&& (pos2
< srcendpos
) && (*(pos2
+ 1) == ':'))
3230 /* There is a node name. "node_name::" becomes "node_name!". */
3232 strncpy (retbuf
, pos1
, disp
);
3233 retpos
[disp
] = '!';
3234 retpos
= retpos
+ disp
+ 1;
3236 pos2
= strchr (pos1
, ':');
3241 /* There is a device name. "dev_name:" becomes "/dev_name/". */
3244 strncpy (retpos
, pos1
, disp
);
3245 retpos
= retpos
+ disp
;
3250 /* No explicit device; we must look ahead and prepend /sys$disk/ if
3251 the path is absolute. */
3252 if ((*pos1
== '[' || *pos1
== '<') && (pos1
< srcendpos
)
3253 && !strchr (".-]>", *(pos1
+ 1)))
3255 strncpy (retpos
, "/sys$disk/", 10);
3259 /* Process the path part. */
3260 while (*pos1
== '[' || *pos1
== '<')
3264 if (*pos1
== ']' || *pos1
== '>')
3266 /* Special case, [] translates to '.'. */
3272 /* '[000000' means root dir. It can be present in the middle of
3273 the path due to expansion of logical devices, in which case
3275 if (!strncmp (pos1
, "000000", 6) && path_present
> 1 &&
3276 (*(pos1
+ 6) == ']' || *(pos1
+ 6) == '>' || *(pos1
+ 6) == '.'))
3279 if (*pos1
== '.') pos1
++;
3281 else if (*pos1
== '.')
3283 /* Relative path. */
3287 /* There is a qualified path. */
3288 while (*pos1
&& *pos1
!= ']' && *pos1
!= '>')
3293 /* '.' is used to separate directories. Replace it with '/'
3294 but only if there isn't already '/' just before. */
3295 if (*(retpos
- 1) != '/')
3298 if (pos1
+ 1 < srcendpos
3300 && *(pos1
+ 1) == '.')
3302 /* Ellipsis refers to entire subtree; replace
3311 /* When after '.' '[' '<' is equivalent to Unix ".." but
3312 there may be several in a row. */
3313 if (*(pos1
- 1) == '.' || *(pos1
- 1) == '[' ||
3316 while (*pos1
== '-')
3326 /* Otherwise fall through to default. */
3328 *(retpos
++) = *(pos1
++);
3335 if (pos1
< srcendpos
)
3337 /* Now add the actual file name, until the version suffix if any */
3340 pos2
= strchr (pos1
, ';');
3341 disp
= pos2
? (pos2
- pos1
) : (srcendpos
- pos1
);
3342 strncpy (retpos
, pos1
, disp
);
3344 if (pos2
&& pos2
< srcendpos
)
3346 /* There is a non-empty version suffix. ";<ver>" becomes ".<ver>" */
3348 disp
= srcendpos
- pos2
- 1;
3349 strncpy (retpos
, pos2
+ 1, disp
);
3359 /* Translate a VMS syntax directory specification in to Unix syntax. If
3360 PREFIXFLAG is set, append an underscore "/". If no indicators of VMS syntax
3361 found, return input string. Also translate a dirname that contains no
3362 slashes, in case it's a logical name. */
3365 __gnat_to_canonical_dir_spec (char *dirspec
, int prefixflag
)
3369 strcpy (new_canonical_dirspec
, "");
3370 if (strlen (dirspec
))
3374 if (strchr (dirspec
, ']') || strchr (dirspec
, ':'))
3376 strncpy (new_canonical_dirspec
,
3377 __gnat_translate_vms (dirspec
),
3380 else if (!strchr (dirspec
, '/') && (dirspec1
= getenv (dirspec
)) != 0)
3382 strncpy (new_canonical_dirspec
,
3383 __gnat_translate_vms (dirspec1
),
3388 strncpy (new_canonical_dirspec
, dirspec
, MAXPATH
);
3392 len
= strlen (new_canonical_dirspec
);
3393 if (prefixflag
&& new_canonical_dirspec
[len
-1] != '/')
3394 strncat (new_canonical_dirspec
, "/", MAXPATH
);
3396 new_canonical_dirspec
[MAXPATH
- 1] = (char) 0;
3398 return new_canonical_dirspec
;
3402 /* Translate a VMS syntax file specification into Unix syntax.
3403 If no indicators of VMS syntax found, check if it's an uppercase
3404 alphanumeric_ name and if so try it out as an environment
3405 variable (logical name). If all else fails return the
3409 __gnat_to_canonical_file_spec (char *filespec
)
3413 strncpy (new_canonical_filespec
, "", MAXPATH
);
3415 if (strchr (filespec
, ']') || strchr (filespec
, ':'))
3417 char *tspec
= (char *) __gnat_translate_vms (filespec
);
3419 if (tspec
!= (char *) -1)
3420 strncpy (new_canonical_filespec
, tspec
, MAXPATH
);
3422 else if ((strlen (filespec
) == strspn (filespec
,
3423 "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_"))
3424 && (filespec1
= getenv (filespec
)))
3426 char *tspec
= (char *) __gnat_translate_vms (filespec1
);
3428 if (tspec
!= (char *) -1)
3429 strncpy (new_canonical_filespec
, tspec
, MAXPATH
);
3433 strncpy (new_canonical_filespec
, filespec
, MAXPATH
);
3436 new_canonical_filespec
[MAXPATH
- 1] = (char) 0;
3438 return new_canonical_filespec
;
3441 /* Translate a VMS syntax path specification into Unix syntax.
3442 If no indicators of VMS syntax found, return input string. */
3445 __gnat_to_canonical_path_spec (char *pathspec
)
3447 char *curr
, *next
, buff
[MAXPATH
];
3452 /* If there are /'s, assume it's a Unix path spec and return. */
3453 if (strchr (pathspec
, '/'))
3456 new_canonical_pathspec
[0] = 0;
3461 next
= strchr (curr
, ',');
3463 next
= strchr (curr
, 0);
3465 strncpy (buff
, curr
, next
- curr
);
3466 buff
[next
- curr
] = 0;
3468 /* Check for wildcards and expand if present. */
3469 if (strchr (buff
, '*') || strchr (buff
, '%') || strstr (buff
, "..."))
3473 dirs
= __gnat_to_canonical_file_list_init (buff
, 1);
3474 for (i
= 0; i
< dirs
; i
++)
3478 next_dir
= __gnat_to_canonical_file_list_next ();
3479 strncat (new_canonical_pathspec
, next_dir
, MAXPATH
);
3481 /* Don't append the separator after the last expansion. */
3483 strncat (new_canonical_pathspec
, ":", MAXPATH
);
3486 __gnat_to_canonical_file_list_free ();
3489 strncat (new_canonical_pathspec
,
3490 __gnat_to_canonical_dir_spec (buff
, 0), MAXPATH
);
3495 strncat (new_canonical_pathspec
, ":", MAXPATH
);
3499 new_canonical_pathspec
[MAXPATH
- 1] = (char) 0;
3501 return new_canonical_pathspec
;
3504 static char filename_buff
[MAXPATH
];
3507 translate_unix (char *name
, int type ATTRIBUTE_UNUSED
)
3509 strncpy (filename_buff
, name
, MAXPATH
);
3510 filename_buff
[MAXPATH
- 1] = (char) 0;
3514 /* Translate a Unix syntax directory specification into VMS syntax. The
3515 PREFIXFLAG has no effect, but is kept for symmetry with
3516 to_canonical_dir_spec. If indicators of VMS syntax found, return input
3520 __gnat_to_host_dir_spec (char *dirspec
, int prefixflag ATTRIBUTE_UNUSED
)
3522 int len
= strlen (dirspec
);
3524 strncpy (new_host_dirspec
, dirspec
, MAXPATH
);
3525 new_host_dirspec
[MAXPATH
- 1] = (char) 0;
3527 if (strchr (new_host_dirspec
, ']') || strchr (new_host_dirspec
, ':'))
3528 return new_host_dirspec
;
3530 while (len
> 1 && new_host_dirspec
[len
- 1] == '/')
3532 new_host_dirspec
[len
- 1] = 0;
3536 decc$
to_vms (new_host_dirspec
, translate_unix
, 1, 2);
3537 strncpy (new_host_dirspec
, filename_buff
, MAXPATH
);
3538 new_host_dirspec
[MAXPATH
- 1] = (char) 0;
3540 return new_host_dirspec
;
3543 /* Translate a Unix syntax file specification into VMS syntax.
3544 If indicators of VMS syntax found, return input string. */
3547 __gnat_to_host_file_spec (char *filespec
)
3549 strncpy (new_host_filespec
, "", MAXPATH
);
3550 if (strchr (filespec
, ']') || strchr (filespec
, ':'))
3552 strncpy (new_host_filespec
, filespec
, MAXPATH
);
3556 decc$
to_vms (filespec
, translate_unix
, 1, 1);
3557 strncpy (new_host_filespec
, filename_buff
, MAXPATH
);
3560 new_host_filespec
[MAXPATH
- 1] = (char) 0;
3562 return new_host_filespec
;
3566 __gnat_adjust_os_resource_limits (void)
3568 SYS$
ADJWSL (131072, 0);
3573 /* Dummy functions for Osint import for non-VMS systems. */
3576 __gnat_to_canonical_file_list_init (char *dirspec ATTRIBUTE_UNUSED
,
3577 int onlydirs ATTRIBUTE_UNUSED
)
3583 __gnat_to_canonical_file_list_next (void)
3585 static char empty
[] = "";
3590 __gnat_to_canonical_file_list_free (void)
3595 __gnat_to_canonical_dir_spec (char *dirspec
, int prefixflag ATTRIBUTE_UNUSED
)
3601 __gnat_to_canonical_file_spec (char *filespec
)
3607 __gnat_to_canonical_path_spec (char *pathspec
)
3613 __gnat_to_host_dir_spec (char *dirspec
, int prefixflag ATTRIBUTE_UNUSED
)
3619 __gnat_to_host_file_spec (char *filespec
)
3625 __gnat_adjust_os_resource_limits (void)
3631 #if defined (__mips_vxworks)
3635 CACHE_USER_FLUSH (0, ENTIRE_CACHE
);
3639 #if defined (IS_CROSS) \
3640 || (! ((defined (sparc) || defined (i386)) && defined (sun) \
3641 && defined (__SVR4)) \
3642 && ! (defined (linux) && (defined (i386) || defined (__x86_64__))) \
3643 && ! (defined (linux) && defined (__ia64__)) \
3644 && ! (defined (linux) && defined (powerpc)) \
3645 && ! defined (__FreeBSD__) \
3646 && ! defined (__Lynx__) \
3647 && ! defined (__hpux__) \
3648 && ! defined (__APPLE__) \
3649 && ! defined (_AIX) \
3650 && ! defined (VMS) \
3651 && ! defined (__MINGW32__))
3653 /* Dummy function to satisfy g-trasym.o. See the preprocessor conditional
3654 just above for a list of native platforms that provide a non-dummy
3655 version of this procedure in libaddr2line.a. */
3658 convert_addresses (const char *file_name ATTRIBUTE_UNUSED
,
3659 void *addrs ATTRIBUTE_UNUSED
,
3660 int n_addr ATTRIBUTE_UNUSED
,
3661 void *buf ATTRIBUTE_UNUSED
,
3662 int *len ATTRIBUTE_UNUSED
)
3668 #if defined (_WIN32)
3669 int __gnat_argument_needs_quote
= 1;
3671 int __gnat_argument_needs_quote
= 0;
3674 /* This option is used to enable/disable object files handling from the
3675 binder file by the GNAT Project module. For example, this is disabled on
3676 Windows (prior to GCC 3.4) as it is already done by the mdll module.
3677 Stating with GCC 3.4 the shared libraries are not based on mdll
3678 anymore as it uses the GCC's -shared option */
3679 #if defined (_WIN32) \
3680 && ((__GNUC__ < 3) || ((__GNUC__ == 3) && (__GNUC_MINOR__ < 4)))
3681 int __gnat_prj_add_obj_files
= 0;
3683 int __gnat_prj_add_obj_files
= 1;
3686 /* char used as prefix/suffix for environment variables */
3687 #if defined (_WIN32)
3688 char __gnat_environment_char
= '%';
3690 char __gnat_environment_char
= '$';
3693 /* This functions copy the file attributes from a source file to a
3696 mode = 0 : In this mode copy only the file time stamps (last access and
3697 last modification time stamps).
3699 mode = 1 : In this mode, time stamps and read/write/execute attributes are
3702 Returns 0 if operation was successful and -1 in case of error. */
3705 __gnat_copy_attribs (char *from ATTRIBUTE_UNUSED
, char *to ATTRIBUTE_UNUSED
,
3706 int mode ATTRIBUTE_UNUSED
)
3708 #if defined (VMS) || (defined (__vxworks) && _WRS_VXWORKS_MAJOR < 6) || \
3709 defined (__nucleus__)
3712 #elif defined (_WIN32) && !defined (RTX)
3713 TCHAR wfrom
[GNAT_MAX_PATH_LEN
+ 2];
3714 TCHAR wto
[GNAT_MAX_PATH_LEN
+ 2];
3716 FILETIME fct
, flat
, flwt
;
3719 S2WSC (wfrom
, from
, GNAT_MAX_PATH_LEN
+ 2);
3720 S2WSC (wto
, to
, GNAT_MAX_PATH_LEN
+ 2);
3722 /* retrieve from times */
3725 (wfrom
, GENERIC_READ
, 0, NULL
, OPEN_EXISTING
, FILE_ATTRIBUTE_NORMAL
, NULL
);
3727 if (hfrom
== INVALID_HANDLE_VALUE
)
3730 res
= GetFileTime (hfrom
, &fct
, &flat
, &flwt
);
3732 CloseHandle (hfrom
);
3737 /* retrieve from times */
3740 (wto
, GENERIC_WRITE
, 0, NULL
, OPEN_EXISTING
, FILE_ATTRIBUTE_NORMAL
, NULL
);
3742 if (hto
== INVALID_HANDLE_VALUE
)
3745 res
= SetFileTime (hto
, NULL
, &flat
, &flwt
);
3752 /* Set file attributes in full mode. */
3756 DWORD attribs
= GetFileAttributes (wfrom
);
3758 if (attribs
== INVALID_FILE_ATTRIBUTES
)
3761 res
= SetFileAttributes (wto
, attribs
);
3769 GNAT_STRUCT_STAT fbuf
;
3770 struct utimbuf tbuf
;
3772 if (GNAT_STAT (from
, &fbuf
) == -1)
3777 tbuf
.actime
= fbuf
.st_atime
;
3778 tbuf
.modtime
= fbuf
.st_mtime
;
3780 if (utime (to
, &tbuf
) == -1)
3787 if (chmod (to
, fbuf
.st_mode
) == -1)
3798 __gnat_lseek (int fd
, long offset
, int whence
)
3800 return (int) lseek (fd
, offset
, whence
);
3803 /* This function returns the major version number of GCC being used. */
3805 get_gcc_version (void)
3810 return (int) (version_string
[0] - '0');
3815 * Set Close_On_Exec as indicated.
3816 * Note: this is used for both GNAT.OS_Lib and GNAT.Sockets.
3820 __gnat_set_close_on_exec (int fd ATTRIBUTE_UNUSED
,
3821 int close_on_exec_p ATTRIBUTE_UNUSED
)
3823 #if defined (F_GETFD) && defined (FD_CLOEXEC) && ! defined (__vxworks)
3824 int flags
= fcntl (fd
, F_GETFD
, 0);
3827 if (close_on_exec_p
)
3828 flags
|= FD_CLOEXEC
;
3830 flags
&= ~FD_CLOEXEC
;
3831 return fcntl (fd
, F_SETFD
, flags
| FD_CLOEXEC
);
3832 #elif defined(_WIN32)
3833 HANDLE h
= (HANDLE
) _get_osfhandle (fd
);
3834 if (h
== (HANDLE
) -1)
3836 if (close_on_exec_p
)
3837 return ! SetHandleInformation (h
, HANDLE_FLAG_INHERIT
, 0);
3838 return ! SetHandleInformation (h
, HANDLE_FLAG_INHERIT
,
3839 HANDLE_FLAG_INHERIT
);
3841 /* TODO: Unimplemented. */
3846 /* Indicates if platforms supports automatic initialization through the
3847 constructor mechanism */
3849 __gnat_binder_supports_auto_init (void)
3858 /* Indicates that Stand-Alone Libraries are automatically initialized through
3859 the constructor mechanism */
3861 __gnat_sals_init_using_constructors (void)
3863 #if defined (__vxworks) || defined (__Lynx__) || defined (VMS)
3872 /* In RTX mode, the procedure to get the time (as file time) is different
3873 in RTSS mode and Win32 mode. In order to avoid duplicating an Ada file,
3874 we introduce an intermediate procedure to link against the corresponding
3875 one in each situation. */
3877 extern void GetTimeAsFileTime (LPFILETIME pTime
);
3879 void GetTimeAsFileTime (LPFILETIME pTime
)
3882 RtGetRtssTimeAsFileTime (pTime
); /* RTSS interface */
3884 GetSystemTimeAsFileTime (pTime
); /* w32 interface */
3889 /* Add symbol that is required to link. It would otherwise be taken from
3890 libgcc.a and it would try to use the gcc constructors that are not
3891 supported by Microsoft linker. */
3893 extern void __main (void);
3901 #if defined (__ANDROID__)
3903 #include <pthread.h>
3906 __gnat_lwp_self (void)
3908 return (void *) pthread_self ();
3911 #elif defined (linux)
3912 /* There is no function in the glibc to retrieve the LWP of the current
3913 thread. We need to do a system call in order to retrieve this
3915 #include <sys/syscall.h>
3917 __gnat_lwp_self (void)
3919 return (void *) syscall (__NR_gettid
);
3924 /* glibc versions earlier than 2.7 do not define the routines to handle
3925 dynamically allocated CPU sets. For these targets, we use the static
3930 /* Dynamic cpu sets */
3933 __gnat_cpu_alloc (size_t count
)
3935 return CPU_ALLOC (count
);
3939 __gnat_cpu_alloc_size (size_t count
)
3941 return CPU_ALLOC_SIZE (count
);
3945 __gnat_cpu_free (cpu_set_t
*set
)
3951 __gnat_cpu_zero (size_t count
, cpu_set_t
*set
)
3953 CPU_ZERO_S (count
, set
);
3957 __gnat_cpu_set (int cpu
, size_t count
, cpu_set_t
*set
)
3959 /* Ada handles CPU numbers starting from 1, while C identifies the first
3960 CPU by a 0, so we need to adjust. */
3961 CPU_SET_S (cpu
- 1, count
, set
);
3964 #else /* !CPU_ALLOC */
3966 /* Static cpu sets */
3969 __gnat_cpu_alloc (size_t count ATTRIBUTE_UNUSED
)
3971 return (cpu_set_t
*) xmalloc (sizeof (cpu_set_t
));
3975 __gnat_cpu_alloc_size (size_t count ATTRIBUTE_UNUSED
)
3977 return sizeof (cpu_set_t
);
3981 __gnat_cpu_free (cpu_set_t
*set
)
3987 __gnat_cpu_zero (size_t count ATTRIBUTE_UNUSED
, cpu_set_t
*set
)
3993 __gnat_cpu_set (int cpu
, size_t count ATTRIBUTE_UNUSED
, cpu_set_t
*set
)
3995 /* Ada handles CPU numbers starting from 1, while C identifies the first
3996 CPU by a 0, so we need to adjust. */
3997 CPU_SET (cpu
- 1, set
);
3999 #endif /* !CPU_ALLOC */
4002 /* Return the load address of the executable, or 0 if not known. In the
4003 specific case of error, (void *)-1 can be returned. Beware: this unit may
4004 be in a shared library. As low-level units are needed, we allow #include
4007 #if defined (__APPLE__)
4008 #include <mach-o/dyld.h>
4009 #elif 0 && defined (__linux__)
4014 __gnat_get_executable_load_address (void)
4016 #if defined (__APPLE__)
4017 return _dyld_get_image_header (0);
4019 #elif 0 && defined (__linux__)
4020 /* Currently disabled as it needs at least -ldl. */
4021 struct link_map
*map
= _r_debug
.r_map
;
4023 return (const void *)map
->l_addr
;