* config/sparc/driver-sparc.c (cpu_names): Add SPARC-T5 entry.
[official-gcc.git] / gcc / ada / adaint.c
blobb1da3e25dd22c03fe7ec1dd9a1a0afefa69bcc6c
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;
2555 START_WAIT:
2557 if (plist_length == 0)
2559 errno = ECHILD;
2560 return -1;
2563 /* -------------------- critical section -------------------- */
2564 EnterCS();
2566 hl_len = plist_length;
2568 #ifdef CERT
2569 hl = (HANDLE *) xmalloc (sizeof (HANDLE) * hl_len);
2570 memmove (hl, HANDLES_LIST, sizeof (HANDLE) * hl_len);
2571 pidl = (int *) xmalloc (sizeof (int) * hl_len);
2572 memmove (pidl, PID_LIST, sizeof (int) * hl_len);
2573 #else
2574 /* Note that index 0 contains the event handle that is signaled when the
2575 process list has changed */
2576 hl = (HANDLE *) xmalloc (sizeof (HANDLE) * hl_len + 1);
2577 hl[0] = ProcListEvt;
2578 memmove (&hl[1], HANDLES_LIST, sizeof (HANDLE) * hl_len);
2579 pidl = (int *) xmalloc (sizeof (int) * hl_len + 1);
2580 memmove (&pidl[1], PID_LIST, sizeof (int) * hl_len);
2581 hl_len++;
2582 #endif
2584 LeaveCS();
2585 /* -------------------- critical section -------------------- */
2587 res = WaitForMultipleObjects (hl_len, hl, FALSE, INFINITE);
2589 /* if the ProcListEvt has been signaled then the list of processes has been
2590 updated to add or remove a handle, just loop over */
2592 if (res - WAIT_OBJECT_0 == 0)
2594 free (hl);
2595 free (pidl);
2596 goto START_WAIT;
2599 h = hl[res - WAIT_OBJECT_0];
2600 GetExitCodeProcess (h, &exitcode);
2601 pid = pidl [res - WAIT_OBJECT_0];
2603 found = __gnat_win32_remove_handle (h, -1);
2605 free (hl);
2606 free (pidl);
2608 /* if not found another process waiting has already handled this process */
2610 if (!found)
2612 goto START_WAIT;
2615 *status = (int) exitcode;
2616 return (int) pid;
2619 #endif
2622 __gnat_portable_no_block_spawn (char *args[] ATTRIBUTE_UNUSED)
2625 #if defined (__vxworks) || defined (__PikeOS__)
2626 /* Not supported. */
2627 return -1;
2629 #elif defined(__DJGPP__)
2630 if (spawnvp (P_WAIT, args[0], args) != 0)
2631 return -1;
2632 else
2633 return 0;
2635 #elif defined (_WIN32)
2637 HANDLE h = NULL;
2638 int pid;
2640 win32_no_block_spawn (args[0], args, &h, &pid);
2641 if (h != NULL)
2643 add_handle (h, pid);
2644 return pid;
2646 else
2647 return -1;
2649 #else
2651 int pid = fork ();
2653 if (pid == 0)
2655 /* The child. */
2656 if (execv (args[0], MAYBE_TO_PTR32 (args)) != 0)
2657 _exit (1);
2660 return pid;
2662 #endif
2666 __gnat_portable_wait (int *process_status)
2668 int status = 0;
2669 int pid = 0;
2671 #if defined (__vxworks) || defined (__PikeOS__)
2672 /* Not sure what to do here, so do nothing but return zero. */
2674 #elif defined (_WIN32)
2676 pid = win32_wait (&status);
2678 #elif defined (__DJGPP__)
2679 /* Child process has already ended in case of DJGPP.
2680 No need to do anything. Just return success. */
2681 #else
2683 pid = waitpid (-1, &status, 0);
2684 status = status & 0xffff;
2685 #endif
2687 *process_status = status;
2688 return pid;
2692 __gnat_portable_no_block_wait (int *process_status)
2694 int status = 0;
2695 int pid = 0;
2697 #if defined (__vxworks) || defined (__PikeOS__) || defined (_WIN32)
2698 /* Not supported. */
2699 status = -1;
2701 #else
2703 pid = waitpid (-1, &status, WNOHANG);
2704 status = status & 0xffff;
2705 #endif
2707 *process_status = status;
2708 return pid;
2711 void
2712 __gnat_os_exit (int status)
2714 exit (status);
2718 __gnat_current_process_id (void)
2720 #if defined (__vxworks) || defined (__PikeOS__)
2721 return -1;
2723 #elif defined (_WIN32)
2725 return (int)GetCurrentProcessId();
2727 #else
2729 return (int)getpid();
2730 #endif
2733 /* Locate file on path, that matches a predicate */
2735 char *
2736 __gnat_locate_file_with_predicate (char *file_name, char *path_val,
2737 int (*predicate)(char *))
2739 char *ptr;
2740 char *file_path = (char *) alloca (strlen (file_name) + 1);
2741 int absolute;
2743 /* Return immediately if file_name is empty */
2745 if (*file_name == '\0')
2746 return 0;
2748 /* Remove quotes around file_name if present */
2750 ptr = file_name;
2751 if (*ptr == '"')
2752 ptr++;
2754 strcpy (file_path, ptr);
2756 ptr = file_path + strlen (file_path) - 1;
2758 if (*ptr == '"')
2759 *ptr = '\0';
2761 /* Handle absolute pathnames. */
2763 absolute = __gnat_is_absolute_path (file_path, strlen (file_name));
2765 if (absolute)
2767 if (predicate (file_path))
2768 return xstrdup (file_path);
2770 return 0;
2773 /* If file_name include directory separator(s), try it first as
2774 a path name relative to the current directory */
2775 for (ptr = file_name; *ptr && *ptr != '/' && *ptr != DIR_SEPARATOR; ptr++)
2778 if (*ptr != 0)
2780 if (predicate (file_name))
2781 return xstrdup (file_name);
2784 if (path_val == 0)
2785 return 0;
2788 /* The result has to be smaller than path_val + file_name. */
2789 char *file_path =
2790 (char *) alloca (strlen (path_val) + strlen (file_name) + 2);
2792 for (;;)
2794 /* Skip the starting quote */
2796 if (*path_val == '"')
2797 path_val++;
2799 for (ptr = file_path; *path_val && *path_val != PATH_SEPARATOR; )
2800 *ptr++ = *path_val++;
2802 /* If directory is empty, it is the current directory*/
2804 if (ptr == file_path)
2806 *ptr = '.';
2808 else
2809 ptr--;
2811 /* Skip the ending quote */
2813 if (*ptr == '"')
2814 ptr--;
2816 if (*ptr != '/' && *ptr != DIR_SEPARATOR)
2817 *++ptr = DIR_SEPARATOR;
2819 strcpy (++ptr, file_name);
2821 if (predicate (file_path))
2822 return xstrdup (file_path);
2824 if (*path_val == 0)
2825 return 0;
2827 /* Skip path separator */
2829 path_val++;
2833 return 0;
2836 /* Locate an executable file, give a Path value. */
2838 char *
2839 __gnat_locate_executable_file (char *file_name, char *path_val)
2841 return __gnat_locate_file_with_predicate
2842 (file_name, path_val, &__gnat_is_executable_file);
2845 /* Locate a regular file, give a Path value. */
2847 char *
2848 __gnat_locate_regular_file (char *file_name, char *path_val)
2850 return __gnat_locate_file_with_predicate
2851 (file_name, path_val, &__gnat_is_regular_file);
2854 /* Locate an executable given a Path argument. This routine is only used by
2855 gnatbl and should not be used otherwise. Use locate_exec_on_path
2856 instead. */
2858 char *
2859 __gnat_locate_exec (char *exec_name, char *path_val)
2861 char *ptr;
2862 if (!strstr (exec_name, HOST_EXECUTABLE_SUFFIX))
2864 char *full_exec_name =
2865 (char *) alloca
2866 (strlen (exec_name) + strlen (HOST_EXECUTABLE_SUFFIX) + 1);
2868 strcpy (full_exec_name, exec_name);
2869 strcat (full_exec_name, HOST_EXECUTABLE_SUFFIX);
2870 ptr = __gnat_locate_executable_file (full_exec_name, path_val);
2872 if (ptr == 0)
2873 return __gnat_locate_executable_file (exec_name, path_val);
2874 return ptr;
2876 else
2877 return __gnat_locate_executable_file (exec_name, path_val);
2880 /* Locate an executable using the Systems default PATH. */
2882 char *
2883 __gnat_locate_exec_on_path (char *exec_name)
2885 char *apath_val;
2887 #if defined (_WIN32)
2888 TCHAR *wpath_val = _tgetenv (_T("PATH"));
2889 TCHAR *wapath_val;
2890 /* In Win32 systems we expand the PATH as for XP environment
2891 variables are not automatically expanded. We also prepend the
2892 ".;" to the path to match normal NT path search semantics */
2894 #define EXPAND_BUFFER_SIZE 32767
2896 wapath_val = (TCHAR *) alloca (EXPAND_BUFFER_SIZE);
2898 wapath_val [0] = '.';
2899 wapath_val [1] = ';';
2901 DWORD res = ExpandEnvironmentStrings
2902 (wpath_val, &wapath_val[2], EXPAND_BUFFER_SIZE - 2);
2904 if (!res) wapath_val [0] = _T('\0');
2906 apath_val = (char *) alloca (EXPAND_BUFFER_SIZE);
2908 WS2SC (apath_val, wapath_val, EXPAND_BUFFER_SIZE);
2910 #else
2911 const char *path_val = getenv ("PATH");
2913 /* If PATH is not defined, proceed with __gnat_locate_exec anyway, so we can
2914 find files that contain directory names. */
2916 if (path_val == NULL) path_val = "";
2917 apath_val = (char *) alloca (strlen (path_val) + 1);
2918 strcpy (apath_val, path_val);
2919 #endif
2921 return __gnat_locate_exec (exec_name, apath_val);
2924 /* Dummy functions for Osint import for non-VMS systems.
2925 ??? To be removed. */
2928 __gnat_to_canonical_file_list_init (char *dirspec ATTRIBUTE_UNUSED,
2929 int onlydirs ATTRIBUTE_UNUSED)
2931 return 0;
2934 char *
2935 __gnat_to_canonical_file_list_next (void)
2937 static char empty[] = "";
2938 return empty;
2941 void
2942 __gnat_to_canonical_file_list_free (void)
2946 char *
2947 __gnat_to_canonical_dir_spec (char *dirspec, int prefixflag ATTRIBUTE_UNUSED)
2949 return dirspec;
2952 char *
2953 __gnat_to_canonical_file_spec (char *filespec)
2955 return filespec;
2958 char *
2959 __gnat_to_canonical_path_spec (char *pathspec)
2961 return pathspec;
2964 char *
2965 __gnat_to_host_dir_spec (char *dirspec, int prefixflag ATTRIBUTE_UNUSED)
2967 return dirspec;
2970 char *
2971 __gnat_to_host_file_spec (char *filespec)
2973 return filespec;
2976 void
2977 __gnat_adjust_os_resource_limits (void)
2981 #if defined (__mips_vxworks)
2983 _flush_cache (void)
2985 CACHE_USER_FLUSH (0, ENTIRE_CACHE);
2987 #endif
2989 #if defined (_WIN32)
2990 int __gnat_argument_needs_quote = 1;
2991 #else
2992 int __gnat_argument_needs_quote = 0;
2993 #endif
2995 /* This option is used to enable/disable object files handling from the
2996 binder file by the GNAT Project module. For example, this is disabled on
2997 Windows (prior to GCC 3.4) as it is already done by the mdll module.
2998 Stating with GCC 3.4 the shared libraries are not based on mdll
2999 anymore as it uses the GCC's -shared option */
3000 #if defined (_WIN32) \
3001 && ((__GNUC__ < 3) || ((__GNUC__ == 3) && (__GNUC_MINOR__ < 4)))
3002 int __gnat_prj_add_obj_files = 0;
3003 #else
3004 int __gnat_prj_add_obj_files = 1;
3005 #endif
3007 /* char used as prefix/suffix for environment variables */
3008 #if defined (_WIN32)
3009 char __gnat_environment_char = '%';
3010 #else
3011 char __gnat_environment_char = '$';
3012 #endif
3014 /* This functions copy the file attributes from a source file to a
3015 destination file.
3017 mode = 0 : In this mode copy only the file time stamps (last access and
3018 last modification time stamps).
3020 mode = 1 : In this mode, time stamps and read/write/execute attributes are
3021 copied.
3023 mode = 2 : In this mode, only read/write/execute attributes are copied
3025 Returns 0 if operation was successful and -1 in case of error. */
3028 __gnat_copy_attribs (char *from ATTRIBUTE_UNUSED, char *to ATTRIBUTE_UNUSED,
3029 int mode ATTRIBUTE_UNUSED)
3031 #if (defined (__vxworks) && _WRS_VXWORKS_MAJOR < 6)
3032 return -1;
3034 #elif defined (_WIN32)
3035 TCHAR wfrom [GNAT_MAX_PATH_LEN + 2];
3036 TCHAR wto [GNAT_MAX_PATH_LEN + 2];
3037 BOOL res;
3038 FILETIME fct, flat, flwt;
3039 HANDLE hfrom, hto;
3041 S2WSC (wfrom, from, GNAT_MAX_PATH_LEN + 2);
3042 S2WSC (wto, to, GNAT_MAX_PATH_LEN + 2);
3044 /* Do we need to copy the timestamp ? */
3046 if (mode != 2) {
3047 /* retrieve from times */
3049 hfrom = CreateFile
3050 (wfrom, GENERIC_READ, 0, NULL, OPEN_EXISTING,
3051 FILE_ATTRIBUTE_NORMAL, NULL);
3053 if (hfrom == INVALID_HANDLE_VALUE)
3054 return -1;
3056 res = GetFileTime (hfrom, &fct, &flat, &flwt);
3058 CloseHandle (hfrom);
3060 if (res == 0)
3061 return -1;
3063 /* retrieve from times */
3065 hto = CreateFile
3066 (wto, GENERIC_WRITE, 0, NULL, OPEN_EXISTING,
3067 FILE_ATTRIBUTE_NORMAL, NULL);
3069 if (hto == INVALID_HANDLE_VALUE)
3070 return -1;
3072 res = SetFileTime (hto, NULL, &flat, &flwt);
3074 CloseHandle (hto);
3076 if (res == 0)
3077 return -1;
3080 /* Do we need to copy the permissions ? */
3081 /* Set file attributes in full mode. */
3083 if (mode != 0)
3085 DWORD attribs = GetFileAttributes (wfrom);
3087 if (attribs == INVALID_FILE_ATTRIBUTES)
3088 return -1;
3090 res = SetFileAttributes (wto, attribs);
3091 if (res == 0)
3092 return -1;
3095 return 0;
3097 #else
3098 GNAT_STRUCT_STAT fbuf;
3099 struct utimbuf tbuf;
3101 if (GNAT_STAT (from, &fbuf) == -1) {
3102 return -1;
3105 /* Do we need to copy timestamp ? */
3106 if (mode != 2) {
3107 tbuf.actime = fbuf.st_atime;
3108 tbuf.modtime = fbuf.st_mtime;
3110 if (utime (to, &tbuf) == -1) {
3111 return -1;
3115 /* Do we need to copy file permissions ? */
3116 if (mode != 0 && (chmod (to, fbuf.st_mode) == -1)) {
3117 return -1;
3120 return 0;
3121 #endif
3125 __gnat_lseek (int fd, long offset, int whence)
3127 return (int) lseek (fd, offset, whence);
3130 /* This function returns the major version number of GCC being used. */
3132 get_gcc_version (void)
3134 #ifdef IN_RTS
3135 return __GNUC__;
3136 #else
3137 return (int) (version_string[0] - '0');
3138 #endif
3142 * Set Close_On_Exec as indicated.
3143 * Note: this is used for both GNAT.OS_Lib and GNAT.Sockets.
3147 __gnat_set_close_on_exec (int fd ATTRIBUTE_UNUSED,
3148 int close_on_exec_p ATTRIBUTE_UNUSED)
3150 #if defined (F_GETFD) && defined (FD_CLOEXEC) && ! defined (__vxworks)
3151 int flags = fcntl (fd, F_GETFD, 0);
3152 if (flags < 0)
3153 return flags;
3154 if (close_on_exec_p)
3155 flags |= FD_CLOEXEC;
3156 else
3157 flags &= ~FD_CLOEXEC;
3158 return fcntl (fd, F_SETFD, flags);
3159 #elif defined(_WIN32)
3160 HANDLE h = (HANDLE) _get_osfhandle (fd);
3161 if (h == (HANDLE) -1)
3162 return -1;
3163 if (close_on_exec_p)
3164 return ! SetHandleInformation (h, HANDLE_FLAG_INHERIT, 0);
3165 return ! SetHandleInformation (h, HANDLE_FLAG_INHERIT,
3166 HANDLE_FLAG_INHERIT);
3167 #else
3168 /* TODO: Unimplemented. */
3169 return -1;
3170 #endif
3173 /* Indicates if platforms supports automatic initialization through the
3174 constructor mechanism */
3176 __gnat_binder_supports_auto_init (void)
3178 return 1;
3181 /* Indicates that Stand-Alone Libraries are automatically initialized through
3182 the constructor mechanism */
3184 __gnat_sals_init_using_constructors (void)
3186 #if defined (__vxworks) || defined (__Lynx__)
3187 return 0;
3188 #else
3189 return 1;
3190 #endif
3193 #if defined (__linux__) || defined (__ANDROID__)
3194 /* There is no function in the glibc to retrieve the LWP of the current
3195 thread. We need to do a system call in order to retrieve this
3196 information. */
3197 #include <sys/syscall.h>
3198 void *
3199 __gnat_lwp_self (void)
3201 return (void *) syscall (__NR_gettid);
3203 #endif
3205 #if defined (__APPLE__)
3206 #include <mach/thread_info.h>
3207 #include <mach/mach_init.h>
3208 #include <mach/thread_act.h>
3210 /* System-wide thread identifier. Note it could be truncated on 32 bit
3211 hosts.
3212 Previously was: pthread_mach_thread_np (pthread_self ()). */
3213 void *
3214 __gnat_lwp_self (void)
3216 thread_identifier_info_data_t data;
3217 mach_msg_type_number_t count = THREAD_IDENTIFIER_INFO_COUNT;
3218 kern_return_t kret;
3220 kret = thread_info (mach_thread_self (), THREAD_IDENTIFIER_INFO,
3221 (thread_info_t) &data, &count);
3222 if (kret == KERN_SUCCESS)
3223 return (void *)(uintptr_t)data.thread_id;
3224 else
3225 return 0;
3227 #endif
3229 #if defined (__linux__)
3230 #include <sched.h>
3232 /* glibc versions earlier than 2.7 do not define the routines to handle
3233 dynamically allocated CPU sets. For these targets, we use the static
3234 versions. */
3236 #ifdef CPU_ALLOC
3238 /* Dynamic cpu sets */
3240 cpu_set_t *
3241 __gnat_cpu_alloc (size_t count)
3243 return CPU_ALLOC (count);
3246 size_t
3247 __gnat_cpu_alloc_size (size_t count)
3249 return CPU_ALLOC_SIZE (count);
3252 void
3253 __gnat_cpu_free (cpu_set_t *set)
3255 CPU_FREE (set);
3258 void
3259 __gnat_cpu_zero (size_t count, cpu_set_t *set)
3261 CPU_ZERO_S (count, set);
3264 void
3265 __gnat_cpu_set (int cpu, size_t count, cpu_set_t *set)
3267 /* Ada handles CPU numbers starting from 1, while C identifies the first
3268 CPU by a 0, so we need to adjust. */
3269 CPU_SET_S (cpu - 1, count, set);
3272 #else /* !CPU_ALLOC */
3274 /* Static cpu sets */
3276 cpu_set_t *
3277 __gnat_cpu_alloc (size_t count ATTRIBUTE_UNUSED)
3279 return (cpu_set_t *) xmalloc (sizeof (cpu_set_t));
3282 size_t
3283 __gnat_cpu_alloc_size (size_t count ATTRIBUTE_UNUSED)
3285 return sizeof (cpu_set_t);
3288 void
3289 __gnat_cpu_free (cpu_set_t *set)
3291 free (set);
3294 void
3295 __gnat_cpu_zero (size_t count ATTRIBUTE_UNUSED, cpu_set_t *set)
3297 CPU_ZERO (set);
3300 void
3301 __gnat_cpu_set (int cpu, size_t count ATTRIBUTE_UNUSED, cpu_set_t *set)
3303 /* Ada handles CPU numbers starting from 1, while C identifies the first
3304 CPU by a 0, so we need to adjust. */
3305 CPU_SET (cpu - 1, set);
3307 #endif /* !CPU_ALLOC */
3308 #endif /* __linux__ */
3310 /* Return the load address of the executable, or 0 if not known. In the
3311 specific case of error, (void *)-1 can be returned. Beware: this unit may
3312 be in a shared library. As low-level units are needed, we allow #include
3313 here. */
3315 #if defined (__APPLE__)
3316 #include <mach-o/dyld.h>
3317 #endif
3319 const void *
3320 __gnat_get_executable_load_address (void)
3322 #if defined (__APPLE__)
3323 return _dyld_get_image_header (0);
3325 #elif 0 && defined (__linux__)
3326 /* Currently disabled as it needs at least -ldl. */
3327 struct link_map *map = _r_debug.r_map;
3329 return (const void *)map->l_addr;
3331 #else
3332 return NULL;
3333 #endif
3336 void
3337 __gnat_kill (int pid, int sig, int close ATTRIBUTE_UNUSED)
3339 #if defined(_WIN32)
3340 HANDLE h = OpenProcess (PROCESS_ALL_ACCESS, FALSE, pid);
3341 if (h == NULL)
3342 return;
3343 if (sig == 9)
3345 TerminateProcess (h, 1);
3347 else if (sig == SIGINT)
3348 GenerateConsoleCtrlEvent (CTRL_C_EVENT, pid);
3349 else if (sig == SIGBREAK)
3350 GenerateConsoleCtrlEvent (CTRL_BREAK_EVENT, pid);
3351 /* ??? The last two alternatives don't really work. SIGBREAK requires setting
3352 up process groups at start time which we don't do; treating SIGINT is just
3353 not possible apparently. So we really only support signal 9. Fortunately
3354 that's all we use in GNAT.Expect */
3356 CloseHandle (h);
3357 #elif defined (__vxworks)
3358 /* Not implemented */
3359 #else
3360 kill (pid, sig);
3361 #endif
3364 void __gnat_killprocesstree (int pid, int sig_num)
3366 #if defined(_WIN32)
3367 PROCESSENTRY32 pe;
3369 memset(&pe, 0, sizeof(PROCESSENTRY32));
3370 pe.dwSize = sizeof(PROCESSENTRY32);
3372 HANDLE hSnap = CreateToolhelp32Snapshot (TH32CS_SNAPPROCESS, 0);
3374 /* cannot take snapshot, just kill the parent process */
3376 if (hSnap == INVALID_HANDLE_VALUE)
3378 __gnat_kill (pid, sig_num, 1);
3379 return;
3382 if (Process32First(hSnap, &pe))
3384 BOOL bContinue = TRUE;
3386 /* kill child processes first */
3388 while (bContinue)
3390 if (pe.th32ParentProcessID == (DWORD)pid)
3391 __gnat_killprocesstree (pe.th32ProcessID, sig_num);
3393 bContinue = Process32Next (hSnap, &pe);
3397 CloseHandle (hSnap);
3399 /* kill process */
3401 __gnat_kill (pid, sig_num, 1);
3403 #elif defined (__vxworks)
3404 /* not implemented */
3406 #elif defined (__linux__)
3407 DIR *dir;
3408 struct dirent *d;
3410 /* read all processes' pid and ppid */
3412 dir = opendir ("/proc");
3414 /* cannot open proc, just kill the parent process */
3416 if (!dir)
3418 __gnat_kill (pid, sig_num, 1);
3419 return;
3422 /* kill child processes first */
3424 while ((d = readdir (dir)) != NULL)
3426 if ((d->d_type & DT_DIR) == DT_DIR)
3428 char statfile[64];
3429 int _pid, _ppid;
3431 /* read /proc/<PID>/stat */
3433 if (strlen (d->d_name) >= sizeof (statfile) - strlen ("/proc//stat"))
3434 continue;
3435 strcpy (statfile, "/proc/");
3436 strcat (statfile, d->d_name);
3437 strcat (statfile, "/stat");
3439 FILE *fd = fopen (statfile, "r");
3441 if (fd)
3443 const int match = fscanf (fd, "%d %*s %*s %d", &_pid, &_ppid);
3444 fclose (fd);
3446 if (match == 2 && _ppid == pid)
3447 __gnat_killprocesstree (_pid, sig_num);
3452 closedir (dir);
3454 /* kill process */
3456 __gnat_kill (pid, sig_num, 1);
3457 #else
3458 __gnat_kill (pid, sig_num, 1);
3459 #endif
3460 /* Note on Solaris it is possible to read /proc/<PID>/status.
3461 The 5th and 6th words are the pid and the 7th and 8th the ppid.
3462 See: /usr/include/sys/procfs.h (struct pstatus).
3466 #ifdef __cplusplus
3468 #endif