Mark ChangeLog
[official-gcc.git] / gcc / ada / adaint.c
blobf94f3bfb5f284d8c0c73a43e5826a0457dc6b1eb
1 /****************************************************************************
2 * *
3 * GNAT COMPILER COMPONENTS *
4 * *
5 * A D A I N T *
6 * *
7 * C Implementation File *
8 * *
9 * Copyright (C) 1992-2005, 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 #if defined(VMS) && defined (__LONG_POINTERS)
282 /* Return a 32 bit pointer to an array of 32 bit pointers
283 given a 64 bit pointer to an array of 64 bit pointers */
285 typedef __char_ptr32 *__char_ptr_char_ptr32 __attribute__ ((mode (SI)));
287 static __char_ptr_char_ptr32
288 to_ptr32 (char **ptr64)
290 int argc;
291 __char_ptr_char_ptr32 short_argv;
293 for (argc=0; ptr64[argc]; argc++);
295 /* Reallocate argv with 32 bit pointers. */
296 short_argv = (__char_ptr_char_ptr32) decc$malloc
297 (sizeof (__char_ptr32) * (argc + 1));
299 for (argc=0; ptr64[argc]; argc++)
300 short_argv[argc] = (__char_ptr32) decc$strdup (ptr64[argc]);
302 short_argv[argc] = (__char_ptr32) 0;
303 return short_argv;
306 #define MAYBE_TO_PTR32(argv) to_ptr32 (argv)
307 #else
308 #define MAYBE_TO_PTR32(argv) argv
309 #endif
311 void
312 __gnat_to_gm_time
313 (OS_Time *p_time,
314 int *p_year,
315 int *p_month,
316 int *p_day,
317 int *p_hours,
318 int *p_mins,
319 int *p_secs)
321 struct tm *res;
322 time_t time = (time_t) *p_time;
324 #ifdef _WIN32
325 /* On Windows systems, the time is sometimes rounded up to the nearest
326 even second, so if the number of seconds is odd, increment it. */
327 if (time & 1)
328 time++;
329 #endif
331 #ifdef VMS
332 res = localtime (&time);
333 #else
334 res = gmtime (&time);
335 #endif
337 if (res)
339 *p_year = res->tm_year;
340 *p_month = res->tm_mon;
341 *p_day = res->tm_mday;
342 *p_hours = res->tm_hour;
343 *p_mins = res->tm_min;
344 *p_secs = res->tm_sec;
346 else
347 *p_year = *p_month = *p_day = *p_hours = *p_mins = *p_secs = 0;
350 /* Place the contents of the symbolic link named PATH in the buffer BUF,
351 which has size BUFSIZ. If PATH is a symbolic link, then return the number
352 of characters of its content in BUF. Otherwise, return -1. For Windows,
353 OS/2 and vxworks, always return -1. */
356 __gnat_readlink (char *path ATTRIBUTE_UNUSED,
357 char *buf ATTRIBUTE_UNUSED,
358 size_t bufsiz ATTRIBUTE_UNUSED)
360 #if defined (MSDOS) || defined (_WIN32) || defined (__EMX__)
361 return -1;
362 #elif defined (__INTERIX) || defined (VMS)
363 return -1;
364 #elif defined (__vxworks)
365 return -1;
366 #else
367 return readlink (path, buf, bufsiz);
368 #endif
371 /* Creates a symbolic link named NEWPATH which contains the string OLDPATH. If
372 NEWPATH exists it will NOT be overwritten. For Windows, OS/2, VxWorks,
373 Interix and VMS, always return -1. */
376 __gnat_symlink (char *oldpath ATTRIBUTE_UNUSED,
377 char *newpath ATTRIBUTE_UNUSED)
379 #if defined (MSDOS) || defined (_WIN32) || defined (__EMX__)
380 return -1;
381 #elif defined (__INTERIX) || defined (VMS)
382 return -1;
383 #elif defined (__vxworks)
384 return -1;
385 #else
386 return symlink (oldpath, newpath);
387 #endif
390 /* Try to lock a file, return 1 if success. */
392 #if defined (__vxworks) || defined (MSDOS) || defined (_WIN32)
394 /* Version that does not use link. */
397 __gnat_try_lock (char *dir, char *file)
399 char full_path[256];
400 int fd;
402 sprintf (full_path, "%s%c%s", dir, DIR_SEPARATOR, file);
403 fd = open (full_path, O_CREAT | O_EXCL, 0600);
404 if (fd < 0)
405 return 0;
407 close (fd);
408 return 1;
411 #elif defined (__EMX__) || defined (VMS)
413 /* More cases that do not use link; identical code, to solve too long
414 line problem ??? */
417 __gnat_try_lock (char *dir, char *file)
419 char full_path[256];
420 int fd;
422 sprintf (full_path, "%s%c%s", dir, DIR_SEPARATOR, file);
423 fd = open (full_path, O_CREAT | O_EXCL, 0600);
424 if (fd < 0)
425 return 0;
427 close (fd);
428 return 1;
431 #else
433 /* Version using link(), more secure over NFS. */
434 /* See TN 6913-016 for discussion ??? */
437 __gnat_try_lock (char *dir, char *file)
439 char full_path[256];
440 char temp_file[256];
441 struct stat stat_result;
442 int fd;
444 sprintf (full_path, "%s%c%s", dir, DIR_SEPARATOR, file);
445 sprintf (temp_file, "%s%cTMP-%ld-%ld",
446 dir, DIR_SEPARATOR, (long)getpid(), (long)getppid ());
448 /* Create the temporary file and write the process number. */
449 fd = open (temp_file, O_CREAT | O_WRONLY, 0600);
450 if (fd < 0)
451 return 0;
453 close (fd);
455 /* Link it with the new file. */
456 link (temp_file, full_path);
458 /* Count the references on the old one. If we have a count of two, then
459 the link did succeed. Remove the temporary file before returning. */
460 __gnat_stat (temp_file, &stat_result);
461 unlink (temp_file);
462 return stat_result.st_nlink == 2;
464 #endif
466 /* Return the maximum file name length. */
469 __gnat_get_maximum_file_name_length (void)
471 #if defined (MSDOS)
472 return 8;
473 #elif defined (VMS)
474 if (getenv ("GNAT$EXTENDED_FILE_SPECIFICATIONS"))
475 return -1;
476 else
477 return 39;
478 #else
479 return -1;
480 #endif
483 /* Return nonzero if file names are case sensitive. */
486 __gnat_get_file_names_case_sensitive (void)
488 #if defined (__EMX__) || defined (MSDOS) || defined (VMS) || defined (WINNT)
489 return 0;
490 #else
491 return 1;
492 #endif
495 char
496 __gnat_get_default_identifier_character_set (void)
498 #if defined (__EMX__) || defined (MSDOS)
499 return 'p';
500 #else
501 return '1';
502 #endif
505 /* Return the current working directory. */
507 void
508 __gnat_get_current_dir (char *dir, int *length)
510 #ifdef VMS
511 /* Force Unix style, which is what GNAT uses internally. */
512 getcwd (dir, *length, 0);
513 #else
514 getcwd (dir, *length);
515 #endif
517 *length = strlen (dir);
519 if (dir [*length - 1] != DIR_SEPARATOR)
521 dir [*length] = DIR_SEPARATOR;
522 ++(*length);
524 dir[*length] = '\0';
527 /* Return the suffix for object files. */
529 void
530 __gnat_get_object_suffix_ptr (int *len, const char **value)
532 *value = HOST_OBJECT_SUFFIX;
534 if (*value == 0)
535 *len = 0;
536 else
537 *len = strlen (*value);
539 return;
542 /* Return the suffix for executable files. */
544 void
545 __gnat_get_executable_suffix_ptr (int *len, const char **value)
547 *value = HOST_EXECUTABLE_SUFFIX;
548 if (!*value)
549 *len = 0;
550 else
551 *len = strlen (*value);
553 return;
556 /* Return the suffix for debuggable files. Usually this is the same as the
557 executable extension. */
559 void
560 __gnat_get_debuggable_suffix_ptr (int *len, const char **value)
562 #ifndef MSDOS
563 *value = HOST_EXECUTABLE_SUFFIX;
564 #else
565 /* On DOS, the extensionless COFF file is what gdb likes. */
566 *value = "";
567 #endif
569 if (*value == 0)
570 *len = 0;
571 else
572 *len = strlen (*value);
574 return;
578 __gnat_open_read (char *path, int fmode)
580 int fd;
581 int o_fmode = O_BINARY;
583 if (fmode)
584 o_fmode = O_TEXT;
586 #if defined (VMS)
587 /* Optional arguments mbc,deq,fop increase read performance. */
588 fd = open (path, O_RDONLY | o_fmode, 0444,
589 "mbc=16", "deq=64", "fop=tef");
590 #elif defined (__vxworks)
591 fd = open (path, O_RDONLY | o_fmode, 0444);
592 #else
593 fd = open (path, O_RDONLY | o_fmode);
594 #endif
596 return fd < 0 ? -1 : fd;
599 #if defined (__EMX__) || defined (__MINGW32__)
600 #define PERM (S_IREAD | S_IWRITE)
601 #elif defined (VMS)
602 /* Excerpt from DECC C RTL Reference Manual:
603 To create files with OpenVMS RMS default protections using the UNIX
604 system-call functions umask, mkdir, creat, and open, call mkdir, creat,
605 and open with a file-protection mode argument of 0777 in a program
606 that never specifically calls umask. These default protections include
607 correctly establishing protections based on ACLs, previous versions of
608 files, and so on. */
609 #define PERM 0777
610 #else
611 #define PERM (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH)
612 #endif
615 __gnat_open_rw (char *path, int fmode)
617 int fd;
618 int o_fmode = O_BINARY;
620 if (fmode)
621 o_fmode = O_TEXT;
623 #if defined (VMS)
624 fd = open (path, O_RDWR | o_fmode, PERM,
625 "mbc=16", "deq=64", "fop=tef");
626 #else
627 fd = open (path, O_RDWR | o_fmode, PERM);
628 #endif
630 return fd < 0 ? -1 : fd;
634 __gnat_open_create (char *path, int fmode)
636 int fd;
637 int o_fmode = O_BINARY;
639 if (fmode)
640 o_fmode = O_TEXT;
642 #if defined (VMS)
643 fd = open (path, O_WRONLY | O_CREAT | O_TRUNC | o_fmode, PERM,
644 "mbc=16", "deq=64", "fop=tef");
645 #else
646 fd = open (path, O_WRONLY | O_CREAT | O_TRUNC | o_fmode, PERM);
647 #endif
649 return fd < 0 ? -1 : fd;
653 __gnat_create_output_file (char *path)
655 int fd;
656 #if defined (VMS)
657 fd = open (path, O_WRONLY | O_CREAT | O_TRUNC | O_TEXT, PERM,
658 "rfm=stmlf", "ctx=rec", "rat=none", "rop=nlk",
659 "shr=del,get,put,upd");
660 #else
661 fd = open (path, O_WRONLY | O_CREAT | O_TRUNC | O_TEXT, PERM);
662 #endif
664 return fd < 0 ? -1 : fd;
668 __gnat_open_append (char *path, int fmode)
670 int fd;
671 int o_fmode = O_BINARY;
673 if (fmode)
674 o_fmode = O_TEXT;
676 #if defined (VMS)
677 fd = open (path, O_WRONLY | O_CREAT | O_APPEND | o_fmode, PERM,
678 "mbc=16", "deq=64", "fop=tef");
679 #else
680 fd = open (path, O_WRONLY | O_CREAT | O_APPEND | o_fmode, PERM);
681 #endif
683 return fd < 0 ? -1 : fd;
686 /* Open a new file. Return error (-1) if the file already exists. */
689 __gnat_open_new (char *path, int fmode)
691 int fd;
692 int o_fmode = O_BINARY;
694 if (fmode)
695 o_fmode = O_TEXT;
697 #if defined (VMS)
698 fd = open (path, O_WRONLY | O_CREAT | O_EXCL | o_fmode, PERM,
699 "mbc=16", "deq=64", "fop=tef");
700 #else
701 fd = open (path, O_WRONLY | O_CREAT | O_EXCL | o_fmode, PERM);
702 #endif
704 return fd < 0 ? -1 : fd;
707 /* Open a new temp file. Return error (-1) if the file already exists.
708 Special options for VMS allow the file to be shared between parent and child
709 processes, however they really slow down output. Used in gnatchop. */
712 __gnat_open_new_temp (char *path, int fmode)
714 int fd;
715 int o_fmode = O_BINARY;
717 strcpy (path, "GNAT-XXXXXX");
719 #if (defined (__FreeBSD__) || defined (linux)) && !defined (__vxworks)
720 return mkstemp (path);
721 #elif defined (__Lynx__)
722 mktemp (path);
723 #else
724 if (mktemp (path) == NULL)
725 return -1;
726 #endif
728 if (fmode)
729 o_fmode = O_TEXT;
731 #if defined (VMS)
732 fd = open (path, O_WRONLY | O_CREAT | O_EXCL | o_fmode, PERM,
733 "rfm=stmlf", "ctx=rec", "rat=none", "shr=del,get,put,upd",
734 "mbc=16", "deq=64", "fop=tef");
735 #else
736 fd = open (path, O_WRONLY | O_CREAT | O_EXCL | o_fmode, PERM);
737 #endif
739 return fd < 0 ? -1 : fd;
742 /* Return the number of bytes in the specified file. */
744 long
745 __gnat_file_length (int fd)
747 int ret;
748 struct stat statbuf;
750 ret = fstat (fd, &statbuf);
751 if (ret || !S_ISREG (statbuf.st_mode))
752 return 0;
754 return (statbuf.st_size);
757 /* Return the number of bytes in the specified named file. */
759 long
760 __gnat_named_file_length (char *name)
762 int ret;
763 struct stat statbuf;
765 ret = __gnat_stat (name, &statbuf);
766 if (ret || !S_ISREG (statbuf.st_mode))
767 return 0;
769 return (statbuf.st_size);
772 /* Create a temporary filename and put it in string pointed to by
773 TMP_FILENAME. */
775 void
776 __gnat_tmp_name (char *tmp_filename)
778 #ifdef __MINGW32__
780 char *pname;
782 /* tempnam tries to create a temporary file in directory pointed to by
783 TMP environment variable, in c:\temp if TMP is not set, and in
784 directory specified by P_tmpdir in stdio.h if c:\temp does not
785 exist. The filename will be created with the prefix "gnat-". */
787 pname = (char *) tempnam ("c:\\temp", "gnat-");
789 /* if pname is NULL, the file was not created properly, the disk is full
790 or there is no more free temporary files */
792 if (pname == NULL)
793 *tmp_filename = '\0';
795 /* If pname start with a back slash and not path information it means that
796 the filename is valid for the current working directory. */
798 else if (pname[0] == '\\')
800 strcpy (tmp_filename, ".\\");
801 strcat (tmp_filename, pname+1);
803 else
804 strcpy (tmp_filename, pname);
806 free (pname);
809 #elif defined (linux) || defined (__FreeBSD__)
810 #define MAX_SAFE_PATH 1000
811 char *tmpdir = getenv ("TMPDIR");
813 /* If tmpdir is longer than MAX_SAFE_PATH, revert to default value to avoid
814 a buffer overflow. */
815 if (tmpdir == NULL || strlen (tmpdir) > MAX_SAFE_PATH)
816 strcpy (tmp_filename, "/tmp/gnat-XXXXXX");
817 else
818 sprintf (tmp_filename, "%s/gnat-XXXXXX", tmpdir);
820 close (mkstemp(tmp_filename));
821 #else
822 tmpnam (tmp_filename);
823 #endif
826 /* Read the next entry in a directory. The returned string points somewhere
827 in the buffer. */
829 char *
830 __gnat_readdir (DIR *dirp, char *buffer)
832 /* If possible, try to use the thread-safe version. */
833 #ifdef HAVE_READDIR_R
834 if (readdir_r (dirp, buffer) != NULL)
835 return ((struct dirent*) buffer)->d_name;
836 else
837 return NULL;
839 #else
840 struct dirent *dirent = (struct dirent *) readdir (dirp);
842 if (dirent != NULL)
844 strcpy (buffer, dirent->d_name);
845 return buffer;
847 else
848 return NULL;
850 #endif
853 /* Returns 1 if readdir is thread safe, 0 otherwise. */
856 __gnat_readdir_is_thread_safe (void)
858 #ifdef HAVE_READDIR_R
859 return 1;
860 #else
861 return 0;
862 #endif
865 #ifdef _WIN32
866 /* Number of seconds between <Jan 1st 1601> and <Jan 1st 1970>. */
867 static const unsigned long long w32_epoch_offset = 11644473600ULL;
869 /* Returns the file modification timestamp using Win32 routines which are
870 immune against daylight saving time change. It is in fact not possible to
871 use fstat for this purpose as the DST modify the st_mtime field of the
872 stat structure. */
874 static time_t
875 win32_filetime (HANDLE h)
877 union
879 FILETIME ft_time;
880 unsigned long long ull_time;
881 } t_write;
883 /* GetFileTime returns FILETIME data which are the number of 100 nanosecs
884 since <Jan 1st 1601>. This function must return the number of seconds
885 since <Jan 1st 1970>. */
887 if (GetFileTime (h, NULL, NULL, &t_write.ft_time))
888 return (time_t) (t_write.ull_time / 10000000ULL
889 - w32_epoch_offset);
890 return (time_t) 0;
892 #endif
894 /* Return a GNAT time stamp given a file name. */
896 OS_Time
897 __gnat_file_time_name (char *name)
900 #if defined (__EMX__) || defined (MSDOS)
901 int fd = open (name, O_RDONLY | O_BINARY);
902 time_t ret = __gnat_file_time_fd (fd);
903 close (fd);
904 return (OS_Time)ret;
906 #elif defined (_WIN32)
907 time_t ret = 0;
908 HANDLE h = CreateFile (name, GENERIC_READ, FILE_SHARE_READ, 0,
909 OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0);
911 if (h != INVALID_HANDLE_VALUE)
913 ret = win32_filetime (h);
914 CloseHandle (h);
916 return (OS_Time) ret;
917 #else
918 struct stat statbuf;
919 if (__gnat_stat (name, &statbuf) != 0) {
920 return (OS_Time)-1;
921 } else {
922 #ifdef VMS
923 /* VMS has file versioning. */
924 return (OS_Time)statbuf.st_ctime;
925 #else
926 return (OS_Time)statbuf.st_mtime;
927 #endif
929 #endif
932 /* Return a GNAT time stamp given a file descriptor. */
934 OS_Time
935 __gnat_file_time_fd (int fd)
937 /* The following workaround code is due to the fact that under EMX and
938 DJGPP fstat attempts to convert time values to GMT rather than keep the
939 actual OS timestamp of the file. By using the OS2/DOS functions directly
940 the GNAT timestamp are independent of this behavior, which is desired to
941 facilitate the distribution of GNAT compiled libraries. */
943 #if defined (__EMX__) || defined (MSDOS)
944 #ifdef __EMX__
946 FILESTATUS fs;
947 int ret = DosQueryFileInfo (fd, 1, (unsigned char *) &fs,
948 sizeof (FILESTATUS));
950 unsigned file_year = fs.fdateLastWrite.year;
951 unsigned file_month = fs.fdateLastWrite.month;
952 unsigned file_day = fs.fdateLastWrite.day;
953 unsigned file_hour = fs.ftimeLastWrite.hours;
954 unsigned file_min = fs.ftimeLastWrite.minutes;
955 unsigned file_tsec = fs.ftimeLastWrite.twosecs;
957 #else
958 struct ftime fs;
959 int ret = getftime (fd, &fs);
961 unsigned file_year = fs.ft_year;
962 unsigned file_month = fs.ft_month;
963 unsigned file_day = fs.ft_day;
964 unsigned file_hour = fs.ft_hour;
965 unsigned file_min = fs.ft_min;
966 unsigned file_tsec = fs.ft_tsec;
967 #endif
969 /* Calculate the seconds since epoch from the time components. First count
970 the whole days passed. The value for years returned by the DOS and OS2
971 functions count years from 1980, so to compensate for the UNIX epoch which
972 begins in 1970 start with 10 years worth of days and add days for each
973 four year period since then. */
975 time_t tot_secs;
976 int cum_days[12] = {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334};
977 int days_passed = 3652 + (file_year / 4) * 1461;
978 int years_since_leap = file_year % 4;
980 if (years_since_leap == 1)
981 days_passed += 366;
982 else if (years_since_leap == 2)
983 days_passed += 731;
984 else if (years_since_leap == 3)
985 days_passed += 1096;
987 if (file_year > 20)
988 days_passed -= 1;
990 days_passed += cum_days[file_month - 1];
991 if (years_since_leap == 0 && file_year != 20 && file_month > 2)
992 days_passed++;
994 days_passed += file_day - 1;
996 /* OK - have whole days. Multiply -- then add in other parts. */
998 tot_secs = days_passed * 86400;
999 tot_secs += file_hour * 3600;
1000 tot_secs += file_min * 60;
1001 tot_secs += file_tsec * 2;
1002 return (OS_Time) tot_secs;
1004 #elif defined (_WIN32)
1005 HANDLE h = (HANDLE) _get_osfhandle (fd);
1006 time_t ret = win32_filetime (h);
1007 return (OS_Time) ret;
1009 #else
1010 struct stat statbuf;
1012 if (fstat (fd, &statbuf) != 0) {
1013 return (OS_Time) -1;
1014 } else {
1015 #ifdef VMS
1016 /* VMS has file versioning. */
1017 return (OS_Time) statbuf.st_ctime;
1018 #else
1019 return (OS_Time) statbuf.st_mtime;
1020 #endif
1022 #endif
1025 /* Set the file time stamp. */
1027 void
1028 __gnat_set_file_time_name (char *name, time_t time_stamp)
1030 #if defined (__EMX__) || defined (MSDOS) || defined (__vxworks)
1032 /* Code to implement __gnat_set_file_time_name for these systems. */
1034 #elif defined (_WIN32)
1035 union
1037 FILETIME ft_time;
1038 unsigned long long ull_time;
1039 } t_write;
1041 HANDLE h = CreateFile (name, GENERIC_WRITE, FILE_SHARE_WRITE, NULL,
1042 OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS,
1043 NULL);
1044 if (h == INVALID_HANDLE_VALUE)
1045 return;
1046 /* Add number of seconds between <Jan 1st 1601> and <Jan 1st 1970> */
1047 t_write.ull_time = ((unsigned long long)time_stamp + w32_epoch_offset);
1048 /* Convert to 100 nanosecond units */
1049 t_write.ull_time *= 10000000ULL;
1051 SetFileTime(h, NULL, NULL, &t_write.ft_time);
1052 CloseHandle (h);
1053 return;
1055 #elif defined (VMS)
1056 struct FAB fab;
1057 struct NAM nam;
1059 struct
1061 unsigned long long backup, create, expire, revise;
1062 unsigned long uic;
1063 union
1065 unsigned short value;
1066 struct
1068 unsigned system : 4;
1069 unsigned owner : 4;
1070 unsigned group : 4;
1071 unsigned world : 4;
1072 } bits;
1073 } prot;
1074 } Fat = { 0, 0, 0, 0, 0, { 0 }};
1076 ATRDEF atrlst[]
1078 { ATR$S_CREDATE, ATR$C_CREDATE, &Fat.create },
1079 { ATR$S_REVDATE, ATR$C_REVDATE, &Fat.revise },
1080 { ATR$S_EXPDATE, ATR$C_EXPDATE, &Fat.expire },
1081 { ATR$S_BAKDATE, ATR$C_BAKDATE, &Fat.backup },
1082 { ATR$S_FPRO, ATR$C_FPRO, &Fat.prot },
1083 { ATR$S_UIC, ATR$C_UIC, &Fat.uic },
1084 { 0, 0, 0}
1087 FIBDEF fib;
1088 struct dsc$descriptor_fib fibdsc = {sizeof (fib), (void *) &fib};
1090 struct IOSB iosb;
1092 unsigned long long newtime;
1093 unsigned long long revtime;
1094 long status;
1095 short chan;
1097 struct vstring file;
1098 struct dsc$descriptor_s filedsc
1099 = {NAM$C_MAXRSS, DSC$K_DTYPE_T, DSC$K_CLASS_S, (void *) file.string};
1100 struct vstring device;
1101 struct dsc$descriptor_s devicedsc
1102 = {NAM$C_MAXRSS, DSC$K_DTYPE_T, DSC$K_CLASS_S, (void *) device.string};
1103 struct vstring timev;
1104 struct dsc$descriptor_s timedsc
1105 = {NAM$C_MAXRSS, DSC$K_DTYPE_T, DSC$K_CLASS_S, (void *) timev.string};
1106 struct vstring result;
1107 struct dsc$descriptor_s resultdsc
1108 = {NAM$C_MAXRSS, DSC$K_DTYPE_VT, DSC$K_CLASS_VS, (void *) result.string};
1110 tryfile = (char *) __gnat_to_host_dir_spec (name, 0);
1112 /* Allocate and initialize a FAB and NAM structures. */
1113 fab = cc$rms_fab;
1114 nam = cc$rms_nam;
1116 nam.nam$l_esa = file.string;
1117 nam.nam$b_ess = NAM$C_MAXRSS;
1118 nam.nam$l_rsa = result.string;
1119 nam.nam$b_rss = NAM$C_MAXRSS;
1120 fab.fab$l_fna = tryfile;
1121 fab.fab$b_fns = strlen (tryfile);
1122 fab.fab$l_nam = &nam;
1124 /* Validate filespec syntax and device existence. */
1125 status = SYS$PARSE (&fab, 0, 0);
1126 if ((status & 1) != 1)
1127 LIB$SIGNAL (status);
1129 file.string[nam.nam$b_esl] = 0;
1131 /* Find matching filespec. */
1132 status = SYS$SEARCH (&fab, 0, 0);
1133 if ((status & 1) != 1)
1134 LIB$SIGNAL (status);
1136 file.string[nam.nam$b_esl] = 0;
1137 result.string[result.length=nam.nam$b_rsl] = 0;
1139 /* Get the device name and assign an IO channel. */
1140 strncpy (device.string, nam.nam$l_dev, nam.nam$b_dev);
1141 devicedsc.dsc$w_length = nam.nam$b_dev;
1142 chan = 0;
1143 status = SYS$ASSIGN (&devicedsc, &chan, 0, 0, 0);
1144 if ((status & 1) != 1)
1145 LIB$SIGNAL (status);
1147 /* Initialize the FIB and fill in the directory id field. */
1148 memset (&fib, 0, sizeof (fib));
1149 fib.fib$w_did[0] = nam.nam$w_did[0];
1150 fib.fib$w_did[1] = nam.nam$w_did[1];
1151 fib.fib$w_did[2] = nam.nam$w_did[2];
1152 fib.fib$l_acctl = 0;
1153 fib.fib$l_wcc = 0;
1154 strcpy (file.string, (strrchr (result.string, ']') + 1));
1155 filedsc.dsc$w_length = strlen (file.string);
1156 result.string[result.length = 0] = 0;
1158 /* Open and close the file to fill in the attributes. */
1159 status
1160 = SYS$QIOW (0, chan, IO$_ACCESS|IO$M_ACCESS, &iosb, 0, 0,
1161 &fibdsc, &filedsc, &result.length, &resultdsc, &atrlst, 0);
1162 if ((status & 1) != 1)
1163 LIB$SIGNAL (status);
1164 if ((iosb.status & 1) != 1)
1165 LIB$SIGNAL (iosb.status);
1167 result.string[result.length] = 0;
1168 status = SYS$QIOW (0, chan, IO$_DEACCESS, &iosb, 0, 0, &fibdsc, 0, 0, 0,
1169 &atrlst, 0);
1170 if ((status & 1) != 1)
1171 LIB$SIGNAL (status);
1172 if ((iosb.status & 1) != 1)
1173 LIB$SIGNAL (iosb.status);
1176 time_t t;
1178 /* Set creation time to requested time. */
1179 unix_time_to_vms (time_stamp, newtime);
1181 t = time ((time_t) 0);
1183 /* Set revision time to now in local time. */
1184 unix_time_to_vms (t, revtime);
1187 /* Reopen the file, modify the times and then close. */
1188 fib.fib$l_acctl = FIB$M_WRITE;
1189 status
1190 = SYS$QIOW (0, chan, IO$_ACCESS|IO$M_ACCESS, &iosb, 0, 0,
1191 &fibdsc, &filedsc, &result.length, &resultdsc, &atrlst, 0);
1192 if ((status & 1) != 1)
1193 LIB$SIGNAL (status);
1194 if ((iosb.status & 1) != 1)
1195 LIB$SIGNAL (iosb.status);
1197 Fat.create = newtime;
1198 Fat.revise = revtime;
1200 status = SYS$QIOW (0, chan, IO$_DEACCESS, &iosb, 0, 0,
1201 &fibdsc, 0, 0, 0, &atrlst, 0);
1202 if ((status & 1) != 1)
1203 LIB$SIGNAL (status);
1204 if ((iosb.status & 1) != 1)
1205 LIB$SIGNAL (iosb.status);
1207 /* Deassign the channel and exit. */
1208 status = SYS$DASSGN (chan);
1209 if ((status & 1) != 1)
1210 LIB$SIGNAL (status);
1211 #else
1212 struct utimbuf utimbuf;
1213 time_t t;
1215 /* Set modification time to requested time. */
1216 utimbuf.modtime = time_stamp;
1218 /* Set access time to now in local time. */
1219 t = time ((time_t) 0);
1220 utimbuf.actime = mktime (localtime (&t));
1222 utime (name, &utimbuf);
1223 #endif
1226 void
1227 __gnat_get_env_value_ptr (char *name, int *len, char **value)
1229 *value = getenv (name);
1230 if (!*value)
1231 *len = 0;
1232 else
1233 *len = strlen (*value);
1235 return;
1238 /* VMS specific declarations for set_env_value. */
1240 #ifdef VMS
1242 static char *to_host_path_spec (char *);
1244 struct descriptor_s
1246 unsigned short len, mbz;
1247 __char_ptr32 adr;
1250 typedef struct _ile3
1252 unsigned short len, code;
1253 __char_ptr32 adr;
1254 unsigned short *retlen_adr;
1255 } ile_s;
1257 #endif
1259 void
1260 __gnat_set_env_value (char *name, char *value)
1262 #ifdef MSDOS
1264 #elif defined (VMS)
1265 struct descriptor_s name_desc;
1266 /* Put in JOB table for now, so that the project stuff at least works. */
1267 struct descriptor_s table_desc = {7, 0, "LNM$JOB"};
1268 char *host_pathspec = value;
1269 char *copy_pathspec;
1270 int num_dirs_in_pathspec = 1;
1271 char *ptr;
1272 long status;
1274 name_desc.len = strlen (name);
1275 name_desc.mbz = 0;
1276 name_desc.adr = name;
1278 if (*host_pathspec == 0)
1279 /* deassign */
1281 status = LIB$DELETE_LOGICAL (&name_desc, &table_desc);
1282 /* no need to check status; if the logical name is not
1283 defined, that's fine. */
1284 return;
1287 ptr = host_pathspec;
1288 while (*ptr++)
1289 if (*ptr == ',')
1290 num_dirs_in_pathspec++;
1293 int i, status;
1294 ile_s *ile_array = alloca (sizeof (ile_s) * (num_dirs_in_pathspec + 1));
1295 char *copy_pathspec = alloca (strlen (host_pathspec) + 1);
1296 char *curr, *next;
1298 strcpy (copy_pathspec, host_pathspec);
1299 curr = copy_pathspec;
1300 for (i = 0; i < num_dirs_in_pathspec; i++)
1302 next = strchr (curr, ',');
1303 if (next == 0)
1304 next = strchr (curr, 0);
1306 *next = 0;
1307 ile_array[i].len = strlen (curr);
1309 /* Code 2 from lnmdef.h means its a string. */
1310 ile_array[i].code = 2;
1311 ile_array[i].adr = curr;
1313 /* retlen_adr is ignored. */
1314 ile_array[i].retlen_adr = 0;
1315 curr = next + 1;
1318 /* Terminating item must be zero. */
1319 ile_array[i].len = 0;
1320 ile_array[i].code = 0;
1321 ile_array[i].adr = 0;
1322 ile_array[i].retlen_adr = 0;
1324 status = LIB$SET_LOGICAL (&name_desc, 0, &table_desc, 0, ile_array);
1325 if ((status & 1) != 1)
1326 LIB$SIGNAL (status);
1329 #else
1330 int size = strlen (name) + strlen (value) + 2;
1331 char *expression;
1333 expression = (char *) xmalloc (size * sizeof (char));
1335 sprintf (expression, "%s=%s", name, value);
1336 putenv (expression);
1337 #endif
1340 #ifdef _WIN32
1341 #include <windows.h>
1342 #endif
1344 /* Get the list of installed standard libraries from the
1345 HKEY_LOCAL_MACHINE\SOFTWARE\Ada Core Technologies\GNAT\Standard Libraries
1346 key. */
1348 char *
1349 __gnat_get_libraries_from_registry (void)
1351 char *result = (char *) "";
1353 #if defined (_WIN32) && ! defined (__vxworks) && ! defined (CROSS_COMPILE)
1355 HKEY reg_key;
1356 DWORD name_size, value_size;
1357 char name[256];
1358 char value[256];
1359 DWORD type;
1360 DWORD index;
1361 LONG res;
1363 /* First open the key. */
1364 res = RegOpenKeyExA (HKEY_LOCAL_MACHINE, "SOFTWARE", 0, KEY_READ, &reg_key);
1366 if (res == ERROR_SUCCESS)
1367 res = RegOpenKeyExA (reg_key, "Ada Core Technologies", 0,
1368 KEY_READ, &reg_key);
1370 if (res == ERROR_SUCCESS)
1371 res = RegOpenKeyExA (reg_key, "GNAT", 0, KEY_READ, &reg_key);
1373 if (res == ERROR_SUCCESS)
1374 res = RegOpenKeyExA (reg_key, "Standard Libraries", 0, KEY_READ, &reg_key);
1376 /* If the key exists, read out all the values in it and concatenate them
1377 into a path. */
1378 for (index = 0; res == ERROR_SUCCESS; index++)
1380 value_size = name_size = 256;
1381 res = RegEnumValue (reg_key, index, name, &name_size, 0,
1382 &type, (LPBYTE)value, &value_size);
1384 if (res == ERROR_SUCCESS && type == REG_SZ)
1386 char *old_result = result;
1388 result = (char *) xmalloc (strlen (old_result) + value_size + 2);
1389 strcpy (result, old_result);
1390 strcat (result, value);
1391 strcat (result, ";");
1395 /* Remove the trailing ";". */
1396 if (result[0] != 0)
1397 result[strlen (result) - 1] = 0;
1399 #endif
1400 return result;
1404 __gnat_stat (char *name, struct stat *statbuf)
1406 #ifdef _WIN32
1407 /* Under Windows the directory name for the stat function must not be
1408 terminated by a directory separator except if just after a drive name. */
1409 int name_len = strlen (name);
1410 char last_char = name[name_len - 1];
1411 char win32_name[GNAT_MAX_PATH_LEN + 2];
1413 if (name_len > GNAT_MAX_PATH_LEN)
1414 return -1;
1416 strcpy (win32_name, name);
1418 while (name_len > 1 && (last_char == '\\' || last_char == '/'))
1420 win32_name[name_len - 1] = '\0';
1421 name_len--;
1422 last_char = win32_name[name_len - 1];
1425 if (name_len == 2 && win32_name[1] == ':')
1426 strcat (win32_name, "\\");
1428 return stat (win32_name, statbuf);
1430 #else
1431 return stat (name, statbuf);
1432 #endif
1436 __gnat_file_exists (char *name)
1438 struct stat statbuf;
1440 return !__gnat_stat (name, &statbuf);
1444 __gnat_is_absolute_path (char *name, int length)
1446 return (length != 0) &&
1447 (*name == '/' || *name == DIR_SEPARATOR
1448 #if defined (__EMX__) || defined (MSDOS) || defined (WINNT)
1449 || (length > 1 && isalpha (name[0]) && name[1] == ':')
1450 #endif
1455 __gnat_is_regular_file (char *name)
1457 int ret;
1458 struct stat statbuf;
1460 ret = __gnat_stat (name, &statbuf);
1461 return (!ret && S_ISREG (statbuf.st_mode));
1465 __gnat_is_directory (char *name)
1467 int ret;
1468 struct stat statbuf;
1470 ret = __gnat_stat (name, &statbuf);
1471 return (!ret && S_ISDIR (statbuf.st_mode));
1475 __gnat_is_readable_file (char *name)
1477 int ret;
1478 int mode;
1479 struct stat statbuf;
1481 ret = __gnat_stat (name, &statbuf);
1482 mode = statbuf.st_mode & S_IRUSR;
1483 return (!ret && mode);
1487 __gnat_is_writable_file (char *name)
1489 int ret;
1490 int mode;
1491 struct stat statbuf;
1493 ret = __gnat_stat (name, &statbuf);
1494 mode = statbuf.st_mode & S_IWUSR;
1495 return (!ret && mode);
1498 void
1499 __gnat_set_writable (char *name)
1501 #ifndef __vxworks
1502 struct stat statbuf;
1504 if (stat (name, &statbuf) == 0)
1506 statbuf.st_mode = statbuf.st_mode | S_IWUSR;
1507 chmod (name, statbuf.st_mode);
1509 #endif
1512 void
1513 __gnat_set_executable (char *name)
1515 #ifndef __vxworks
1516 struct stat statbuf;
1518 if (stat (name, &statbuf) == 0)
1520 statbuf.st_mode = statbuf.st_mode | S_IXUSR;
1521 chmod (name, statbuf.st_mode);
1523 #endif
1526 void
1527 __gnat_set_readonly (char *name)
1529 #ifndef __vxworks
1530 struct stat statbuf;
1532 if (stat (name, &statbuf) == 0)
1534 statbuf.st_mode = statbuf.st_mode & 07577;
1535 chmod (name, statbuf.st_mode);
1537 #endif
1541 __gnat_is_symbolic_link (char *name ATTRIBUTE_UNUSED)
1543 #if defined (__vxworks)
1544 return 0;
1546 #elif defined (_AIX) || defined (__APPLE__) || defined (__unix__)
1547 int ret;
1548 struct stat statbuf;
1550 ret = lstat (name, &statbuf);
1551 return (!ret && S_ISLNK (statbuf.st_mode));
1553 #else
1554 return 0;
1555 #endif
1558 #if defined (sun) && defined (__SVR4)
1559 /* Using fork on Solaris will duplicate all the threads. fork1, which
1560 duplicates only the active thread, must be used instead, or spawning
1561 subprocess from a program with tasking will lead into numerous problems. */
1562 #define fork fork1
1563 #endif
1566 __gnat_portable_spawn (char *args[])
1568 int status = 0;
1569 int finished ATTRIBUTE_UNUSED;
1570 int pid ATTRIBUTE_UNUSED;
1572 #if defined (MSDOS) || defined (_WIN32)
1573 /* args[0] must be quotes as it could contain a full pathname with spaces */
1574 char *args_0 = args[0];
1575 args[0] = (char *)xmalloc (strlen (args_0) + 3);
1576 strcpy (args[0], "\"");
1577 strcat (args[0], args_0);
1578 strcat (args[0], "\"");
1580 status = spawnvp (P_WAIT, args_0, (char* const*)args);
1582 /* restore previous value */
1583 free (args[0]);
1584 args[0] = (char *)args_0;
1586 if (status < 0)
1587 return -1;
1588 else
1589 return status;
1591 #elif defined (__vxworks)
1592 return -1;
1593 #else
1595 #ifdef __EMX__
1596 pid = spawnvp (P_NOWAIT, args[0], args);
1597 if (pid == -1)
1598 return -1;
1600 #else
1601 pid = fork ();
1602 if (pid < 0)
1603 return -1;
1605 if (pid == 0)
1607 /* The child. */
1608 if (execv (args[0], MAYBE_TO_PTR32 (args)) != 0)
1609 #if defined (VMS)
1610 return -1; /* execv is in parent context on VMS. */
1611 #else
1612 _exit (1);
1613 #endif
1615 #endif
1617 /* The parent. */
1618 finished = waitpid (pid, &status, 0);
1620 if (finished != pid || WIFEXITED (status) == 0)
1621 return -1;
1623 return WEXITSTATUS (status);
1624 #endif
1626 return 0;
1629 /* Create a copy of the given file descriptor.
1630 Return -1 if an error occurred. */
1633 __gnat_dup (int oldfd)
1635 #if defined (__vxworks)
1636 /* Not supported on VxWorks. */
1637 return -1;
1638 #else
1639 return dup (oldfd);
1640 #endif
1643 /* Make newfd be the copy of oldfd, closing newfd first if necessary.
1644 Return -1 if an error occured. */
1647 __gnat_dup2 (int oldfd, int newfd)
1649 #if defined (__vxworks)
1650 /* Not supported on VxWorks. */
1651 return -1;
1652 #else
1653 return dup2 (oldfd, newfd);
1654 #endif
1657 /* WIN32 code to implement a wait call that wait for any child process. */
1659 #ifdef _WIN32
1661 /* Synchronization code, to be thread safe. */
1663 static CRITICAL_SECTION plist_cs;
1665 void
1666 __gnat_plist_init (void)
1668 InitializeCriticalSection (&plist_cs);
1671 static void
1672 plist_enter (void)
1674 EnterCriticalSection (&plist_cs);
1677 static void
1678 plist_leave (void)
1680 LeaveCriticalSection (&plist_cs);
1683 typedef struct _process_list
1685 HANDLE h;
1686 struct _process_list *next;
1687 } Process_List;
1689 static Process_List *PLIST = NULL;
1691 static int plist_length = 0;
1693 static void
1694 add_handle (HANDLE h)
1696 Process_List *pl;
1698 pl = (Process_List *) xmalloc (sizeof (Process_List));
1700 plist_enter();
1702 /* -------------------- critical section -------------------- */
1703 pl->h = h;
1704 pl->next = PLIST;
1705 PLIST = pl;
1706 ++plist_length;
1707 /* -------------------- critical section -------------------- */
1709 plist_leave();
1712 static void
1713 remove_handle (HANDLE h)
1715 Process_List *pl;
1716 Process_List *prev = NULL;
1718 plist_enter();
1720 /* -------------------- critical section -------------------- */
1721 pl = PLIST;
1722 while (pl)
1724 if (pl->h == h)
1726 if (pl == PLIST)
1727 PLIST = pl->next;
1728 else
1729 prev->next = pl->next;
1730 free (pl);
1731 break;
1733 else
1735 prev = pl;
1736 pl = pl->next;
1740 --plist_length;
1741 /* -------------------- critical section -------------------- */
1743 plist_leave();
1746 static int
1747 win32_no_block_spawn (char *command, char *args[])
1749 BOOL result;
1750 STARTUPINFO SI;
1751 PROCESS_INFORMATION PI;
1752 SECURITY_ATTRIBUTES SA;
1753 int csize = 1;
1754 char *full_command;
1755 int k;
1757 /* compute the total command line length */
1758 k = 0;
1759 while (args[k])
1761 csize += strlen (args[k]) + 1;
1762 k++;
1765 full_command = (char *) xmalloc (csize);
1767 /* Startup info. */
1768 SI.cb = sizeof (STARTUPINFO);
1769 SI.lpReserved = NULL;
1770 SI.lpReserved2 = NULL;
1771 SI.lpDesktop = NULL;
1772 SI.cbReserved2 = 0;
1773 SI.lpTitle = NULL;
1774 SI.dwFlags = 0;
1775 SI.wShowWindow = SW_HIDE;
1777 /* Security attributes. */
1778 SA.nLength = sizeof (SECURITY_ATTRIBUTES);
1779 SA.bInheritHandle = TRUE;
1780 SA.lpSecurityDescriptor = NULL;
1782 /* Prepare the command string. */
1783 strcpy (full_command, command);
1784 strcat (full_command, " ");
1786 k = 1;
1787 while (args[k])
1789 strcat (full_command, args[k]);
1790 strcat (full_command, " ");
1791 k++;
1794 result = CreateProcess
1795 (NULL, (char *) full_command, &SA, NULL, TRUE,
1796 GetPriorityClass (GetCurrentProcess()), NULL, NULL, &SI, &PI);
1798 free (full_command);
1800 if (result == TRUE)
1802 add_handle (PI.hProcess);
1803 CloseHandle (PI.hThread);
1804 return (int) PI.hProcess;
1806 else
1807 return -1;
1810 static int
1811 win32_wait (int *status)
1813 DWORD exitcode;
1814 HANDLE *hl;
1815 HANDLE h;
1816 DWORD res;
1817 int k;
1818 Process_List *pl;
1820 if (plist_length == 0)
1822 errno = ECHILD;
1823 return -1;
1826 hl = (HANDLE *) xmalloc (sizeof (HANDLE) * plist_length);
1828 k = 0;
1829 plist_enter();
1831 /* -------------------- critical section -------------------- */
1832 pl = PLIST;
1833 while (pl)
1835 hl[k++] = pl->h;
1836 pl = pl->next;
1838 /* -------------------- critical section -------------------- */
1840 plist_leave();
1842 res = WaitForMultipleObjects (plist_length, hl, FALSE, INFINITE);
1843 h = hl[res - WAIT_OBJECT_0];
1844 free (hl);
1846 remove_handle (h);
1848 GetExitCodeProcess (h, &exitcode);
1849 CloseHandle (h);
1851 *status = (int) exitcode;
1852 return (int) h;
1855 #endif
1858 __gnat_portable_no_block_spawn (char *args[])
1860 int pid = 0;
1862 #if defined (__EMX__) || defined (MSDOS)
1864 /* ??? For PC machines I (Franco) don't know the system calls to implement
1865 this routine. So I'll fake it as follows. This routine will behave
1866 exactly like the blocking portable_spawn and will systematically return
1867 a pid of 0 unless the spawned task did not complete successfully, in
1868 which case we return a pid of -1. To synchronize with this the
1869 portable_wait below systematically returns a pid of 0 and reports that
1870 the subprocess terminated successfully. */
1872 if (spawnvp (P_WAIT, args[0], args) != 0)
1873 return -1;
1875 #elif defined (_WIN32)
1877 pid = win32_no_block_spawn (args[0], args);
1878 return pid;
1880 #elif defined (__vxworks)
1881 return -1;
1883 #else
1884 pid = fork ();
1886 if (pid == 0)
1888 /* The child. */
1889 if (execv (args[0], MAYBE_TO_PTR32 (args)) != 0)
1890 #if defined (VMS)
1891 return -1; /* execv is in parent context on VMS. */
1892 #else
1893 _exit (1);
1894 #endif
1897 #endif
1899 return pid;
1903 __gnat_portable_wait (int *process_status)
1905 int status = 0;
1906 int pid = 0;
1908 #if defined (_WIN32)
1910 pid = win32_wait (&status);
1912 #elif defined (__EMX__) || defined (MSDOS)
1913 /* ??? See corresponding comment in portable_no_block_spawn. */
1915 #elif defined (__vxworks)
1916 /* Not sure what to do here, so do same as __EMX__ case, i.e., nothing but
1917 return zero. */
1918 #else
1920 pid = waitpid (-1, &status, 0);
1921 status = status & 0xffff;
1922 #endif
1924 *process_status = status;
1925 return pid;
1929 __gnat_waitpid (int pid)
1931 int status = 0;
1933 #if defined (_WIN32)
1934 cwait (&status, pid, _WAIT_CHILD);
1935 #elif defined (__EMX__) || defined (MSDOS) || defined (__vxworks)
1936 /* Status is already zero, so nothing to do. */
1937 #else
1938 waitpid (pid, &status, 0);
1939 status = WEXITSTATUS (status);
1940 #endif
1942 return status;
1945 void
1946 __gnat_os_exit (int status)
1948 exit (status);
1951 /* Locate a regular file, give a Path value. */
1953 char *
1954 __gnat_locate_regular_file (char *file_name, char *path_val)
1956 char *ptr;
1957 int absolute = __gnat_is_absolute_path (file_name, strlen (file_name));
1959 /* Handle absolute pathnames. */
1960 if (absolute)
1962 if (__gnat_is_regular_file (file_name))
1963 return xstrdup (file_name);
1965 return 0;
1968 /* If file_name include directory separator(s), try it first as
1969 a path name relative to the current directory */
1970 for (ptr = file_name; *ptr && *ptr != '/' && *ptr != DIR_SEPARATOR; ptr++)
1973 if (*ptr != 0)
1975 if (__gnat_is_regular_file (file_name))
1976 return xstrdup (file_name);
1979 if (path_val == 0)
1980 return 0;
1983 /* The result has to be smaller than path_val + file_name. */
1984 char *file_path = alloca (strlen (path_val) + strlen (file_name) + 2);
1986 for (;;)
1988 for (; *path_val == PATH_SEPARATOR; path_val++)
1991 if (*path_val == 0)
1992 return 0;
1994 for (ptr = file_path; *path_val && *path_val != PATH_SEPARATOR; )
1995 *ptr++ = *path_val++;
1997 ptr--;
1998 if (*ptr != '/' && *ptr != DIR_SEPARATOR)
1999 *++ptr = DIR_SEPARATOR;
2001 strcpy (++ptr, file_name);
2003 if (__gnat_is_regular_file (file_path))
2004 return xstrdup (file_path);
2008 return 0;
2011 /* Locate an executable given a Path argument. This routine is only used by
2012 gnatbl and should not be used otherwise. Use locate_exec_on_path
2013 instead. */
2015 char *
2016 __gnat_locate_exec (char *exec_name, char *path_val)
2018 if (!strstr (exec_name, HOST_EXECUTABLE_SUFFIX))
2020 char *full_exec_name
2021 = alloca (strlen (exec_name) + strlen (HOST_EXECUTABLE_SUFFIX) + 1);
2023 strcpy (full_exec_name, exec_name);
2024 strcat (full_exec_name, HOST_EXECUTABLE_SUFFIX);
2025 return __gnat_locate_regular_file (full_exec_name, path_val);
2027 else
2028 return __gnat_locate_regular_file (exec_name, path_val);
2031 /* Locate an executable using the Systems default PATH. */
2033 char *
2034 __gnat_locate_exec_on_path (char *exec_name)
2036 char *apath_val;
2037 #ifdef VMS
2038 char *path_val = "/VAXC$PATH";
2039 #else
2040 char *path_val = getenv ("PATH");
2041 #endif
2042 #ifdef _WIN32
2043 /* In Win32 systems we expand the PATH as for XP environment
2044 variables are not automatically expanded. */
2045 int len = strlen (path_val) * 3;
2046 char *expanded_path_val = alloca (len + 1);
2048 DWORD res = ExpandEnvironmentStrings (path_val, expanded_path_val, len);
2050 if (res != 0)
2052 path_val = expanded_path_val;
2054 #endif
2056 apath_val = alloca (strlen (path_val) + 1);
2057 strcpy (apath_val, path_val);
2059 return __gnat_locate_exec (exec_name, apath_val);
2062 #ifdef VMS
2064 /* These functions are used to translate to and from VMS and Unix syntax
2065 file, directory and path specifications. */
2067 #define MAXPATH 256
2068 #define MAXNAMES 256
2069 #define NEW_CANONICAL_FILELIST_INCREMENT 64
2071 static char new_canonical_dirspec [MAXPATH];
2072 static char new_canonical_filespec [MAXPATH];
2073 static char new_canonical_pathspec [MAXNAMES*MAXPATH];
2074 static unsigned new_canonical_filelist_index;
2075 static unsigned new_canonical_filelist_in_use;
2076 static unsigned new_canonical_filelist_allocated;
2077 static char **new_canonical_filelist;
2078 static char new_host_pathspec [MAXNAMES*MAXPATH];
2079 static char new_host_dirspec [MAXPATH];
2080 static char new_host_filespec [MAXPATH];
2082 /* Routine is called repeatedly by decc$from_vms via
2083 __gnat_to_canonical_file_list_init until it returns 0 or the expansion
2084 runs out. */
2086 static int
2087 wildcard_translate_unix (char *name)
2089 char *ver;
2090 char buff [MAXPATH];
2092 strncpy (buff, name, MAXPATH);
2093 buff [MAXPATH - 1] = (char) 0;
2094 ver = strrchr (buff, '.');
2096 /* Chop off the version. */
2097 if (ver)
2098 *ver = 0;
2100 /* Dynamically extend the allocation by the increment. */
2101 if (new_canonical_filelist_in_use == new_canonical_filelist_allocated)
2103 new_canonical_filelist_allocated += NEW_CANONICAL_FILELIST_INCREMENT;
2104 new_canonical_filelist = (char **) xrealloc
2105 (new_canonical_filelist,
2106 new_canonical_filelist_allocated * sizeof (char *));
2109 new_canonical_filelist[new_canonical_filelist_in_use++] = xstrdup (buff);
2111 return 1;
2114 /* Translate a wildcard VMS file spec into a list of Unix file specs. First do
2115 full translation and copy the results into a list (_init), then return them
2116 one at a time (_next). If onlydirs set, only expand directory files. */
2119 __gnat_to_canonical_file_list_init (char *filespec, int onlydirs)
2121 int len;
2122 char buff [MAXPATH];
2124 len = strlen (filespec);
2125 strncpy (buff, filespec, MAXPATH);
2127 /* Only look for directories */
2128 if (onlydirs && !strstr (&buff [len-5], "*.dir"))
2129 strncat (buff, "*.dir", MAXPATH);
2131 buff [MAXPATH - 1] = (char) 0;
2133 decc$from_vms (buff, wildcard_translate_unix, 1);
2135 /* Remove the .dir extension. */
2136 if (onlydirs)
2138 int i;
2139 char *ext;
2141 for (i = 0; i < new_canonical_filelist_in_use; i++)
2143 ext = strstr (new_canonical_filelist[i], ".dir");
2144 if (ext)
2145 *ext = 0;
2149 return new_canonical_filelist_in_use;
2152 /* Return the next filespec in the list. */
2154 char *
2155 __gnat_to_canonical_file_list_next ()
2157 return new_canonical_filelist[new_canonical_filelist_index++];
2160 /* Free storage used in the wildcard expansion. */
2162 void
2163 __gnat_to_canonical_file_list_free ()
2165 int i;
2167 for (i = 0; i < new_canonical_filelist_in_use; i++)
2168 free (new_canonical_filelist[i]);
2170 free (new_canonical_filelist);
2172 new_canonical_filelist_in_use = 0;
2173 new_canonical_filelist_allocated = 0;
2174 new_canonical_filelist_index = 0;
2175 new_canonical_filelist = 0;
2178 /* Translate a VMS syntax directory specification in to Unix syntax. If
2179 PREFIXFLAG is set, append an underscore "/". If no indicators of VMS syntax
2180 found, return input string. Also translate a dirname that contains no
2181 slashes, in case it's a logical name. */
2183 char *
2184 __gnat_to_canonical_dir_spec (char *dirspec, int prefixflag)
2186 int len;
2188 strcpy (new_canonical_dirspec, "");
2189 if (strlen (dirspec))
2191 char *dirspec1;
2193 if (strchr (dirspec, ']') || strchr (dirspec, ':'))
2195 strncpy (new_canonical_dirspec,
2196 (char *) decc$translate_vms (dirspec),
2197 MAXPATH);
2199 else if (!strchr (dirspec, '/') && (dirspec1 = getenv (dirspec)) != 0)
2201 strncpy (new_canonical_dirspec,
2202 (char *) decc$translate_vms (dirspec1),
2203 MAXPATH);
2205 else
2207 strncpy (new_canonical_dirspec, dirspec, MAXPATH);
2211 len = strlen (new_canonical_dirspec);
2212 if (prefixflag && new_canonical_dirspec [len-1] != '/')
2213 strncat (new_canonical_dirspec, "/", MAXPATH);
2215 new_canonical_dirspec [MAXPATH - 1] = (char) 0;
2217 return new_canonical_dirspec;
2221 /* Translate a VMS syntax file specification into Unix syntax.
2222 If no indicators of VMS syntax found, return input string. */
2224 char *
2225 __gnat_to_canonical_file_spec (char *filespec)
2227 strncpy (new_canonical_filespec, "", MAXPATH);
2229 if (strchr (filespec, ']') || strchr (filespec, ':'))
2231 strncpy (new_canonical_filespec,
2232 (char *) decc$translate_vms (filespec),
2233 MAXPATH);
2235 else
2237 strncpy (new_canonical_filespec, filespec, MAXPATH);
2240 new_canonical_filespec [MAXPATH - 1] = (char) 0;
2242 return new_canonical_filespec;
2245 /* Translate a VMS syntax path specification into Unix syntax.
2246 If no indicators of VMS syntax found, return input string. */
2248 char *
2249 __gnat_to_canonical_path_spec (char *pathspec)
2251 char *curr, *next, buff [MAXPATH];
2253 if (pathspec == 0)
2254 return pathspec;
2256 /* If there are /'s, assume it's a Unix path spec and return. */
2257 if (strchr (pathspec, '/'))
2258 return pathspec;
2260 new_canonical_pathspec[0] = 0;
2261 curr = pathspec;
2263 for (;;)
2265 next = strchr (curr, ',');
2266 if (next == 0)
2267 next = strchr (curr, 0);
2269 strncpy (buff, curr, next - curr);
2270 buff[next - curr] = 0;
2272 /* Check for wildcards and expand if present. */
2273 if (strchr (buff, '*') || strchr (buff, '%') || strstr (buff, "..."))
2275 int i, dirs;
2277 dirs = __gnat_to_canonical_file_list_init (buff, 1);
2278 for (i = 0; i < dirs; i++)
2280 char *next_dir;
2282 next_dir = __gnat_to_canonical_file_list_next ();
2283 strncat (new_canonical_pathspec, next_dir, MAXPATH);
2285 /* Don't append the separator after the last expansion. */
2286 if (i+1 < dirs)
2287 strncat (new_canonical_pathspec, ":", MAXPATH);
2290 __gnat_to_canonical_file_list_free ();
2292 else
2293 strncat (new_canonical_pathspec,
2294 __gnat_to_canonical_dir_spec (buff, 0), MAXPATH);
2296 if (*next == 0)
2297 break;
2299 strncat (new_canonical_pathspec, ":", MAXPATH);
2300 curr = next + 1;
2303 new_canonical_pathspec [MAXPATH - 1] = (char) 0;
2305 return new_canonical_pathspec;
2308 static char filename_buff [MAXPATH];
2310 static int
2311 translate_unix (char *name, int type)
2313 strncpy (filename_buff, name, MAXPATH);
2314 filename_buff [MAXPATH - 1] = (char) 0;
2315 return 0;
2318 /* Translate a Unix syntax path spec into a VMS style (comma separated list of
2319 directories. */
2321 static char *
2322 to_host_path_spec (char *pathspec)
2324 char *curr, *next, buff [MAXPATH];
2326 if (pathspec == 0)
2327 return pathspec;
2329 /* Can't very well test for colons, since that's the Unix separator! */
2330 if (strchr (pathspec, ']') || strchr (pathspec, ','))
2331 return pathspec;
2333 new_host_pathspec[0] = 0;
2334 curr = pathspec;
2336 for (;;)
2338 next = strchr (curr, ':');
2339 if (next == 0)
2340 next = strchr (curr, 0);
2342 strncpy (buff, curr, next - curr);
2343 buff[next - curr] = 0;
2345 strncat (new_host_pathspec, __gnat_to_host_dir_spec (buff, 0), MAXPATH);
2346 if (*next == 0)
2347 break;
2348 strncat (new_host_pathspec, ",", MAXPATH);
2349 curr = next + 1;
2352 new_host_pathspec [MAXPATH - 1] = (char) 0;
2354 return new_host_pathspec;
2357 /* Translate a Unix syntax directory specification into VMS syntax. The
2358 PREFIXFLAG has no effect, but is kept for symmetry with
2359 to_canonical_dir_spec. If indicators of VMS syntax found, return input
2360 string. */
2362 char *
2363 __gnat_to_host_dir_spec (char *dirspec, int prefixflag ATTRIBUTE_UNUSED)
2365 int len = strlen (dirspec);
2367 strncpy (new_host_dirspec, dirspec, MAXPATH);
2368 new_host_dirspec [MAXPATH - 1] = (char) 0;
2370 if (strchr (new_host_dirspec, ']') || strchr (new_host_dirspec, ':'))
2371 return new_host_dirspec;
2373 while (len > 1 && new_host_dirspec[len - 1] == '/')
2375 new_host_dirspec[len - 1] = 0;
2376 len--;
2379 decc$to_vms (new_host_dirspec, translate_unix, 1, 2);
2380 strncpy (new_host_dirspec, filename_buff, MAXPATH);
2381 new_host_dirspec [MAXPATH - 1] = (char) 0;
2383 return new_host_dirspec;
2386 /* Translate a Unix syntax file specification into VMS syntax.
2387 If indicators of VMS syntax found, return input string. */
2389 char *
2390 __gnat_to_host_file_spec (char *filespec)
2392 strncpy (new_host_filespec, "", MAXPATH);
2393 if (strchr (filespec, ']') || strchr (filespec, ':'))
2395 strncpy (new_host_filespec, filespec, MAXPATH);
2397 else
2399 decc$to_vms (filespec, translate_unix, 1, 1);
2400 strncpy (new_host_filespec, filename_buff, MAXPATH);
2403 new_host_filespec [MAXPATH - 1] = (char) 0;
2405 return new_host_filespec;
2408 void
2409 __gnat_adjust_os_resource_limits ()
2411 SYS$ADJWSL (131072, 0);
2414 #else /* VMS */
2416 /* Dummy functions for Osint import for non-VMS systems. */
2419 __gnat_to_canonical_file_list_init
2420 (char *dirspec ATTRIBUTE_UNUSED, int onlydirs ATTRIBUTE_UNUSED)
2422 return 0;
2425 char *
2426 __gnat_to_canonical_file_list_next (void)
2428 return (char *) "";
2431 void
2432 __gnat_to_canonical_file_list_free (void)
2436 char *
2437 __gnat_to_canonical_dir_spec (char *dirspec, int prefixflag ATTRIBUTE_UNUSED)
2439 return dirspec;
2442 char *
2443 __gnat_to_canonical_file_spec (char *filespec)
2445 return filespec;
2448 char *
2449 __gnat_to_canonical_path_spec (char *pathspec)
2451 return pathspec;
2454 char *
2455 __gnat_to_host_dir_spec (char *dirspec, int prefixflag ATTRIBUTE_UNUSED)
2457 return dirspec;
2460 char *
2461 __gnat_to_host_file_spec (char *filespec)
2463 return filespec;
2466 void
2467 __gnat_adjust_os_resource_limits (void)
2471 #endif
2473 /* For EMX, we cannot include dummy in libgcc, since it is too difficult
2474 to coordinate this with the EMX distribution. Consequently, we put the
2475 definition of dummy which is used for exception handling, here. */
2477 #if defined (__EMX__)
2478 void __dummy () {}
2479 #endif
2481 #if defined (__mips_vxworks)
2483 _flush_cache()
2485 CACHE_USER_FLUSH (0, ENTIRE_CACHE);
2487 #endif
2489 #if defined (CROSS_COMPILE) \
2490 || (! (defined (sparc) && defined (sun) && defined (__SVR4)) \
2491 && ! (defined (linux) && defined (i386)) \
2492 && ! defined (__FreeBSD__) \
2493 && ! defined (__hpux__) \
2494 && ! defined (_AIX) \
2495 && ! (defined (__alpha__) && defined (__osf__)) \
2496 && ! defined (__MINGW32__) \
2497 && ! (defined (__mips) && defined (__sgi)))
2499 /* Dummy function to satisfy g-trasym.o. Currently Solaris sparc, HP/UX,
2500 GNU/Linux x86, Tru64 & Windows provide a non-dummy version of this
2501 procedure in libaddr2line.a. */
2503 void
2504 convert_addresses (void *addrs ATTRIBUTE_UNUSED,
2505 int n_addr ATTRIBUTE_UNUSED,
2506 void *buf ATTRIBUTE_UNUSED,
2507 int *len ATTRIBUTE_UNUSED)
2509 *len = 0;
2511 #endif
2513 #if defined (_WIN32)
2514 int __gnat_argument_needs_quote = 1;
2515 #else
2516 int __gnat_argument_needs_quote = 0;
2517 #endif
2519 /* This option is used to enable/disable object files handling from the
2520 binder file by the GNAT Project module. For example, this is disabled on
2521 Windows (prior to GCC 3.4) as it is already done by the mdll module.
2522 Stating with GCC 3.4 the shared libraries are not based on mdll
2523 anymore as it uses the GCC's -shared option */
2524 #if defined (_WIN32) \
2525 && ((__GNUC__ < 3) || ((__GNUC__ == 3) && (__GNUC_MINOR__ < 4)))
2526 int __gnat_prj_add_obj_files = 0;
2527 #else
2528 int __gnat_prj_add_obj_files = 1;
2529 #endif
2531 /* char used as prefix/suffix for environment variables */
2532 #if defined (_WIN32)
2533 char __gnat_environment_char = '%';
2534 #else
2535 char __gnat_environment_char = '$';
2536 #endif
2538 /* This functions copy the file attributes from a source file to a
2539 destination file.
2541 mode = 0 : In this mode copy only the file time stamps (last access and
2542 last modification time stamps).
2544 mode = 1 : In this mode, time stamps and read/write/execute attributes are
2545 copied.
2547 Returns 0 if operation was successful and -1 in case of error. */
2550 __gnat_copy_attribs (char *from, char *to, int mode)
2552 #if defined (VMS) || defined (__vxworks)
2553 return -1;
2554 #else
2555 struct stat fbuf;
2556 struct utimbuf tbuf;
2558 if (stat (from, &fbuf) == -1)
2560 return -1;
2563 tbuf.actime = fbuf.st_atime;
2564 tbuf.modtime = fbuf.st_mtime;
2566 if (utime (to, &tbuf) == -1)
2568 return -1;
2571 if (mode == 1)
2573 if (chmod (to, fbuf.st_mode) == -1)
2575 return -1;
2579 return 0;
2580 #endif
2583 /* This function is installed in libgcc.a. */
2584 extern void __gnat_install_locks (void (*) (void), void (*) (void));
2586 /* This function offers a hook for libgnarl to set the
2587 locking subprograms for libgcc_eh.
2588 This is only needed on OpenVMS, since other platforms use standard
2589 --enable-threads=posix option, or similar. */
2591 void
2592 __gnatlib_install_locks (void (*lock) (void) ATTRIBUTE_UNUSED,
2593 void (*unlock) (void) ATTRIBUTE_UNUSED)
2595 #if defined (IN_RTS) && defined (VMS)
2596 __gnat_install_locks (lock, unlock);
2597 /* There is a bootstrap path issue if adaint is build with this
2598 symbol unresolved for the stage1 compiler. Since the compiler
2599 does not use tasking, we simply make __gnatlib_install_locks
2600 a no-op in this case. */
2601 #endif
2605 __gnat_lseek (int fd, long offset, int whence)
2607 return (int) lseek (fd, offset, whence);
2610 /* This function returns the version of GCC being used. Here it's GCC 3. */
2612 get_gcc_version (void)
2614 return 3;
2618 __gnat_set_close_on_exec (int fd, int close_on_exec_p)
2620 #if defined (F_GETFD) && defined (FD_CLOEXEC) && ! defined (__vxworks)
2621 int flags = fcntl (fd, F_GETFD, 0);
2622 if (flags < 0)
2623 return flags;
2624 if (close_on_exec_p)
2625 flags |= FD_CLOEXEC;
2626 else
2627 flags &= ~FD_CLOEXEC;
2628 return fcntl (fd, F_SETFD, flags | FD_CLOEXEC);
2629 #else
2630 return -1;
2631 /* For the Windows case, we should use SetHandleInformation to remove
2632 the HANDLE_INHERIT property from fd. This is not implemented yet,
2633 but for our purposes (support of GNAT.Expect) this does not matter,
2634 as by default handles are *not* inherited. */
2635 #endif