* builtins.def (BUILT_IN_SETJMP): Revert latest change.
[official-gcc.git] / gcc / ada / adaint.c
blob10325b0f1d05418c3485eb5409752743dd0a4c34
1 /****************************************************************************
2 * *
3 * GNAT COMPILER COMPONENTS *
4 * *
5 * A D A I N T *
6 * *
7 * C Implementation File *
8 * *
9 * Copyright (C) 1992-2017, Free Software Foundation, Inc. *
10 * *
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. *
17 * *
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. *
21 * *
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/>. *
26 * *
27 * GNAT was originally developed by the GNAT team at New York University. *
28 * Extensive contributions were provided by Ada Core Technologies Inc. *
29 * *
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 access to errno is thread safe. */
38 #define _REENTRANT
39 #define _THREAD_SAFE
41 /* Use 64 bit Large File API */
42 #ifndef _LARGEFILE_SOURCE
43 #define _LARGEFILE_SOURCE
44 #endif
45 #define _FILE_OFFSET_BITS 64
47 #ifdef __vxworks
49 /* No need to redefine exit here. */
50 #undef exit
52 /* We want to use the POSIX variants of include files. */
53 #define POSIX
54 #include "vxWorks.h"
56 #if defined (__mips_vxworks)
57 #include "cacheLib.h"
58 #endif /* __mips_vxworks */
60 /* If SMP, access vxCpuConfiguredGet */
61 #ifdef _WRS_CONFIG_SMP
62 #include <vxCpuLib.h>
63 #endif /* _WRS_CONFIG_SMP */
65 /* We need to know the VxWorks version because some file operations
66 (such as chmod) are only available on VxWorks 6. */
67 #include "version.h"
69 #endif /* VxWorks */
71 #if defined (__APPLE__)
72 #include <unistd.h>
73 #endif
75 #if defined (__hpux__)
76 #include <sys/param.h>
77 #include <sys/pstat.h>
78 #endif
80 #ifdef __PikeOS__
81 #define __BSD_VISIBLE 1
82 #endif
84 #ifdef IN_RTS
85 #include "tconfig.h"
86 #include "tsystem.h"
87 #include <sys/stat.h>
88 #include <fcntl.h>
89 #include <time.h>
91 #if defined (__vxworks) || defined (__ANDROID__)
92 /* S_IREAD and S_IWRITE are not defined in VxWorks or Android */
93 #ifndef S_IREAD
94 #define S_IREAD (S_IRUSR | S_IRGRP | S_IROTH)
95 #endif
97 #ifndef S_IWRITE
98 #define S_IWRITE (S_IWUSR)
99 #endif
100 #endif
102 /* We don't have libiberty, so use malloc. */
103 #define xmalloc(S) malloc (S)
104 #define xrealloc(V,S) realloc (V,S)
105 #else
106 #include "config.h"
107 #include "system.h"
108 #include "version.h"
109 #endif
111 #ifdef __cplusplus
112 extern "C" {
113 #endif
115 #if defined (__DJGPP__)
117 /* For isalpha-like tests in the compiler, we're expected to resort to
118 safe-ctype.h/ISALPHA. This isn't available for the runtime library
119 build, so we fallback on ctype.h/isalpha there. */
121 #ifdef IN_RTS
122 #include <ctype.h>
123 #define ISALPHA isalpha
124 #endif
126 #elif defined (__MINGW32__) || defined (__CYGWIN__)
128 #include "mingw32.h"
130 /* Current code page and CCS encoding to use, set in initialize.c. */
131 UINT __gnat_current_codepage;
132 UINT __gnat_current_ccs_encoding;
134 #include <sys/utime.h>
136 /* For isalpha-like tests in the compiler, we're expected to resort to
137 safe-ctype.h/ISALPHA. This isn't available for the runtime library
138 build, so we fallback on ctype.h/isalpha there. */
140 #ifdef IN_RTS
141 #include <ctype.h>
142 #define ISALPHA isalpha
143 #endif
145 #elif defined (__Lynx__)
147 /* Lynx utime.h only defines the entities of interest to us if
148 defined (VMOS_DEV), so ... */
149 #define VMOS_DEV
150 #include <utime.h>
151 #undef VMOS_DEV
153 #else
154 #include <utime.h>
155 #endif
157 /* wait.h processing */
158 #ifdef __MINGW32__
159 # if OLD_MINGW
160 # include <sys/wait.h>
161 # endif
162 #elif defined (__vxworks) && defined (__RTP__)
163 # include <wait.h>
164 #elif defined (__Lynx__)
165 /* ??? We really need wait.h and it includes resource.h on Lynx. GCC
166 has a resource.h header as well, included instead of the lynx
167 version in our setup, causing lots of errors. We don't really need
168 the lynx contents of this file, so just workaround the issue by
169 preventing the inclusion of the GCC header from doing anything. */
170 # define GCC_RESOURCE_H
171 # include <sys/wait.h>
172 #elif defined (__PikeOS__)
173 /* No wait() or waitpid() calls available. */
174 #else
175 /* Default case. */
176 #include <sys/wait.h>
177 #endif
179 #if defined (__DJGPP__)
180 #include <process.h>
181 #include <signal.h>
182 #include <dir.h>
183 #include <utime.h>
184 #undef DIR_SEPARATOR
185 #define DIR_SEPARATOR '\\'
187 #elif defined (_WIN32)
189 #include <windows.h>
190 #include <accctrl.h>
191 #include <aclapi.h>
192 #include <tlhelp32.h>
193 #include <signal.h>
194 #undef DIR_SEPARATOR
195 #define DIR_SEPARATOR '\\'
197 #else
198 #include <utime.h>
199 #endif
201 #include "adaint.h"
203 /* Define symbols O_BINARY and O_TEXT as harmless zeroes if they are not
204 defined in the current system. On DOS-like systems these flags control
205 whether the file is opened/created in text-translation mode (CR/LF in
206 external file mapped to LF in internal file), but in Unix-like systems,
207 no text translation is required, so these flags have no effect. */
209 #ifndef O_BINARY
210 #define O_BINARY 0
211 #endif
213 #ifndef O_TEXT
214 #define O_TEXT 0
215 #endif
217 #ifndef HOST_EXECUTABLE_SUFFIX
218 #define HOST_EXECUTABLE_SUFFIX ""
219 #endif
221 #ifndef HOST_OBJECT_SUFFIX
222 #define HOST_OBJECT_SUFFIX ".o"
223 #endif
225 #ifndef PATH_SEPARATOR
226 #define PATH_SEPARATOR ':'
227 #endif
229 #ifndef DIR_SEPARATOR
230 #define DIR_SEPARATOR '/'
231 #endif
233 /* Check for cross-compilation. */
234 #if defined (CROSS_COMPILE) || defined (CROSS_DIRECTORY_STRUCTURE)
235 #define IS_CROSS 1
236 int __gnat_is_cross_compiler = 1;
237 #else
238 #undef IS_CROSS
239 int __gnat_is_cross_compiler = 0;
240 #endif
242 char __gnat_dir_separator = DIR_SEPARATOR;
244 char __gnat_path_separator = PATH_SEPARATOR;
246 /* The GNAT_LIBRARY_TEMPLATE contains a list of expressions that define
247 the base filenames that libraries specified with -lsomelib options
248 may have. This is used by GNATMAKE to check whether an executable
249 is up-to-date or not. The syntax is
251 library_template ::= { pattern ; } pattern NUL
252 pattern ::= [ prefix ] * [ postfix ]
254 These should only specify names of static libraries as it makes
255 no sense to determine at link time if dynamic-link libraries are
256 up to date or not. Any libraries that are not found are supposed
257 to be up-to-date:
259 * if they are needed but not present, the link
260 will fail,
262 * otherwise they are libraries in the system paths and so
263 they are considered part of the system and not checked
264 for that reason.
266 ??? This should be part of a GNAT host-specific compiler
267 file instead of being included in all user applications
268 as well. This is only a temporary work-around for 3.11b. */
270 #ifndef GNAT_LIBRARY_TEMPLATE
271 #define GNAT_LIBRARY_TEMPLATE "lib*.a"
272 #endif
274 const char *__gnat_library_template = GNAT_LIBRARY_TEMPLATE;
276 #if defined (__vxworks)
277 #define GNAT_MAX_PATH_LEN PATH_MAX
279 #else
281 #if defined (__MINGW32__)
282 #include "mingw32.h"
284 #if OLD_MINGW
285 #include <sys/param.h>
286 #endif
288 #else
289 #include <sys/param.h>
290 #endif
292 #ifdef MAXPATHLEN
293 #define GNAT_MAX_PATH_LEN MAXPATHLEN
294 #else
295 #define GNAT_MAX_PATH_LEN 256
296 #endif
298 #endif
300 /* Used for runtime check that Ada constant File_Attributes_Size is no
301 less than the actual size of struct file_attributes (see Osint
302 initialization). */
303 int __gnat_size_of_file_attributes = sizeof (struct file_attributes);
305 void __gnat_stat_to_attr (int fd, char* name, struct file_attributes* attr);
307 /* The __gnat_max_path_len variable is used to export the maximum
308 length of a path name to Ada code. max_path_len is also provided
309 for compatibility with older GNAT versions, please do not use
310 it. */
312 int __gnat_max_path_len = GNAT_MAX_PATH_LEN;
313 int max_path_len = GNAT_MAX_PATH_LEN;
315 /* Control whether we can use ACL on Windows. */
317 int __gnat_use_acl = 1;
319 /* The following macro HAVE_READDIR_R should be defined if the
320 system provides the routine readdir_r.
321 ... but we never define it anywhere??? */
322 #undef HAVE_READDIR_R
324 #define MAYBE_TO_PTR32(argv) argv
326 static const char ATTR_UNSET = 127;
328 /* Reset the file attributes as if no system call had been performed */
330 void
331 __gnat_reset_attributes (struct file_attributes* attr)
333 attr->exists = ATTR_UNSET;
334 attr->error = EINVAL;
336 attr->writable = ATTR_UNSET;
337 attr->readable = ATTR_UNSET;
338 attr->executable = ATTR_UNSET;
340 attr->regular = ATTR_UNSET;
341 attr->symbolic_link = ATTR_UNSET;
342 attr->directory = ATTR_UNSET;
344 attr->timestamp = (OS_Time)-2;
345 attr->file_length = -1;
349 __gnat_error_attributes (struct file_attributes *attr) {
350 return attr->error;
353 OS_Time
354 __gnat_current_time (void)
356 time_t res = time (NULL);
357 return (OS_Time) res;
360 /* Return the current local time as a string in the ISO 8601 format of
361 "YYYY-MM-DD HH:MM:SS.SS". The returned string is 22 + 1 (NULL) characters
362 long. */
364 void
365 __gnat_current_time_string (char *result)
367 const char *format = "%Y-%m-%d %H:%M:%S";
368 /* Format string necessary to describe the ISO 8601 format */
370 const time_t t_val = time (NULL);
372 strftime (result, 22, format, localtime (&t_val));
373 /* Convert the local time into a string following the ISO format, copying
374 at most 22 characters into the result string. */
376 result [19] = '.';
377 result [20] = '0';
378 result [21] = '0';
379 /* The sub-seconds are manually set to zero since type time_t lacks the
380 precision necessary for nanoseconds. */
383 void
384 __gnat_to_gm_time (OS_Time *p_time, int *p_year, int *p_month, int *p_day,
385 int *p_hours, int *p_mins, int *p_secs)
387 struct tm *res;
388 time_t time = (time_t) *p_time;
390 #ifdef _WIN32
391 /* On Windows systems, the time is sometimes rounded up to the nearest
392 even second, so if the number of seconds is odd, increment it. */
393 if (time & 1)
394 time++;
395 #endif
397 res = gmtime (&time);
398 if (res)
400 *p_year = res->tm_year;
401 *p_month = res->tm_mon;
402 *p_day = res->tm_mday;
403 *p_hours = res->tm_hour;
404 *p_mins = res->tm_min;
405 *p_secs = res->tm_sec;
407 else
408 *p_year = *p_month = *p_day = *p_hours = *p_mins = *p_secs = 0;
411 void
412 __gnat_to_os_time (OS_Time *p_time, int year, int month, int day,
413 int hours, int mins, int secs)
415 struct tm v;
417 v.tm_year = year;
418 v.tm_mon = month;
419 v.tm_mday = day;
420 v.tm_hour = hours;
421 v.tm_min = mins;
422 v.tm_sec = secs;
423 v.tm_isdst = -1;
425 /* returns -1 of failing, this is s-os_lib Invalid_Time */
427 *p_time = (OS_Time) mktime (&v);
430 /* Place the contents of the symbolic link named PATH in the buffer BUF,
431 which has size BUFSIZ. If PATH is a symbolic link, then return the number
432 of characters of its content in BUF. Otherwise, return -1.
433 For systems not supporting symbolic links, always return -1. */
436 __gnat_readlink (char *path ATTRIBUTE_UNUSED,
437 char *buf ATTRIBUTE_UNUSED,
438 size_t bufsiz ATTRIBUTE_UNUSED)
440 #if defined (_WIN32) \
441 || defined(__vxworks) || defined (__PikeOS__)
442 return -1;
443 #else
444 return readlink (path, buf, bufsiz);
445 #endif
448 /* Creates a symbolic link named NEWPATH which contains the string OLDPATH.
449 If NEWPATH exists it will NOT be overwritten.
450 For systems not supporting symbolic links, always return -1. */
453 __gnat_symlink (char *oldpath ATTRIBUTE_UNUSED,
454 char *newpath ATTRIBUTE_UNUSED)
456 #if defined (_WIN32) \
457 || defined(__vxworks) || defined (__PikeOS__)
458 return -1;
459 #else
460 return symlink (oldpath, newpath);
461 #endif
464 /* Try to lock a file, return 1 if success. */
466 #if defined (__vxworks) \
467 || defined (_WIN32) || defined (__PikeOS__)
469 /* Version that does not use link. */
472 __gnat_try_lock (char *dir, char *file)
474 int fd;
475 #ifdef __MINGW32__
476 TCHAR wfull_path[GNAT_MAX_PATH_LEN];
477 TCHAR wfile[GNAT_MAX_PATH_LEN];
478 TCHAR wdir[GNAT_MAX_PATH_LEN];
480 S2WSC (wdir, dir, GNAT_MAX_PATH_LEN);
481 S2WSC (wfile, file, GNAT_MAX_PATH_LEN);
483 /* ??? the code below crash on MingW64 for obscure reasons, a ticket
484 has been opened here:
486 https://sourceforge.net/p/mingw-w64/bugs/414/
488 As a workaround an equivalent set of code has been put in place below.
490 _stprintf (wfull_path, _T("%s%c%s"), wdir, _T(DIR_SEPARATOR), wfile);
493 _tcscpy (wfull_path, wdir);
494 _tcscat (wfull_path, L"\\");
495 _tcscat (wfull_path, wfile);
497 fd = _topen (wfull_path, O_CREAT | O_EXCL, 0600);
498 #else
499 char full_path[256];
501 sprintf (full_path, "%s%c%s", dir, DIR_SEPARATOR, file);
502 fd = open (full_path, O_CREAT | O_EXCL, 0600);
503 #endif
505 if (fd < 0)
506 return 0;
508 close (fd);
509 return 1;
512 #else
514 /* Version using link(), more secure over NFS. */
515 /* See TN 6913-016 for discussion ??? */
518 __gnat_try_lock (char *dir, char *file)
520 char full_path[256];
521 char temp_file[256];
522 GNAT_STRUCT_STAT stat_result;
523 int fd;
525 sprintf (full_path, "%s%c%s", dir, DIR_SEPARATOR, file);
526 sprintf (temp_file, "%s%cTMP-%ld-%ld",
527 dir, DIR_SEPARATOR, (long)getpid(), (long)getppid ());
529 /* Create the temporary file and write the process number. */
530 fd = open (temp_file, O_CREAT | O_WRONLY, 0600);
531 if (fd < 0)
532 return 0;
534 close (fd);
536 /* Link it with the new file. */
537 link (temp_file, full_path);
539 /* Count the references on the old one. If we have a count of two, then
540 the link did succeed. Remove the temporary file before returning. */
541 __gnat_stat (temp_file, &stat_result);
542 unlink (temp_file);
543 return stat_result.st_nlink == 2;
545 #endif
547 /* Return the maximum file name length. */
550 __gnat_get_maximum_file_name_length (void)
552 return -1;
555 /* Return nonzero if file names are case sensitive. */
557 static int file_names_case_sensitive_cache = -1;
560 __gnat_get_file_names_case_sensitive (void)
562 if (file_names_case_sensitive_cache == -1)
564 const char *sensitive = getenv ("GNAT_FILE_NAME_CASE_SENSITIVE");
566 if (sensitive != NULL
567 && (sensitive[0] == '0' || sensitive[0] == '1')
568 && sensitive[1] == '\0')
569 file_names_case_sensitive_cache = sensitive[0] - '0';
570 else
572 /* By default, we suppose filesystems aren't case sensitive on
573 Windows and Darwin (but they are on arm-darwin). */
574 #if defined (WINNT) || defined (__DJGPP__) \
575 || (defined (__APPLE__) && !(defined (__arm__) || defined (__arm64__)))
576 file_names_case_sensitive_cache = 0;
577 #else
578 file_names_case_sensitive_cache = 1;
579 #endif
582 return file_names_case_sensitive_cache;
585 /* Return nonzero if environment variables are case sensitive. */
588 __gnat_get_env_vars_case_sensitive (void)
590 #if defined (WINNT) || defined (__DJGPP__)
591 return 0;
592 #else
593 return 1;
594 #endif
597 char
598 __gnat_get_default_identifier_character_set (void)
600 return '1';
603 /* Return the current working directory. */
605 void
606 __gnat_get_current_dir (char *dir, int *length)
608 #if defined (__MINGW32__)
609 TCHAR wdir[GNAT_MAX_PATH_LEN];
611 _tgetcwd (wdir, *length);
613 WS2SC (dir, wdir, GNAT_MAX_PATH_LEN);
615 #else
616 char* result = getcwd (dir, *length);
617 /* If the current directory does not exist, set length = 0
618 to indicate error. That can't happen on windows, where
619 you can't delete a directory if it is the current
620 directory of some process. */
621 if (!result)
623 *length = 0;
624 return;
626 #endif
628 *length = strlen (dir);
630 if (dir [*length - 1] != DIR_SEPARATOR)
632 dir [*length] = DIR_SEPARATOR;
633 ++(*length);
635 dir[*length] = '\0';
638 /* Return the suffix for object files. */
640 void
641 __gnat_get_object_suffix_ptr (int *len, const char **value)
643 *value = HOST_OBJECT_SUFFIX;
645 if (*value == 0)
646 *len = 0;
647 else
648 *len = strlen (*value);
650 return;
653 /* Return the suffix for executable files. */
655 void
656 __gnat_get_executable_suffix_ptr (int *len, const char **value)
658 *value = HOST_EXECUTABLE_SUFFIX;
659 if (!*value)
660 *len = 0;
661 else
662 *len = strlen (*value);
664 return;
667 /* Return the suffix for debuggable files. Usually this is the same as the
668 executable extension. */
670 void
671 __gnat_get_debuggable_suffix_ptr (int *len, const char **value)
673 *value = HOST_EXECUTABLE_SUFFIX;
675 if (*value == 0)
676 *len = 0;
677 else
678 *len = strlen (*value);
680 return;
683 /* Returns the OS filename and corresponding encoding. */
685 void
686 __gnat_os_filename (char *filename ATTRIBUTE_UNUSED,
687 char *w_filename ATTRIBUTE_UNUSED,
688 char *os_name, int *o_length,
689 char *encoding ATTRIBUTE_UNUSED, int *e_length)
691 #if defined (_WIN32) && ! defined (__vxworks) && ! defined (IS_CROSS)
692 WS2SC (os_name, (TCHAR *)w_filename, (DWORD)*o_length);
693 *o_length = strlen (os_name);
694 strcpy (encoding, "encoding=utf8");
695 *e_length = strlen (encoding);
696 #else
697 strcpy (os_name, filename);
698 *o_length = strlen (filename);
699 *e_length = 0;
700 #endif
703 /* Delete a file. */
706 __gnat_unlink (char *path)
708 #if defined (__MINGW32__) && ! defined (__vxworks) && ! defined (IS_CROSS)
710 TCHAR wpath[GNAT_MAX_PATH_LEN];
712 S2WSC (wpath, path, GNAT_MAX_PATH_LEN);
713 return _tunlink (wpath);
715 #else
716 return unlink (path);
717 #endif
720 /* Rename a file. */
723 __gnat_rename (char *from, char *to)
725 #if defined (__MINGW32__) && ! defined (__vxworks) && ! defined (IS_CROSS)
727 TCHAR wfrom[GNAT_MAX_PATH_LEN], wto[GNAT_MAX_PATH_LEN];
729 S2WSC (wfrom, from, GNAT_MAX_PATH_LEN);
730 S2WSC (wto, to, GNAT_MAX_PATH_LEN);
731 return _trename (wfrom, wto);
733 #else
734 return rename (from, to);
735 #endif
738 /* Changing directory. */
741 __gnat_chdir (char *path)
743 #if defined (__MINGW32__) && ! defined (__vxworks) && ! defined (IS_CROSS)
745 TCHAR wpath[GNAT_MAX_PATH_LEN];
747 S2WSC (wpath, path, GNAT_MAX_PATH_LEN);
748 return _tchdir (wpath);
750 #else
751 return chdir (path);
752 #endif
755 /* Removing a directory. */
758 __gnat_rmdir (char *path)
760 #if defined (__MINGW32__) && ! defined (__vxworks) && ! defined (IS_CROSS)
762 TCHAR wpath[GNAT_MAX_PATH_LEN];
764 S2WSC (wpath, path, GNAT_MAX_PATH_LEN);
765 return _trmdir (wpath);
767 #elif defined (VTHREADS)
768 /* rmdir not available */
769 return -1;
770 #else
771 return rmdir (path);
772 #endif
775 #if defined (_WIN32) || defined (__linux__) || defined (__sun__) \
776 || defined (__FreeBSD__) || defined(__DragonFly__)
777 #define HAS_TARGET_WCHAR_T
778 #endif
780 #ifdef HAS_TARGET_WCHAR_T
781 #include <wchar.h>
782 #endif
785 __gnat_fputwc(int c, FILE *stream)
787 #ifdef HAS_TARGET_WCHAR_T
788 return fputwc ((wchar_t)c, stream);
789 #else
790 return fputc (c, stream);
791 #endif
794 FILE *
795 __gnat_fopen (char *path, char *mode, int encoding ATTRIBUTE_UNUSED)
797 #if defined (_WIN32) && ! defined (__vxworks) && ! defined (IS_CROSS)
798 TCHAR wpath[GNAT_MAX_PATH_LEN];
799 TCHAR wmode[10];
801 S2WS (wmode, mode, 10);
803 if (encoding == Encoding_Unspecified)
804 S2WSC (wpath, path, GNAT_MAX_PATH_LEN);
805 else if (encoding == Encoding_UTF8)
806 S2WSU (wpath, path, GNAT_MAX_PATH_LEN);
807 else
808 S2WS (wpath, path, GNAT_MAX_PATH_LEN);
810 return _tfopen (wpath, wmode);
812 #else
813 return GNAT_FOPEN (path, mode);
814 #endif
817 FILE *
818 __gnat_freopen (char *path,
819 char *mode,
820 FILE *stream,
821 int encoding ATTRIBUTE_UNUSED)
823 #if defined (_WIN32) && ! defined (__vxworks) && ! defined (IS_CROSS)
824 TCHAR wpath[GNAT_MAX_PATH_LEN];
825 TCHAR wmode[10];
827 S2WS (wmode, mode, 10);
829 if (encoding == Encoding_Unspecified)
830 S2WSC (wpath, path, GNAT_MAX_PATH_LEN);
831 else if (encoding == Encoding_UTF8)
832 S2WSU (wpath, path, GNAT_MAX_PATH_LEN);
833 else
834 S2WS (wpath, path, GNAT_MAX_PATH_LEN);
836 return _tfreopen (wpath, wmode, stream);
837 #else
838 return freopen (path, mode, stream);
839 #endif
843 __gnat_open_read (char *path, int fmode)
845 int fd;
846 int o_fmode = O_BINARY;
848 if (fmode)
849 o_fmode = O_TEXT;
851 #if defined (__vxworks)
852 fd = open (path, O_RDONLY | o_fmode, 0444);
853 #elif defined (__MINGW32__)
855 TCHAR wpath[GNAT_MAX_PATH_LEN];
857 S2WSC (wpath, path, GNAT_MAX_PATH_LEN);
858 fd = _topen (wpath, O_RDONLY | o_fmode, 0444);
860 #else
861 fd = GNAT_OPEN (path, O_RDONLY | o_fmode);
862 #endif
864 return fd < 0 ? -1 : fd;
867 #if defined (__MINGW32__)
868 #define PERM (S_IREAD | S_IWRITE)
869 #else
870 #define PERM (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH)
871 #endif
874 __gnat_open_rw (char *path, int fmode)
876 int fd;
877 int o_fmode = O_BINARY;
879 if (fmode)
880 o_fmode = O_TEXT;
882 #if defined (__MINGW32__)
884 TCHAR wpath[GNAT_MAX_PATH_LEN];
886 S2WSC (wpath, path, GNAT_MAX_PATH_LEN);
887 fd = _topen (wpath, O_RDWR | o_fmode, PERM);
889 #else
890 fd = GNAT_OPEN (path, O_RDWR | o_fmode, PERM);
891 #endif
893 return fd < 0 ? -1 : fd;
897 __gnat_open_create (char *path, int fmode)
899 int fd;
900 int o_fmode = O_BINARY;
902 if (fmode)
903 o_fmode = O_TEXT;
905 #if defined (__MINGW32__)
907 TCHAR wpath[GNAT_MAX_PATH_LEN];
909 S2WSC (wpath, path, GNAT_MAX_PATH_LEN);
910 fd = _topen (wpath, O_WRONLY | O_CREAT | O_TRUNC | o_fmode, PERM);
912 #else
913 fd = GNAT_OPEN (path, O_WRONLY | O_CREAT | O_TRUNC | o_fmode, PERM);
914 #endif
916 return fd < 0 ? -1 : fd;
920 __gnat_create_output_file (char *path)
922 int fd;
923 #if defined (__MINGW32__)
925 TCHAR wpath[GNAT_MAX_PATH_LEN];
927 S2WSC (wpath, path, GNAT_MAX_PATH_LEN);
928 fd = _topen (wpath, O_WRONLY | O_CREAT | O_TRUNC | O_TEXT, PERM);
930 #else
931 fd = GNAT_OPEN (path, O_WRONLY | O_CREAT | O_TRUNC | O_TEXT, PERM);
932 #endif
934 return fd < 0 ? -1 : fd;
938 __gnat_create_output_file_new (char *path)
940 int fd;
941 #if defined (__MINGW32__)
943 TCHAR wpath[GNAT_MAX_PATH_LEN];
945 S2WSC (wpath, path, GNAT_MAX_PATH_LEN);
946 fd = _topen (wpath, O_WRONLY | O_CREAT | O_TRUNC | O_TEXT | O_EXCL, PERM);
948 #else
949 fd = GNAT_OPEN (path, O_WRONLY | O_CREAT | O_TRUNC | O_TEXT | O_EXCL, PERM);
950 #endif
952 return fd < 0 ? -1 : fd;
956 __gnat_open_append (char *path, int fmode)
958 int fd;
959 int o_fmode = O_BINARY;
961 if (fmode)
962 o_fmode = O_TEXT;
964 #if defined (__MINGW32__)
966 TCHAR wpath[GNAT_MAX_PATH_LEN];
968 S2WSC (wpath, path, GNAT_MAX_PATH_LEN);
969 fd = _topen (wpath, O_WRONLY | O_CREAT | O_APPEND | o_fmode, PERM);
971 #else
972 fd = GNAT_OPEN (path, O_WRONLY | O_CREAT | O_APPEND | o_fmode, PERM);
973 #endif
975 return fd < 0 ? -1 : fd;
978 /* Open a new file. Return error (-1) if the file already exists. */
981 __gnat_open_new (char *path, int fmode)
983 int fd;
984 int o_fmode = O_BINARY;
986 if (fmode)
987 o_fmode = O_TEXT;
989 #if defined (__MINGW32__)
991 TCHAR wpath[GNAT_MAX_PATH_LEN];
993 S2WSC (wpath, path, GNAT_MAX_PATH_LEN);
994 fd = _topen (wpath, O_WRONLY | O_CREAT | O_EXCL | o_fmode, PERM);
996 #else
997 fd = GNAT_OPEN (path, O_WRONLY | O_CREAT | O_EXCL | o_fmode, PERM);
998 #endif
1000 return fd < 0 ? -1 : fd;
1003 /* Open a new temp file. Return error (-1) if the file already exists. */
1006 __gnat_open_new_temp (char *path, int fmode)
1008 int fd;
1009 int o_fmode = O_BINARY;
1011 strcpy (path, "GNAT-XXXXXX");
1013 #if (defined (__FreeBSD__) || defined (__NetBSD__) || defined (__OpenBSD__) \
1014 || defined (__linux__) || defined (__GLIBC__) || defined (__ANDROID__) \
1015 || defined (__DragonFly__)) && !defined (__vxworks)
1016 return mkstemp (path);
1017 #elif defined (__Lynx__)
1018 mktemp (path);
1019 #else
1020 if (mktemp (path) == NULL)
1021 return -1;
1022 #endif
1024 if (fmode)
1025 o_fmode = O_TEXT;
1027 fd = GNAT_OPEN (path, O_WRONLY | O_CREAT | O_EXCL | o_fmode, PERM);
1028 return fd < 0 ? -1 : fd;
1032 __gnat_open (char *path, int fmode)
1034 int fd;
1036 #if defined (__MINGW32__)
1038 TCHAR wpath[GNAT_MAX_PATH_LEN];
1040 S2WSC (wpath, path, GNAT_MAX_PATH_LEN);
1041 fd = _topen (wpath, fmode, PERM);
1043 #else
1044 fd = GNAT_OPEN (path, fmode, PERM);
1045 #endif
1047 return fd < 0 ? -1 : fd;
1050 /****************************************************************
1051 ** Perform a call to GNAT_STAT or GNAT_FSTAT, and extract as much information
1052 ** as possible from it, storing the result in a cache for later reuse
1053 ****************************************************************/
1055 void
1056 __gnat_stat_to_attr (int fd, char* name, struct file_attributes* attr)
1058 GNAT_STRUCT_STAT statbuf;
1059 int ret, error;
1061 if (fd != -1) {
1062 /* GNAT_FSTAT returns -1 and sets errno for failure */
1063 ret = GNAT_FSTAT (fd, &statbuf);
1064 error = ret ? errno : 0;
1066 } else {
1067 /* __gnat_stat returns errno value directly */
1068 error = __gnat_stat (name, &statbuf);
1069 ret = error ? -1 : 0;
1073 * A missing file is reported as an attr structure with error == 0 and
1074 * exists == 0.
1077 if (error == 0 || error == ENOENT)
1078 attr->error = 0;
1079 else
1080 attr->error = error;
1082 attr->regular = (!ret && S_ISREG (statbuf.st_mode));
1083 attr->directory = (!ret && S_ISDIR (statbuf.st_mode));
1085 if (!attr->regular)
1086 attr->file_length = 0;
1087 else
1088 /* st_size may be 32 bits, or 64 bits which is converted to long. We
1089 don't return a useful value for files larger than 2 gigabytes in
1090 either case. */
1091 attr->file_length = statbuf.st_size; /* all systems */
1093 attr->exists = !ret;
1095 #if !defined (_WIN32)
1096 /* on Windows requires extra system call, see __gnat_is_readable_file_attr */
1097 attr->readable = (!ret && (statbuf.st_mode & S_IRUSR));
1098 attr->writable = (!ret && (statbuf.st_mode & S_IWUSR));
1099 attr->executable = (!ret && (statbuf.st_mode & S_IXUSR));
1100 #endif
1102 if (ret != 0) {
1103 attr->timestamp = (OS_Time)-1;
1104 } else {
1105 attr->timestamp = (OS_Time)statbuf.st_mtime;
1109 /****************************************************************
1110 ** Return the number of bytes in the specified file
1111 ****************************************************************/
1113 __int64
1114 __gnat_file_length_attr (int fd, char* name, struct file_attributes* attr)
1116 if (attr->file_length == -1) {
1117 __gnat_stat_to_attr (fd, name, attr);
1120 return attr->file_length;
1123 __int64
1124 __gnat_file_length (int fd)
1126 struct file_attributes attr;
1127 __gnat_reset_attributes (&attr);
1128 return __gnat_file_length_attr (fd, NULL, &attr);
1131 long
1132 __gnat_file_length_long (int fd)
1134 struct file_attributes attr;
1135 __gnat_reset_attributes (&attr);
1136 return (long)__gnat_file_length_attr (fd, NULL, &attr);
1139 __int64
1140 __gnat_named_file_length (char *name)
1142 struct file_attributes attr;
1143 __gnat_reset_attributes (&attr);
1144 return __gnat_file_length_attr (-1, name, &attr);
1147 /* Create a temporary filename and put it in string pointed to by
1148 TMP_FILENAME. */
1150 void
1151 __gnat_tmp_name (char *tmp_filename)
1153 #if defined (__MINGW32__)
1155 char *pname;
1156 char prefix[25];
1158 /* tempnam tries to create a temporary file in directory pointed to by
1159 TMP environment variable, in c:\temp if TMP is not set, and in
1160 directory specified by P_tmpdir in stdio.h if c:\temp does not
1161 exist. The filename will be created with the prefix "gnat-". */
1163 sprintf (prefix, "gnat-%d-", (int)getpid());
1164 pname = (char *) _tempnam ("c:\\temp", prefix);
1166 /* if pname is NULL, the file was not created properly, the disk is full
1167 or there is no more free temporary files */
1169 if (pname == NULL)
1170 *tmp_filename = '\0';
1172 /* If pname start with a back slash and not path information it means that
1173 the filename is valid for the current working directory. */
1175 else if (pname[0] == '\\')
1177 strcpy (tmp_filename, ".\\");
1178 strcat (tmp_filename, pname+1);
1180 else
1181 strcpy (tmp_filename, pname);
1183 free (pname);
1186 #elif defined (__linux__) || defined (__FreeBSD__) || defined (__NetBSD__) \
1187 || defined (__OpenBSD__) || defined (__GLIBC__) || defined (__ANDROID__) \
1188 || defined (__DragonFly__)
1189 #define MAX_SAFE_PATH 1000
1190 char *tmpdir = getenv ("TMPDIR");
1192 /* If tmpdir is longer than MAX_SAFE_PATH, revert to default value to avoid
1193 a buffer overflow. */
1194 if (tmpdir == NULL || strlen (tmpdir) > MAX_SAFE_PATH)
1195 #ifdef __ANDROID__
1196 strcpy (tmp_filename, "/cache/gnat-XXXXXX");
1197 #else
1198 strcpy (tmp_filename, "/tmp/gnat-XXXXXX");
1199 #endif
1200 else
1201 sprintf (tmp_filename, "%s/gnat-XXXXXX", tmpdir);
1203 close (mkstemp(tmp_filename));
1204 #elif defined (__vxworks) && !defined (VTHREADS)
1205 int index;
1206 char *pos;
1207 char *savepos;
1208 static ushort_t seed = 0; /* used to generate unique name */
1210 /* Generate a unique name. */
1211 strcpy (tmp_filename, "tmp");
1213 index = 5;
1214 savepos = pos = tmp_filename + strlen (tmp_filename) + index;
1215 *pos = '\0';
1217 while (1)
1219 FILE *f;
1220 ushort_t t;
1222 /* Fill up the name buffer from the last position. */
1223 seed++;
1224 for (t = seed; 0 <= --index; t >>= 3)
1225 *--pos = '0' + (t & 07);
1227 /* Check to see if its unique, if not bump the seed and try again. */
1228 f = fopen (tmp_filename, "r");
1229 if (f == NULL)
1230 break;
1231 fclose (f);
1232 pos = savepos;
1233 index = 5;
1235 #else
1236 tmpnam (tmp_filename);
1237 #endif
1240 /* Open directory and returns a DIR pointer. */
1242 DIR* __gnat_opendir (char *name)
1244 #if defined (__MINGW32__)
1245 TCHAR wname[GNAT_MAX_PATH_LEN];
1247 S2WSC (wname, name, GNAT_MAX_PATH_LEN);
1248 return (DIR*)_topendir (wname);
1250 #else
1251 return opendir (name);
1252 #endif
1255 /* Read the next entry in a directory. The returned string points somewhere
1256 in the buffer. */
1258 #if defined (__sun__)
1259 /* For Solaris, be sure to use the 64-bit version, otherwise NFS reads may
1260 fail with EOVERFLOW if the server uses 64-bit cookies. */
1261 #define dirent dirent64
1262 #define readdir readdir64
1263 #endif
1265 char *
1266 __gnat_readdir (DIR *dirp, char *buffer, int *len)
1268 #if defined (__MINGW32__)
1269 struct _tdirent *dirent = _treaddir ((_TDIR*)dirp);
1271 if (dirent != NULL)
1273 WS2SC (buffer, dirent->d_name, GNAT_MAX_PATH_LEN);
1274 *len = strlen (buffer);
1276 return buffer;
1278 else
1279 return NULL;
1281 #elif defined (HAVE_READDIR_R)
1282 /* If possible, try to use the thread-safe version. */
1283 if (readdir_r (dirp, buffer) != NULL)
1285 *len = strlen (((struct dirent*) buffer)->d_name);
1286 return ((struct dirent*) buffer)->d_name;
1288 else
1289 return NULL;
1291 #else
1292 struct dirent *dirent = (struct dirent *) readdir (dirp);
1294 if (dirent != NULL)
1296 strcpy (buffer, dirent->d_name);
1297 *len = strlen (buffer);
1298 return buffer;
1300 else
1301 return NULL;
1303 #endif
1306 /* Close a directory entry. */
1308 int __gnat_closedir (DIR *dirp)
1310 #if defined (__MINGW32__)
1311 return _tclosedir ((_TDIR*)dirp);
1313 #else
1314 return closedir (dirp);
1315 #endif
1318 /* Returns 1 if readdir is thread safe, 0 otherwise. */
1321 __gnat_readdir_is_thread_safe (void)
1323 #ifdef HAVE_READDIR_R
1324 return 1;
1325 #else
1326 return 0;
1327 #endif
1330 #if defined (_WIN32)
1331 /* Number of seconds between <Jan 1st 1601> and <Jan 1st 1970>. */
1332 static const unsigned long long w32_epoch_offset = 11644473600ULL;
1334 /* Returns the file modification timestamp using Win32 routines which are
1335 immune against daylight saving time change. It is in fact not possible to
1336 use fstat for this purpose as the DST modify the st_mtime field of the
1337 stat structure. */
1339 static time_t
1340 win32_filetime (HANDLE h)
1342 union
1344 FILETIME ft_time;
1345 unsigned long long ull_time;
1346 } t_write;
1348 /* GetFileTime returns FILETIME data which are the number of 100 nanosecs
1349 since <Jan 1st 1601>. This function must return the number of seconds
1350 since <Jan 1st 1970>. */
1352 if (GetFileTime (h, NULL, NULL, &t_write.ft_time))
1353 return (time_t) (t_write.ull_time / 10000000ULL - w32_epoch_offset);
1354 return (time_t) 0;
1357 /* As above but starting from a FILETIME. */
1358 static void
1359 f2t (const FILETIME *ft, __time64_t *t)
1361 union
1363 FILETIME ft_time;
1364 unsigned long long ull_time;
1365 } t_write;
1367 t_write.ft_time = *ft;
1368 *t = (__time64_t) (t_write.ull_time / 10000000ULL - w32_epoch_offset);
1370 #endif
1372 /* Return a GNAT time stamp given a file name. */
1374 OS_Time
1375 __gnat_file_time_name_attr (char* name, struct file_attributes* attr)
1377 if (attr->timestamp == (OS_Time)-2) {
1378 #if defined (_WIN32)
1379 BOOL res;
1380 WIN32_FILE_ATTRIBUTE_DATA fad;
1381 __time64_t ret = -1;
1382 TCHAR wname[GNAT_MAX_PATH_LEN];
1383 S2WSC (wname, name, GNAT_MAX_PATH_LEN);
1385 if ((res = GetFileAttributesEx (wname, GetFileExInfoStandard, &fad)))
1386 f2t (&fad.ftLastWriteTime, &ret);
1387 attr->timestamp = (OS_Time) ret;
1388 #else
1389 __gnat_stat_to_attr (-1, name, attr);
1390 #endif
1392 return attr->timestamp;
1395 OS_Time
1396 __gnat_file_time_name (char *name)
1398 struct file_attributes attr;
1399 __gnat_reset_attributes (&attr);
1400 return __gnat_file_time_name_attr (name, &attr);
1403 /* Return a GNAT time stamp given a file descriptor. */
1405 OS_Time
1406 __gnat_file_time_fd_attr (int fd, struct file_attributes* attr)
1408 if (attr->timestamp == (OS_Time)-2) {
1409 #if defined (_WIN32)
1410 HANDLE h = (HANDLE) _get_osfhandle (fd);
1411 time_t ret = win32_filetime (h);
1412 attr->timestamp = (OS_Time) ret;
1414 #else
1415 __gnat_stat_to_attr (fd, NULL, attr);
1416 #endif
1419 return attr->timestamp;
1422 OS_Time
1423 __gnat_file_time_fd (int fd)
1425 struct file_attributes attr;
1426 __gnat_reset_attributes (&attr);
1427 return __gnat_file_time_fd_attr (fd, &attr);
1430 /* Set the file time stamp. */
1432 void
1433 __gnat_set_file_time_name (char *name, time_t time_stamp)
1435 #if defined (__vxworks)
1437 /* Code to implement __gnat_set_file_time_name for these systems. */
1439 #elif defined (_WIN32)
1440 union
1442 FILETIME ft_time;
1443 unsigned long long ull_time;
1444 } t_write;
1445 TCHAR wname[GNAT_MAX_PATH_LEN];
1447 S2WSC (wname, name, GNAT_MAX_PATH_LEN);
1449 HANDLE h = CreateFile
1450 (wname, GENERIC_WRITE, FILE_SHARE_WRITE, NULL,
1451 OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS,
1452 NULL);
1453 if (h == INVALID_HANDLE_VALUE)
1454 return;
1455 /* Add number of seconds between <Jan 1st 1601> and <Jan 1st 1970> */
1456 t_write.ull_time = ((unsigned long long)time_stamp + w32_epoch_offset);
1457 /* Convert to 100 nanosecond units */
1458 t_write.ull_time *= 10000000ULL;
1460 SetFileTime(h, NULL, NULL, &t_write.ft_time);
1461 CloseHandle (h);
1462 return;
1464 #else
1465 struct utimbuf utimbuf;
1466 time_t t;
1468 /* Set modification time to requested time. */
1469 utimbuf.modtime = time_stamp;
1471 /* Set access time to now in local time. */
1472 t = time ((time_t) 0);
1473 utimbuf.actime = mktime (localtime (&t));
1475 utime (name, &utimbuf);
1476 #endif
1479 /* Get the list of installed standard libraries from the
1480 HKEY_LOCAL_MACHINE\SOFTWARE\Ada Core Technologies\GNAT\Standard Libraries
1481 key. */
1483 char *
1484 __gnat_get_libraries_from_registry (void)
1486 char *result = (char *) xmalloc (1);
1488 result[0] = '\0';
1490 #if defined (_WIN32) && ! defined (__vxworks) && ! defined (IS_CROSS)
1492 HKEY reg_key;
1493 DWORD name_size, value_size;
1494 char name[256];
1495 char value[256];
1496 DWORD type;
1497 DWORD index;
1498 LONG res;
1500 /* First open the key. */
1501 res = RegOpenKeyExA (HKEY_LOCAL_MACHINE, "SOFTWARE", 0, KEY_READ, &reg_key);
1503 if (res == ERROR_SUCCESS)
1504 res = RegOpenKeyExA (reg_key, "Ada Core Technologies", 0,
1505 KEY_READ, &reg_key);
1507 if (res == ERROR_SUCCESS)
1508 res = RegOpenKeyExA (reg_key, "GNAT", 0, KEY_READ, &reg_key);
1510 if (res == ERROR_SUCCESS)
1511 res = RegOpenKeyExA (reg_key, "Standard Libraries", 0, KEY_READ, &reg_key);
1513 /* If the key exists, read out all the values in it and concatenate them
1514 into a path. */
1515 for (index = 0; res == ERROR_SUCCESS; index++)
1517 value_size = name_size = 256;
1518 res = RegEnumValueA (reg_key, index, name, &name_size, 0,
1519 &type, (LPBYTE)value, &value_size);
1521 if (res == ERROR_SUCCESS && type == REG_SZ)
1523 char *old_result = result;
1525 result = (char *) xmalloc (strlen (old_result) + value_size + 2);
1526 strcpy (result, old_result);
1527 strcat (result, value);
1528 strcat (result, ";");
1529 free (old_result);
1533 /* Remove the trailing ";". */
1534 if (result[0] != 0)
1535 result[strlen (result) - 1] = 0;
1537 #endif
1538 return result;
1541 /* Query information for the given file NAME and return it in STATBUF.
1542 * Returns 0 for success, or errno value for failure.
1545 __gnat_stat (char *name, GNAT_STRUCT_STAT *statbuf)
1547 #ifdef __MINGW32__
1548 WIN32_FILE_ATTRIBUTE_DATA fad;
1549 TCHAR wname [GNAT_MAX_PATH_LEN + 2];
1550 int name_len;
1551 BOOL res;
1552 DWORD error;
1554 S2WSC (wname, name, GNAT_MAX_PATH_LEN + 2);
1555 name_len = _tcslen (wname);
1557 if (name_len > GNAT_MAX_PATH_LEN)
1558 return EINVAL;
1560 ZeroMemory (statbuf, sizeof(GNAT_STRUCT_STAT));
1562 res = GetFileAttributesEx (wname, GetFileExInfoStandard, &fad);
1564 if (res == FALSE) {
1565 error = GetLastError();
1567 /* Check file existence using GetFileAttributes() which does not fail on
1568 special Windows files like con:, aux:, nul: etc... */
1570 if (GetFileAttributes(wname) != INVALID_FILE_ATTRIBUTES) {
1571 /* Just pretend that it is a regular and readable file */
1572 statbuf->st_mode = S_IFREG | S_IREAD | S_IWRITE;
1573 return 0;
1576 switch (error) {
1577 case ERROR_ACCESS_DENIED:
1578 case ERROR_SHARING_VIOLATION:
1579 case ERROR_LOCK_VIOLATION:
1580 case ERROR_SHARING_BUFFER_EXCEEDED:
1581 return EACCES;
1582 case ERROR_BUFFER_OVERFLOW:
1583 return ENAMETOOLONG;
1584 case ERROR_NOT_ENOUGH_MEMORY:
1585 return ENOMEM;
1586 default:
1587 return ENOENT;
1591 f2t (&fad.ftCreationTime, &statbuf->st_ctime);
1592 f2t (&fad.ftLastWriteTime, &statbuf->st_mtime);
1593 f2t (&fad.ftLastAccessTime, &statbuf->st_atime);
1595 statbuf->st_size =
1596 (__int64)fad.nFileSizeLow | (__int64)fad.nFileSizeHigh << 32;
1598 /* We do not have the S_IEXEC attribute, but this is not used on GNAT. */
1599 statbuf->st_mode = S_IREAD;
1601 if (fad.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
1602 statbuf->st_mode |= S_IFDIR;
1603 else
1604 statbuf->st_mode |= S_IFREG;
1606 if (!(fad.dwFileAttributes & FILE_ATTRIBUTE_READONLY))
1607 statbuf->st_mode |= S_IWRITE;
1609 return 0;
1611 #else
1612 return GNAT_STAT (name, statbuf) == 0 ? 0 : errno;
1613 #endif
1616 /*************************************************************************
1617 ** Check whether a file exists
1618 *************************************************************************/
1621 __gnat_file_exists_attr (char* name, struct file_attributes* attr)
1623 if (attr->exists == ATTR_UNSET)
1624 __gnat_stat_to_attr (-1, name, attr);
1626 return attr->exists;
1630 __gnat_file_exists (char *name)
1632 struct file_attributes attr;
1633 __gnat_reset_attributes (&attr);
1634 return __gnat_file_exists_attr (name, &attr);
1637 /**********************************************************************
1638 ** Whether name is an absolute path
1639 **********************************************************************/
1642 __gnat_is_absolute_path (char *name, int length)
1644 #ifdef __vxworks
1645 /* On VxWorks systems, an absolute path can be represented (depending on
1646 the host platform) as either /dir/file, or device:/dir/file, or
1647 device:drive_letter:/dir/file. */
1649 int index;
1651 if (name[0] == '/')
1652 return 1;
1654 for (index = 0; index < length; index++)
1656 if (name[index] == ':' &&
1657 ((name[index + 1] == '/') ||
1658 (isalpha (name[index + 1]) && index + 2 <= length &&
1659 name[index + 2] == '/')))
1660 return 1;
1662 else if (name[index] == '/')
1663 return 0;
1665 return 0;
1666 #else
1667 return (length != 0) &&
1668 (*name == '/' || *name == DIR_SEPARATOR
1669 #if defined (WINNT) || defined(__DJGPP__)
1670 || (length > 1 && ISALPHA (name[0]) && name[1] == ':')
1671 #endif
1673 #endif
1677 __gnat_is_regular_file_attr (char* name, struct file_attributes* attr)
1679 if (attr->regular == ATTR_UNSET)
1680 __gnat_stat_to_attr (-1, name, attr);
1682 return attr->regular;
1686 __gnat_is_regular_file (char *name)
1688 struct file_attributes attr;
1690 __gnat_reset_attributes (&attr);
1691 return __gnat_is_regular_file_attr (name, &attr);
1695 __gnat_is_regular_file_fd (int fd)
1697 int ret;
1698 GNAT_STRUCT_STAT statbuf;
1700 ret = GNAT_FSTAT (fd, &statbuf);
1701 return (!ret && S_ISREG (statbuf.st_mode));
1705 __gnat_is_directory_attr (char* name, struct file_attributes* attr)
1707 if (attr->directory == ATTR_UNSET)
1708 __gnat_stat_to_attr (-1, name, attr);
1710 return attr->directory;
1714 __gnat_is_directory (char *name)
1716 struct file_attributes attr;
1718 __gnat_reset_attributes (&attr);
1719 return __gnat_is_directory_attr (name, &attr);
1722 #if defined (_WIN32)
1724 /* Returns the same constant as GetDriveType but takes a pathname as
1725 argument. */
1727 static UINT
1728 GetDriveTypeFromPath (TCHAR *wfullpath)
1730 TCHAR wdrv[MAX_PATH];
1731 TCHAR wpath[MAX_PATH];
1732 TCHAR wfilename[MAX_PATH];
1733 TCHAR wext[MAX_PATH];
1735 _tsplitpath (wfullpath, wdrv, wpath, wfilename, wext);
1737 if (_tcslen (wdrv) != 0)
1739 /* we have a drive specified. */
1740 _tcscat (wdrv, _T("\\"));
1741 return GetDriveType (wdrv);
1743 else
1745 /* No drive specified. */
1747 /* Is this a relative path, if so get current drive type. */
1748 if (wpath[0] != _T('\\') ||
1749 (_tcslen (wpath) > 2 && wpath[0] == _T('\\')
1750 && wpath[1] != _T('\\')))
1751 return GetDriveType (NULL);
1753 UINT result = GetDriveType (wpath);
1755 /* Cannot guess the drive type, is this \\.\ ? */
1757 if (result == DRIVE_NO_ROOT_DIR &&
1758 _tcslen (wpath) >= 4 && wpath[0] == _T('\\') && wpath[1] == _T('\\')
1759 && wpath[2] == _T('.') && wpath[3] == _T('\\'))
1761 if (_tcslen (wpath) == 4)
1762 _tcscat (wpath, wfilename);
1764 LPTSTR p = &wpath[4];
1765 LPTSTR b = _tcschr (p, _T('\\'));
1767 if (b != NULL)
1769 /* logical drive \\.\c\dir\file */
1770 *b++ = _T(':');
1771 *b++ = _T('\\');
1772 *b = _T('\0');
1774 else
1775 _tcscat (p, _T(":\\"));
1777 return GetDriveType (p);
1780 return result;
1784 /* This MingW section contains code to work with ACL. */
1785 static int
1786 __gnat_check_OWNER_ACL (TCHAR *wname,
1787 DWORD CheckAccessDesired,
1788 GENERIC_MAPPING CheckGenericMapping)
1790 DWORD dwAccessDesired, dwAccessAllowed;
1791 PRIVILEGE_SET PrivilegeSet;
1792 DWORD dwPrivSetSize = sizeof (PRIVILEGE_SET);
1793 BOOL fAccessGranted = FALSE;
1794 HANDLE hToken = NULL;
1795 DWORD nLength = 0;
1796 PSECURITY_DESCRIPTOR pSD = NULL;
1798 GetFileSecurity
1799 (wname, OWNER_SECURITY_INFORMATION |
1800 GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION,
1801 NULL, 0, &nLength);
1803 if ((pSD = (SECURITY_DESCRIPTOR *) HeapAlloc
1804 (GetProcessHeap (), HEAP_ZERO_MEMORY, nLength)) == NULL)
1805 return 0;
1807 /* Obtain the security descriptor. */
1809 if (!GetFileSecurity
1810 (wname, OWNER_SECURITY_INFORMATION |
1811 GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION,
1812 pSD, nLength, &nLength))
1813 goto error;
1815 if (!ImpersonateSelf (SecurityImpersonation))
1816 goto error;
1818 if (!OpenThreadToken
1819 (GetCurrentThread(), TOKEN_DUPLICATE | TOKEN_QUERY, FALSE, &hToken))
1820 goto error;
1822 /* Undoes the effect of ImpersonateSelf. */
1824 RevertToSelf ();
1826 /* We want to test for write permissions. */
1828 dwAccessDesired = CheckAccessDesired;
1830 MapGenericMask (&dwAccessDesired, &CheckGenericMapping);
1832 if (!AccessCheck
1833 (pSD , /* security descriptor to check */
1834 hToken, /* impersonation token */
1835 dwAccessDesired, /* requested access rights */
1836 &CheckGenericMapping, /* pointer to GENERIC_MAPPING */
1837 &PrivilegeSet, /* receives privileges used in check */
1838 &dwPrivSetSize, /* size of PrivilegeSet buffer */
1839 &dwAccessAllowed, /* receives mask of allowed access rights */
1840 &fAccessGranted))
1841 goto error;
1843 CloseHandle (hToken);
1844 HeapFree (GetProcessHeap (), 0, pSD);
1845 return fAccessGranted;
1847 error:
1848 if (hToken)
1849 CloseHandle (hToken);
1850 HeapFree (GetProcessHeap (), 0, pSD);
1851 return 0;
1854 static void
1855 __gnat_set_OWNER_ACL (TCHAR *wname,
1856 ACCESS_MODE AccessMode,
1857 DWORD AccessPermissions)
1859 PACL pOldDACL = NULL;
1860 PACL pNewDACL = NULL;
1861 PSECURITY_DESCRIPTOR pSD = NULL;
1862 EXPLICIT_ACCESS ea;
1863 TCHAR username [100];
1864 DWORD unsize = 100;
1866 /* Get current user, he will act as the owner */
1868 if (!GetUserName (username, &unsize))
1869 return;
1871 if (GetNamedSecurityInfo
1872 (wname,
1873 SE_FILE_OBJECT,
1874 DACL_SECURITY_INFORMATION,
1875 NULL, NULL, &pOldDACL, NULL, &pSD) != ERROR_SUCCESS)
1876 return;
1878 BuildExplicitAccessWithName
1879 (&ea, username, AccessPermissions, (ACCESS_MODE) AccessMode, NO_INHERITANCE);
1881 if (AccessMode == SET_ACCESS)
1883 /* SET_ACCESS, we want to set an explicte set of permissions, do not
1884 merge with current DACL. */
1885 if (SetEntriesInAcl (1, &ea, NULL, &pNewDACL) != ERROR_SUCCESS)
1886 return;
1888 else
1889 if (SetEntriesInAcl (1, &ea, pOldDACL, &pNewDACL) != ERROR_SUCCESS)
1890 return;
1892 if (SetNamedSecurityInfo
1893 (wname, SE_FILE_OBJECT,
1894 DACL_SECURITY_INFORMATION, NULL, NULL, pNewDACL, NULL) != ERROR_SUCCESS)
1895 return;
1897 LocalFree (pSD);
1898 LocalFree (pNewDACL);
1901 /* Check if it is possible to use ACL for wname, the file must not be on a
1902 network drive. */
1904 static int
1905 __gnat_can_use_acl (TCHAR *wname)
1907 return __gnat_use_acl && GetDriveTypeFromPath (wname) != DRIVE_REMOTE;
1910 #endif /* defined (_WIN32) */
1913 __gnat_is_readable_file_attr (char* name, struct file_attributes* attr)
1915 if (attr->readable == ATTR_UNSET)
1917 #if defined (_WIN32)
1918 TCHAR wname [GNAT_MAX_PATH_LEN + 2];
1919 GENERIC_MAPPING GenericMapping;
1921 S2WSC (wname, name, GNAT_MAX_PATH_LEN + 2);
1923 if (__gnat_can_use_acl (wname))
1925 ZeroMemory (&GenericMapping, sizeof (GENERIC_MAPPING));
1926 GenericMapping.GenericRead = GENERIC_READ;
1927 attr->readable =
1928 __gnat_check_OWNER_ACL (wname, FILE_READ_DATA, GenericMapping);
1930 else
1931 attr->readable = GetFileAttributes (wname) != INVALID_FILE_ATTRIBUTES;
1932 #else
1933 __gnat_stat_to_attr (-1, name, attr);
1934 #endif
1937 return attr->readable;
1941 __gnat_is_read_accessible_file (char *name)
1943 #if defined (_WIN32)
1944 TCHAR wname [GNAT_MAX_PATH_LEN + 2];
1946 S2WSC (wname, name, GNAT_MAX_PATH_LEN + 2);
1948 return !_waccess (wname, 4);
1950 #elif defined (__vxworks)
1951 int fd;
1953 if ((fd = open (name, O_RDONLY, 0)) < 0)
1954 return 0;
1955 close (fd);
1956 return 1;
1958 #else
1959 return !access (name, R_OK);
1960 #endif
1964 __gnat_is_readable_file (char *name)
1966 struct file_attributes attr;
1968 __gnat_reset_attributes (&attr);
1969 return __gnat_is_readable_file_attr (name, &attr);
1973 __gnat_is_writable_file_attr (char* name, struct file_attributes* attr)
1975 if (attr->writable == ATTR_UNSET)
1977 #if defined (_WIN32)
1978 TCHAR wname [GNAT_MAX_PATH_LEN + 2];
1979 GENERIC_MAPPING GenericMapping;
1981 S2WSC (wname, name, GNAT_MAX_PATH_LEN + 2);
1983 if (__gnat_can_use_acl (wname))
1985 ZeroMemory (&GenericMapping, sizeof (GENERIC_MAPPING));
1986 GenericMapping.GenericWrite = GENERIC_WRITE;
1988 attr->writable = __gnat_check_OWNER_ACL
1989 (wname, FILE_WRITE_DATA | FILE_APPEND_DATA, GenericMapping)
1990 && !(GetFileAttributes (wname) & FILE_ATTRIBUTE_READONLY);
1992 else
1993 attr->writable =
1994 !(GetFileAttributes (wname) & FILE_ATTRIBUTE_READONLY);
1996 #else
1997 __gnat_stat_to_attr (-1, name, attr);
1998 #endif
2001 return attr->writable;
2005 __gnat_is_writable_file (char *name)
2007 struct file_attributes attr;
2009 __gnat_reset_attributes (&attr);
2010 return __gnat_is_writable_file_attr (name, &attr);
2014 __gnat_is_write_accessible_file (char *name)
2016 #if defined (_WIN32)
2017 TCHAR wname [GNAT_MAX_PATH_LEN + 2];
2019 S2WSC (wname, name, GNAT_MAX_PATH_LEN + 2);
2021 return !_waccess (wname, 2);
2023 #elif defined (__vxworks)
2024 int fd;
2026 if ((fd = open (name, O_WRONLY, 0)) < 0)
2027 return 0;
2028 close (fd);
2029 return 1;
2031 #else
2032 return !access (name, W_OK);
2033 #endif
2037 __gnat_is_executable_file_attr (char* name, struct file_attributes* attr)
2039 if (attr->executable == ATTR_UNSET)
2041 #if defined (_WIN32)
2042 TCHAR wname [GNAT_MAX_PATH_LEN + 2];
2043 GENERIC_MAPPING GenericMapping;
2045 S2WSC (wname, name, GNAT_MAX_PATH_LEN + 2);
2047 if (__gnat_can_use_acl (wname))
2049 ZeroMemory (&GenericMapping, sizeof (GENERIC_MAPPING));
2050 GenericMapping.GenericExecute = GENERIC_EXECUTE;
2052 attr->executable =
2053 __gnat_check_OWNER_ACL (wname, FILE_EXECUTE, GenericMapping);
2055 else
2057 TCHAR *l, *last = _tcsstr(wname, _T(".exe"));
2059 /* look for last .exe */
2060 if (last)
2061 while ((l = _tcsstr(last+1, _T(".exe"))))
2062 last = l;
2064 attr->executable =
2065 GetFileAttributes (wname) != INVALID_FILE_ATTRIBUTES
2066 && (last - wname) == (int) (_tcslen (wname) - 4);
2068 #else
2069 __gnat_stat_to_attr (-1, name, attr);
2070 #endif
2073 return attr->regular && attr->executable;
2077 __gnat_is_executable_file (char *name)
2079 struct file_attributes attr;
2081 __gnat_reset_attributes (&attr);
2082 return __gnat_is_executable_file_attr (name, &attr);
2085 void
2086 __gnat_set_writable (char *name)
2088 #if defined (_WIN32)
2089 TCHAR wname [GNAT_MAX_PATH_LEN + 2];
2091 S2WSC (wname, name, GNAT_MAX_PATH_LEN + 2);
2093 if (__gnat_can_use_acl (wname))
2094 __gnat_set_OWNER_ACL (wname, GRANT_ACCESS, FILE_GENERIC_WRITE);
2096 SetFileAttributes
2097 (wname, GetFileAttributes (wname) & ~FILE_ATTRIBUTE_READONLY);
2098 #elif ! (defined (__vxworks) && _WRS_VXWORKS_MAJOR < 6)
2099 GNAT_STRUCT_STAT statbuf;
2101 if (GNAT_STAT (name, &statbuf) == 0)
2103 statbuf.st_mode = statbuf.st_mode | S_IWUSR;
2104 chmod (name, statbuf.st_mode);
2106 #endif
2109 /* must match definition in s-os_lib.ads */
2110 #define S_OWNER 1
2111 #define S_GROUP 2
2112 #define S_OTHERS 4
2114 void
2115 __gnat_set_executable (char *name, int mode ATTRIBUTE_UNUSED)
2117 #if defined (_WIN32)
2118 TCHAR wname [GNAT_MAX_PATH_LEN + 2];
2120 S2WSC (wname, name, GNAT_MAX_PATH_LEN + 2);
2122 if (__gnat_can_use_acl (wname))
2123 __gnat_set_OWNER_ACL (wname, GRANT_ACCESS, FILE_GENERIC_EXECUTE);
2125 #elif ! (defined (__vxworks) && _WRS_VXWORKS_MAJOR < 6)
2126 GNAT_STRUCT_STAT statbuf;
2128 if (GNAT_STAT (name, &statbuf) == 0)
2130 if (mode & S_OWNER)
2131 statbuf.st_mode = statbuf.st_mode | S_IXUSR;
2132 if (mode & S_GROUP)
2133 statbuf.st_mode = statbuf.st_mode | S_IXGRP;
2134 if (mode & S_OTHERS)
2135 statbuf.st_mode = statbuf.st_mode | S_IXOTH;
2136 chmod (name, statbuf.st_mode);
2138 #endif
2141 void
2142 __gnat_set_non_writable (char *name)
2144 #if defined (_WIN32)
2145 TCHAR wname [GNAT_MAX_PATH_LEN + 2];
2147 S2WSC (wname, name, GNAT_MAX_PATH_LEN + 2);
2149 if (__gnat_can_use_acl (wname))
2150 __gnat_set_OWNER_ACL
2151 (wname, DENY_ACCESS,
2152 FILE_WRITE_DATA | FILE_APPEND_DATA |
2153 FILE_WRITE_EA | FILE_WRITE_ATTRIBUTES);
2155 SetFileAttributes
2156 (wname, GetFileAttributes (wname) | FILE_ATTRIBUTE_READONLY);
2157 #elif ! (defined (__vxworks) && _WRS_VXWORKS_MAJOR < 6)
2158 GNAT_STRUCT_STAT statbuf;
2160 if (GNAT_STAT (name, &statbuf) == 0)
2162 statbuf.st_mode = statbuf.st_mode & 07577;
2163 chmod (name, statbuf.st_mode);
2165 #endif
2168 void
2169 __gnat_set_readable (char *name)
2171 #if defined (_WIN32)
2172 TCHAR wname [GNAT_MAX_PATH_LEN + 2];
2174 S2WSC (wname, name, GNAT_MAX_PATH_LEN + 2);
2176 if (__gnat_can_use_acl (wname))
2177 __gnat_set_OWNER_ACL (wname, GRANT_ACCESS, FILE_GENERIC_READ);
2179 #elif ! (defined (__vxworks) && _WRS_VXWORKS_MAJOR < 6)
2180 GNAT_STRUCT_STAT statbuf;
2182 if (GNAT_STAT (name, &statbuf) == 0)
2184 chmod (name, statbuf.st_mode | S_IREAD);
2186 #endif
2189 void
2190 __gnat_set_non_readable (char *name)
2192 #if defined (_WIN32)
2193 TCHAR wname [GNAT_MAX_PATH_LEN + 2];
2195 S2WSC (wname, name, GNAT_MAX_PATH_LEN + 2);
2197 if (__gnat_can_use_acl (wname))
2198 __gnat_set_OWNER_ACL (wname, DENY_ACCESS, FILE_GENERIC_READ);
2200 #elif ! (defined (__vxworks) && _WRS_VXWORKS_MAJOR < 6)
2201 GNAT_STRUCT_STAT statbuf;
2203 if (GNAT_STAT (name, &statbuf) == 0)
2205 chmod (name, statbuf.st_mode & (~S_IREAD));
2207 #endif
2211 __gnat_is_symbolic_link_attr (char* name ATTRIBUTE_UNUSED,
2212 struct file_attributes* attr)
2214 if (attr->symbolic_link == ATTR_UNSET)
2216 #if defined (__vxworks)
2217 attr->symbolic_link = 0;
2219 #elif defined (_AIX) || defined (__APPLE__) || defined (__unix__)
2220 int ret;
2221 GNAT_STRUCT_STAT statbuf;
2222 ret = GNAT_LSTAT (name, &statbuf);
2223 attr->symbolic_link = (!ret && S_ISLNK (statbuf.st_mode));
2224 #else
2225 attr->symbolic_link = 0;
2226 #endif
2228 return attr->symbolic_link;
2232 __gnat_is_symbolic_link (char *name ATTRIBUTE_UNUSED)
2234 struct file_attributes attr;
2236 __gnat_reset_attributes (&attr);
2237 return __gnat_is_symbolic_link_attr (name, &attr);
2240 #if defined (__sun__)
2241 /* Using fork on Solaris will duplicate all the threads. fork1, which
2242 duplicates only the active thread, must be used instead, or spawning
2243 subprocess from a program with tasking will lead into numerous problems. */
2244 #define fork fork1
2245 #endif
2248 __gnat_portable_spawn (char *args[] ATTRIBUTE_UNUSED)
2250 int status ATTRIBUTE_UNUSED = 0;
2251 int finished ATTRIBUTE_UNUSED;
2252 int pid ATTRIBUTE_UNUSED;
2254 #if defined (__vxworks) || defined(__PikeOS__)
2255 return -1;
2257 #elif defined (__DJGPP__) || defined (_WIN32)
2258 /* args[0] must be quotes as it could contain a full pathname with spaces */
2259 char *args_0 = args[0];
2260 args[0] = (char *)xmalloc (strlen (args_0) + 3);
2261 strcpy (args[0], "\"");
2262 strcat (args[0], args_0);
2263 strcat (args[0], "\"");
2265 status = spawnvp (P_WAIT, args_0, (char ** const)args);
2267 /* restore previous value */
2268 free (args[0]);
2269 args[0] = (char *)args_0;
2271 if (status < 0)
2272 return -1;
2273 else
2274 return status;
2276 #else
2278 pid = fork ();
2279 if (pid < 0)
2280 return -1;
2282 if (pid == 0)
2284 /* The child. */
2285 if (execv (args[0], MAYBE_TO_PTR32 (args)) != 0)
2286 _exit (1);
2289 /* The parent. */
2290 finished = waitpid (pid, &status, 0);
2292 if (finished != pid || WIFEXITED (status) == 0)
2293 return -1;
2295 return WEXITSTATUS (status);
2296 #endif
2298 return 0;
2301 /* Create a copy of the given file descriptor.
2302 Return -1 if an error occurred. */
2305 __gnat_dup (int oldfd)
2307 #if defined (__vxworks) && !defined (__RTP__)
2308 /* Not supported on VxWorks 5.x, but supported on VxWorks 6.0 when using
2309 RTPs. */
2310 return -1;
2311 #else
2312 return dup (oldfd);
2313 #endif
2316 /* Make newfd be the copy of oldfd, closing newfd first if necessary.
2317 Return -1 if an error occurred. */
2320 __gnat_dup2 (int oldfd ATTRIBUTE_UNUSED, int newfd ATTRIBUTE_UNUSED)
2322 #if defined (__vxworks) && !defined (__RTP__)
2323 /* Not supported on VxWorks 5.x, but supported on VxWorks 6.0 when using
2324 RTPs. */
2325 return -1;
2326 #elif defined (__PikeOS__)
2327 /* Not supported. */
2328 return -1;
2329 #elif defined (_WIN32)
2330 /* Special case when oldfd and newfd are identical and are the standard
2331 input, output or error as this makes Windows XP hangs. Note that we
2332 do that only for standard file descriptors that are known to be valid. */
2333 if (oldfd == newfd && newfd >= 0 && newfd <= 2)
2334 return newfd;
2335 else
2336 return dup2 (oldfd, newfd);
2337 #else
2338 return dup2 (oldfd, newfd);
2339 #endif
2343 __gnat_number_of_cpus (void)
2345 int cores = 1;
2347 #if defined (__linux__) || defined (__sun__) || defined (_AIX) \
2348 || defined (__APPLE__) || defined (__FreeBSD__) || defined (__OpenBSD__) \
2349 || defined (__DragonFly__) || defined (__NetBSD__)
2350 cores = (int) sysconf (_SC_NPROCESSORS_ONLN);
2352 #elif defined (__hpux__)
2353 struct pst_dynamic psd;
2354 if (pstat_getdynamic (&psd, sizeof (psd), 1, 0) != -1)
2355 cores = (int) psd.psd_proc_cnt;
2357 #elif defined (_WIN32)
2358 SYSTEM_INFO sysinfo;
2359 GetSystemInfo (&sysinfo);
2360 cores = (int) sysinfo.dwNumberOfProcessors;
2362 #elif defined (_WRS_CONFIG_SMP)
2363 unsigned int vxCpuConfiguredGet (void);
2365 cores = vxCpuConfiguredGet ();
2367 #endif
2369 return cores;
2372 /* WIN32 code to implement a wait call that wait for any child process. */
2374 #if defined (_WIN32)
2376 /* Synchronization code, to be thread safe. */
2378 #ifdef CERT
2380 /* For the Cert run times on native Windows we use dummy functions
2381 for locking and unlocking tasks since we do not support multiple
2382 threads on this configuration (Cert run time on native Windows). */
2384 static void EnterCS (void) {}
2385 static void LeaveCS (void) {}
2386 static void SignalListChanged (void) {}
2388 #else
2390 CRITICAL_SECTION ProcListCS;
2391 HANDLE ProcListEvt = NULL;
2393 static void EnterCS (void)
2395 EnterCriticalSection(&ProcListCS);
2398 static void LeaveCS (void)
2400 LeaveCriticalSection(&ProcListCS);
2403 static void SignalListChanged (void)
2405 SetEvent (ProcListEvt);
2408 #endif
2410 static HANDLE *HANDLES_LIST = NULL;
2411 static int *PID_LIST = NULL, plist_length = 0, plist_max_length = 0;
2413 static void
2414 add_handle (HANDLE h, int pid)
2416 /* -------------------- critical section -------------------- */
2417 EnterCS();
2419 if (plist_length == plist_max_length)
2421 plist_max_length += 100;
2422 HANDLES_LIST =
2423 (HANDLE *) xrealloc (HANDLES_LIST, sizeof (HANDLE) * plist_max_length);
2424 PID_LIST =
2425 (int *) xrealloc (PID_LIST, sizeof (int) * plist_max_length);
2428 HANDLES_LIST[plist_length] = h;
2429 PID_LIST[plist_length] = pid;
2430 ++plist_length;
2432 SignalListChanged();
2433 LeaveCS();
2434 /* -------------------- critical section -------------------- */
2438 __gnat_win32_remove_handle (HANDLE h, int pid)
2440 int j;
2441 int found = 0;
2443 /* -------------------- critical section -------------------- */
2444 EnterCS();
2446 for (j = 0; j < plist_length; j++)
2448 if ((HANDLES_LIST[j] == h) || (PID_LIST[j] == pid))
2450 CloseHandle (h);
2451 --plist_length;
2452 HANDLES_LIST[j] = HANDLES_LIST[plist_length];
2453 PID_LIST[j] = PID_LIST[plist_length];
2454 found = 1;
2455 break;
2459 LeaveCS();
2460 /* -------------------- critical section -------------------- */
2462 if (found)
2463 SignalListChanged();
2465 return found;
2468 static void
2469 win32_no_block_spawn (char *command, char *args[], HANDLE *h, int *pid)
2471 BOOL result;
2472 STARTUPINFO SI;
2473 PROCESS_INFORMATION PI;
2474 SECURITY_ATTRIBUTES SA;
2475 int csize = 1;
2476 char *full_command;
2477 int k;
2479 /* compute the total command line length */
2480 k = 0;
2481 while (args[k])
2483 csize += strlen (args[k]) + 1;
2484 k++;
2487 full_command = (char *) xmalloc (csize);
2489 /* Startup info. */
2490 SI.cb = sizeof (STARTUPINFO);
2491 SI.lpReserved = NULL;
2492 SI.lpReserved2 = NULL;
2493 SI.lpDesktop = NULL;
2494 SI.cbReserved2 = 0;
2495 SI.lpTitle = NULL;
2496 SI.dwFlags = 0;
2497 SI.wShowWindow = SW_HIDE;
2499 /* Security attributes. */
2500 SA.nLength = sizeof (SECURITY_ATTRIBUTES);
2501 SA.bInheritHandle = TRUE;
2502 SA.lpSecurityDescriptor = NULL;
2504 /* Prepare the command string. */
2505 strcpy (full_command, command);
2506 strcat (full_command, " ");
2508 k = 1;
2509 while (args[k])
2511 strcat (full_command, args[k]);
2512 strcat (full_command, " ");
2513 k++;
2517 int wsize = csize * 2;
2518 TCHAR *wcommand = (TCHAR *) xmalloc (wsize);
2520 S2WSC (wcommand, full_command, wsize);
2522 free (full_command);
2524 result = CreateProcess
2525 (NULL, wcommand, &SA, NULL, TRUE,
2526 GetPriorityClass (GetCurrentProcess()), NULL, NULL, &SI, &PI);
2528 free (wcommand);
2531 if (result == TRUE)
2533 CloseHandle (PI.hThread);
2534 *h = PI.hProcess;
2535 *pid = PI.dwProcessId;
2537 else
2539 *h = NULL;
2540 *pid = 0;
2544 static int
2545 win32_wait (int *status)
2547 DWORD exitcode, pid;
2548 HANDLE *hl;
2549 HANDLE h;
2550 int *pidl;
2551 DWORD res;
2552 int hl_len;
2553 int found;
2554 int pos;
2556 START_WAIT:
2558 if (plist_length == 0)
2560 errno = ECHILD;
2561 return -1;
2564 /* -------------------- critical section -------------------- */
2565 EnterCS();
2567 /* ??? We can't wait for more than MAXIMUM_WAIT_OBJECTS due to a Win32
2568 limitation */
2569 if (plist_length < MAXIMUM_WAIT_OBJECTS)
2570 hl_len = plist_length;
2571 else
2573 errno = EINVAL;
2574 return -1;
2577 #ifdef CERT
2578 hl = (HANDLE *) xmalloc (sizeof (HANDLE) * hl_len);
2579 memmove (hl, HANDLES_LIST, sizeof (HANDLE) * hl_len);
2580 pidl = (int *) xmalloc (sizeof (int) * hl_len);
2581 memmove (pidl, PID_LIST, sizeof (int) * hl_len);
2582 #else
2583 /* Note that index 0 contains the event handle that is signaled when the
2584 process list has changed */
2585 hl = (HANDLE *) xmalloc (sizeof (HANDLE) * hl_len + 1);
2586 hl[0] = ProcListEvt;
2587 memmove (&hl[1], HANDLES_LIST, sizeof (HANDLE) * hl_len);
2588 pidl = (int *) xmalloc (sizeof (int) * hl_len + 1);
2589 memmove (&pidl[1], PID_LIST, sizeof (int) * hl_len);
2590 hl_len++;
2591 #endif
2593 LeaveCS();
2594 /* -------------------- critical section -------------------- */
2596 res = WaitForMultipleObjects (hl_len, hl, FALSE, INFINITE);
2598 /* If there was an error, exit now */
2599 if (res == WAIT_FAILED)
2601 errno = EINVAL;
2602 return -1;
2605 /* if the ProcListEvt has been signaled then the list of processes has been
2606 updated to add or remove a handle, just loop over */
2608 if (res - WAIT_OBJECT_0 == 0)
2610 free (hl);
2611 free (pidl);
2612 goto START_WAIT;
2615 /* Handle two distinct groups of return codes: finished waits and abandoned
2616 waits */
2618 if (res < WAIT_ABANDONED_0)
2619 pos = res - WAIT_OBJECT_0;
2620 else
2621 pos = res - WAIT_ABANDONED_0;
2623 h = hl[pos];
2624 GetExitCodeProcess (h, &exitcode);
2625 pid = pidl [pos];
2627 found = __gnat_win32_remove_handle (h, -1);
2629 free (hl);
2630 free (pidl);
2632 /* if not found another process waiting has already handled this process */
2634 if (!found)
2636 goto START_WAIT;
2639 *status = (int) exitcode;
2640 return (int) pid;
2643 #endif
2646 __gnat_portable_no_block_spawn (char *args[] ATTRIBUTE_UNUSED)
2649 #if defined (__vxworks) || defined (__PikeOS__)
2650 /* Not supported. */
2651 return -1;
2653 #elif defined(__DJGPP__)
2654 if (spawnvp (P_WAIT, args[0], args) != 0)
2655 return -1;
2656 else
2657 return 0;
2659 #elif defined (_WIN32)
2661 HANDLE h = NULL;
2662 int pid;
2664 win32_no_block_spawn (args[0], args, &h, &pid);
2665 if (h != NULL)
2667 add_handle (h, pid);
2668 return pid;
2670 else
2671 return -1;
2673 #else
2675 int pid = fork ();
2677 if (pid == 0)
2679 /* The child. */
2680 if (execv (args[0], MAYBE_TO_PTR32 (args)) != 0)
2681 _exit (1);
2684 return pid;
2686 #endif
2690 __gnat_portable_wait (int *process_status)
2692 int status = 0;
2693 int pid = 0;
2695 #if defined (__vxworks) || defined (__PikeOS__)
2696 /* Not sure what to do here, so do nothing but return zero. */
2698 #elif defined (_WIN32)
2700 pid = win32_wait (&status);
2702 #elif defined (__DJGPP__)
2703 /* Child process has already ended in case of DJGPP.
2704 No need to do anything. Just return success. */
2705 #else
2707 pid = waitpid (-1, &status, 0);
2708 status = status & 0xffff;
2709 #endif
2711 *process_status = status;
2712 return pid;
2716 __gnat_portable_no_block_wait (int *process_status)
2718 int status = 0;
2719 int pid = 0;
2721 #if defined (__vxworks) || defined (__PikeOS__) || defined (_WIN32)
2722 /* Not supported. */
2723 status = -1;
2725 #else
2727 pid = waitpid (-1, &status, WNOHANG);
2728 status = status & 0xffff;
2729 #endif
2731 *process_status = status;
2732 return pid;
2735 void
2736 __gnat_os_exit (int status)
2738 exit (status);
2742 __gnat_current_process_id (void)
2744 #if defined (__vxworks) || defined (__PikeOS__)
2745 return -1;
2747 #elif defined (_WIN32)
2749 return (int)GetCurrentProcessId();
2751 #else
2753 return (int)getpid();
2754 #endif
2757 /* Locate file on path, that matches a predicate */
2759 char *
2760 __gnat_locate_file_with_predicate (char *file_name, char *path_val,
2761 int (*predicate)(char *))
2763 char *ptr;
2764 char *file_path = (char *) alloca (strlen (file_name) + 1);
2765 int absolute;
2767 /* Return immediately if file_name is empty */
2769 if (*file_name == '\0')
2770 return 0;
2772 /* Remove quotes around file_name if present */
2774 ptr = file_name;
2775 if (*ptr == '"')
2776 ptr++;
2778 strcpy (file_path, ptr);
2780 ptr = file_path + strlen (file_path) - 1;
2782 if (*ptr == '"')
2783 *ptr = '\0';
2785 /* Handle absolute pathnames. */
2787 absolute = __gnat_is_absolute_path (file_path, strlen (file_name));
2789 if (absolute)
2791 if (predicate (file_path))
2792 return xstrdup (file_path);
2794 return 0;
2797 /* If file_name include directory separator(s), try it first as
2798 a path name relative to the current directory */
2799 for (ptr = file_name; *ptr && *ptr != '/' && *ptr != DIR_SEPARATOR; ptr++)
2802 if (*ptr != 0)
2804 if (predicate (file_name))
2805 return xstrdup (file_name);
2808 if (path_val == 0)
2809 return 0;
2812 /* The result has to be smaller than path_val + file_name. */
2813 char *file_path =
2814 (char *) alloca (strlen (path_val) + strlen (file_name) + 2);
2816 for (;;)
2818 /* Skip the starting quote */
2820 if (*path_val == '"')
2821 path_val++;
2823 for (ptr = file_path; *path_val && *path_val != PATH_SEPARATOR; )
2824 *ptr++ = *path_val++;
2826 /* If directory is empty, it is the current directory*/
2828 if (ptr == file_path)
2830 *ptr = '.';
2832 else
2833 ptr--;
2835 /* Skip the ending quote */
2837 if (*ptr == '"')
2838 ptr--;
2840 if (*ptr != '/' && *ptr != DIR_SEPARATOR)
2841 *++ptr = DIR_SEPARATOR;
2843 strcpy (++ptr, file_name);
2845 if (predicate (file_path))
2846 return xstrdup (file_path);
2848 if (*path_val == 0)
2849 return 0;
2851 /* Skip path separator */
2853 path_val++;
2857 return 0;
2860 /* Locate an executable file, give a Path value. */
2862 char *
2863 __gnat_locate_executable_file (char *file_name, char *path_val)
2865 return __gnat_locate_file_with_predicate
2866 (file_name, path_val, &__gnat_is_executable_file);
2869 /* Locate a regular file, give a Path value. */
2871 char *
2872 __gnat_locate_regular_file (char *file_name, char *path_val)
2874 return __gnat_locate_file_with_predicate
2875 (file_name, path_val, &__gnat_is_regular_file);
2878 /* Locate an executable given a Path argument. This routine is only used by
2879 gnatbl and should not be used otherwise. Use locate_exec_on_path
2880 instead. */
2882 char *
2883 __gnat_locate_exec (char *exec_name, char *path_val)
2885 char *ptr;
2886 if (!strstr (exec_name, HOST_EXECUTABLE_SUFFIX))
2888 char *full_exec_name =
2889 (char *) alloca
2890 (strlen (exec_name) + strlen (HOST_EXECUTABLE_SUFFIX) + 1);
2892 strcpy (full_exec_name, exec_name);
2893 strcat (full_exec_name, HOST_EXECUTABLE_SUFFIX);
2894 ptr = __gnat_locate_executable_file (full_exec_name, path_val);
2896 if (ptr == 0)
2897 return __gnat_locate_executable_file (exec_name, path_val);
2898 return ptr;
2900 else
2901 return __gnat_locate_executable_file (exec_name, path_val);
2904 /* Locate an executable using the Systems default PATH. */
2906 char *
2907 __gnat_locate_exec_on_path (char *exec_name)
2909 char *apath_val;
2911 #if defined (_WIN32)
2912 TCHAR *wpath_val = _tgetenv (_T("PATH"));
2913 TCHAR *wapath_val;
2914 /* In Win32 systems we expand the PATH as for XP environment
2915 variables are not automatically expanded. We also prepend the
2916 ".;" to the path to match normal NT path search semantics */
2918 #define EXPAND_BUFFER_SIZE 32767
2920 wapath_val = (TCHAR *) alloca (EXPAND_BUFFER_SIZE);
2922 wapath_val [0] = '.';
2923 wapath_val [1] = ';';
2925 DWORD res = ExpandEnvironmentStrings
2926 (wpath_val, &wapath_val[2], EXPAND_BUFFER_SIZE - 2);
2928 if (!res) wapath_val [0] = _T('\0');
2930 apath_val = (char *) alloca (EXPAND_BUFFER_SIZE);
2932 WS2SC (apath_val, wapath_val, EXPAND_BUFFER_SIZE);
2934 #else
2935 const char *path_val = getenv ("PATH");
2937 /* If PATH is not defined, proceed with __gnat_locate_exec anyway, so we can
2938 find files that contain directory names. */
2940 if (path_val == NULL) path_val = "";
2941 apath_val = (char *) alloca (strlen (path_val) + 1);
2942 strcpy (apath_val, path_val);
2943 #endif
2945 return __gnat_locate_exec (exec_name, apath_val);
2948 /* Dummy functions for Osint import for non-VMS systems.
2949 ??? To be removed. */
2952 __gnat_to_canonical_file_list_init (char *dirspec ATTRIBUTE_UNUSED,
2953 int onlydirs ATTRIBUTE_UNUSED)
2955 return 0;
2958 char *
2959 __gnat_to_canonical_file_list_next (void)
2961 static char empty[] = "";
2962 return empty;
2965 void
2966 __gnat_to_canonical_file_list_free (void)
2970 char *
2971 __gnat_to_canonical_dir_spec (char *dirspec, int prefixflag ATTRIBUTE_UNUSED)
2973 return dirspec;
2976 char *
2977 __gnat_to_canonical_file_spec (char *filespec)
2979 return filespec;
2982 char *
2983 __gnat_to_canonical_path_spec (char *pathspec)
2985 return pathspec;
2988 char *
2989 __gnat_to_host_dir_spec (char *dirspec, int prefixflag ATTRIBUTE_UNUSED)
2991 return dirspec;
2994 char *
2995 __gnat_to_host_file_spec (char *filespec)
2997 return filespec;
3000 void
3001 __gnat_adjust_os_resource_limits (void)
3005 #if defined (__mips_vxworks)
3007 _flush_cache (void)
3009 CACHE_USER_FLUSH (0, ENTIRE_CACHE);
3011 #endif
3013 #if defined (_WIN32)
3014 int __gnat_argument_needs_quote = 1;
3015 #else
3016 int __gnat_argument_needs_quote = 0;
3017 #endif
3019 /* This option is used to enable/disable object files handling from the
3020 binder file by the GNAT Project module. For example, this is disabled on
3021 Windows (prior to GCC 3.4) as it is already done by the mdll module.
3022 Stating with GCC 3.4 the shared libraries are not based on mdll
3023 anymore as it uses the GCC's -shared option */
3024 #if defined (_WIN32) \
3025 && ((__GNUC__ < 3) || ((__GNUC__ == 3) && (__GNUC_MINOR__ < 4)))
3026 int __gnat_prj_add_obj_files = 0;
3027 #else
3028 int __gnat_prj_add_obj_files = 1;
3029 #endif
3031 /* char used as prefix/suffix for environment variables */
3032 #if defined (_WIN32)
3033 char __gnat_environment_char = '%';
3034 #else
3035 char __gnat_environment_char = '$';
3036 #endif
3038 /* This functions copy the file attributes from a source file to a
3039 destination file.
3041 mode = 0 : In this mode copy only the file time stamps (last access and
3042 last modification time stamps).
3044 mode = 1 : In this mode, time stamps and read/write/execute attributes are
3045 copied.
3047 mode = 2 : In this mode, only read/write/execute attributes are copied
3049 Returns 0 if operation was successful and -1 in case of error. */
3052 __gnat_copy_attribs (char *from ATTRIBUTE_UNUSED, char *to ATTRIBUTE_UNUSED,
3053 int mode ATTRIBUTE_UNUSED)
3055 #if (defined (__vxworks) && _WRS_VXWORKS_MAJOR < 6)
3056 return -1;
3058 #elif defined (_WIN32)
3059 TCHAR wfrom [GNAT_MAX_PATH_LEN + 2];
3060 TCHAR wto [GNAT_MAX_PATH_LEN + 2];
3061 BOOL res;
3062 FILETIME fct, flat, flwt;
3063 HANDLE hfrom, hto;
3065 S2WSC (wfrom, from, GNAT_MAX_PATH_LEN + 2);
3066 S2WSC (wto, to, GNAT_MAX_PATH_LEN + 2);
3068 /* Do we need to copy the timestamp ? */
3070 if (mode != 2) {
3071 /* retrieve from times */
3073 hfrom = CreateFile
3074 (wfrom, GENERIC_READ, 0, NULL, OPEN_EXISTING,
3075 FILE_ATTRIBUTE_NORMAL, NULL);
3077 if (hfrom == INVALID_HANDLE_VALUE)
3078 return -1;
3080 res = GetFileTime (hfrom, &fct, &flat, &flwt);
3082 CloseHandle (hfrom);
3084 if (res == 0)
3085 return -1;
3087 /* retrieve from times */
3089 hto = CreateFile
3090 (wto, GENERIC_WRITE, 0, NULL, OPEN_EXISTING,
3091 FILE_ATTRIBUTE_NORMAL, NULL);
3093 if (hto == INVALID_HANDLE_VALUE)
3094 return -1;
3096 res = SetFileTime (hto, NULL, &flat, &flwt);
3098 CloseHandle (hto);
3100 if (res == 0)
3101 return -1;
3104 /* Do we need to copy the permissions ? */
3105 /* Set file attributes in full mode. */
3107 if (mode != 0)
3109 DWORD attribs = GetFileAttributes (wfrom);
3111 if (attribs == INVALID_FILE_ATTRIBUTES)
3112 return -1;
3114 res = SetFileAttributes (wto, attribs);
3115 if (res == 0)
3116 return -1;
3119 return 0;
3121 #else
3122 GNAT_STRUCT_STAT fbuf;
3123 struct utimbuf tbuf;
3125 if (GNAT_STAT (from, &fbuf) == -1) {
3126 return -1;
3129 /* Do we need to copy timestamp ? */
3130 if (mode != 2) {
3131 tbuf.actime = fbuf.st_atime;
3132 tbuf.modtime = fbuf.st_mtime;
3134 if (utime (to, &tbuf) == -1) {
3135 return -1;
3139 /* Do we need to copy file permissions ? */
3140 if (mode != 0 && (chmod (to, fbuf.st_mode) == -1)) {
3141 return -1;
3144 return 0;
3145 #endif
3149 __gnat_lseek (int fd, long offset, int whence)
3151 return (int) lseek (fd, offset, whence);
3154 /* This function returns the major version number of GCC being used. */
3156 get_gcc_version (void)
3158 #ifdef IN_RTS
3159 return __GNUC__;
3160 #else
3161 return (int) (version_string[0] - '0');
3162 #endif
3166 * Set Close_On_Exec as indicated.
3167 * Note: this is used for both GNAT.OS_Lib and GNAT.Sockets.
3171 __gnat_set_close_on_exec (int fd ATTRIBUTE_UNUSED,
3172 int close_on_exec_p ATTRIBUTE_UNUSED)
3174 #if defined (F_GETFD) && defined (FD_CLOEXEC) && ! defined (__vxworks)
3175 int flags = fcntl (fd, F_GETFD, 0);
3176 if (flags < 0)
3177 return flags;
3178 if (close_on_exec_p)
3179 flags |= FD_CLOEXEC;
3180 else
3181 flags &= ~FD_CLOEXEC;
3182 return fcntl (fd, F_SETFD, flags);
3183 #elif defined(_WIN32)
3184 HANDLE h = (HANDLE) _get_osfhandle (fd);
3185 if (h == (HANDLE) -1)
3186 return -1;
3187 if (close_on_exec_p)
3188 return ! SetHandleInformation (h, HANDLE_FLAG_INHERIT, 0);
3189 return ! SetHandleInformation (h, HANDLE_FLAG_INHERIT,
3190 HANDLE_FLAG_INHERIT);
3191 #else
3192 /* TODO: Unimplemented. */
3193 return -1;
3194 #endif
3197 /* Indicates if platforms supports automatic initialization through the
3198 constructor mechanism */
3200 __gnat_binder_supports_auto_init (void)
3202 return 1;
3205 /* Indicates that Stand-Alone Libraries are automatically initialized through
3206 the constructor mechanism */
3208 __gnat_sals_init_using_constructors (void)
3210 #if defined (__vxworks) || defined (__Lynx__)
3211 return 0;
3212 #else
3213 return 1;
3214 #endif
3217 #if defined (__linux__) || defined (__ANDROID__)
3218 /* There is no function in the glibc to retrieve the LWP of the current
3219 thread. We need to do a system call in order to retrieve this
3220 information. */
3221 #include <sys/syscall.h>
3222 void *
3223 __gnat_lwp_self (void)
3225 return (void *) syscall (__NR_gettid);
3227 #endif
3229 #if defined (__APPLE__)
3230 #include <mach/thread_info.h>
3231 #include <mach/mach_init.h>
3232 #include <mach/thread_act.h>
3234 /* System-wide thread identifier. Note it could be truncated on 32 bit
3235 hosts.
3236 Previously was: pthread_mach_thread_np (pthread_self ()). */
3237 void *
3238 __gnat_lwp_self (void)
3240 thread_identifier_info_data_t data;
3241 mach_msg_type_number_t count = THREAD_IDENTIFIER_INFO_COUNT;
3242 kern_return_t kret;
3244 kret = thread_info (mach_thread_self (), THREAD_IDENTIFIER_INFO,
3245 (thread_info_t) &data, &count);
3246 if (kret == KERN_SUCCESS)
3247 return (void *)(uintptr_t)data.thread_id;
3248 else
3249 return 0;
3251 #endif
3253 #if defined (__linux__)
3254 #include <sched.h>
3256 /* glibc versions earlier than 2.7 do not define the routines to handle
3257 dynamically allocated CPU sets. For these targets, we use the static
3258 versions. */
3260 #ifdef CPU_ALLOC
3262 /* Dynamic cpu sets */
3264 cpu_set_t *
3265 __gnat_cpu_alloc (size_t count)
3267 return CPU_ALLOC (count);
3270 size_t
3271 __gnat_cpu_alloc_size (size_t count)
3273 return CPU_ALLOC_SIZE (count);
3276 void
3277 __gnat_cpu_free (cpu_set_t *set)
3279 CPU_FREE (set);
3282 void
3283 __gnat_cpu_zero (size_t count, cpu_set_t *set)
3285 CPU_ZERO_S (count, set);
3288 void
3289 __gnat_cpu_set (int cpu, size_t count, cpu_set_t *set)
3291 /* Ada handles CPU numbers starting from 1, while C identifies the first
3292 CPU by a 0, so we need to adjust. */
3293 CPU_SET_S (cpu - 1, count, set);
3296 #else /* !CPU_ALLOC */
3298 /* Static cpu sets */
3300 cpu_set_t *
3301 __gnat_cpu_alloc (size_t count ATTRIBUTE_UNUSED)
3303 return (cpu_set_t *) xmalloc (sizeof (cpu_set_t));
3306 size_t
3307 __gnat_cpu_alloc_size (size_t count ATTRIBUTE_UNUSED)
3309 return sizeof (cpu_set_t);
3312 void
3313 __gnat_cpu_free (cpu_set_t *set)
3315 free (set);
3318 void
3319 __gnat_cpu_zero (size_t count ATTRIBUTE_UNUSED, cpu_set_t *set)
3321 CPU_ZERO (set);
3324 void
3325 __gnat_cpu_set (int cpu, size_t count ATTRIBUTE_UNUSED, cpu_set_t *set)
3327 /* Ada handles CPU numbers starting from 1, while C identifies the first
3328 CPU by a 0, so we need to adjust. */
3329 CPU_SET (cpu - 1, set);
3331 #endif /* !CPU_ALLOC */
3332 #endif /* __linux__ */
3334 /* Return the load address of the executable, or 0 if not known. In the
3335 specific case of error, (void *)-1 can be returned. Beware: this unit may
3336 be in a shared library. As low-level units are needed, we allow #include
3337 here. */
3339 #if defined (__APPLE__)
3340 #include <mach-o/dyld.h>
3341 #endif
3343 const void *
3344 __gnat_get_executable_load_address (void)
3346 #if defined (__APPLE__)
3347 return _dyld_get_image_header (0);
3349 #elif 0 && defined (__linux__)
3350 /* Currently disabled as it needs at least -ldl. */
3351 struct link_map *map = _r_debug.r_map;
3353 return (const void *)map->l_addr;
3355 #else
3356 return NULL;
3357 #endif
3360 void
3361 __gnat_kill (int pid, int sig, int close ATTRIBUTE_UNUSED)
3363 #if defined(_WIN32)
3364 HANDLE h = OpenProcess (PROCESS_ALL_ACCESS, FALSE, pid);
3365 if (h == NULL)
3366 return;
3367 if (sig == 9)
3369 TerminateProcess (h, 1);
3371 else if (sig == SIGINT)
3372 GenerateConsoleCtrlEvent (CTRL_C_EVENT, pid);
3373 else if (sig == SIGBREAK)
3374 GenerateConsoleCtrlEvent (CTRL_BREAK_EVENT, pid);
3375 /* ??? The last two alternatives don't really work. SIGBREAK requires setting
3376 up process groups at start time which we don't do; treating SIGINT is just
3377 not possible apparently. So we really only support signal 9. Fortunately
3378 that's all we use in GNAT.Expect */
3380 CloseHandle (h);
3381 #elif defined (__vxworks)
3382 /* Not implemented */
3383 #else
3384 kill (pid, sig);
3385 #endif
3388 void __gnat_killprocesstree (int pid, int sig_num)
3390 #if defined(_WIN32)
3391 PROCESSENTRY32 pe;
3393 memset(&pe, 0, sizeof(PROCESSENTRY32));
3394 pe.dwSize = sizeof(PROCESSENTRY32);
3396 HANDLE hSnap = CreateToolhelp32Snapshot (TH32CS_SNAPPROCESS, 0);
3398 /* cannot take snapshot, just kill the parent process */
3400 if (hSnap == INVALID_HANDLE_VALUE)
3402 __gnat_kill (pid, sig_num, 1);
3403 return;
3406 if (Process32First(hSnap, &pe))
3408 BOOL bContinue = TRUE;
3410 /* kill child processes first */
3412 while (bContinue)
3414 if (pe.th32ParentProcessID == (DWORD)pid)
3415 __gnat_killprocesstree (pe.th32ProcessID, sig_num);
3417 bContinue = Process32Next (hSnap, &pe);
3421 CloseHandle (hSnap);
3423 /* kill process */
3425 __gnat_kill (pid, sig_num, 1);
3427 #elif defined (__vxworks)
3428 /* not implemented */
3430 #elif defined (__linux__)
3431 DIR *dir;
3432 struct dirent *d;
3434 /* read all processes' pid and ppid */
3436 dir = opendir ("/proc");
3438 /* cannot open proc, just kill the parent process */
3440 if (!dir)
3442 __gnat_kill (pid, sig_num, 1);
3443 return;
3446 /* kill child processes first */
3448 while ((d = readdir (dir)) != NULL)
3450 if ((d->d_type & DT_DIR) == DT_DIR)
3452 char statfile[64];
3453 int _pid, _ppid;
3455 /* read /proc/<PID>/stat */
3457 if (strlen (d->d_name) >= sizeof (statfile) - strlen ("/proc//stat"))
3458 continue;
3459 strcpy (statfile, "/proc/");
3460 strcat (statfile, d->d_name);
3461 strcat (statfile, "/stat");
3463 FILE *fd = fopen (statfile, "r");
3465 if (fd)
3467 const int match = fscanf (fd, "%d %*s %*s %d", &_pid, &_ppid);
3468 fclose (fd);
3470 if (match == 2 && _ppid == pid)
3471 __gnat_killprocesstree (_pid, sig_num);
3476 closedir (dir);
3478 /* kill process */
3480 __gnat_kill (pid, sig_num, 1);
3481 #else
3482 __gnat_kill (pid, sig_num, 1);
3483 #endif
3484 /* Note on Solaris it is possible to read /proc/<PID>/status.
3485 The 5th and 6th words are the pid and the 7th and 8th the ppid.
3486 See: /usr/include/sys/procfs.h (struct pstatus).
3490 #ifdef __cplusplus
3492 #endif