2003-12-26 Guilhem Lavaux <guilhem@kaffe.org>
[official-gcc.git] / gcc / ada / adaint.c
blobb7130d8fbb12a57fa81c2b011466d03d71f47939
1 /****************************************************************************
2 * *
3 * GNAT COMPILER COMPONENTS *
4 * *
5 * A D A I N T *
6 * *
7 * C Implementation File *
8 * *
9 * Copyright (C) 1992-2003, 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 2, or (at your option) any later ver- *
14 * sion. GNAT is distributed in the hope that it will be useful, but WITH- *
15 * OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY *
16 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License *
17 * for more details. You should have received a copy of the GNU General *
18 * Public License distributed with GNAT; see file COPYING. If not, write *
19 * to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, *
20 * MA 02111-1307, USA. *
21 * *
22 * As a special exception, if you link this file with other files to *
23 * produce an executable, this file does not by itself cause the resulting *
24 * executable to be covered by the GNU General Public License. This except- *
25 * ion does not however invalidate any other reasons why the executable *
26 * file might be covered by the GNU Public License. *
27 * *
28 * GNAT was originally developed by the GNAT team at New York University. *
29 * Extensive contributions were provided by Ada Core Technologies Inc. *
30 * *
31 ****************************************************************************/
33 /* This file contains those routines named by Import pragmas in
34 packages in the GNAT hierarchy (especially GNAT.OS_Lib) and in
35 package Osint. Many of the subprograms in OS_Lib import standard
36 library calls directly. This file contains all other routines. */
38 #ifdef __vxworks
40 /* No need to redefine exit here. */
41 #undef exit
43 /* We want to use the POSIX variants of include files. */
44 #define POSIX
45 #include "vxWorks.h"
47 #if defined (__mips_vxworks)
48 #include "cacheLib.h"
49 #endif /* __mips_vxworks */
51 #endif /* VxWorks */
53 #ifdef VMS
54 #define _POSIX_EXIT 1
55 #endif
57 #ifdef IN_RTS
58 #include "tconfig.h"
59 #include "tsystem.h"
61 #include <sys/stat.h>
62 #include <fcntl.h>
63 #include <time.h>
64 #ifdef VMS
65 #include <unixio.h>
66 #endif
68 /* We don't have libiberty, so use malloc. */
69 #define xmalloc(S) malloc (S)
70 #define xrealloc(V,S) realloc (V,S)
71 #else
72 #include "config.h"
73 #include "system.h"
74 #endif
76 #ifdef __MINGW32__
77 #include "mingw32.h"
78 #include <sys/utime.h>
79 #include <ctype.h>
80 #else
81 #ifndef VMS
82 #include <utime.h>
83 #endif
84 #endif
86 #ifdef __MINGW32__
87 #if OLD_MINGW
88 #include <sys/wait.h>
89 #endif
90 #else
91 #include <sys/wait.h>
92 #endif
94 #if defined (__EMX__) || defined (MSDOS) || defined (_WIN32)
95 #elif defined (VMS)
97 /* Header files and definitions for __gnat_set_file_time_name. */
99 #include <rms.h>
100 #include <atrdef.h>
101 #include <fibdef.h>
102 #include <stsdef.h>
103 #include <iodef.h>
104 #include <errno.h>
105 #include <descrip.h>
106 #include <string.h>
107 #include <unixlib.h>
109 /* Use native 64-bit arithmetic. */
110 #define unix_time_to_vms(X,Y) \
111 { unsigned long long reftime, tmptime = (X); \
112 $DESCRIPTOR (unixtime,"1-JAN-1970 0:00:00.00"); \
113 SYS$BINTIM (&unixtime, &reftime); \
114 Y = tmptime * 10000000 + reftime; }
116 /* descrip.h doesn't have everything ... */
117 struct dsc$descriptor_fib
119 unsigned long fib$l_len;
120 struct fibdef *fib$l_addr;
123 /* I/O Status Block. */
124 struct IOSB
126 unsigned short status, count;
127 unsigned long devdep;
130 static char *tryfile;
132 /* Variable length string. */
133 struct vstring
135 short length;
136 char string[NAM$C_MAXRSS+1];
139 #else
140 #include <utime.h>
141 #endif
143 #if defined (__EMX__) || defined (MSDOS) || defined (_WIN32)
144 #include <process.h>
145 #endif
147 #if defined (_WIN32)
148 #include <dir.h>
149 #include <windows.h>
150 #endif
152 #include "adaint.h"
154 /* Define symbols O_BINARY and O_TEXT as harmless zeroes if they are not
155 defined in the current system. On DOS-like systems these flags control
156 whether the file is opened/created in text-translation mode (CR/LF in
157 external file mapped to LF in internal file), but in Unix-like systems,
158 no text translation is required, so these flags have no effect. */
160 #if defined (__EMX__)
161 #include <os2.h>
162 #endif
164 #if defined (MSDOS)
165 #include <dos.h>
166 #endif
168 #ifndef O_BINARY
169 #define O_BINARY 0
170 #endif
172 #ifndef O_TEXT
173 #define O_TEXT 0
174 #endif
176 #ifndef HOST_EXECUTABLE_SUFFIX
177 #define HOST_EXECUTABLE_SUFFIX ""
178 #endif
180 #ifndef HOST_OBJECT_SUFFIX
181 #define HOST_OBJECT_SUFFIX ".o"
182 #endif
184 #ifndef PATH_SEPARATOR
185 #define PATH_SEPARATOR ':'
186 #endif
188 #ifndef DIR_SEPARATOR
189 #define DIR_SEPARATOR '/'
190 #endif
192 char __gnat_dir_separator = DIR_SEPARATOR;
194 char __gnat_path_separator = PATH_SEPARATOR;
196 /* The GNAT_LIBRARY_TEMPLATE contains a list of expressions that define
197 the base filenames that libraries specified with -lsomelib options
198 may have. This is used by GNATMAKE to check whether an executable
199 is up-to-date or not. The syntax is
201 library_template ::= { pattern ; } pattern NUL
202 pattern ::= [ prefix ] * [ postfix ]
204 These should only specify names of static libraries as it makes
205 no sense to determine at link time if dynamic-link libraries are
206 up to date or not. Any libraries that are not found are supposed
207 to be up-to-date:
209 * if they are needed but not present, the link
210 will fail,
212 * otherwise they are libraries in the system paths and so
213 they are considered part of the system and not checked
214 for that reason.
216 ??? This should be part of a GNAT host-specific compiler
217 file instead of being included in all user applications
218 as well. This is only a temporary work-around for 3.11b. */
220 #ifndef GNAT_LIBRARY_TEMPLATE
221 #if defined (__EMX__)
222 #define GNAT_LIBRARY_TEMPLATE "*.a"
223 #elif defined (VMS)
224 #define GNAT_LIBRARY_TEMPLATE "*.olb"
225 #else
226 #define GNAT_LIBRARY_TEMPLATE "lib*.a"
227 #endif
228 #endif
230 const char *__gnat_library_template = GNAT_LIBRARY_TEMPLATE;
232 /* This variable is used in hostparm.ads to say whether the host is a VMS
233 system. */
234 #ifdef VMS
235 const int __gnat_vmsp = 1;
236 #else
237 const int __gnat_vmsp = 0;
238 #endif
240 #ifdef __EMX__
241 #define GNAT_MAX_PATH_LEN MAX_PATH
243 #elif defined (VMS)
244 #define GNAT_MAX_PATH_LEN 256 /* PATH_MAX */
246 #elif defined (__vxworks) || defined (__OPENNT)
247 #define GNAT_MAX_PATH_LEN PATH_MAX
249 #else
251 #if defined (__MINGW32__)
252 #include "mingw32.h"
254 #if OLD_MINGW
255 #include <sys/param.h>
256 #endif
258 #else
259 #include <sys/param.h>
260 #endif
262 #define GNAT_MAX_PATH_LEN MAXPATHLEN
264 #endif
266 /* The __gnat_max_path_len variable is used to export the maximum
267 length of a path name to Ada code. max_path_len is also provided
268 for compatibility with older GNAT versions, please do not use
269 it. */
271 int __gnat_max_path_len = GNAT_MAX_PATH_LEN;
272 int max_path_len = GNAT_MAX_PATH_LEN;
274 /* The following macro HAVE_READDIR_R should be defined if the
275 system provides the routine readdir_r. */
276 #undef HAVE_READDIR_R
278 void
279 __gnat_to_gm_time
280 (OS_Time *p_time,
281 int *p_year,
282 int *p_month,
283 int *p_day,
284 int *p_hours,
285 int *p_mins,
286 int *p_secs)
288 struct tm *res;
289 time_t time = (time_t) *p_time;
291 #ifdef _WIN32
292 /* On Windows systems, the time is sometimes rounded up to the nearest
293 even second, so if the number of seconds is odd, increment it. */
294 if (time & 1)
295 time++;
296 #endif
298 #ifdef VMS
299 res = localtime (&time);
300 #else
301 res = gmtime (&time);
302 #endif
304 if (res)
306 *p_year = res->tm_year;
307 *p_month = res->tm_mon;
308 *p_day = res->tm_mday;
309 *p_hours = res->tm_hour;
310 *p_mins = res->tm_min;
311 *p_secs = res->tm_sec;
313 else
314 *p_year = *p_month = *p_day = *p_hours = *p_mins = *p_secs = 0;
317 /* Place the contents of the symbolic link named PATH in the buffer BUF,
318 which has size BUFSIZ. If PATH is a symbolic link, then return the number
319 of characters of its content in BUF. Otherwise, return -1. For Windows,
320 OS/2 and vxworks, always return -1. */
323 __gnat_readlink (char *path ATTRIBUTE_UNUSED,
324 char *buf ATTRIBUTE_UNUSED,
325 size_t bufsiz ATTRIBUTE_UNUSED)
327 #if defined (MSDOS) || defined (_WIN32) || defined (__EMX__)
328 return -1;
329 #elif defined (__INTERIX) || defined (VMS)
330 return -1;
331 #elif defined (__vxworks)
332 return -1;
333 #else
334 return readlink (path, buf, bufsiz);
335 #endif
338 /* Creates a symbolic link named NEWPATH which contains the string OLDPATH. If
339 NEWPATH exists it will NOT be overwritten. For Windows, OS/2, VxWorks,
340 Interix and VMS, always return -1. */
343 __gnat_symlink (char *oldpath ATTRIBUTE_UNUSED,
344 char *newpath ATTRIBUTE_UNUSED)
346 #if defined (MSDOS) || defined (_WIN32) || defined (__EMX__)
347 return -1;
348 #elif defined (__INTERIX) || defined (VMS)
349 return -1;
350 #elif defined (__vxworks)
351 return -1;
352 #else
353 return symlink (oldpath, newpath);
354 #endif
357 /* Try to lock a file, return 1 if success. */
359 #if defined (__vxworks) || defined (MSDOS) || defined (_WIN32)
361 /* Version that does not use link. */
364 __gnat_try_lock (char *dir, char *file)
366 char full_path[256];
367 int fd;
369 sprintf (full_path, "%s%c%s", dir, DIR_SEPARATOR, file);
370 fd = open (full_path, O_CREAT | O_EXCL, 0600);
371 if (fd < 0)
372 return 0;
374 close (fd);
375 return 1;
378 #elif defined (__EMX__) || defined (VMS)
380 /* More cases that do not use link; identical code, to solve too long
381 line problem ??? */
384 __gnat_try_lock (char *dir, char *file)
386 char full_path[256];
387 int fd;
389 sprintf (full_path, "%s%c%s", dir, DIR_SEPARATOR, file);
390 fd = open (full_path, O_CREAT | O_EXCL, 0600);
391 if (fd < 0)
392 return 0;
394 close (fd);
395 return 1;
398 #else
400 /* Version using link(), more secure over NFS. */
401 /* See TN 6913-016 for discussion ??? */
404 __gnat_try_lock (char *dir, char *file)
406 char full_path[256];
407 char temp_file[256];
408 struct stat stat_result;
409 int fd;
411 sprintf (full_path, "%s%c%s", dir, DIR_SEPARATOR, file);
412 sprintf (temp_file, "%s-%ld-%ld", dir, (long) getpid(), (long) getppid ());
414 /* Create the temporary file and write the process number. */
415 fd = open (temp_file, O_CREAT | O_WRONLY, 0600);
416 if (fd < 0)
417 return 0;
419 close (fd);
421 /* Link it with the new file. */
422 link (temp_file, full_path);
424 /* Count the references on the old one. If we have a count of two, then
425 the link did succeed. Remove the temporary file before returning. */
426 __gnat_stat (temp_file, &stat_result);
427 unlink (temp_file);
428 return stat_result.st_nlink == 2;
430 #endif
432 /* Return the maximum file name length. */
435 __gnat_get_maximum_file_name_length (void)
437 #if defined (MSDOS)
438 return 8;
439 #elif defined (VMS)
440 if (getenv ("GNAT$EXTENDED_FILE_SPECIFICATIONS"))
441 return -1;
442 else
443 return 39;
444 #else
445 return -1;
446 #endif
449 /* Return nonzero if file names are case sensitive. */
452 __gnat_get_file_names_case_sensitive (void)
454 #if defined (__EMX__) || defined (MSDOS) || defined (VMS) || defined (WINNT)
455 return 0;
456 #else
457 return 1;
458 #endif
461 char
462 __gnat_get_default_identifier_character_set (void)
464 #if defined (__EMX__) || defined (MSDOS)
465 return 'p';
466 #else
467 return '1';
468 #endif
471 /* Return the current working directory. */
473 void
474 __gnat_get_current_dir (char *dir, int *length)
476 #ifdef VMS
477 /* Force Unix style, which is what GNAT uses internally. */
478 getcwd (dir, *length, 0);
479 #else
480 getcwd (dir, *length);
481 #endif
483 *length = strlen (dir);
485 if (dir [*length - 1] != DIR_SEPARATOR)
487 dir [*length] = DIR_SEPARATOR;
488 ++(*length);
490 dir[*length] = '\0';
493 /* Return the suffix for object files. */
495 void
496 __gnat_get_object_suffix_ptr (int *len, const char **value)
498 *value = HOST_OBJECT_SUFFIX;
500 if (*value == 0)
501 *len = 0;
502 else
503 *len = strlen (*value);
505 return;
508 /* Return the suffix for executable files. */
510 void
511 __gnat_get_executable_suffix_ptr (int *len, const char **value)
513 *value = HOST_EXECUTABLE_SUFFIX;
514 if (!*value)
515 *len = 0;
516 else
517 *len = strlen (*value);
519 return;
522 /* Return the suffix for debuggable files. Usually this is the same as the
523 executable extension. */
525 void
526 __gnat_get_debuggable_suffix_ptr (int *len, const char **value)
528 #ifndef MSDOS
529 *value = HOST_EXECUTABLE_SUFFIX;
530 #else
531 /* On DOS, the extensionless COFF file is what gdb likes. */
532 *value = "";
533 #endif
535 if (*value == 0)
536 *len = 0;
537 else
538 *len = strlen (*value);
540 return;
544 __gnat_open_read (char *path, int fmode)
546 int fd;
547 int o_fmode = O_BINARY;
549 if (fmode)
550 o_fmode = O_TEXT;
552 #if defined (VMS)
553 /* Optional arguments mbc,deq,fop increase read performance. */
554 fd = open (path, O_RDONLY | o_fmode, 0444,
555 "mbc=16", "deq=64", "fop=tef");
556 #elif defined (__vxworks)
557 fd = open (path, O_RDONLY | o_fmode, 0444);
558 #else
559 fd = open (path, O_RDONLY | o_fmode);
560 #endif
562 return fd < 0 ? -1 : fd;
565 #if defined (__EMX__) || defined (__MINGW32__)
566 #define PERM (S_IREAD | S_IWRITE)
567 #elif defined (VMS)
568 /* Excerpt from DECC C RTL Reference Manual:
569 To create files with OpenVMS RMS default protections using the UNIX
570 system-call functions umask, mkdir, creat, and open, call mkdir, creat,
571 and open with a file-protection mode argument of 0777 in a program
572 that never specifically calls umask. These default protections include
573 correctly establishing protections based on ACLs, previous versions of
574 files, and so on. */
575 #define PERM 0777
576 #else
577 #define PERM (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH)
578 #endif
581 __gnat_open_rw (char *path, int fmode)
583 int fd;
584 int o_fmode = O_BINARY;
586 if (fmode)
587 o_fmode = O_TEXT;
589 #if defined (VMS)
590 fd = open (path, O_RDWR | o_fmode, PERM,
591 "mbc=16", "deq=64", "fop=tef");
592 #else
593 fd = open (path, O_RDWR | o_fmode, PERM);
594 #endif
596 return fd < 0 ? -1 : fd;
600 __gnat_open_create (char *path, int fmode)
602 int fd;
603 int o_fmode = O_BINARY;
605 if (fmode)
606 o_fmode = O_TEXT;
608 #if defined (VMS)
609 fd = open (path, O_WRONLY | O_CREAT | O_TRUNC | o_fmode, PERM,
610 "mbc=16", "deq=64", "fop=tef");
611 #else
612 fd = open (path, O_WRONLY | O_CREAT | O_TRUNC | o_fmode, PERM);
613 #endif
615 return fd < 0 ? -1 : fd;
619 __gnat_open_append (char *path, int fmode)
621 int fd;
622 int o_fmode = O_BINARY;
624 if (fmode)
625 o_fmode = O_TEXT;
627 #if defined (VMS)
628 fd = open (path, O_WRONLY | O_CREAT | O_APPEND | o_fmode, PERM,
629 "mbc=16", "deq=64", "fop=tef");
630 #else
631 fd = open (path, O_WRONLY | O_CREAT | O_APPEND | o_fmode, PERM);
632 #endif
634 return fd < 0 ? -1 : fd;
637 /* Open a new file. Return error (-1) if the file already exists. */
640 __gnat_open_new (char *path, int fmode)
642 int fd;
643 int o_fmode = O_BINARY;
645 if (fmode)
646 o_fmode = O_TEXT;
648 #if defined (VMS)
649 fd = open (path, O_WRONLY | O_CREAT | O_EXCL | o_fmode, PERM,
650 "mbc=16", "deq=64", "fop=tef");
651 #else
652 fd = open (path, O_WRONLY | O_CREAT | O_EXCL | o_fmode, PERM);
653 #endif
655 return fd < 0 ? -1 : fd;
658 /* Open a new temp file. Return error (-1) if the file already exists.
659 Special options for VMS allow the file to be shared between parent and child
660 processes, however they really slow down output. Used in gnatchop. */
663 __gnat_open_new_temp (char *path, int fmode)
665 int fd;
666 int o_fmode = O_BINARY;
668 strcpy (path, "GNAT-XXXXXX");
670 #if (defined (__FreeBSD__) || defined (linux)) && !defined (__vxworks)
671 return mkstemp (path);
672 #elif defined (__Lynx__)
673 mktemp (path);
674 #else
675 if (mktemp (path) == NULL)
676 return -1;
677 #endif
679 if (fmode)
680 o_fmode = O_TEXT;
682 #if defined (VMS)
683 fd = open (path, O_WRONLY | O_CREAT | O_EXCL | o_fmode, PERM,
684 "rfm=stmlf", "ctx=rec", "rat=none", "shr=del,get,put,upd",
685 "mbc=16", "deq=64", "fop=tef");
686 #else
687 fd = open (path, O_WRONLY | O_CREAT | O_EXCL | o_fmode, PERM);
688 #endif
690 return fd < 0 ? -1 : fd;
693 /* Return the number of bytes in the specified file. */
695 long
696 __gnat_file_length (int fd)
698 int ret;
699 struct stat statbuf;
701 ret = fstat (fd, &statbuf);
702 if (ret || !S_ISREG (statbuf.st_mode))
703 return 0;
705 return (statbuf.st_size);
708 /* Create a temporary filename and put it in string pointed to by
709 TMP_FILENAME. */
711 void
712 __gnat_tmp_name (char *tmp_filename)
714 #ifdef __MINGW32__
716 char *pname;
718 /* tempnam tries to create a temporary file in directory pointed to by
719 TMP environment variable, in c:\temp if TMP is not set, and in
720 directory specified by P_tmpdir in stdio.h if c:\temp does not
721 exist. The filename will be created with the prefix "gnat-". */
723 pname = (char *) tempnam ("c:\\temp", "gnat-");
725 /* if pname is NULL, the file was not created properly, the disk is full
726 or there is no more free temporary files */
728 if (pname == NULL)
729 *tmp_filename = '\0';
731 /* If pname start with a back slash and not path information it means that
732 the filename is valid for the current working directory. */
734 else if (pname[0] == '\\')
736 strcpy (tmp_filename, ".\\");
737 strcat (tmp_filename, pname+1);
739 else
740 strcpy (tmp_filename, pname);
742 free (pname);
745 #elif defined (linux) || defined (__FreeBSD__)
746 #define MAX_SAFE_PATH 1000
747 char *tmpdir = getenv ("TMPDIR");
749 /* If tmpdir is longer than MAX_SAFE_PATH, revert to default value to avoid
750 a buffer overflow. */
751 if (tmpdir == NULL || strlen (tmpdir) > MAX_SAFE_PATH)
752 strcpy (tmp_filename, "/tmp/gnat-XXXXXX");
753 else
754 sprintf (tmp_filename, "%s/gnat-XXXXXX", tmpdir);
756 close (mkstemp(tmp_filename));
757 #else
758 tmpnam (tmp_filename);
759 #endif
762 /* Read the next entry in a directory. The returned string points somewhere
763 in the buffer. */
765 char *
766 __gnat_readdir (DIR *dirp, char *buffer)
768 /* If possible, try to use the thread-safe version. */
769 #ifdef HAVE_READDIR_R
770 if (readdir_r (dirp, buffer) != NULL)
771 return ((struct dirent*) buffer)->d_name;
772 else
773 return NULL;
775 #else
776 struct dirent *dirent = readdir (dirp);
778 if (dirent != NULL)
780 strcpy (buffer, dirent->d_name);
781 return buffer;
783 else
784 return NULL;
786 #endif
789 /* Returns 1 if readdir is thread safe, 0 otherwise. */
792 __gnat_readdir_is_thread_safe (void)
794 #ifdef HAVE_READDIR_R
795 return 1;
796 #else
797 return 0;
798 #endif
801 #ifdef _WIN32
802 /* Number of seconds between <Jan 1st 1601> and <Jan 1st 1970>. */
803 static const unsigned long long w32_epoch_offset = 11644473600ULL;
805 /* Returns the file modification timestamp using Win32 routines which are
806 immune against daylight saving time change. It is in fact not possible to
807 use fstat for this purpose as the DST modify the st_mtime field of the
808 stat structure. */
810 static time_t
811 win32_filetime (HANDLE h)
813 union
815 FILETIME ft_time;
816 unsigned long long ull_time;
817 } t_write;
819 /* GetFileTime returns FILETIME data which are the number of 100 nanosecs
820 since <Jan 1st 1601>. This function must return the number of seconds
821 since <Jan 1st 1970>. */
823 if (GetFileTime (h, NULL, NULL, &t_write.ft_time))
824 return (time_t) (t_write.ull_time / 10000000ULL
825 - w32_epoch_offset);
826 return (time_t) 0;
828 #endif
830 /* Return a GNAT time stamp given a file name. */
832 time_t
833 __gnat_file_time_name (char *name)
836 #if defined (__EMX__) || defined (MSDOS)
837 int fd = open (name, O_RDONLY | O_BINARY);
838 time_t ret = __gnat_file_time_fd (fd);
839 close (fd);
840 return ret;
842 #elif defined (_WIN32)
843 time_t ret = 0;
844 HANDLE h = CreateFile (name, GENERIC_READ, FILE_SHARE_READ, 0,
845 OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0);
847 if (h != INVALID_HANDLE_VALUE)
849 ret = win32_filetime (h);
850 CloseHandle (h);
852 return ret;
853 #else
854 struct stat statbuf;
855 (void) __gnat_stat (name, &statbuf);
856 #ifdef VMS
857 /* VMS has file versioning. */
858 return statbuf.st_ctime;
859 #else
860 return statbuf.st_mtime;
861 #endif
862 #endif
865 /* Return a GNAT time stamp given a file descriptor. */
867 time_t
868 __gnat_file_time_fd (int fd)
870 /* The following workaround code is due to the fact that under EMX and
871 DJGPP fstat attempts to convert time values to GMT rather than keep the
872 actual OS timestamp of the file. By using the OS2/DOS functions directly
873 the GNAT timestamp are independent of this behavior, which is desired to
874 facilitate the distribution of GNAT compiled libraries. */
876 #if defined (__EMX__) || defined (MSDOS)
877 #ifdef __EMX__
879 FILESTATUS fs;
880 int ret = DosQueryFileInfo (fd, 1, (unsigned char *) &fs,
881 sizeof (FILESTATUS));
883 unsigned file_year = fs.fdateLastWrite.year;
884 unsigned file_month = fs.fdateLastWrite.month;
885 unsigned file_day = fs.fdateLastWrite.day;
886 unsigned file_hour = fs.ftimeLastWrite.hours;
887 unsigned file_min = fs.ftimeLastWrite.minutes;
888 unsigned file_tsec = fs.ftimeLastWrite.twosecs;
890 #else
891 struct ftime fs;
892 int ret = getftime (fd, &fs);
894 unsigned file_year = fs.ft_year;
895 unsigned file_month = fs.ft_month;
896 unsigned file_day = fs.ft_day;
897 unsigned file_hour = fs.ft_hour;
898 unsigned file_min = fs.ft_min;
899 unsigned file_tsec = fs.ft_tsec;
900 #endif
902 /* Calculate the seconds since epoch from the time components. First count
903 the whole days passed. The value for years returned by the DOS and OS2
904 functions count years from 1980, so to compensate for the UNIX epoch which
905 begins in 1970 start with 10 years worth of days and add days for each
906 four year period since then. */
908 time_t tot_secs;
909 int cum_days[12] = {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334};
910 int days_passed = 3652 + (file_year / 4) * 1461;
911 int years_since_leap = file_year % 4;
913 if (years_since_leap == 1)
914 days_passed += 366;
915 else if (years_since_leap == 2)
916 days_passed += 731;
917 else if (years_since_leap == 3)
918 days_passed += 1096;
920 if (file_year > 20)
921 days_passed -= 1;
923 days_passed += cum_days[file_month - 1];
924 if (years_since_leap == 0 && file_year != 20 && file_month > 2)
925 days_passed++;
927 days_passed += file_day - 1;
929 /* OK - have whole days. Multiply -- then add in other parts. */
931 tot_secs = days_passed * 86400;
932 tot_secs += file_hour * 3600;
933 tot_secs += file_min * 60;
934 tot_secs += file_tsec * 2;
935 return tot_secs;
937 #elif defined (_WIN32)
938 HANDLE h = (HANDLE) _get_osfhandle (fd);
939 time_t ret = win32_filetime (h);
940 return ret;
942 #else
943 struct stat statbuf;
945 (void) fstat (fd, &statbuf);
947 #ifdef VMS
948 /* VMS has file versioning. */
949 return statbuf.st_ctime;
950 #else
951 return statbuf.st_mtime;
952 #endif
953 #endif
956 /* Set the file time stamp. */
958 void
959 __gnat_set_file_time_name (char *name, time_t time_stamp)
961 #if defined (__EMX__) || defined (MSDOS) || defined (__vxworks)
963 /* Code to implement __gnat_set_file_time_name for these systems. */
965 #elif defined (_WIN32)
966 union
968 FILETIME ft_time;
969 unsigned long long ull_time;
970 } t_write;
972 HANDLE h = CreateFile (name, GENERIC_WRITE, FILE_SHARE_WRITE, NULL,
973 OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS,
974 NULL);
975 if (h == INVALID_HANDLE_VALUE)
976 return;
977 /* Add number of seconds between <Jan 1st 1601> and <Jan 1st 1970> */
978 t_write.ull_time = ((unsigned long long)time_stamp + w32_epoch_offset);
979 /* Convert to 100 nanosecond units */
980 t_write.ull_time *= 10000000ULL;
982 SetFileTime(h, NULL, NULL, &t_write.ft_time);
983 CloseHandle (h);
984 return;
986 #elif defined (VMS)
987 struct FAB fab;
988 struct NAM nam;
990 struct
992 unsigned long long backup, create, expire, revise;
993 unsigned long uic;
994 union
996 unsigned short value;
997 struct
999 unsigned system : 4;
1000 unsigned owner : 4;
1001 unsigned group : 4;
1002 unsigned world : 4;
1003 } bits;
1004 } prot;
1005 } Fat = { 0, 0, 0, 0, 0, { 0 }};
1007 ATRDEF atrlst[]
1009 { ATR$S_CREDATE, ATR$C_CREDATE, &Fat.create },
1010 { ATR$S_REVDATE, ATR$C_REVDATE, &Fat.revise },
1011 { ATR$S_EXPDATE, ATR$C_EXPDATE, &Fat.expire },
1012 { ATR$S_BAKDATE, ATR$C_BAKDATE, &Fat.backup },
1013 { ATR$S_FPRO, ATR$C_FPRO, &Fat.prot },
1014 { ATR$S_UIC, ATR$C_UIC, &Fat.uic },
1015 { 0, 0, 0}
1018 FIBDEF fib;
1019 struct dsc$descriptor_fib fibdsc = {sizeof (fib), (void *) &fib};
1021 struct IOSB iosb;
1023 unsigned long long newtime;
1024 unsigned long long revtime;
1025 long status;
1026 short chan;
1028 struct vstring file;
1029 struct dsc$descriptor_s filedsc
1030 = {NAM$C_MAXRSS, DSC$K_DTYPE_T, DSC$K_CLASS_S, (void *) file.string};
1031 struct vstring device;
1032 struct dsc$descriptor_s devicedsc
1033 = {NAM$C_MAXRSS, DSC$K_DTYPE_T, DSC$K_CLASS_S, (void *) device.string};
1034 struct vstring timev;
1035 struct dsc$descriptor_s timedsc
1036 = {NAM$C_MAXRSS, DSC$K_DTYPE_T, DSC$K_CLASS_S, (void *) timev.string};
1037 struct vstring result;
1038 struct dsc$descriptor_s resultdsc
1039 = {NAM$C_MAXRSS, DSC$K_DTYPE_VT, DSC$K_CLASS_VS, (void *) result.string};
1041 tryfile = (char *) __gnat_to_host_dir_spec (name, 0);
1043 /* Allocate and initialize a FAB and NAM structures. */
1044 fab = cc$rms_fab;
1045 nam = cc$rms_nam;
1047 nam.nam$l_esa = file.string;
1048 nam.nam$b_ess = NAM$C_MAXRSS;
1049 nam.nam$l_rsa = result.string;
1050 nam.nam$b_rss = NAM$C_MAXRSS;
1051 fab.fab$l_fna = tryfile;
1052 fab.fab$b_fns = strlen (tryfile);
1053 fab.fab$l_nam = &nam;
1055 /* Validate filespec syntax and device existence. */
1056 status = SYS$PARSE (&fab, 0, 0);
1057 if ((status & 1) != 1)
1058 LIB$SIGNAL (status);
1060 file.string[nam.nam$b_esl] = 0;
1062 /* Find matching filespec. */
1063 status = SYS$SEARCH (&fab, 0, 0);
1064 if ((status & 1) != 1)
1065 LIB$SIGNAL (status);
1067 file.string[nam.nam$b_esl] = 0;
1068 result.string[result.length=nam.nam$b_rsl] = 0;
1070 /* Get the device name and assign an IO channel. */
1071 strncpy (device.string, nam.nam$l_dev, nam.nam$b_dev);
1072 devicedsc.dsc$w_length = nam.nam$b_dev;
1073 chan = 0;
1074 status = SYS$ASSIGN (&devicedsc, &chan, 0, 0, 0);
1075 if ((status & 1) != 1)
1076 LIB$SIGNAL (status);
1078 /* Initialize the FIB and fill in the directory id field. */
1079 memset (&fib, 0, sizeof (fib));
1080 fib.fib$w_did[0] = nam.nam$w_did[0];
1081 fib.fib$w_did[1] = nam.nam$w_did[1];
1082 fib.fib$w_did[2] = nam.nam$w_did[2];
1083 fib.fib$l_acctl = 0;
1084 fib.fib$l_wcc = 0;
1085 strcpy (file.string, (strrchr (result.string, ']') + 1));
1086 filedsc.dsc$w_length = strlen (file.string);
1087 result.string[result.length = 0] = 0;
1089 /* Open and close the file to fill in the attributes. */
1090 status
1091 = SYS$QIOW (0, chan, IO$_ACCESS|IO$M_ACCESS, &iosb, 0, 0,
1092 &fibdsc, &filedsc, &result.length, &resultdsc, &atrlst, 0);
1093 if ((status & 1) != 1)
1094 LIB$SIGNAL (status);
1095 if ((iosb.status & 1) != 1)
1096 LIB$SIGNAL (iosb.status);
1098 result.string[result.length] = 0;
1099 status = SYS$QIOW (0, chan, IO$_DEACCESS, &iosb, 0, 0, &fibdsc, 0, 0, 0,
1100 &atrlst, 0);
1101 if ((status & 1) != 1)
1102 LIB$SIGNAL (status);
1103 if ((iosb.status & 1) != 1)
1104 LIB$SIGNAL (iosb.status);
1107 time_t t;
1109 /* Set creation time to requested time. */
1110 unix_time_to_vms (time_stamp, newtime);
1112 t = time ((time_t) 0);
1114 /* Set revision time to now in local time. */
1115 unix_time_to_vms (t, revtime);
1118 /* Reopen the file, modify the times and then close. */
1119 fib.fib$l_acctl = FIB$M_WRITE;
1120 status
1121 = SYS$QIOW (0, chan, IO$_ACCESS|IO$M_ACCESS, &iosb, 0, 0,
1122 &fibdsc, &filedsc, &result.length, &resultdsc, &atrlst, 0);
1123 if ((status & 1) != 1)
1124 LIB$SIGNAL (status);
1125 if ((iosb.status & 1) != 1)
1126 LIB$SIGNAL (iosb.status);
1128 Fat.create = newtime;
1129 Fat.revise = revtime;
1131 status = SYS$QIOW (0, chan, IO$_DEACCESS, &iosb, 0, 0,
1132 &fibdsc, 0, 0, 0, &atrlst, 0);
1133 if ((status & 1) != 1)
1134 LIB$SIGNAL (status);
1135 if ((iosb.status & 1) != 1)
1136 LIB$SIGNAL (iosb.status);
1138 /* Deassign the channel and exit. */
1139 status = SYS$DASSGN (chan);
1140 if ((status & 1) != 1)
1141 LIB$SIGNAL (status);
1142 #else
1143 struct utimbuf utimbuf;
1144 time_t t;
1146 /* Set modification time to requested time. */
1147 utimbuf.modtime = time_stamp;
1149 /* Set access time to now in local time. */
1150 t = time ((time_t) 0);
1151 utimbuf.actime = mktime (localtime (&t));
1153 utime (name, &utimbuf);
1154 #endif
1157 void
1158 __gnat_get_env_value_ptr (char *name, int *len, char **value)
1160 *value = getenv (name);
1161 if (!*value)
1162 *len = 0;
1163 else
1164 *len = strlen (*value);
1166 return;
1169 /* VMS specific declarations for set_env_value. */
1171 #ifdef VMS
1173 static char *to_host_path_spec (char *);
1175 struct descriptor_s
1177 unsigned short len, mbz;
1178 char *adr;
1181 typedef struct _ile3
1183 unsigned short len, code;
1184 char *adr;
1185 unsigned short *retlen_adr;
1186 } ile_s;
1188 #endif
1190 void
1191 __gnat_set_env_value (char *name, char *value)
1193 #ifdef MSDOS
1195 #elif defined (VMS)
1196 struct descriptor_s name_desc;
1197 /* Put in JOB table for now, so that the project stuff at least works. */
1198 struct descriptor_s table_desc = {7, 0, "LNM$JOB"};
1199 char *host_pathspec = value;
1200 char *copy_pathspec;
1201 int num_dirs_in_pathspec = 1;
1202 char *ptr;
1203 long status;
1205 name_desc.len = strlen (name);
1206 name_desc.mbz = 0;
1207 name_desc.adr = name;
1209 if (*host_pathspec == 0)
1210 /* deassign */
1212 status = LIB$DELETE_LOGICAL (&name_desc, &table_desc);
1213 /* no need to check status; if the logical name is not
1214 defined, that's fine. */
1215 return;
1218 ptr = host_pathspec;
1219 while (*ptr++)
1220 if (*ptr == ',')
1221 num_dirs_in_pathspec++;
1224 int i, status;
1225 ile_s *ile_array = alloca (sizeof (ile_s) * (num_dirs_in_pathspec + 1));
1226 char *copy_pathspec = alloca (strlen (host_pathspec) + 1);
1227 char *curr, *next;
1229 strcpy (copy_pathspec, host_pathspec);
1230 curr = copy_pathspec;
1231 for (i = 0; i < num_dirs_in_pathspec; i++)
1233 next = strchr (curr, ',');
1234 if (next == 0)
1235 next = strchr (curr, 0);
1237 *next = 0;
1238 ile_array[i].len = strlen (curr);
1240 /* Code 2 from lnmdef.h means its a string. */
1241 ile_array[i].code = 2;
1242 ile_array[i].adr = curr;
1244 /* retlen_adr is ignored. */
1245 ile_array[i].retlen_adr = 0;
1246 curr = next + 1;
1249 /* Terminating item must be zero. */
1250 ile_array[i].len = 0;
1251 ile_array[i].code = 0;
1252 ile_array[i].adr = 0;
1253 ile_array[i].retlen_adr = 0;
1255 status = LIB$SET_LOGICAL (&name_desc, 0, &table_desc, 0, ile_array);
1256 if ((status & 1) != 1)
1257 LIB$SIGNAL (status);
1260 #else
1261 int size = strlen (name) + strlen (value) + 2;
1262 char *expression;
1264 expression = (char *) xmalloc (size * sizeof (char));
1266 sprintf (expression, "%s=%s", name, value);
1267 putenv (expression);
1268 #endif
1271 #ifdef _WIN32
1272 #include <windows.h>
1273 #endif
1275 /* Get the list of installed standard libraries from the
1276 HKEY_LOCAL_MACHINE\SOFTWARE\Ada Core Technologies\GNAT\Standard Libraries
1277 key. */
1279 char *
1280 __gnat_get_libraries_from_registry (void)
1282 char *result = (char *) "";
1284 #if defined (_WIN32) && ! defined (__vxworks) && ! defined (CROSS_COMPILE)
1286 HKEY reg_key;
1287 DWORD name_size, value_size;
1288 char name[256];
1289 char value[256];
1290 DWORD type;
1291 DWORD index;
1292 LONG res;
1294 /* First open the key. */
1295 res = RegOpenKeyExA (HKEY_LOCAL_MACHINE, "SOFTWARE", 0, KEY_READ, &reg_key);
1297 if (res == ERROR_SUCCESS)
1298 res = RegOpenKeyExA (reg_key, "Ada Core Technologies", 0,
1299 KEY_READ, &reg_key);
1301 if (res == ERROR_SUCCESS)
1302 res = RegOpenKeyExA (reg_key, "GNAT", 0, KEY_READ, &reg_key);
1304 if (res == ERROR_SUCCESS)
1305 res = RegOpenKeyExA (reg_key, "Standard Libraries", 0, KEY_READ, &reg_key);
1307 /* If the key exists, read out all the values in it and concatenate them
1308 into a path. */
1309 for (index = 0; res == ERROR_SUCCESS; index++)
1311 value_size = name_size = 256;
1312 res = RegEnumValue (reg_key, index, name, &name_size, 0,
1313 &type, value, &value_size);
1315 if (res == ERROR_SUCCESS && type == REG_SZ)
1317 char *old_result = result;
1319 result = (char *) xmalloc (strlen (old_result) + value_size + 2);
1320 strcpy (result, old_result);
1321 strcat (result, value);
1322 strcat (result, ";");
1326 /* Remove the trailing ";". */
1327 if (result[0] != 0)
1328 result[strlen (result) - 1] = 0;
1330 #endif
1331 return result;
1335 __gnat_stat (char *name, struct stat *statbuf)
1337 #ifdef _WIN32
1338 /* Under Windows the directory name for the stat function must not be
1339 terminated by a directory separator except if just after a drive name. */
1340 int name_len = strlen (name);
1341 char last_char = name[name_len - 1];
1342 char win32_name[GNAT_MAX_PATH_LEN + 2];
1344 if (name_len > GNAT_MAX_PATH_LEN)
1345 return -1;
1347 strcpy (win32_name, name);
1349 while (name_len > 1 && (last_char == '\\' || last_char == '/'))
1351 win32_name[name_len - 1] = '\0';
1352 name_len--;
1353 last_char = win32_name[name_len - 1];
1356 if (name_len == 2 && win32_name[1] == ':')
1357 strcat (win32_name, "\\");
1359 return stat (win32_name, statbuf);
1361 #else
1362 return stat (name, statbuf);
1363 #endif
1367 __gnat_file_exists (char *name)
1369 struct stat statbuf;
1371 return !__gnat_stat (name, &statbuf);
1375 __gnat_is_absolute_path (char *name)
1377 return (*name == '/' || *name == DIR_SEPARATOR
1378 #if defined (__EMX__) || defined (MSDOS) || defined (WINNT)
1379 || (strlen (name) > 1 && isalpha (name[0]) && name[1] == ':')
1380 #endif
1385 __gnat_is_regular_file (char *name)
1387 int ret;
1388 struct stat statbuf;
1390 ret = __gnat_stat (name, &statbuf);
1391 return (!ret && S_ISREG (statbuf.st_mode));
1395 __gnat_is_directory (char *name)
1397 int ret;
1398 struct stat statbuf;
1400 ret = __gnat_stat (name, &statbuf);
1401 return (!ret && S_ISDIR (statbuf.st_mode));
1405 __gnat_is_readable_file (char *name)
1407 int ret;
1408 int mode;
1409 struct stat statbuf;
1411 ret = __gnat_stat (name, &statbuf);
1412 mode = statbuf.st_mode & S_IRUSR;
1413 return (!ret && mode);
1417 __gnat_is_writable_file (char *name)
1419 int ret;
1420 int mode;
1421 struct stat statbuf;
1423 ret = __gnat_stat (name, &statbuf);
1424 mode = statbuf.st_mode & S_IWUSR;
1425 return (!ret && mode);
1428 void
1429 __gnat_set_writable (char *name)
1431 #ifndef __vxworks
1432 struct stat statbuf;
1434 if (stat (name, &statbuf) == 0)
1436 statbuf.st_mode = statbuf.st_mode | S_IWUSR;
1437 chmod (name, statbuf.st_mode);
1439 #endif
1442 void
1443 __gnat_set_readonly (char *name)
1445 #ifndef __vxworks
1446 struct stat statbuf;
1448 if (stat (name, &statbuf) == 0)
1450 statbuf.st_mode = statbuf.st_mode & 07577;
1451 chmod (name, statbuf.st_mode);
1453 #endif
1457 __gnat_is_symbolic_link (char *name ATTRIBUTE_UNUSED)
1459 #if defined (__vxworks)
1460 return 0;
1462 #elif defined (_AIX) || defined (unix)
1463 int ret;
1464 struct stat statbuf;
1466 ret = lstat (name, &statbuf);
1467 return (!ret && S_ISLNK (statbuf.st_mode));
1469 #else
1470 return 0;
1471 #endif
1474 #ifdef VMS
1475 /* Defined in VMS header files. */
1476 #if defined (__ALPHA)
1477 #define fork() (decc$$alloc_vfork_blocks() >= 0 ? \
1478 LIB$GET_CURRENT_INVO_CONTEXT (decc$$get_vfork_jmpbuf()) : -1)
1479 #elif defined (__IA64)
1480 #define fork() (decc$$alloc_vfork_blocks() >= 0 ? \
1481 LIB$I64_GET_CURR_INVO_CONTEXT(decc$$get_vfork_jmpbuf()) : -1)
1482 #endif
1483 #endif
1485 #if defined (sun) && defined (__SVR4)
1486 /* Using fork on Solaris will duplicate all the threads. fork1, which
1487 duplicates only the active thread, must be used instead, or spawning
1488 subprocess from a program with tasking will lead into numerous problems. */
1489 #define fork fork1
1490 #endif
1493 __gnat_portable_spawn (char *args[])
1495 int status = 0;
1496 int finished ATTRIBUTE_UNUSED;
1497 int pid ATTRIBUTE_UNUSED;
1499 #if defined (MSDOS) || defined (_WIN32)
1500 status = spawnvp (P_WAIT, args[0],(const char* const*)args);
1501 if (status < 0)
1502 return -1;
1503 else
1504 return status;
1506 #elif defined (__vxworks)
1507 return -1;
1508 #else
1510 #ifdef __EMX__
1511 pid = spawnvp (P_NOWAIT, args[0], args);
1512 if (pid == -1)
1513 return -1;
1515 #else
1516 pid = fork ();
1517 if (pid < 0)
1518 return -1;
1520 if (pid == 0)
1522 /* The child. */
1523 if (execv (args[0], args) != 0)
1524 #if defined (VMS)
1525 return -1; /* execv is in parent context on VMS. */
1526 #else
1527 _exit (1);
1528 #endif
1530 #endif
1532 /* The parent. */
1533 finished = waitpid (pid, &status, 0);
1535 if (finished != pid || WIFEXITED (status) == 0)
1536 return -1;
1538 return WEXITSTATUS (status);
1539 #endif
1541 return 0;
1544 /* WIN32 code to implement a wait call that wait for any child process. */
1546 #ifdef _WIN32
1548 /* Synchronization code, to be thread safe. */
1550 static CRITICAL_SECTION plist_cs;
1552 void
1553 __gnat_plist_init (void)
1555 InitializeCriticalSection (&plist_cs);
1558 static void
1559 plist_enter (void)
1561 EnterCriticalSection (&plist_cs);
1564 static void
1565 plist_leave (void)
1567 LeaveCriticalSection (&plist_cs);
1570 typedef struct _process_list
1572 HANDLE h;
1573 struct _process_list *next;
1574 } Process_List;
1576 static Process_List *PLIST = NULL;
1578 static int plist_length = 0;
1580 static void
1581 add_handle (HANDLE h)
1583 Process_List *pl;
1585 pl = (Process_List *) xmalloc (sizeof (Process_List));
1587 plist_enter();
1589 /* -------------------- critical section -------------------- */
1590 pl->h = h;
1591 pl->next = PLIST;
1592 PLIST = pl;
1593 ++plist_length;
1594 /* -------------------- critical section -------------------- */
1596 plist_leave();
1599 static void
1600 remove_handle (HANDLE h)
1602 Process_List *pl;
1603 Process_List *prev = NULL;
1605 plist_enter();
1607 /* -------------------- critical section -------------------- */
1608 pl = PLIST;
1609 while (pl)
1611 if (pl->h == h)
1613 if (pl == PLIST)
1614 PLIST = pl->next;
1615 else
1616 prev->next = pl->next;
1617 free (pl);
1618 break;
1620 else
1622 prev = pl;
1623 pl = pl->next;
1627 --plist_length;
1628 /* -------------------- critical section -------------------- */
1630 plist_leave();
1633 static int
1634 win32_no_block_spawn (char *command, char *args[])
1636 BOOL result;
1637 STARTUPINFO SI;
1638 PROCESS_INFORMATION PI;
1639 SECURITY_ATTRIBUTES SA;
1640 int csize = 1;
1641 char *full_command;
1642 int k;
1644 /* compute the total command line length */
1645 k = 0;
1646 while (args[k])
1648 csize += strlen (args[k]) + 1;
1649 k++;
1652 full_command = (char *) xmalloc (csize);
1654 /* Startup info. */
1655 SI.cb = sizeof (STARTUPINFO);
1656 SI.lpReserved = NULL;
1657 SI.lpReserved2 = NULL;
1658 SI.lpDesktop = NULL;
1659 SI.cbReserved2 = 0;
1660 SI.lpTitle = NULL;
1661 SI.dwFlags = 0;
1662 SI.wShowWindow = SW_HIDE;
1664 /* Security attributes. */
1665 SA.nLength = sizeof (SECURITY_ATTRIBUTES);
1666 SA.bInheritHandle = TRUE;
1667 SA.lpSecurityDescriptor = NULL;
1669 /* Prepare the command string. */
1670 strcpy (full_command, command);
1671 strcat (full_command, " ");
1673 k = 1;
1674 while (args[k])
1676 strcat (full_command, args[k]);
1677 strcat (full_command, " ");
1678 k++;
1681 result = CreateProcess (NULL, (char *) full_command, &SA, NULL, TRUE,
1682 NORMAL_PRIORITY_CLASS, NULL, NULL, &SI, &PI);
1684 free (full_command);
1686 if (result == TRUE)
1688 add_handle (PI.hProcess);
1689 CloseHandle (PI.hThread);
1690 return (int) PI.hProcess;
1692 else
1693 return -1;
1696 static int
1697 win32_wait (int *status)
1699 DWORD exitcode;
1700 HANDLE *hl;
1701 HANDLE h;
1702 DWORD res;
1703 int k;
1704 Process_List *pl;
1706 if (plist_length == 0)
1708 errno = ECHILD;
1709 return -1;
1712 hl = (HANDLE *) xmalloc (sizeof (HANDLE) * plist_length);
1714 k = 0;
1715 plist_enter();
1717 /* -------------------- critical section -------------------- */
1718 pl = PLIST;
1719 while (pl)
1721 hl[k++] = pl->h;
1722 pl = pl->next;
1724 /* -------------------- critical section -------------------- */
1726 plist_leave();
1728 res = WaitForMultipleObjects (plist_length, hl, FALSE, INFINITE);
1729 h = hl[res - WAIT_OBJECT_0];
1730 free (hl);
1732 remove_handle (h);
1734 GetExitCodeProcess (h, &exitcode);
1735 CloseHandle (h);
1737 *status = (int) exitcode;
1738 return (int) h;
1741 #endif
1744 __gnat_portable_no_block_spawn (char *args[])
1746 int pid = 0;
1748 #if defined (__EMX__) || defined (MSDOS)
1750 /* ??? For PC machines I (Franco) don't know the system calls to implement
1751 this routine. So I'll fake it as follows. This routine will behave
1752 exactly like the blocking portable_spawn and will systematically return
1753 a pid of 0 unless the spawned task did not complete successfully, in
1754 which case we return a pid of -1. To synchronize with this the
1755 portable_wait below systematically returns a pid of 0 and reports that
1756 the subprocess terminated successfully. */
1758 if (spawnvp (P_WAIT, args[0], args) != 0)
1759 return -1;
1761 #elif defined (_WIN32)
1763 pid = win32_no_block_spawn (args[0], args);
1764 return pid;
1766 #elif defined (__vxworks)
1767 return -1;
1769 #else
1770 pid = fork ();
1772 if (pid == 0)
1774 /* The child. */
1775 if (execv (args[0], args) != 0)
1776 #if defined (VMS)
1777 return -1; /* execv is in parent context on VMS. */
1778 #else
1779 _exit (1);
1780 #endif
1783 #endif
1785 return pid;
1789 __gnat_portable_wait (int *process_status)
1791 int status = 0;
1792 int pid = 0;
1794 #if defined (_WIN32)
1796 pid = win32_wait (&status);
1798 #elif defined (__EMX__) || defined (MSDOS)
1799 /* ??? See corresponding comment in portable_no_block_spawn. */
1801 #elif defined (__vxworks)
1802 /* Not sure what to do here, so do same as __EMX__ case, i.e., nothing but
1803 return zero. */
1804 #else
1806 pid = waitpid (-1, &status, 0);
1807 status = status & 0xffff;
1808 #endif
1810 *process_status = status;
1811 return pid;
1815 __gnat_waitpid (int pid)
1817 int status = 0;
1819 #if defined (_WIN32)
1820 cwait (&status, pid, _WAIT_CHILD);
1821 #elif defined (__EMX__) || defined (MSDOS) || defined (__vxworks)
1822 /* Status is already zero, so nothing to do. */
1823 #else
1824 waitpid (pid, &status, 0);
1825 status = WEXITSTATUS (status);
1826 #endif
1828 return status;
1831 void
1832 __gnat_os_exit (int status)
1834 exit (status);
1837 /* Locate a regular file, give a Path value. */
1839 char *
1840 __gnat_locate_regular_file (char *file_name, char *path_val)
1842 char *ptr;
1843 int absolute = __gnat_is_absolute_path (file_name);
1845 /* Handle absolute pathnames. */
1846 if (absolute)
1848 if (__gnat_is_regular_file (file_name))
1849 return xstrdup (file_name);
1851 return 0;
1854 /* If file_name include directory separator(s), try it first as
1855 a path name relative to the current directory */
1856 for (ptr = file_name; *ptr && *ptr != '/' && *ptr != DIR_SEPARATOR; ptr++)
1859 if (*ptr != 0)
1861 if (__gnat_is_regular_file (file_name))
1862 return xstrdup (file_name);
1865 if (path_val == 0)
1866 return 0;
1869 /* The result has to be smaller than path_val + file_name. */
1870 char *file_path = alloca (strlen (path_val) + strlen (file_name) + 2);
1872 for (;;)
1874 for (; *path_val == PATH_SEPARATOR; path_val++)
1877 if (*path_val == 0)
1878 return 0;
1880 for (ptr = file_path; *path_val && *path_val != PATH_SEPARATOR; )
1881 *ptr++ = *path_val++;
1883 ptr--;
1884 if (*ptr != '/' && *ptr != DIR_SEPARATOR)
1885 *++ptr = DIR_SEPARATOR;
1887 strcpy (++ptr, file_name);
1889 if (__gnat_is_regular_file (file_path))
1890 return xstrdup (file_path);
1894 return 0;
1897 /* Locate an executable given a Path argument. This routine is only used by
1898 gnatbl and should not be used otherwise. Use locate_exec_on_path
1899 instead. */
1901 char *
1902 __gnat_locate_exec (char *exec_name, char *path_val)
1904 if (!strstr (exec_name, HOST_EXECUTABLE_SUFFIX))
1906 char *full_exec_name
1907 = alloca (strlen (exec_name) + strlen (HOST_EXECUTABLE_SUFFIX) + 1);
1909 strcpy (full_exec_name, exec_name);
1910 strcat (full_exec_name, HOST_EXECUTABLE_SUFFIX);
1911 return __gnat_locate_regular_file (full_exec_name, path_val);
1913 else
1914 return __gnat_locate_regular_file (exec_name, path_val);
1917 /* Locate an executable using the Systems default PATH. */
1919 char *
1920 __gnat_locate_exec_on_path (char *exec_name)
1922 char *apath_val;
1923 #ifdef VMS
1924 char *path_val = "/VAXC$PATH";
1925 #else
1926 char *path_val = getenv ("PATH");
1927 #endif
1928 #ifdef _WIN32
1929 /* In Win32 systems we expand the PATH as for XP environment
1930 variables are not automatically expanded. */
1931 int len = strlen (path_val) * 3;
1932 char *expanded_path_val = alloca (len + 1);
1934 DWORD res = ExpandEnvironmentStrings (path_val, expanded_path_val, len);
1936 if (res != 0)
1938 path_val = expanded_path_val;
1940 #endif
1942 apath_val = alloca (strlen (path_val) + 1);
1943 strcpy (apath_val, path_val);
1945 return __gnat_locate_exec (exec_name, apath_val);
1948 #ifdef VMS
1950 /* These functions are used to translate to and from VMS and Unix syntax
1951 file, directory and path specifications. */
1953 #define MAXPATH 256
1954 #define MAXNAMES 256
1955 #define NEW_CANONICAL_FILELIST_INCREMENT 64
1957 static char new_canonical_dirspec [MAXPATH];
1958 static char new_canonical_filespec [MAXPATH];
1959 static char new_canonical_pathspec [MAXNAMES*MAXPATH];
1960 static unsigned new_canonical_filelist_index;
1961 static unsigned new_canonical_filelist_in_use;
1962 static unsigned new_canonical_filelist_allocated;
1963 static char **new_canonical_filelist;
1964 static char new_host_pathspec [MAXNAMES*MAXPATH];
1965 static char new_host_dirspec [MAXPATH];
1966 static char new_host_filespec [MAXPATH];
1968 /* Routine is called repeatedly by decc$from_vms via
1969 __gnat_to_canonical_file_list_init until it returns 0 or the expansion
1970 runs out. */
1972 static int
1973 wildcard_translate_unix (char *name)
1975 char *ver;
1976 char buff [MAXPATH];
1978 strncpy (buff, name, MAXPATH);
1979 buff [MAXPATH - 1] = (char) 0;
1980 ver = strrchr (buff, '.');
1982 /* Chop off the version. */
1983 if (ver)
1984 *ver = 0;
1986 /* Dynamically extend the allocation by the increment. */
1987 if (new_canonical_filelist_in_use == new_canonical_filelist_allocated)
1989 new_canonical_filelist_allocated += NEW_CANONICAL_FILELIST_INCREMENT;
1990 new_canonical_filelist = (char **) xrealloc
1991 (new_canonical_filelist,
1992 new_canonical_filelist_allocated * sizeof (char *));
1995 new_canonical_filelist[new_canonical_filelist_in_use++] = xstrdup (buff);
1997 return 1;
2000 /* Translate a wildcard VMS file spec into a list of Unix file specs. First do
2001 full translation and copy the results into a list (_init), then return them
2002 one at a time (_next). If onlydirs set, only expand directory files. */
2005 __gnat_to_canonical_file_list_init (char *filespec, int onlydirs)
2007 int len;
2008 char buff [MAXPATH];
2010 len = strlen (filespec);
2011 strncpy (buff, filespec, MAXPATH);
2013 /* Only look for directories */
2014 if (onlydirs && !strstr (&buff [len-5], "*.dir"))
2015 strncat (buff, "*.dir", MAXPATH);
2017 buff [MAXPATH - 1] = (char) 0;
2019 decc$from_vms (buff, wildcard_translate_unix, 1);
2021 /* Remove the .dir extension. */
2022 if (onlydirs)
2024 int i;
2025 char *ext;
2027 for (i = 0; i < new_canonical_filelist_in_use; i++)
2029 ext = strstr (new_canonical_filelist[i], ".dir");
2030 if (ext)
2031 *ext = 0;
2035 return new_canonical_filelist_in_use;
2038 /* Return the next filespec in the list. */
2040 char *
2041 __gnat_to_canonical_file_list_next ()
2043 return new_canonical_filelist[new_canonical_filelist_index++];
2046 /* Free storage used in the wildcard expansion. */
2048 void
2049 __gnat_to_canonical_file_list_free ()
2051 int i;
2053 for (i = 0; i < new_canonical_filelist_in_use; i++)
2054 free (new_canonical_filelist[i]);
2056 free (new_canonical_filelist);
2058 new_canonical_filelist_in_use = 0;
2059 new_canonical_filelist_allocated = 0;
2060 new_canonical_filelist_index = 0;
2061 new_canonical_filelist = 0;
2064 /* Translate a VMS syntax directory specification in to Unix syntax. If
2065 PREFIXFLAG is set, append an underscore "/". If no indicators of VMS syntax
2066 found, return input string. Also translate a dirname that contains no
2067 slashes, in case it's a logical name. */
2069 char *
2070 __gnat_to_canonical_dir_spec (char *dirspec, int prefixflag)
2072 int len;
2074 strcpy (new_canonical_dirspec, "");
2075 if (strlen (dirspec))
2077 char *dirspec1;
2079 if (strchr (dirspec, ']') || strchr (dirspec, ':'))
2081 strncpy (new_canonical_dirspec,
2082 (char *) decc$translate_vms (dirspec),
2083 MAXPATH);
2085 else if (!strchr (dirspec, '/') && (dirspec1 = getenv (dirspec)) != 0)
2087 strncpy (new_canonical_dirspec,
2088 (char *) decc$translate_vms (dirspec1),
2089 MAXPATH);
2091 else
2093 strncpy (new_canonical_dirspec, dirspec, MAXPATH);
2097 len = strlen (new_canonical_dirspec);
2098 if (prefixflag && new_canonical_dirspec [len-1] != '/')
2099 strncat (new_canonical_dirspec, "/", MAXPATH);
2101 new_canonical_dirspec [MAXPATH - 1] = (char) 0;
2103 return new_canonical_dirspec;
2107 /* Translate a VMS syntax file specification into Unix syntax.
2108 If no indicators of VMS syntax found, return input string. */
2110 char *
2111 __gnat_to_canonical_file_spec (char *filespec)
2113 strncpy (new_canonical_filespec, "", MAXPATH);
2115 if (strchr (filespec, ']') || strchr (filespec, ':'))
2117 strncpy (new_canonical_filespec,
2118 (char *) decc$translate_vms (filespec),
2119 MAXPATH);
2121 else
2123 strncpy (new_canonical_filespec, filespec, MAXPATH);
2126 new_canonical_filespec [MAXPATH - 1] = (char) 0;
2128 return new_canonical_filespec;
2131 /* Translate a VMS syntax path specification into Unix syntax.
2132 If no indicators of VMS syntax found, return input string. */
2134 char *
2135 __gnat_to_canonical_path_spec (char *pathspec)
2137 char *curr, *next, buff [MAXPATH];
2139 if (pathspec == 0)
2140 return pathspec;
2142 /* If there are /'s, assume it's a Unix path spec and return. */
2143 if (strchr (pathspec, '/'))
2144 return pathspec;
2146 new_canonical_pathspec[0] = 0;
2147 curr = pathspec;
2149 for (;;)
2151 next = strchr (curr, ',');
2152 if (next == 0)
2153 next = strchr (curr, 0);
2155 strncpy (buff, curr, next - curr);
2156 buff[next - curr] = 0;
2158 /* Check for wildcards and expand if present. */
2159 if (strchr (buff, '*') || strchr (buff, '%') || strstr (buff, "..."))
2161 int i, dirs;
2163 dirs = __gnat_to_canonical_file_list_init (buff, 1);
2164 for (i = 0; i < dirs; i++)
2166 char *next_dir;
2168 next_dir = __gnat_to_canonical_file_list_next ();
2169 strncat (new_canonical_pathspec, next_dir, MAXPATH);
2171 /* Don't append the separator after the last expansion. */
2172 if (i+1 < dirs)
2173 strncat (new_canonical_pathspec, ":", MAXPATH);
2176 __gnat_to_canonical_file_list_free ();
2178 else
2179 strncat (new_canonical_pathspec,
2180 __gnat_to_canonical_dir_spec (buff, 0), MAXPATH);
2182 if (*next == 0)
2183 break;
2185 strncat (new_canonical_pathspec, ":", MAXPATH);
2186 curr = next + 1;
2189 new_canonical_pathspec [MAXPATH - 1] = (char) 0;
2191 return new_canonical_pathspec;
2194 static char filename_buff [MAXPATH];
2196 static int
2197 translate_unix (char *name, int type)
2199 strncpy (filename_buff, name, MAXPATH);
2200 filename_buff [MAXPATH - 1] = (char) 0;
2201 return 0;
2204 /* Translate a Unix syntax path spec into a VMS style (comma separated list of
2205 directories. */
2207 static char *
2208 to_host_path_spec (char *pathspec)
2210 char *curr, *next, buff [MAXPATH];
2212 if (pathspec == 0)
2213 return pathspec;
2215 /* Can't very well test for colons, since that's the Unix separator! */
2216 if (strchr (pathspec, ']') || strchr (pathspec, ','))
2217 return pathspec;
2219 new_host_pathspec[0] = 0;
2220 curr = pathspec;
2222 for (;;)
2224 next = strchr (curr, ':');
2225 if (next == 0)
2226 next = strchr (curr, 0);
2228 strncpy (buff, curr, next - curr);
2229 buff[next - curr] = 0;
2231 strncat (new_host_pathspec, __gnat_to_host_dir_spec (buff, 0), MAXPATH);
2232 if (*next == 0)
2233 break;
2234 strncat (new_host_pathspec, ",", MAXPATH);
2235 curr = next + 1;
2238 new_host_pathspec [MAXPATH - 1] = (char) 0;
2240 return new_host_pathspec;
2243 /* Translate a Unix syntax directory specification into VMS syntax. The
2244 PREFIXFLAG has no effect, but is kept for symmetry with
2245 to_canonical_dir_spec. If indicators of VMS syntax found, return input
2246 string. */
2248 char *
2249 __gnat_to_host_dir_spec (char *dirspec, int prefixflag ATTRIBUTE_UNUSED)
2251 int len = strlen (dirspec);
2253 strncpy (new_host_dirspec, dirspec, MAXPATH);
2254 new_host_dirspec [MAXPATH - 1] = (char) 0;
2256 if (strchr (new_host_dirspec, ']') || strchr (new_host_dirspec, ':'))
2257 return new_host_dirspec;
2259 while (len > 1 && new_host_dirspec[len - 1] == '/')
2261 new_host_dirspec[len - 1] = 0;
2262 len--;
2265 decc$to_vms (new_host_dirspec, translate_unix, 1, 2);
2266 strncpy (new_host_dirspec, filename_buff, MAXPATH);
2267 new_host_dirspec [MAXPATH - 1] = (char) 0;
2269 return new_host_dirspec;
2272 /* Translate a Unix syntax file specification into VMS syntax.
2273 If indicators of VMS syntax found, return input string. */
2275 char *
2276 __gnat_to_host_file_spec (char *filespec)
2278 strncpy (new_host_filespec, "", MAXPATH);
2279 if (strchr (filespec, ']') || strchr (filespec, ':'))
2281 strncpy (new_host_filespec, filespec, MAXPATH);
2283 else
2285 decc$to_vms (filespec, translate_unix, 1, 1);
2286 strncpy (new_host_filespec, filename_buff, MAXPATH);
2289 new_host_filespec [MAXPATH - 1] = (char) 0;
2291 return new_host_filespec;
2294 void
2295 __gnat_adjust_os_resource_limits ()
2297 SYS$ADJWSL (131072, 0);
2300 #else /* VMS */
2302 /* Dummy functions for Osint import for non-VMS systems. */
2305 __gnat_to_canonical_file_list_init
2306 (char *dirspec ATTRIBUTE_UNUSED, int onlydirs ATTRIBUTE_UNUSED)
2308 return 0;
2311 char *
2312 __gnat_to_canonical_file_list_next (void)
2314 return (char *) "";
2317 void
2318 __gnat_to_canonical_file_list_free (void)
2322 char *
2323 __gnat_to_canonical_dir_spec (char *dirspec, int prefixflag ATTRIBUTE_UNUSED)
2325 return dirspec;
2328 char *
2329 __gnat_to_canonical_file_spec (char *filespec)
2331 return filespec;
2334 char *
2335 __gnat_to_canonical_path_spec (char *pathspec)
2337 return pathspec;
2340 char *
2341 __gnat_to_host_dir_spec (char *dirspec, int prefixflag ATTRIBUTE_UNUSED)
2343 return dirspec;
2346 char *
2347 __gnat_to_host_file_spec (char *filespec)
2349 return filespec;
2352 void
2353 __gnat_adjust_os_resource_limits (void)
2357 #endif
2359 /* For EMX, we cannot include dummy in libgcc, since it is too difficult
2360 to coordinate this with the EMX distribution. Consequently, we put the
2361 definition of dummy which is used for exception handling, here. */
2363 #if defined (__EMX__)
2364 void __dummy () {}
2365 #endif
2367 #if defined (__mips_vxworks)
2369 _flush_cache()
2371 CACHE_USER_FLUSH (0, ENTIRE_CACHE);
2373 #endif
2375 #if defined (CROSS_COMPILE) \
2376 || (! (defined (sparc) && defined (sun) && defined (__SVR4)) \
2377 && ! (defined (linux) && defined (i386)) \
2378 && ! defined (hpux) \
2379 && ! defined (_AIX) \
2380 && ! (defined (__alpha__) && defined (__osf__)) \
2381 && ! defined (__MINGW32__))
2383 /* Dummy function to satisfy g-trasym.o. Currently Solaris sparc, HP/UX,
2384 GNU/Linux x86, Tru64 & Windows provide a non-dummy version of this
2385 procedure in libaddr2line.a. */
2387 void
2388 convert_addresses (void *addrs ATTRIBUTE_UNUSED,
2389 int n_addr ATTRIBUTE_UNUSED,
2390 void *buf ATTRIBUTE_UNUSED,
2391 int *len ATTRIBUTE_UNUSED)
2393 *len = 0;
2395 #endif
2397 #if defined (_WIN32)
2398 int __gnat_argument_needs_quote = 1;
2399 #else
2400 int __gnat_argument_needs_quote = 0;
2401 #endif
2403 /* This option is used to enable/disable object files handling from the
2404 binder file by the GNAT Project module. For example, this is disabled on
2405 Windows as it is already done by the mdll module. */
2406 #if defined (_WIN32)
2407 int __gnat_prj_add_obj_files = 0;
2408 #else
2409 int __gnat_prj_add_obj_files = 1;
2410 #endif
2412 /* char used as prefix/suffix for environment variables */
2413 #if defined (_WIN32)
2414 char __gnat_environment_char = '%';
2415 #else
2416 char __gnat_environment_char = '$';
2417 #endif
2419 /* This functions copy the file attributes from a source file to a
2420 destination file.
2422 mode = 0 : In this mode copy only the file time stamps (last access and
2423 last modification time stamps).
2425 mode = 1 : In this mode, time stamps and read/write/execute attributes are
2426 copied.
2428 Returns 0 if operation was successful and -1 in case of error. */
2431 __gnat_copy_attribs (char *from, char *to, int mode)
2433 #if defined (VMS) || defined (__vxworks)
2434 return -1;
2435 #else
2436 struct stat fbuf;
2437 struct utimbuf tbuf;
2439 if (stat (from, &fbuf) == -1)
2441 return -1;
2444 tbuf.actime = fbuf.st_atime;
2445 tbuf.modtime = fbuf.st_mtime;
2447 if (utime (to, &tbuf) == -1)
2449 return -1;
2452 if (mode == 1)
2454 if (chmod (to, fbuf.st_mode) == -1)
2456 return -1;
2460 return 0;
2461 #endif
2464 /* This function is installed in libgcc.a. */
2465 extern void __gnat_install_locks (void (*) (void), void (*) (void));
2467 /* This function offers a hook for libgnarl to set the
2468 locking subprograms for libgcc_eh.
2469 This is only needed on OpenVMS, since other platforms use standard
2470 --enable-threads=posix option, or similar. */
2472 void
2473 __gnatlib_install_locks (void (*lock) (void) ATTRIBUTE_UNUSED,
2474 void (*unlock) (void) ATTRIBUTE_UNUSED)
2476 #if defined (IN_RTS) && defined (VMS)
2477 __gnat_install_locks (lock, unlock);
2478 /* There is a bootstrap path issue if adaint is build with this
2479 symbol unresolved for the stage1 compiler. Since the compiler
2480 does not use tasking, we simply make __gnatlib_install_locks
2481 a no-op in this case. */
2482 #endif
2486 __gnat_lseek (int fd, long offset, int whence)
2488 return (int) lseek (fd, offset, whence);