2004-12-07 Eric Christopher <echristo@redhat.com>
[official-gcc.git] / gcc / ada / adaint.c
blob8ed3b40fe188a52eeef69b9b684c5e56926b65a1
1 /****************************************************************************
2 * *
3 * GNAT COMPILER COMPONENTS *
4 * *
5 * A D A I N T *
6 * *
7 * C Implementation File *
8 * *
9 * Copyright (C) 1992-2004, 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 #undef DIR_SEPARATOR
151 #define DIR_SEPARATOR '\\'
152 #endif
154 #include "adaint.h"
156 /* Define symbols O_BINARY and O_TEXT as harmless zeroes if they are not
157 defined in the current system. On DOS-like systems these flags control
158 whether the file is opened/created in text-translation mode (CR/LF in
159 external file mapped to LF in internal file), but in Unix-like systems,
160 no text translation is required, so these flags have no effect. */
162 #if defined (__EMX__)
163 #include <os2.h>
164 #endif
166 #if defined (MSDOS)
167 #include <dos.h>
168 #endif
170 #ifndef O_BINARY
171 #define O_BINARY 0
172 #endif
174 #ifndef O_TEXT
175 #define O_TEXT 0
176 #endif
178 #ifndef HOST_EXECUTABLE_SUFFIX
179 #define HOST_EXECUTABLE_SUFFIX ""
180 #endif
182 #ifndef HOST_OBJECT_SUFFIX
183 #define HOST_OBJECT_SUFFIX ".o"
184 #endif
186 #ifndef PATH_SEPARATOR
187 #define PATH_SEPARATOR ':'
188 #endif
190 #ifndef DIR_SEPARATOR
191 #define DIR_SEPARATOR '/'
192 #endif
194 char __gnat_dir_separator = DIR_SEPARATOR;
196 char __gnat_path_separator = PATH_SEPARATOR;
198 /* The GNAT_LIBRARY_TEMPLATE contains a list of expressions that define
199 the base filenames that libraries specified with -lsomelib options
200 may have. This is used by GNATMAKE to check whether an executable
201 is up-to-date or not. The syntax is
203 library_template ::= { pattern ; } pattern NUL
204 pattern ::= [ prefix ] * [ postfix ]
206 These should only specify names of static libraries as it makes
207 no sense to determine at link time if dynamic-link libraries are
208 up to date or not. Any libraries that are not found are supposed
209 to be up-to-date:
211 * if they are needed but not present, the link
212 will fail,
214 * otherwise they are libraries in the system paths and so
215 they are considered part of the system and not checked
216 for that reason.
218 ??? This should be part of a GNAT host-specific compiler
219 file instead of being included in all user applications
220 as well. This is only a temporary work-around for 3.11b. */
222 #ifndef GNAT_LIBRARY_TEMPLATE
223 #if defined (__EMX__)
224 #define GNAT_LIBRARY_TEMPLATE "*.a"
225 #elif defined (VMS)
226 #define GNAT_LIBRARY_TEMPLATE "*.olb"
227 #else
228 #define GNAT_LIBRARY_TEMPLATE "lib*.a"
229 #endif
230 #endif
232 const char *__gnat_library_template = GNAT_LIBRARY_TEMPLATE;
234 /* This variable is used in hostparm.ads to say whether the host is a VMS
235 system. */
236 #ifdef VMS
237 const int __gnat_vmsp = 1;
238 #else
239 const int __gnat_vmsp = 0;
240 #endif
242 #ifdef __EMX__
243 #define GNAT_MAX_PATH_LEN MAX_PATH
245 #elif defined (VMS)
246 #define GNAT_MAX_PATH_LEN 256 /* PATH_MAX */
248 #elif defined (__vxworks) || defined (__OPENNT)
249 #define GNAT_MAX_PATH_LEN PATH_MAX
251 #else
253 #if defined (__MINGW32__)
254 #include "mingw32.h"
256 #if OLD_MINGW
257 #include <sys/param.h>
258 #endif
260 #else
261 #include <sys/param.h>
262 #endif
264 #define GNAT_MAX_PATH_LEN MAXPATHLEN
266 #endif
268 /* The __gnat_max_path_len variable is used to export the maximum
269 length of a path name to Ada code. max_path_len is also provided
270 for compatibility with older GNAT versions, please do not use
271 it. */
273 int __gnat_max_path_len = GNAT_MAX_PATH_LEN;
274 int max_path_len = GNAT_MAX_PATH_LEN;
276 /* The following macro HAVE_READDIR_R should be defined if the
277 system provides the routine readdir_r. */
278 #undef HAVE_READDIR_R
280 void
281 __gnat_to_gm_time
282 (OS_Time *p_time,
283 int *p_year,
284 int *p_month,
285 int *p_day,
286 int *p_hours,
287 int *p_mins,
288 int *p_secs)
290 struct tm *res;
291 time_t time = (time_t) *p_time;
293 #ifdef _WIN32
294 /* On Windows systems, the time is sometimes rounded up to the nearest
295 even second, so if the number of seconds is odd, increment it. */
296 if (time & 1)
297 time++;
298 #endif
300 #ifdef VMS
301 res = localtime (&time);
302 #else
303 res = gmtime (&time);
304 #endif
306 if (res)
308 *p_year = res->tm_year;
309 *p_month = res->tm_mon;
310 *p_day = res->tm_mday;
311 *p_hours = res->tm_hour;
312 *p_mins = res->tm_min;
313 *p_secs = res->tm_sec;
315 else
316 *p_year = *p_month = *p_day = *p_hours = *p_mins = *p_secs = 0;
319 /* Place the contents of the symbolic link named PATH in the buffer BUF,
320 which has size BUFSIZ. If PATH is a symbolic link, then return the number
321 of characters of its content in BUF. Otherwise, return -1. For Windows,
322 OS/2 and vxworks, always return -1. */
325 __gnat_readlink (char *path ATTRIBUTE_UNUSED,
326 char *buf ATTRIBUTE_UNUSED,
327 size_t bufsiz ATTRIBUTE_UNUSED)
329 #if defined (MSDOS) || defined (_WIN32) || defined (__EMX__)
330 return -1;
331 #elif defined (__INTERIX) || defined (VMS)
332 return -1;
333 #elif defined (__vxworks)
334 return -1;
335 #else
336 return readlink (path, buf, bufsiz);
337 #endif
340 /* Creates a symbolic link named NEWPATH which contains the string OLDPATH. If
341 NEWPATH exists it will NOT be overwritten. For Windows, OS/2, VxWorks,
342 Interix and VMS, always return -1. */
345 __gnat_symlink (char *oldpath ATTRIBUTE_UNUSED,
346 char *newpath ATTRIBUTE_UNUSED)
348 #if defined (MSDOS) || defined (_WIN32) || defined (__EMX__)
349 return -1;
350 #elif defined (__INTERIX) || defined (VMS)
351 return -1;
352 #elif defined (__vxworks)
353 return -1;
354 #else
355 return symlink (oldpath, newpath);
356 #endif
359 /* Try to lock a file, return 1 if success. */
361 #if defined (__vxworks) || defined (MSDOS) || defined (_WIN32)
363 /* Version that does not use link. */
366 __gnat_try_lock (char *dir, char *file)
368 char full_path[256];
369 int fd;
371 sprintf (full_path, "%s%c%s", dir, DIR_SEPARATOR, file);
372 fd = open (full_path, O_CREAT | O_EXCL, 0600);
373 if (fd < 0)
374 return 0;
376 close (fd);
377 return 1;
380 #elif defined (__EMX__) || defined (VMS)
382 /* More cases that do not use link; identical code, to solve too long
383 line problem ??? */
386 __gnat_try_lock (char *dir, char *file)
388 char full_path[256];
389 int fd;
391 sprintf (full_path, "%s%c%s", dir, DIR_SEPARATOR, file);
392 fd = open (full_path, O_CREAT | O_EXCL, 0600);
393 if (fd < 0)
394 return 0;
396 close (fd);
397 return 1;
400 #else
402 /* Version using link(), more secure over NFS. */
403 /* See TN 6913-016 for discussion ??? */
406 __gnat_try_lock (char *dir, char *file)
408 char full_path[256];
409 char temp_file[256];
410 struct stat stat_result;
411 int fd;
413 sprintf (full_path, "%s%c%s", dir, DIR_SEPARATOR, file);
414 sprintf (temp_file, "%s%cTMP-%ld-%ld",
415 dir, DIR_SEPARATOR, (long)getpid(), (long)getppid ());
417 /* Create the temporary file and write the process number. */
418 fd = open (temp_file, O_CREAT | O_WRONLY, 0600);
419 if (fd < 0)
420 return 0;
422 close (fd);
424 /* Link it with the new file. */
425 link (temp_file, full_path);
427 /* Count the references on the old one. If we have a count of two, then
428 the link did succeed. Remove the temporary file before returning. */
429 __gnat_stat (temp_file, &stat_result);
430 unlink (temp_file);
431 return stat_result.st_nlink == 2;
433 #endif
435 /* Return the maximum file name length. */
438 __gnat_get_maximum_file_name_length (void)
440 #if defined (MSDOS)
441 return 8;
442 #elif defined (VMS)
443 if (getenv ("GNAT$EXTENDED_FILE_SPECIFICATIONS"))
444 return -1;
445 else
446 return 39;
447 #else
448 return -1;
449 #endif
452 /* Return nonzero if file names are case sensitive. */
455 __gnat_get_file_names_case_sensitive (void)
457 #if defined (__EMX__) || defined (MSDOS) || defined (VMS) || defined (WINNT)
458 return 0;
459 #else
460 return 1;
461 #endif
464 char
465 __gnat_get_default_identifier_character_set (void)
467 #if defined (__EMX__) || defined (MSDOS)
468 return 'p';
469 #else
470 return '1';
471 #endif
474 /* Return the current working directory. */
476 void
477 __gnat_get_current_dir (char *dir, int *length)
479 #ifdef VMS
480 /* Force Unix style, which is what GNAT uses internally. */
481 getcwd (dir, *length, 0);
482 #else
483 getcwd (dir, *length);
484 #endif
486 *length = strlen (dir);
488 if (dir [*length - 1] != DIR_SEPARATOR)
490 dir [*length] = DIR_SEPARATOR;
491 ++(*length);
493 dir[*length] = '\0';
496 /* Return the suffix for object files. */
498 void
499 __gnat_get_object_suffix_ptr (int *len, const char **value)
501 *value = HOST_OBJECT_SUFFIX;
503 if (*value == 0)
504 *len = 0;
505 else
506 *len = strlen (*value);
508 return;
511 /* Return the suffix for executable files. */
513 void
514 __gnat_get_executable_suffix_ptr (int *len, const char **value)
516 *value = HOST_EXECUTABLE_SUFFIX;
517 if (!*value)
518 *len = 0;
519 else
520 *len = strlen (*value);
522 return;
525 /* Return the suffix for debuggable files. Usually this is the same as the
526 executable extension. */
528 void
529 __gnat_get_debuggable_suffix_ptr (int *len, const char **value)
531 #ifndef MSDOS
532 *value = HOST_EXECUTABLE_SUFFIX;
533 #else
534 /* On DOS, the extensionless COFF file is what gdb likes. */
535 *value = "";
536 #endif
538 if (*value == 0)
539 *len = 0;
540 else
541 *len = strlen (*value);
543 return;
547 __gnat_open_read (char *path, int fmode)
549 int fd;
550 int o_fmode = O_BINARY;
552 if (fmode)
553 o_fmode = O_TEXT;
555 #if defined (VMS)
556 /* Optional arguments mbc,deq,fop increase read performance. */
557 fd = open (path, O_RDONLY | o_fmode, 0444,
558 "mbc=16", "deq=64", "fop=tef");
559 #elif defined (__vxworks)
560 fd = open (path, O_RDONLY | o_fmode, 0444);
561 #else
562 fd = open (path, O_RDONLY | o_fmode);
563 #endif
565 return fd < 0 ? -1 : fd;
568 #if defined (__EMX__) || defined (__MINGW32__)
569 #define PERM (S_IREAD | S_IWRITE)
570 #elif defined (VMS)
571 /* Excerpt from DECC C RTL Reference Manual:
572 To create files with OpenVMS RMS default protections using the UNIX
573 system-call functions umask, mkdir, creat, and open, call mkdir, creat,
574 and open with a file-protection mode argument of 0777 in a program
575 that never specifically calls umask. These default protections include
576 correctly establishing protections based on ACLs, previous versions of
577 files, and so on. */
578 #define PERM 0777
579 #else
580 #define PERM (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH)
581 #endif
584 __gnat_open_rw (char *path, int fmode)
586 int fd;
587 int o_fmode = O_BINARY;
589 if (fmode)
590 o_fmode = O_TEXT;
592 #if defined (VMS)
593 fd = open (path, O_RDWR | o_fmode, PERM,
594 "mbc=16", "deq=64", "fop=tef");
595 #else
596 fd = open (path, O_RDWR | o_fmode, PERM);
597 #endif
599 return fd < 0 ? -1 : fd;
603 __gnat_open_create (char *path, int fmode)
605 int fd;
606 int o_fmode = O_BINARY;
608 if (fmode)
609 o_fmode = O_TEXT;
611 #if defined (VMS)
612 fd = open (path, O_WRONLY | O_CREAT | O_TRUNC | o_fmode, PERM,
613 "mbc=16", "deq=64", "fop=tef");
614 #else
615 fd = open (path, O_WRONLY | O_CREAT | O_TRUNC | o_fmode, PERM);
616 #endif
618 return fd < 0 ? -1 : fd;
622 __gnat_create_output_file (char *path)
624 int fd;
625 #if defined (VMS)
626 fd = open (path, O_WRONLY | O_CREAT | O_TRUNC | O_TEXT, PERM,
627 "rfm=stmlf", "ctx=rec", "rat=none", "rop=nlk",
628 "shr=del,get,put,upd");
629 #else
630 fd = open (path, O_WRONLY | O_CREAT | O_TRUNC | O_TEXT, PERM);
631 #endif
633 return fd < 0 ? -1 : fd;
637 __gnat_open_append (char *path, int fmode)
639 int fd;
640 int o_fmode = O_BINARY;
642 if (fmode)
643 o_fmode = O_TEXT;
645 #if defined (VMS)
646 fd = open (path, O_WRONLY | O_CREAT | O_APPEND | o_fmode, PERM,
647 "mbc=16", "deq=64", "fop=tef");
648 #else
649 fd = open (path, O_WRONLY | O_CREAT | O_APPEND | o_fmode, PERM);
650 #endif
652 return fd < 0 ? -1 : fd;
655 /* Open a new file. Return error (-1) if the file already exists. */
658 __gnat_open_new (char *path, int fmode)
660 int fd;
661 int o_fmode = O_BINARY;
663 if (fmode)
664 o_fmode = O_TEXT;
666 #if defined (VMS)
667 fd = open (path, O_WRONLY | O_CREAT | O_EXCL | o_fmode, PERM,
668 "mbc=16", "deq=64", "fop=tef");
669 #else
670 fd = open (path, O_WRONLY | O_CREAT | O_EXCL | o_fmode, PERM);
671 #endif
673 return fd < 0 ? -1 : fd;
676 /* Open a new temp file. Return error (-1) if the file already exists.
677 Special options for VMS allow the file to be shared between parent and child
678 processes, however they really slow down output. Used in gnatchop. */
681 __gnat_open_new_temp (char *path, int fmode)
683 int fd;
684 int o_fmode = O_BINARY;
686 strcpy (path, "GNAT-XXXXXX");
688 #if (defined (__FreeBSD__) || defined (linux)) && !defined (__vxworks)
689 return mkstemp (path);
690 #elif defined (__Lynx__)
691 mktemp (path);
692 #else
693 if (mktemp (path) == NULL)
694 return -1;
695 #endif
697 if (fmode)
698 o_fmode = O_TEXT;
700 #if defined (VMS)
701 fd = open (path, O_WRONLY | O_CREAT | O_EXCL | o_fmode, PERM,
702 "rfm=stmlf", "ctx=rec", "rat=none", "shr=del,get,put,upd",
703 "mbc=16", "deq=64", "fop=tef");
704 #else
705 fd = open (path, O_WRONLY | O_CREAT | O_EXCL | o_fmode, PERM);
706 #endif
708 return fd < 0 ? -1 : fd;
711 /* Return the number of bytes in the specified file. */
713 long
714 __gnat_file_length (int fd)
716 int ret;
717 struct stat statbuf;
719 ret = fstat (fd, &statbuf);
720 if (ret || !S_ISREG (statbuf.st_mode))
721 return 0;
723 return (statbuf.st_size);
726 /* Return the number of bytes in the specified named file. */
728 long
729 __gnat_named_file_length (char *name)
731 int ret;
732 struct stat statbuf;
734 ret = __gnat_stat (name, &statbuf);
735 if (ret || !S_ISREG (statbuf.st_mode))
736 return 0;
738 return (statbuf.st_size);
741 /* Create a temporary filename and put it in string pointed to by
742 TMP_FILENAME. */
744 void
745 __gnat_tmp_name (char *tmp_filename)
747 #ifdef __MINGW32__
749 char *pname;
751 /* tempnam tries to create a temporary file in directory pointed to by
752 TMP environment variable, in c:\temp if TMP is not set, and in
753 directory specified by P_tmpdir in stdio.h if c:\temp does not
754 exist. The filename will be created with the prefix "gnat-". */
756 pname = (char *) tempnam ("c:\\temp", "gnat-");
758 /* if pname is NULL, the file was not created properly, the disk is full
759 or there is no more free temporary files */
761 if (pname == NULL)
762 *tmp_filename = '\0';
764 /* If pname start with a back slash and not path information it means that
765 the filename is valid for the current working directory. */
767 else if (pname[0] == '\\')
769 strcpy (tmp_filename, ".\\");
770 strcat (tmp_filename, pname+1);
772 else
773 strcpy (tmp_filename, pname);
775 free (pname);
778 #elif defined (linux) || defined (__FreeBSD__)
779 #define MAX_SAFE_PATH 1000
780 char *tmpdir = getenv ("TMPDIR");
782 /* If tmpdir is longer than MAX_SAFE_PATH, revert to default value to avoid
783 a buffer overflow. */
784 if (tmpdir == NULL || strlen (tmpdir) > MAX_SAFE_PATH)
785 strcpy (tmp_filename, "/tmp/gnat-XXXXXX");
786 else
787 sprintf (tmp_filename, "%s/gnat-XXXXXX", tmpdir);
789 close (mkstemp(tmp_filename));
790 #else
791 tmpnam (tmp_filename);
792 #endif
795 /* Read the next entry in a directory. The returned string points somewhere
796 in the buffer. */
798 char *
799 __gnat_readdir (DIR *dirp, char *buffer)
801 /* If possible, try to use the thread-safe version. */
802 #ifdef HAVE_READDIR_R
803 if (readdir_r (dirp, buffer) != NULL)
804 return ((struct dirent*) buffer)->d_name;
805 else
806 return NULL;
808 #else
809 struct dirent *dirent = (struct dirent *) readdir (dirp);
811 if (dirent != NULL)
813 strcpy (buffer, dirent->d_name);
814 return buffer;
816 else
817 return NULL;
819 #endif
822 /* Returns 1 if readdir is thread safe, 0 otherwise. */
825 __gnat_readdir_is_thread_safe (void)
827 #ifdef HAVE_READDIR_R
828 return 1;
829 #else
830 return 0;
831 #endif
834 #ifdef _WIN32
835 /* Number of seconds between <Jan 1st 1601> and <Jan 1st 1970>. */
836 static const unsigned long long w32_epoch_offset = 11644473600ULL;
838 /* Returns the file modification timestamp using Win32 routines which are
839 immune against daylight saving time change. It is in fact not possible to
840 use fstat for this purpose as the DST modify the st_mtime field of the
841 stat structure. */
843 static time_t
844 win32_filetime (HANDLE h)
846 union
848 FILETIME ft_time;
849 unsigned long long ull_time;
850 } t_write;
852 /* GetFileTime returns FILETIME data which are the number of 100 nanosecs
853 since <Jan 1st 1601>. This function must return the number of seconds
854 since <Jan 1st 1970>. */
856 if (GetFileTime (h, NULL, NULL, &t_write.ft_time))
857 return (time_t) (t_write.ull_time / 10000000ULL
858 - w32_epoch_offset);
859 return (time_t) 0;
861 #endif
863 /* Return a GNAT time stamp given a file name. */
865 OS_Time
866 __gnat_file_time_name (char *name)
869 #if defined (__EMX__) || defined (MSDOS)
870 int fd = open (name, O_RDONLY | O_BINARY);
871 time_t ret = __gnat_file_time_fd (fd);
872 close (fd);
873 return (OS_Time)ret;
875 #elif defined (_WIN32)
876 time_t ret = 0;
877 HANDLE h = CreateFile (name, GENERIC_READ, FILE_SHARE_READ, 0,
878 OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0);
880 if (h != INVALID_HANDLE_VALUE)
882 ret = win32_filetime (h);
883 CloseHandle (h);
885 return (OS_Time) ret;
886 #else
887 struct stat statbuf;
888 if (__gnat_stat (name, &statbuf) != 0) {
889 return (OS_Time)-1;
890 } else {
891 #ifdef VMS
892 /* VMS has file versioning. */
893 return (OS_Time)statbuf.st_ctime;
894 #else
895 return (OS_Time)statbuf.st_mtime;
896 #endif
898 #endif
901 /* Return a GNAT time stamp given a file descriptor. */
903 OS_Time
904 __gnat_file_time_fd (int fd)
906 /* The following workaround code is due to the fact that under EMX and
907 DJGPP fstat attempts to convert time values to GMT rather than keep the
908 actual OS timestamp of the file. By using the OS2/DOS functions directly
909 the GNAT timestamp are independent of this behavior, which is desired to
910 facilitate the distribution of GNAT compiled libraries. */
912 #if defined (__EMX__) || defined (MSDOS)
913 #ifdef __EMX__
915 FILESTATUS fs;
916 int ret = DosQueryFileInfo (fd, 1, (unsigned char *) &fs,
917 sizeof (FILESTATUS));
919 unsigned file_year = fs.fdateLastWrite.year;
920 unsigned file_month = fs.fdateLastWrite.month;
921 unsigned file_day = fs.fdateLastWrite.day;
922 unsigned file_hour = fs.ftimeLastWrite.hours;
923 unsigned file_min = fs.ftimeLastWrite.minutes;
924 unsigned file_tsec = fs.ftimeLastWrite.twosecs;
926 #else
927 struct ftime fs;
928 int ret = getftime (fd, &fs);
930 unsigned file_year = fs.ft_year;
931 unsigned file_month = fs.ft_month;
932 unsigned file_day = fs.ft_day;
933 unsigned file_hour = fs.ft_hour;
934 unsigned file_min = fs.ft_min;
935 unsigned file_tsec = fs.ft_tsec;
936 #endif
938 /* Calculate the seconds since epoch from the time components. First count
939 the whole days passed. The value for years returned by the DOS and OS2
940 functions count years from 1980, so to compensate for the UNIX epoch which
941 begins in 1970 start with 10 years worth of days and add days for each
942 four year period since then. */
944 time_t tot_secs;
945 int cum_days[12] = {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334};
946 int days_passed = 3652 + (file_year / 4) * 1461;
947 int years_since_leap = file_year % 4;
949 if (years_since_leap == 1)
950 days_passed += 366;
951 else if (years_since_leap == 2)
952 days_passed += 731;
953 else if (years_since_leap == 3)
954 days_passed += 1096;
956 if (file_year > 20)
957 days_passed -= 1;
959 days_passed += cum_days[file_month - 1];
960 if (years_since_leap == 0 && file_year != 20 && file_month > 2)
961 days_passed++;
963 days_passed += file_day - 1;
965 /* OK - have whole days. Multiply -- then add in other parts. */
967 tot_secs = days_passed * 86400;
968 tot_secs += file_hour * 3600;
969 tot_secs += file_min * 60;
970 tot_secs += file_tsec * 2;
971 return (OS_Time) tot_secs;
973 #elif defined (_WIN32)
974 HANDLE h = (HANDLE) _get_osfhandle (fd);
975 time_t ret = win32_filetime (h);
976 return (OS_Time) ret;
978 #else
979 struct stat statbuf;
981 if (fstat (fd, &statbuf) != 0) {
982 return (OS_Time) -1;
983 } else {
984 #ifdef VMS
985 /* VMS has file versioning. */
986 return (OS_Time) statbuf.st_ctime;
987 #else
988 return (OS_Time) statbuf.st_mtime;
989 #endif
991 #endif
994 /* Set the file time stamp. */
996 void
997 __gnat_set_file_time_name (char *name, time_t time_stamp)
999 #if defined (__EMX__) || defined (MSDOS) || defined (__vxworks)
1001 /* Code to implement __gnat_set_file_time_name for these systems. */
1003 #elif defined (_WIN32)
1004 union
1006 FILETIME ft_time;
1007 unsigned long long ull_time;
1008 } t_write;
1010 HANDLE h = CreateFile (name, GENERIC_WRITE, FILE_SHARE_WRITE, NULL,
1011 OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS,
1012 NULL);
1013 if (h == INVALID_HANDLE_VALUE)
1014 return;
1015 /* Add number of seconds between <Jan 1st 1601> and <Jan 1st 1970> */
1016 t_write.ull_time = ((unsigned long long)time_stamp + w32_epoch_offset);
1017 /* Convert to 100 nanosecond units */
1018 t_write.ull_time *= 10000000ULL;
1020 SetFileTime(h, NULL, NULL, &t_write.ft_time);
1021 CloseHandle (h);
1022 return;
1024 #elif defined (VMS)
1025 struct FAB fab;
1026 struct NAM nam;
1028 struct
1030 unsigned long long backup, create, expire, revise;
1031 unsigned long uic;
1032 union
1034 unsigned short value;
1035 struct
1037 unsigned system : 4;
1038 unsigned owner : 4;
1039 unsigned group : 4;
1040 unsigned world : 4;
1041 } bits;
1042 } prot;
1043 } Fat = { 0, 0, 0, 0, 0, { 0 }};
1045 ATRDEF atrlst[]
1047 { ATR$S_CREDATE, ATR$C_CREDATE, &Fat.create },
1048 { ATR$S_REVDATE, ATR$C_REVDATE, &Fat.revise },
1049 { ATR$S_EXPDATE, ATR$C_EXPDATE, &Fat.expire },
1050 { ATR$S_BAKDATE, ATR$C_BAKDATE, &Fat.backup },
1051 { ATR$S_FPRO, ATR$C_FPRO, &Fat.prot },
1052 { ATR$S_UIC, ATR$C_UIC, &Fat.uic },
1053 { 0, 0, 0}
1056 FIBDEF fib;
1057 struct dsc$descriptor_fib fibdsc = {sizeof (fib), (void *) &fib};
1059 struct IOSB iosb;
1061 unsigned long long newtime;
1062 unsigned long long revtime;
1063 long status;
1064 short chan;
1066 struct vstring file;
1067 struct dsc$descriptor_s filedsc
1068 = {NAM$C_MAXRSS, DSC$K_DTYPE_T, DSC$K_CLASS_S, (void *) file.string};
1069 struct vstring device;
1070 struct dsc$descriptor_s devicedsc
1071 = {NAM$C_MAXRSS, DSC$K_DTYPE_T, DSC$K_CLASS_S, (void *) device.string};
1072 struct vstring timev;
1073 struct dsc$descriptor_s timedsc
1074 = {NAM$C_MAXRSS, DSC$K_DTYPE_T, DSC$K_CLASS_S, (void *) timev.string};
1075 struct vstring result;
1076 struct dsc$descriptor_s resultdsc
1077 = {NAM$C_MAXRSS, DSC$K_DTYPE_VT, DSC$K_CLASS_VS, (void *) result.string};
1079 tryfile = (char *) __gnat_to_host_dir_spec (name, 0);
1081 /* Allocate and initialize a FAB and NAM structures. */
1082 fab = cc$rms_fab;
1083 nam = cc$rms_nam;
1085 nam.nam$l_esa = file.string;
1086 nam.nam$b_ess = NAM$C_MAXRSS;
1087 nam.nam$l_rsa = result.string;
1088 nam.nam$b_rss = NAM$C_MAXRSS;
1089 fab.fab$l_fna = tryfile;
1090 fab.fab$b_fns = strlen (tryfile);
1091 fab.fab$l_nam = &nam;
1093 /* Validate filespec syntax and device existence. */
1094 status = SYS$PARSE (&fab, 0, 0);
1095 if ((status & 1) != 1)
1096 LIB$SIGNAL (status);
1098 file.string[nam.nam$b_esl] = 0;
1100 /* Find matching filespec. */
1101 status = SYS$SEARCH (&fab, 0, 0);
1102 if ((status & 1) != 1)
1103 LIB$SIGNAL (status);
1105 file.string[nam.nam$b_esl] = 0;
1106 result.string[result.length=nam.nam$b_rsl] = 0;
1108 /* Get the device name and assign an IO channel. */
1109 strncpy (device.string, nam.nam$l_dev, nam.nam$b_dev);
1110 devicedsc.dsc$w_length = nam.nam$b_dev;
1111 chan = 0;
1112 status = SYS$ASSIGN (&devicedsc, &chan, 0, 0, 0);
1113 if ((status & 1) != 1)
1114 LIB$SIGNAL (status);
1116 /* Initialize the FIB and fill in the directory id field. */
1117 memset (&fib, 0, sizeof (fib));
1118 fib.fib$w_did[0] = nam.nam$w_did[0];
1119 fib.fib$w_did[1] = nam.nam$w_did[1];
1120 fib.fib$w_did[2] = nam.nam$w_did[2];
1121 fib.fib$l_acctl = 0;
1122 fib.fib$l_wcc = 0;
1123 strcpy (file.string, (strrchr (result.string, ']') + 1));
1124 filedsc.dsc$w_length = strlen (file.string);
1125 result.string[result.length = 0] = 0;
1127 /* Open and close the file to fill in the attributes. */
1128 status
1129 = SYS$QIOW (0, chan, IO$_ACCESS|IO$M_ACCESS, &iosb, 0, 0,
1130 &fibdsc, &filedsc, &result.length, &resultdsc, &atrlst, 0);
1131 if ((status & 1) != 1)
1132 LIB$SIGNAL (status);
1133 if ((iosb.status & 1) != 1)
1134 LIB$SIGNAL (iosb.status);
1136 result.string[result.length] = 0;
1137 status = SYS$QIOW (0, chan, IO$_DEACCESS, &iosb, 0, 0, &fibdsc, 0, 0, 0,
1138 &atrlst, 0);
1139 if ((status & 1) != 1)
1140 LIB$SIGNAL (status);
1141 if ((iosb.status & 1) != 1)
1142 LIB$SIGNAL (iosb.status);
1145 time_t t;
1147 /* Set creation time to requested time. */
1148 unix_time_to_vms (time_stamp, newtime);
1150 t = time ((time_t) 0);
1152 /* Set revision time to now in local time. */
1153 unix_time_to_vms (t, revtime);
1156 /* Reopen the file, modify the times and then close. */
1157 fib.fib$l_acctl = FIB$M_WRITE;
1158 status
1159 = SYS$QIOW (0, chan, IO$_ACCESS|IO$M_ACCESS, &iosb, 0, 0,
1160 &fibdsc, &filedsc, &result.length, &resultdsc, &atrlst, 0);
1161 if ((status & 1) != 1)
1162 LIB$SIGNAL (status);
1163 if ((iosb.status & 1) != 1)
1164 LIB$SIGNAL (iosb.status);
1166 Fat.create = newtime;
1167 Fat.revise = revtime;
1169 status = SYS$QIOW (0, chan, IO$_DEACCESS, &iosb, 0, 0,
1170 &fibdsc, 0, 0, 0, &atrlst, 0);
1171 if ((status & 1) != 1)
1172 LIB$SIGNAL (status);
1173 if ((iosb.status & 1) != 1)
1174 LIB$SIGNAL (iosb.status);
1176 /* Deassign the channel and exit. */
1177 status = SYS$DASSGN (chan);
1178 if ((status & 1) != 1)
1179 LIB$SIGNAL (status);
1180 #else
1181 struct utimbuf utimbuf;
1182 time_t t;
1184 /* Set modification time to requested time. */
1185 utimbuf.modtime = time_stamp;
1187 /* Set access time to now in local time. */
1188 t = time ((time_t) 0);
1189 utimbuf.actime = mktime (localtime (&t));
1191 utime (name, &utimbuf);
1192 #endif
1195 void
1196 __gnat_get_env_value_ptr (char *name, int *len, char **value)
1198 *value = getenv (name);
1199 if (!*value)
1200 *len = 0;
1201 else
1202 *len = strlen (*value);
1204 return;
1207 /* VMS specific declarations for set_env_value. */
1209 #ifdef VMS
1211 static char *to_host_path_spec (char *);
1213 struct descriptor_s
1215 unsigned short len, mbz;
1216 char *adr;
1219 typedef struct _ile3
1221 unsigned short len, code;
1222 char *adr;
1223 unsigned short *retlen_adr;
1224 } ile_s;
1226 #endif
1228 void
1229 __gnat_set_env_value (char *name, char *value)
1231 #ifdef MSDOS
1233 #elif defined (VMS)
1234 struct descriptor_s name_desc;
1235 /* Put in JOB table for now, so that the project stuff at least works. */
1236 struct descriptor_s table_desc = {7, 0, "LNM$JOB"};
1237 char *host_pathspec = value;
1238 char *copy_pathspec;
1239 int num_dirs_in_pathspec = 1;
1240 char *ptr;
1241 long status;
1243 name_desc.len = strlen (name);
1244 name_desc.mbz = 0;
1245 name_desc.adr = name;
1247 if (*host_pathspec == 0)
1248 /* deassign */
1250 status = LIB$DELETE_LOGICAL (&name_desc, &table_desc);
1251 /* no need to check status; if the logical name is not
1252 defined, that's fine. */
1253 return;
1256 ptr = host_pathspec;
1257 while (*ptr++)
1258 if (*ptr == ',')
1259 num_dirs_in_pathspec++;
1262 int i, status;
1263 ile_s *ile_array = alloca (sizeof (ile_s) * (num_dirs_in_pathspec + 1));
1264 char *copy_pathspec = alloca (strlen (host_pathspec) + 1);
1265 char *curr, *next;
1267 strcpy (copy_pathspec, host_pathspec);
1268 curr = copy_pathspec;
1269 for (i = 0; i < num_dirs_in_pathspec; i++)
1271 next = strchr (curr, ',');
1272 if (next == 0)
1273 next = strchr (curr, 0);
1275 *next = 0;
1276 ile_array[i].len = strlen (curr);
1278 /* Code 2 from lnmdef.h means its a string. */
1279 ile_array[i].code = 2;
1280 ile_array[i].adr = curr;
1282 /* retlen_adr is ignored. */
1283 ile_array[i].retlen_adr = 0;
1284 curr = next + 1;
1287 /* Terminating item must be zero. */
1288 ile_array[i].len = 0;
1289 ile_array[i].code = 0;
1290 ile_array[i].adr = 0;
1291 ile_array[i].retlen_adr = 0;
1293 status = LIB$SET_LOGICAL (&name_desc, 0, &table_desc, 0, ile_array);
1294 if ((status & 1) != 1)
1295 LIB$SIGNAL (status);
1298 #else
1299 int size = strlen (name) + strlen (value) + 2;
1300 char *expression;
1302 expression = (char *) xmalloc (size * sizeof (char));
1304 sprintf (expression, "%s=%s", name, value);
1305 putenv (expression);
1306 #endif
1309 #ifdef _WIN32
1310 #include <windows.h>
1311 #endif
1313 /* Get the list of installed standard libraries from the
1314 HKEY_LOCAL_MACHINE\SOFTWARE\Ada Core Technologies\GNAT\Standard Libraries
1315 key. */
1317 char *
1318 __gnat_get_libraries_from_registry (void)
1320 char *result = (char *) "";
1322 #if defined (_WIN32) && ! defined (__vxworks) && ! defined (CROSS_COMPILE)
1324 HKEY reg_key;
1325 DWORD name_size, value_size;
1326 char name[256];
1327 char value[256];
1328 DWORD type;
1329 DWORD index;
1330 LONG res;
1332 /* First open the key. */
1333 res = RegOpenKeyExA (HKEY_LOCAL_MACHINE, "SOFTWARE", 0, KEY_READ, &reg_key);
1335 if (res == ERROR_SUCCESS)
1336 res = RegOpenKeyExA (reg_key, "Ada Core Technologies", 0,
1337 KEY_READ, &reg_key);
1339 if (res == ERROR_SUCCESS)
1340 res = RegOpenKeyExA (reg_key, "GNAT", 0, KEY_READ, &reg_key);
1342 if (res == ERROR_SUCCESS)
1343 res = RegOpenKeyExA (reg_key, "Standard Libraries", 0, KEY_READ, &reg_key);
1345 /* If the key exists, read out all the values in it and concatenate them
1346 into a path. */
1347 for (index = 0; res == ERROR_SUCCESS; index++)
1349 value_size = name_size = 256;
1350 res = RegEnumValue (reg_key, index, name, &name_size, 0,
1351 &type, (LPBYTE)value, &value_size);
1353 if (res == ERROR_SUCCESS && type == REG_SZ)
1355 char *old_result = result;
1357 result = (char *) xmalloc (strlen (old_result) + value_size + 2);
1358 strcpy (result, old_result);
1359 strcat (result, value);
1360 strcat (result, ";");
1364 /* Remove the trailing ";". */
1365 if (result[0] != 0)
1366 result[strlen (result) - 1] = 0;
1368 #endif
1369 return result;
1373 __gnat_stat (char *name, struct stat *statbuf)
1375 #ifdef _WIN32
1376 /* Under Windows the directory name for the stat function must not be
1377 terminated by a directory separator except if just after a drive name. */
1378 int name_len = strlen (name);
1379 char last_char = name[name_len - 1];
1380 char win32_name[GNAT_MAX_PATH_LEN + 2];
1382 if (name_len > GNAT_MAX_PATH_LEN)
1383 return -1;
1385 strcpy (win32_name, name);
1387 while (name_len > 1 && (last_char == '\\' || last_char == '/'))
1389 win32_name[name_len - 1] = '\0';
1390 name_len--;
1391 last_char = win32_name[name_len - 1];
1394 if (name_len == 2 && win32_name[1] == ':')
1395 strcat (win32_name, "\\");
1397 return stat (win32_name, statbuf);
1399 #else
1400 return stat (name, statbuf);
1401 #endif
1405 __gnat_file_exists (char *name)
1407 struct stat statbuf;
1409 return !__gnat_stat (name, &statbuf);
1413 __gnat_is_absolute_path (char *name, int length)
1415 return (length != 0) &&
1416 (*name == '/' || *name == DIR_SEPARATOR
1417 #if defined (__EMX__) || defined (MSDOS) || defined (WINNT)
1418 || (length > 1 && isalpha (name[0]) && name[1] == ':')
1419 #endif
1424 __gnat_is_regular_file (char *name)
1426 int ret;
1427 struct stat statbuf;
1429 ret = __gnat_stat (name, &statbuf);
1430 return (!ret && S_ISREG (statbuf.st_mode));
1434 __gnat_is_directory (char *name)
1436 int ret;
1437 struct stat statbuf;
1439 ret = __gnat_stat (name, &statbuf);
1440 return (!ret && S_ISDIR (statbuf.st_mode));
1444 __gnat_is_readable_file (char *name)
1446 int ret;
1447 int mode;
1448 struct stat statbuf;
1450 ret = __gnat_stat (name, &statbuf);
1451 mode = statbuf.st_mode & S_IRUSR;
1452 return (!ret && mode);
1456 __gnat_is_writable_file (char *name)
1458 int ret;
1459 int mode;
1460 struct stat statbuf;
1462 ret = __gnat_stat (name, &statbuf);
1463 mode = statbuf.st_mode & S_IWUSR;
1464 return (!ret && mode);
1467 void
1468 __gnat_set_writable (char *name)
1470 #ifndef __vxworks
1471 struct stat statbuf;
1473 if (stat (name, &statbuf) == 0)
1475 statbuf.st_mode = statbuf.st_mode | S_IWUSR;
1476 chmod (name, statbuf.st_mode);
1478 #endif
1481 void
1482 __gnat_set_executable (char *name)
1484 #ifndef __vxworks
1485 struct stat statbuf;
1487 if (stat (name, &statbuf) == 0)
1489 statbuf.st_mode = statbuf.st_mode | S_IXUSR;
1490 chmod (name, statbuf.st_mode);
1492 #endif
1495 void
1496 __gnat_set_readonly (char *name)
1498 #ifndef __vxworks
1499 struct stat statbuf;
1501 if (stat (name, &statbuf) == 0)
1503 statbuf.st_mode = statbuf.st_mode & 07577;
1504 chmod (name, statbuf.st_mode);
1506 #endif
1510 __gnat_is_symbolic_link (char *name ATTRIBUTE_UNUSED)
1512 #if defined (__vxworks)
1513 return 0;
1515 #elif defined (_AIX) || defined (__APPLE__) || defined (__unix__)
1516 int ret;
1517 struct stat statbuf;
1519 ret = lstat (name, &statbuf);
1520 return (!ret && S_ISLNK (statbuf.st_mode));
1522 #else
1523 return 0;
1524 #endif
1527 #ifdef VMS
1528 /* Defined in VMS header files. */
1529 #if defined (__ALPHA)
1530 #define fork() (decc$$alloc_vfork_blocks() >= 0 ? \
1531 LIB$GET_CURRENT_INVO_CONTEXT (decc$$get_vfork_jmpbuf()) : -1)
1532 #elif defined (__IA64)
1533 #define fork() (decc$$alloc_vfork_blocks() >= 0 ? \
1534 LIB$I64_GET_CURR_INVO_CONTEXT(decc$$get_vfork_jmpbuf()) : -1)
1535 #endif
1536 #endif
1538 #if defined (sun) && defined (__SVR4)
1539 /* Using fork on Solaris will duplicate all the threads. fork1, which
1540 duplicates only the active thread, must be used instead, or spawning
1541 subprocess from a program with tasking will lead into numerous problems. */
1542 #define fork fork1
1543 #endif
1546 __gnat_portable_spawn (char *args[])
1548 int status = 0;
1549 int finished ATTRIBUTE_UNUSED;
1550 int pid ATTRIBUTE_UNUSED;
1552 #if defined (MSDOS) || defined (_WIN32)
1553 /* args[0] must be quotes as it could contain a full pathname with spaces */
1554 char *args_0 = args[0];
1555 args[0] = (char *)xmalloc (strlen (args_0) + 3);
1556 strcpy (args[0], "\"");
1557 strcat (args[0], args_0);
1558 strcat (args[0], "\"");
1560 status = spawnvp (P_WAIT, args_0, (char* const*)args);
1562 /* restore previous value */
1563 free (args[0]);
1564 args[0] = (char *)args_0;
1566 if (status < 0)
1567 return -1;
1568 else
1569 return status;
1571 #elif defined (__vxworks)
1572 return -1;
1573 #else
1575 #ifdef __EMX__
1576 pid = spawnvp (P_NOWAIT, args[0], args);
1577 if (pid == -1)
1578 return -1;
1580 #else
1581 pid = fork ();
1582 if (pid < 0)
1583 return -1;
1585 if (pid == 0)
1587 /* The child. */
1588 if (execv (args[0], args) != 0)
1589 #if defined (VMS)
1590 return -1; /* execv is in parent context on VMS. */
1591 #else
1592 _exit (1);
1593 #endif
1595 #endif
1597 /* The parent. */
1598 finished = waitpid (pid, &status, 0);
1600 if (finished != pid || WIFEXITED (status) == 0)
1601 return -1;
1603 return WEXITSTATUS (status);
1604 #endif
1606 return 0;
1609 /* Create a copy of the given file descriptor.
1610 Return -1 if an error occurred. */
1613 __gnat_dup (int oldfd)
1615 #if defined (__vxworks)
1616 /* Not supported on VxWorks. */
1617 return -1;
1618 #else
1619 return dup (oldfd);
1620 #endif
1623 /* Make newfd be the copy of oldfd, closing newfd first if necessary.
1624 Return -1 if an error occured. */
1627 __gnat_dup2 (int oldfd, int newfd)
1629 #if defined (__vxworks)
1630 /* Not supported on VxWorks. */
1631 return -1;
1632 #else
1633 return dup2 (oldfd, newfd);
1634 #endif
1637 /* WIN32 code to implement a wait call that wait for any child process. */
1639 #ifdef _WIN32
1641 /* Synchronization code, to be thread safe. */
1643 static CRITICAL_SECTION plist_cs;
1645 void
1646 __gnat_plist_init (void)
1648 InitializeCriticalSection (&plist_cs);
1651 static void
1652 plist_enter (void)
1654 EnterCriticalSection (&plist_cs);
1657 static void
1658 plist_leave (void)
1660 LeaveCriticalSection (&plist_cs);
1663 typedef struct _process_list
1665 HANDLE h;
1666 struct _process_list *next;
1667 } Process_List;
1669 static Process_List *PLIST = NULL;
1671 static int plist_length = 0;
1673 static void
1674 add_handle (HANDLE h)
1676 Process_List *pl;
1678 pl = (Process_List *) xmalloc (sizeof (Process_List));
1680 plist_enter();
1682 /* -------------------- critical section -------------------- */
1683 pl->h = h;
1684 pl->next = PLIST;
1685 PLIST = pl;
1686 ++plist_length;
1687 /* -------------------- critical section -------------------- */
1689 plist_leave();
1692 static void
1693 remove_handle (HANDLE h)
1695 Process_List *pl;
1696 Process_List *prev = NULL;
1698 plist_enter();
1700 /* -------------------- critical section -------------------- */
1701 pl = PLIST;
1702 while (pl)
1704 if (pl->h == h)
1706 if (pl == PLIST)
1707 PLIST = pl->next;
1708 else
1709 prev->next = pl->next;
1710 free (pl);
1711 break;
1713 else
1715 prev = pl;
1716 pl = pl->next;
1720 --plist_length;
1721 /* -------------------- critical section -------------------- */
1723 plist_leave();
1726 static int
1727 win32_no_block_spawn (char *command, char *args[])
1729 BOOL result;
1730 STARTUPINFO SI;
1731 PROCESS_INFORMATION PI;
1732 SECURITY_ATTRIBUTES SA;
1733 int csize = 1;
1734 char *full_command;
1735 int k;
1737 /* compute the total command line length */
1738 k = 0;
1739 while (args[k])
1741 csize += strlen (args[k]) + 1;
1742 k++;
1745 full_command = (char *) xmalloc (csize);
1747 /* Startup info. */
1748 SI.cb = sizeof (STARTUPINFO);
1749 SI.lpReserved = NULL;
1750 SI.lpReserved2 = NULL;
1751 SI.lpDesktop = NULL;
1752 SI.cbReserved2 = 0;
1753 SI.lpTitle = NULL;
1754 SI.dwFlags = 0;
1755 SI.wShowWindow = SW_HIDE;
1757 /* Security attributes. */
1758 SA.nLength = sizeof (SECURITY_ATTRIBUTES);
1759 SA.bInheritHandle = TRUE;
1760 SA.lpSecurityDescriptor = NULL;
1762 /* Prepare the command string. */
1763 strcpy (full_command, command);
1764 strcat (full_command, " ");
1766 k = 1;
1767 while (args[k])
1769 strcat (full_command, args[k]);
1770 strcat (full_command, " ");
1771 k++;
1774 result = CreateProcess
1775 (NULL, (char *) full_command, &SA, NULL, TRUE,
1776 GetPriorityClass (GetCurrentProcess()), NULL, NULL, &SI, &PI);
1778 free (full_command);
1780 if (result == TRUE)
1782 add_handle (PI.hProcess);
1783 CloseHandle (PI.hThread);
1784 return (int) PI.hProcess;
1786 else
1787 return -1;
1790 static int
1791 win32_wait (int *status)
1793 DWORD exitcode;
1794 HANDLE *hl;
1795 HANDLE h;
1796 DWORD res;
1797 int k;
1798 Process_List *pl;
1800 if (plist_length == 0)
1802 errno = ECHILD;
1803 return -1;
1806 hl = (HANDLE *) xmalloc (sizeof (HANDLE) * plist_length);
1808 k = 0;
1809 plist_enter();
1811 /* -------------------- critical section -------------------- */
1812 pl = PLIST;
1813 while (pl)
1815 hl[k++] = pl->h;
1816 pl = pl->next;
1818 /* -------------------- critical section -------------------- */
1820 plist_leave();
1822 res = WaitForMultipleObjects (plist_length, hl, FALSE, INFINITE);
1823 h = hl[res - WAIT_OBJECT_0];
1824 free (hl);
1826 remove_handle (h);
1828 GetExitCodeProcess (h, &exitcode);
1829 CloseHandle (h);
1831 *status = (int) exitcode;
1832 return (int) h;
1835 #endif
1838 __gnat_portable_no_block_spawn (char *args[])
1840 int pid = 0;
1842 #if defined (__EMX__) || defined (MSDOS)
1844 /* ??? For PC machines I (Franco) don't know the system calls to implement
1845 this routine. So I'll fake it as follows. This routine will behave
1846 exactly like the blocking portable_spawn and will systematically return
1847 a pid of 0 unless the spawned task did not complete successfully, in
1848 which case we return a pid of -1. To synchronize with this the
1849 portable_wait below systematically returns a pid of 0 and reports that
1850 the subprocess terminated successfully. */
1852 if (spawnvp (P_WAIT, args[0], args) != 0)
1853 return -1;
1855 #elif defined (_WIN32)
1857 pid = win32_no_block_spawn (args[0], args);
1858 return pid;
1860 #elif defined (__vxworks)
1861 return -1;
1863 #else
1864 pid = fork ();
1866 if (pid == 0)
1868 /* The child. */
1869 if (execv (args[0], args) != 0)
1870 #if defined (VMS)
1871 return -1; /* execv is in parent context on VMS. */
1872 #else
1873 _exit (1);
1874 #endif
1877 #endif
1879 return pid;
1883 __gnat_portable_wait (int *process_status)
1885 int status = 0;
1886 int pid = 0;
1888 #if defined (_WIN32)
1890 pid = win32_wait (&status);
1892 #elif defined (__EMX__) || defined (MSDOS)
1893 /* ??? See corresponding comment in portable_no_block_spawn. */
1895 #elif defined (__vxworks)
1896 /* Not sure what to do here, so do same as __EMX__ case, i.e., nothing but
1897 return zero. */
1898 #else
1900 pid = waitpid (-1, &status, 0);
1901 status = status & 0xffff;
1902 #endif
1904 *process_status = status;
1905 return pid;
1909 __gnat_waitpid (int pid)
1911 int status = 0;
1913 #if defined (_WIN32)
1914 cwait (&status, pid, _WAIT_CHILD);
1915 #elif defined (__EMX__) || defined (MSDOS) || defined (__vxworks)
1916 /* Status is already zero, so nothing to do. */
1917 #else
1918 waitpid (pid, &status, 0);
1919 status = WEXITSTATUS (status);
1920 #endif
1922 return status;
1925 void
1926 __gnat_os_exit (int status)
1928 exit (status);
1931 /* Locate a regular file, give a Path value. */
1933 char *
1934 __gnat_locate_regular_file (char *file_name, char *path_val)
1936 char *ptr;
1937 int absolute = __gnat_is_absolute_path (file_name, strlen (file_name));
1939 /* Handle absolute pathnames. */
1940 if (absolute)
1942 if (__gnat_is_regular_file (file_name))
1943 return xstrdup (file_name);
1945 return 0;
1948 /* If file_name include directory separator(s), try it first as
1949 a path name relative to the current directory */
1950 for (ptr = file_name; *ptr && *ptr != '/' && *ptr != DIR_SEPARATOR; ptr++)
1953 if (*ptr != 0)
1955 if (__gnat_is_regular_file (file_name))
1956 return xstrdup (file_name);
1959 if (path_val == 0)
1960 return 0;
1963 /* The result has to be smaller than path_val + file_name. */
1964 char *file_path = alloca (strlen (path_val) + strlen (file_name) + 2);
1966 for (;;)
1968 for (; *path_val == PATH_SEPARATOR; path_val++)
1971 if (*path_val == 0)
1972 return 0;
1974 for (ptr = file_path; *path_val && *path_val != PATH_SEPARATOR; )
1975 *ptr++ = *path_val++;
1977 ptr--;
1978 if (*ptr != '/' && *ptr != DIR_SEPARATOR)
1979 *++ptr = DIR_SEPARATOR;
1981 strcpy (++ptr, file_name);
1983 if (__gnat_is_regular_file (file_path))
1984 return xstrdup (file_path);
1988 return 0;
1991 /* Locate an executable given a Path argument. This routine is only used by
1992 gnatbl and should not be used otherwise. Use locate_exec_on_path
1993 instead. */
1995 char *
1996 __gnat_locate_exec (char *exec_name, char *path_val)
1998 if (!strstr (exec_name, HOST_EXECUTABLE_SUFFIX))
2000 char *full_exec_name
2001 = alloca (strlen (exec_name) + strlen (HOST_EXECUTABLE_SUFFIX) + 1);
2003 strcpy (full_exec_name, exec_name);
2004 strcat (full_exec_name, HOST_EXECUTABLE_SUFFIX);
2005 return __gnat_locate_regular_file (full_exec_name, path_val);
2007 else
2008 return __gnat_locate_regular_file (exec_name, path_val);
2011 /* Locate an executable using the Systems default PATH. */
2013 char *
2014 __gnat_locate_exec_on_path (char *exec_name)
2016 char *apath_val;
2017 #ifdef VMS
2018 char *path_val = "/VAXC$PATH";
2019 #else
2020 char *path_val = getenv ("PATH");
2021 #endif
2022 #ifdef _WIN32
2023 /* In Win32 systems we expand the PATH as for XP environment
2024 variables are not automatically expanded. */
2025 int len = strlen (path_val) * 3;
2026 char *expanded_path_val = alloca (len + 1);
2028 DWORD res = ExpandEnvironmentStrings (path_val, expanded_path_val, len);
2030 if (res != 0)
2032 path_val = expanded_path_val;
2034 #endif
2036 apath_val = alloca (strlen (path_val) + 1);
2037 strcpy (apath_val, path_val);
2039 return __gnat_locate_exec (exec_name, apath_val);
2042 #ifdef VMS
2044 /* These functions are used to translate to and from VMS and Unix syntax
2045 file, directory and path specifications. */
2047 #define MAXPATH 256
2048 #define MAXNAMES 256
2049 #define NEW_CANONICAL_FILELIST_INCREMENT 64
2051 static char new_canonical_dirspec [MAXPATH];
2052 static char new_canonical_filespec [MAXPATH];
2053 static char new_canonical_pathspec [MAXNAMES*MAXPATH];
2054 static unsigned new_canonical_filelist_index;
2055 static unsigned new_canonical_filelist_in_use;
2056 static unsigned new_canonical_filelist_allocated;
2057 static char **new_canonical_filelist;
2058 static char new_host_pathspec [MAXNAMES*MAXPATH];
2059 static char new_host_dirspec [MAXPATH];
2060 static char new_host_filespec [MAXPATH];
2062 /* Routine is called repeatedly by decc$from_vms via
2063 __gnat_to_canonical_file_list_init until it returns 0 or the expansion
2064 runs out. */
2066 static int
2067 wildcard_translate_unix (char *name)
2069 char *ver;
2070 char buff [MAXPATH];
2072 strncpy (buff, name, MAXPATH);
2073 buff [MAXPATH - 1] = (char) 0;
2074 ver = strrchr (buff, '.');
2076 /* Chop off the version. */
2077 if (ver)
2078 *ver = 0;
2080 /* Dynamically extend the allocation by the increment. */
2081 if (new_canonical_filelist_in_use == new_canonical_filelist_allocated)
2083 new_canonical_filelist_allocated += NEW_CANONICAL_FILELIST_INCREMENT;
2084 new_canonical_filelist = (char **) xrealloc
2085 (new_canonical_filelist,
2086 new_canonical_filelist_allocated * sizeof (char *));
2089 new_canonical_filelist[new_canonical_filelist_in_use++] = xstrdup (buff);
2091 return 1;
2094 /* Translate a wildcard VMS file spec into a list of Unix file specs. First do
2095 full translation and copy the results into a list (_init), then return them
2096 one at a time (_next). If onlydirs set, only expand directory files. */
2099 __gnat_to_canonical_file_list_init (char *filespec, int onlydirs)
2101 int len;
2102 char buff [MAXPATH];
2104 len = strlen (filespec);
2105 strncpy (buff, filespec, MAXPATH);
2107 /* Only look for directories */
2108 if (onlydirs && !strstr (&buff [len-5], "*.dir"))
2109 strncat (buff, "*.dir", MAXPATH);
2111 buff [MAXPATH - 1] = (char) 0;
2113 decc$from_vms (buff, wildcard_translate_unix, 1);
2115 /* Remove the .dir extension. */
2116 if (onlydirs)
2118 int i;
2119 char *ext;
2121 for (i = 0; i < new_canonical_filelist_in_use; i++)
2123 ext = strstr (new_canonical_filelist[i], ".dir");
2124 if (ext)
2125 *ext = 0;
2129 return new_canonical_filelist_in_use;
2132 /* Return the next filespec in the list. */
2134 char *
2135 __gnat_to_canonical_file_list_next ()
2137 return new_canonical_filelist[new_canonical_filelist_index++];
2140 /* Free storage used in the wildcard expansion. */
2142 void
2143 __gnat_to_canonical_file_list_free ()
2145 int i;
2147 for (i = 0; i < new_canonical_filelist_in_use; i++)
2148 free (new_canonical_filelist[i]);
2150 free (new_canonical_filelist);
2152 new_canonical_filelist_in_use = 0;
2153 new_canonical_filelist_allocated = 0;
2154 new_canonical_filelist_index = 0;
2155 new_canonical_filelist = 0;
2158 /* Translate a VMS syntax directory specification in to Unix syntax. If
2159 PREFIXFLAG is set, append an underscore "/". If no indicators of VMS syntax
2160 found, return input string. Also translate a dirname that contains no
2161 slashes, in case it's a logical name. */
2163 char *
2164 __gnat_to_canonical_dir_spec (char *dirspec, int prefixflag)
2166 int len;
2168 strcpy (new_canonical_dirspec, "");
2169 if (strlen (dirspec))
2171 char *dirspec1;
2173 if (strchr (dirspec, ']') || strchr (dirspec, ':'))
2175 strncpy (new_canonical_dirspec,
2176 (char *) decc$translate_vms (dirspec),
2177 MAXPATH);
2179 else if (!strchr (dirspec, '/') && (dirspec1 = getenv (dirspec)) != 0)
2181 strncpy (new_canonical_dirspec,
2182 (char *) decc$translate_vms (dirspec1),
2183 MAXPATH);
2185 else
2187 strncpy (new_canonical_dirspec, dirspec, MAXPATH);
2191 len = strlen (new_canonical_dirspec);
2192 if (prefixflag && new_canonical_dirspec [len-1] != '/')
2193 strncat (new_canonical_dirspec, "/", MAXPATH);
2195 new_canonical_dirspec [MAXPATH - 1] = (char) 0;
2197 return new_canonical_dirspec;
2201 /* Translate a VMS syntax file specification into Unix syntax.
2202 If no indicators of VMS syntax found, return input string. */
2204 char *
2205 __gnat_to_canonical_file_spec (char *filespec)
2207 strncpy (new_canonical_filespec, "", MAXPATH);
2209 if (strchr (filespec, ']') || strchr (filespec, ':'))
2211 strncpy (new_canonical_filespec,
2212 (char *) decc$translate_vms (filespec),
2213 MAXPATH);
2215 else
2217 strncpy (new_canonical_filespec, filespec, MAXPATH);
2220 new_canonical_filespec [MAXPATH - 1] = (char) 0;
2222 return new_canonical_filespec;
2225 /* Translate a VMS syntax path specification into Unix syntax.
2226 If no indicators of VMS syntax found, return input string. */
2228 char *
2229 __gnat_to_canonical_path_spec (char *pathspec)
2231 char *curr, *next, buff [MAXPATH];
2233 if (pathspec == 0)
2234 return pathspec;
2236 /* If there are /'s, assume it's a Unix path spec and return. */
2237 if (strchr (pathspec, '/'))
2238 return pathspec;
2240 new_canonical_pathspec[0] = 0;
2241 curr = pathspec;
2243 for (;;)
2245 next = strchr (curr, ',');
2246 if (next == 0)
2247 next = strchr (curr, 0);
2249 strncpy (buff, curr, next - curr);
2250 buff[next - curr] = 0;
2252 /* Check for wildcards and expand if present. */
2253 if (strchr (buff, '*') || strchr (buff, '%') || strstr (buff, "..."))
2255 int i, dirs;
2257 dirs = __gnat_to_canonical_file_list_init (buff, 1);
2258 for (i = 0; i < dirs; i++)
2260 char *next_dir;
2262 next_dir = __gnat_to_canonical_file_list_next ();
2263 strncat (new_canonical_pathspec, next_dir, MAXPATH);
2265 /* Don't append the separator after the last expansion. */
2266 if (i+1 < dirs)
2267 strncat (new_canonical_pathspec, ":", MAXPATH);
2270 __gnat_to_canonical_file_list_free ();
2272 else
2273 strncat (new_canonical_pathspec,
2274 __gnat_to_canonical_dir_spec (buff, 0), MAXPATH);
2276 if (*next == 0)
2277 break;
2279 strncat (new_canonical_pathspec, ":", MAXPATH);
2280 curr = next + 1;
2283 new_canonical_pathspec [MAXPATH - 1] = (char) 0;
2285 return new_canonical_pathspec;
2288 static char filename_buff [MAXPATH];
2290 static int
2291 translate_unix (char *name, int type)
2293 strncpy (filename_buff, name, MAXPATH);
2294 filename_buff [MAXPATH - 1] = (char) 0;
2295 return 0;
2298 /* Translate a Unix syntax path spec into a VMS style (comma separated list of
2299 directories. */
2301 static char *
2302 to_host_path_spec (char *pathspec)
2304 char *curr, *next, buff [MAXPATH];
2306 if (pathspec == 0)
2307 return pathspec;
2309 /* Can't very well test for colons, since that's the Unix separator! */
2310 if (strchr (pathspec, ']') || strchr (pathspec, ','))
2311 return pathspec;
2313 new_host_pathspec[0] = 0;
2314 curr = pathspec;
2316 for (;;)
2318 next = strchr (curr, ':');
2319 if (next == 0)
2320 next = strchr (curr, 0);
2322 strncpy (buff, curr, next - curr);
2323 buff[next - curr] = 0;
2325 strncat (new_host_pathspec, __gnat_to_host_dir_spec (buff, 0), MAXPATH);
2326 if (*next == 0)
2327 break;
2328 strncat (new_host_pathspec, ",", MAXPATH);
2329 curr = next + 1;
2332 new_host_pathspec [MAXPATH - 1] = (char) 0;
2334 return new_host_pathspec;
2337 /* Translate a Unix syntax directory specification into VMS syntax. The
2338 PREFIXFLAG has no effect, but is kept for symmetry with
2339 to_canonical_dir_spec. If indicators of VMS syntax found, return input
2340 string. */
2342 char *
2343 __gnat_to_host_dir_spec (char *dirspec, int prefixflag ATTRIBUTE_UNUSED)
2345 int len = strlen (dirspec);
2347 strncpy (new_host_dirspec, dirspec, MAXPATH);
2348 new_host_dirspec [MAXPATH - 1] = (char) 0;
2350 if (strchr (new_host_dirspec, ']') || strchr (new_host_dirspec, ':'))
2351 return new_host_dirspec;
2353 while (len > 1 && new_host_dirspec[len - 1] == '/')
2355 new_host_dirspec[len - 1] = 0;
2356 len--;
2359 decc$to_vms (new_host_dirspec, translate_unix, 1, 2);
2360 strncpy (new_host_dirspec, filename_buff, MAXPATH);
2361 new_host_dirspec [MAXPATH - 1] = (char) 0;
2363 return new_host_dirspec;
2366 /* Translate a Unix syntax file specification into VMS syntax.
2367 If indicators of VMS syntax found, return input string. */
2369 char *
2370 __gnat_to_host_file_spec (char *filespec)
2372 strncpy (new_host_filespec, "", MAXPATH);
2373 if (strchr (filespec, ']') || strchr (filespec, ':'))
2375 strncpy (new_host_filespec, filespec, MAXPATH);
2377 else
2379 decc$to_vms (filespec, translate_unix, 1, 1);
2380 strncpy (new_host_filespec, filename_buff, MAXPATH);
2383 new_host_filespec [MAXPATH - 1] = (char) 0;
2385 return new_host_filespec;
2388 void
2389 __gnat_adjust_os_resource_limits ()
2391 SYS$ADJWSL (131072, 0);
2394 #else /* VMS */
2396 /* Dummy functions for Osint import for non-VMS systems. */
2399 __gnat_to_canonical_file_list_init
2400 (char *dirspec ATTRIBUTE_UNUSED, int onlydirs ATTRIBUTE_UNUSED)
2402 return 0;
2405 char *
2406 __gnat_to_canonical_file_list_next (void)
2408 return (char *) "";
2411 void
2412 __gnat_to_canonical_file_list_free (void)
2416 char *
2417 __gnat_to_canonical_dir_spec (char *dirspec, int prefixflag ATTRIBUTE_UNUSED)
2419 return dirspec;
2422 char *
2423 __gnat_to_canonical_file_spec (char *filespec)
2425 return filespec;
2428 char *
2429 __gnat_to_canonical_path_spec (char *pathspec)
2431 return pathspec;
2434 char *
2435 __gnat_to_host_dir_spec (char *dirspec, int prefixflag ATTRIBUTE_UNUSED)
2437 return dirspec;
2440 char *
2441 __gnat_to_host_file_spec (char *filespec)
2443 return filespec;
2446 void
2447 __gnat_adjust_os_resource_limits (void)
2451 #endif
2453 /* For EMX, we cannot include dummy in libgcc, since it is too difficult
2454 to coordinate this with the EMX distribution. Consequently, we put the
2455 definition of dummy which is used for exception handling, here. */
2457 #if defined (__EMX__)
2458 void __dummy () {}
2459 #endif
2461 #if defined (__mips_vxworks)
2463 _flush_cache()
2465 CACHE_USER_FLUSH (0, ENTIRE_CACHE);
2467 #endif
2469 #if defined (CROSS_COMPILE) \
2470 || (! (defined (sparc) && defined (sun) && defined (__SVR4)) \
2471 && ! (defined (linux) && defined (i386)) \
2472 && ! defined (__FreeBSD__) \
2473 && ! defined (__hpux__) \
2474 && ! defined (_AIX) \
2475 && ! (defined (__alpha__) && defined (__osf__)) \
2476 && ! defined (__MINGW32__) \
2477 && ! (defined (__mips) && defined (__sgi)))
2479 /* Dummy function to satisfy g-trasym.o. Currently Solaris sparc, HP/UX,
2480 GNU/Linux x86, Tru64 & Windows provide a non-dummy version of this
2481 procedure in libaddr2line.a. */
2483 void
2484 convert_addresses (void *addrs ATTRIBUTE_UNUSED,
2485 int n_addr ATTRIBUTE_UNUSED,
2486 void *buf ATTRIBUTE_UNUSED,
2487 int *len ATTRIBUTE_UNUSED)
2489 *len = 0;
2491 #endif
2493 #if defined (_WIN32)
2494 int __gnat_argument_needs_quote = 1;
2495 #else
2496 int __gnat_argument_needs_quote = 0;
2497 #endif
2499 /* This option is used to enable/disable object files handling from the
2500 binder file by the GNAT Project module. For example, this is disabled on
2501 Windows (prior to GCC 3.4) as it is already done by the mdll module.
2502 Stating with GCC 3.4 the shared libraries are not based on mdll
2503 anymore as it uses the GCC's -shared option */
2504 #if defined (_WIN32) \
2505 && ((__GNUC__ < 3) || ((__GNUC__ == 3) && (__GNUC_MINOR__ < 4)))
2506 int __gnat_prj_add_obj_files = 0;
2507 #else
2508 int __gnat_prj_add_obj_files = 1;
2509 #endif
2511 /* char used as prefix/suffix for environment variables */
2512 #if defined (_WIN32)
2513 char __gnat_environment_char = '%';
2514 #else
2515 char __gnat_environment_char = '$';
2516 #endif
2518 /* This functions copy the file attributes from a source file to a
2519 destination file.
2521 mode = 0 : In this mode copy only the file time stamps (last access and
2522 last modification time stamps).
2524 mode = 1 : In this mode, time stamps and read/write/execute attributes are
2525 copied.
2527 Returns 0 if operation was successful and -1 in case of error. */
2530 __gnat_copy_attribs (char *from, char *to, int mode)
2532 #if defined (VMS) || defined (__vxworks)
2533 return -1;
2534 #else
2535 struct stat fbuf;
2536 struct utimbuf tbuf;
2538 if (stat (from, &fbuf) == -1)
2540 return -1;
2543 tbuf.actime = fbuf.st_atime;
2544 tbuf.modtime = fbuf.st_mtime;
2546 if (utime (to, &tbuf) == -1)
2548 return -1;
2551 if (mode == 1)
2553 if (chmod (to, fbuf.st_mode) == -1)
2555 return -1;
2559 return 0;
2560 #endif
2563 /* This function is installed in libgcc.a. */
2564 extern void __gnat_install_locks (void (*) (void), void (*) (void));
2566 /* This function offers a hook for libgnarl to set the
2567 locking subprograms for libgcc_eh.
2568 This is only needed on OpenVMS, since other platforms use standard
2569 --enable-threads=posix option, or similar. */
2571 void
2572 __gnatlib_install_locks (void (*lock) (void) ATTRIBUTE_UNUSED,
2573 void (*unlock) (void) ATTRIBUTE_UNUSED)
2575 #if defined (IN_RTS) && defined (VMS)
2576 __gnat_install_locks (lock, unlock);
2577 /* There is a bootstrap path issue if adaint is build with this
2578 symbol unresolved for the stage1 compiler. Since the compiler
2579 does not use tasking, we simply make __gnatlib_install_locks
2580 a no-op in this case. */
2581 #endif
2585 __gnat_lseek (int fd, long offset, int whence)
2587 return (int) lseek (fd, offset, whence);
2590 /* This function returns the version of GCC being used. Here it's GCC 3. */
2592 get_gcc_version (void)
2594 return 3;