Merge -r 127928:132243 from trunk
[official-gcc.git] / gcc / ada / adaint.c
blob3bc20eb672efd7fd4537827a100d370c253760fa
1 /****************************************************************************
2 * *
3 * GNAT COMPILER COMPONENTS *
4 * *
5 * A D A I N T *
6 * *
7 * C Implementation File *
8 * *
9 * Copyright (C) 1992-2007, 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, 51 Franklin Street, Fifth Floor, *
20 * Boston, MA 02110-1301, 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 #define HOST_EXECUTABLE_SUFFIX ".exe"
56 #define HOST_OBJECT_SUFFIX ".obj"
57 #endif
59 #ifdef IN_RTS
60 #include "tconfig.h"
61 #include "tsystem.h"
63 #include <sys/stat.h>
64 #include <fcntl.h>
65 #include <time.h>
66 #ifdef VMS
67 #include <unixio.h>
68 #endif
70 /* We don't have libiberty, so use malloc. */
71 #define xmalloc(S) malloc (S)
72 #define xrealloc(V,S) realloc (V,S)
73 #else
74 #include "config.h"
75 #include "system.h"
76 #include "version.h"
77 #endif
79 #if defined (RTX)
80 #include <windows.h>
81 #include <Rtapi.h>
82 #include <sys/utime.h>
84 #elif defined (__MINGW32__)
86 #include "mingw32.h"
87 #include <sys/utime.h>
88 #include <ctype.h>
90 #elif defined (__Lynx__)
92 /* Lynx utime.h only defines the entities of interest to us if
93 defined (VMOS_DEV), so ... */
94 #define VMOS_DEV
95 #include <utime.h>
96 #undef VMOS_DEV
98 #elif !defined (VMS)
99 #include <utime.h>
100 #endif
102 /* wait.h processing */
103 #ifdef __MINGW32__
104 #if OLD_MINGW
105 #include <sys/wait.h>
106 #endif
107 #elif defined (__vxworks) && defined (__RTP__)
108 #include <wait.h>
109 #elif defined (__Lynx__)
110 /* ??? We really need wait.h and it includes resource.h on Lynx. GCC
111 has a resource.h header as well, included instead of the lynx
112 version in our setup, causing lots of errors. We don't really need
113 the lynx contents of this file, so just workaround the issue by
114 preventing the inclusion of the GCC header from doing anything. */
115 #define GCC_RESOURCE_H
116 #include <sys/wait.h>
117 #elif defined (__nucleus__)
118 /* No wait() or waitpid() calls available */
119 #else
120 /* Default case */
121 #include <sys/wait.h>
122 #endif
124 #if defined (__EMX__) || defined (MSDOS) || defined (_WIN32)
125 #elif defined (VMS)
127 /* Header files and definitions for __gnat_set_file_time_name. */
129 #define __NEW_STARLET 1
130 #include <vms/rms.h>
131 #include <vms/atrdef.h>
132 #include <vms/fibdef.h>
133 #include <vms/stsdef.h>
134 #include <vms/iodef.h>
135 #include <errno.h>
136 #include <vms/descrip.h>
137 #include <string.h>
138 #include <unixlib.h>
140 /* Use native 64-bit arithmetic. */
141 #define unix_time_to_vms(X,Y) \
142 { unsigned long long reftime, tmptime = (X); \
143 $DESCRIPTOR (unixtime,"1-JAN-1970 0:00:00.00"); \
144 SYS$BINTIM (&unixtime, &reftime); \
145 Y = tmptime * 10000000 + reftime; }
147 /* descrip.h doesn't have everything ... */
148 typedef struct fibdef* __fibdef_ptr32 __attribute__ (( mode (SI) ));
149 struct dsc$descriptor_fib
151 unsigned int fib$l_len;
152 __fibdef_ptr32 fib$l_addr;
155 /* I/O Status Block. */
156 struct IOSB
158 unsigned short status, count;
159 unsigned int devdep;
162 static char *tryfile;
164 /* Variable length string. */
165 struct vstring
167 short length;
168 char string[NAM$C_MAXRSS+1];
171 #else
172 #include <utime.h>
173 #endif
175 #if defined (__EMX__) || defined (MSDOS) || defined (_WIN32)
176 #include <process.h>
177 #endif
179 #if defined (_WIN32)
180 #include <dir.h>
181 #include <windows.h>
182 #undef DIR_SEPARATOR
183 #define DIR_SEPARATOR '\\'
184 #endif
186 #include "adaint.h"
188 /* Define symbols O_BINARY and O_TEXT as harmless zeroes if they are not
189 defined in the current system. On DOS-like systems these flags control
190 whether the file is opened/created in text-translation mode (CR/LF in
191 external file mapped to LF in internal file), but in Unix-like systems,
192 no text translation is required, so these flags have no effect. */
194 #if defined (__EMX__)
195 #include <os2.h>
196 #endif
198 #if defined (MSDOS)
199 #include <dos.h>
200 #endif
202 #ifndef O_BINARY
203 #define O_BINARY 0
204 #endif
206 #ifndef O_TEXT
207 #define O_TEXT 0
208 #endif
210 #ifndef HOST_EXECUTABLE_SUFFIX
211 #define HOST_EXECUTABLE_SUFFIX ""
212 #endif
214 #ifndef HOST_OBJECT_SUFFIX
215 #define HOST_OBJECT_SUFFIX ".o"
216 #endif
218 #ifndef PATH_SEPARATOR
219 #define PATH_SEPARATOR ':'
220 #endif
222 #ifndef DIR_SEPARATOR
223 #define DIR_SEPARATOR '/'
224 #endif
226 /* Check for cross-compilation */
227 #ifdef CROSS_DIRECTORY_STRUCTURE
228 int __gnat_is_cross_compiler = 1;
229 #else
230 int __gnat_is_cross_compiler = 0;
231 #endif
233 char __gnat_dir_separator = DIR_SEPARATOR;
235 char __gnat_path_separator = PATH_SEPARATOR;
237 /* The GNAT_LIBRARY_TEMPLATE contains a list of expressions that define
238 the base filenames that libraries specified with -lsomelib options
239 may have. This is used by GNATMAKE to check whether an executable
240 is up-to-date or not. The syntax is
242 library_template ::= { pattern ; } pattern NUL
243 pattern ::= [ prefix ] * [ postfix ]
245 These should only specify names of static libraries as it makes
246 no sense to determine at link time if dynamic-link libraries are
247 up to date or not. Any libraries that are not found are supposed
248 to be up-to-date:
250 * if they are needed but not present, the link
251 will fail,
253 * otherwise they are libraries in the system paths and so
254 they are considered part of the system and not checked
255 for that reason.
257 ??? This should be part of a GNAT host-specific compiler
258 file instead of being included in all user applications
259 as well. This is only a temporary work-around for 3.11b. */
261 #ifndef GNAT_LIBRARY_TEMPLATE
262 #if defined (__EMX__)
263 #define GNAT_LIBRARY_TEMPLATE "*.a"
264 #elif defined (VMS)
265 #define GNAT_LIBRARY_TEMPLATE "*.olb"
266 #else
267 #define GNAT_LIBRARY_TEMPLATE "lib*.a"
268 #endif
269 #endif
271 const char *__gnat_library_template = GNAT_LIBRARY_TEMPLATE;
273 /* This variable is used in hostparm.ads to say whether the host is a VMS
274 system. */
275 #ifdef VMS
276 const int __gnat_vmsp = 1;
277 #else
278 const int __gnat_vmsp = 0;
279 #endif
281 #ifdef __EMX__
282 #define GNAT_MAX_PATH_LEN MAX_PATH
284 #elif defined (VMS)
285 #define GNAT_MAX_PATH_LEN 256 /* PATH_MAX */
287 #elif defined (__vxworks) || defined (__OPENNT) || defined(__nucleus__)
288 #define GNAT_MAX_PATH_LEN PATH_MAX
290 #else
292 #if defined (__MINGW32__)
293 #include "mingw32.h"
295 #if OLD_MINGW
296 #include <sys/param.h>
297 #endif
299 #else
300 #include <sys/param.h>
301 #endif
303 #ifdef MAXPATHLEN
304 #define GNAT_MAX_PATH_LEN MAXPATHLEN
305 #else
306 #define GNAT_MAX_PATH_LEN 256
307 #endif
309 #endif
311 /* The __gnat_max_path_len variable is used to export the maximum
312 length of a path name to Ada code. max_path_len is also provided
313 for compatibility with older GNAT versions, please do not use
314 it. */
316 int __gnat_max_path_len = GNAT_MAX_PATH_LEN;
317 int max_path_len = GNAT_MAX_PATH_LEN;
319 /* The following macro HAVE_READDIR_R should be defined if the
320 system provides the routine readdir_r. */
321 #undef HAVE_READDIR_R
323 #if defined(VMS) && defined (__LONG_POINTERS)
325 /* Return a 32 bit pointer to an array of 32 bit pointers
326 given a 64 bit pointer to an array of 64 bit pointers */
328 typedef __char_ptr32 *__char_ptr_char_ptr32 __attribute__ ((mode (SI)));
330 static __char_ptr_char_ptr32
331 to_ptr32 (char **ptr64)
333 int argc;
334 __char_ptr_char_ptr32 short_argv;
336 for (argc=0; ptr64[argc]; argc++);
338 /* Reallocate argv with 32 bit pointers. */
339 short_argv = (__char_ptr_char_ptr32) decc$malloc
340 (sizeof (__char_ptr32) * (argc + 1));
342 for (argc=0; ptr64[argc]; argc++)
343 short_argv[argc] = (__char_ptr32) decc$strdup (ptr64[argc]);
345 short_argv[argc] = (__char_ptr32) 0;
346 return short_argv;
349 #define MAYBE_TO_PTR32(argv) to_ptr32 (argv)
350 #else
351 #define MAYBE_TO_PTR32(argv) argv
352 #endif
354 OS_Time
355 __gnat_current_time
356 (void)
358 time_t res = time (NULL);
359 return (OS_Time) res;
362 void
363 __gnat_to_gm_time
364 (OS_Time *p_time,
365 int *p_year,
366 int *p_month,
367 int *p_day,
368 int *p_hours,
369 int *p_mins,
370 int *p_secs)
372 struct tm *res;
373 time_t time = (time_t) *p_time;
375 #ifdef _WIN32
376 /* On Windows systems, the time is sometimes rounded up to the nearest
377 even second, so if the number of seconds is odd, increment it. */
378 if (time & 1)
379 time++;
380 #endif
382 #ifdef VMS
383 res = localtime (&time);
384 #else
385 res = gmtime (&time);
386 #endif
388 if (res)
390 *p_year = res->tm_year;
391 *p_month = res->tm_mon;
392 *p_day = res->tm_mday;
393 *p_hours = res->tm_hour;
394 *p_mins = res->tm_min;
395 *p_secs = res->tm_sec;
397 else
398 *p_year = *p_month = *p_day = *p_hours = *p_mins = *p_secs = 0;
401 /* Place the contents of the symbolic link named PATH in the buffer BUF,
402 which has size BUFSIZ. If PATH is a symbolic link, then return the number
403 of characters of its content in BUF. Otherwise, return -1.
404 For systems not supporting symbolic links, always return -1. */
407 __gnat_readlink (char *path ATTRIBUTE_UNUSED,
408 char *buf ATTRIBUTE_UNUSED,
409 size_t bufsiz ATTRIBUTE_UNUSED)
411 #if defined (MSDOS) || defined (_WIN32) || defined (__EMX__) \
412 || defined (VMS) || defined(__vxworks) || defined (__nucleus__)
413 return -1;
414 #else
415 return readlink (path, buf, bufsiz);
416 #endif
419 /* Creates a symbolic link named NEWPATH which contains the string OLDPATH.
420 If NEWPATH exists it will NOT be overwritten.
421 For systems not supporting symbolic links, always return -1. */
424 __gnat_symlink (char *oldpath ATTRIBUTE_UNUSED,
425 char *newpath ATTRIBUTE_UNUSED)
427 #if defined (MSDOS) || defined (_WIN32) || defined (__EMX__) \
428 || defined (VMS) || defined(__vxworks) || defined (__nucleus__)
429 return -1;
430 #else
431 return symlink (oldpath, newpath);
432 #endif
435 /* Try to lock a file, return 1 if success. */
437 #if defined (__vxworks) || defined (__nucleus__) || defined (MSDOS) || defined (_WIN32)
439 /* Version that does not use link. */
442 __gnat_try_lock (char *dir, char *file)
444 int fd;
445 #ifdef __MINGW32__
446 TCHAR wfull_path[GNAT_MAX_PATH_LEN];
447 TCHAR wfile[GNAT_MAX_PATH_LEN];
448 TCHAR wdir[GNAT_MAX_PATH_LEN];
450 S2WSU (wdir, dir, GNAT_MAX_PATH_LEN);
451 S2WSU (wfile, file, GNAT_MAX_PATH_LEN);
453 _stprintf (wfull_path, _T("%s%c%s"), wdir, _T(DIR_SEPARATOR), wfile);
454 fd = _topen (wfull_path, O_CREAT | O_EXCL, 0600);
455 #else
456 char full_path[256];
458 sprintf (full_path, "%s%c%s", dir, DIR_SEPARATOR, file);
459 fd = open (full_path, O_CREAT | O_EXCL, 0600);
460 #endif
462 if (fd < 0)
463 return 0;
465 close (fd);
466 return 1;
469 #elif defined (__EMX__) || defined (VMS)
471 /* More cases that do not use link; identical code, to solve too long
472 line problem ??? */
475 __gnat_try_lock (char *dir, char *file)
477 char full_path[256];
478 int fd;
480 sprintf (full_path, "%s%c%s", dir, DIR_SEPARATOR, file);
481 fd = open (full_path, O_CREAT | O_EXCL, 0600);
483 if (fd < 0)
484 return 0;
486 close (fd);
487 return 1;
490 #else
492 /* Version using link(), more secure over NFS. */
493 /* See TN 6913-016 for discussion ??? */
496 __gnat_try_lock (char *dir, char *file)
498 char full_path[256];
499 char temp_file[256];
500 struct stat stat_result;
501 int fd;
503 sprintf (full_path, "%s%c%s", dir, DIR_SEPARATOR, file);
504 sprintf (temp_file, "%s%cTMP-%ld-%ld",
505 dir, DIR_SEPARATOR, (long)getpid(), (long)getppid ());
507 /* Create the temporary file and write the process number. */
508 fd = open (temp_file, O_CREAT | O_WRONLY, 0600);
509 if (fd < 0)
510 return 0;
512 close (fd);
514 /* Link it with the new file. */
515 link (temp_file, full_path);
517 /* Count the references on the old one. If we have a count of two, then
518 the link did succeed. Remove the temporary file before returning. */
519 __gnat_stat (temp_file, &stat_result);
520 unlink (temp_file);
521 return stat_result.st_nlink == 2;
523 #endif
525 /* Return the maximum file name length. */
528 __gnat_get_maximum_file_name_length (void)
530 #if defined (MSDOS)
531 return 8;
532 #elif defined (VMS)
533 if (getenv ("GNAT$EXTENDED_FILE_SPECIFICATIONS"))
534 return -1;
535 else
536 return 39;
537 #else
538 return -1;
539 #endif
542 /* Return nonzero if file names are case sensitive. */
545 __gnat_get_file_names_case_sensitive (void)
547 #if defined (__EMX__) || defined (MSDOS) || defined (VMS) || defined (WINNT)
548 return 0;
549 #else
550 return 1;
551 #endif
554 char
555 __gnat_get_default_identifier_character_set (void)
557 #if defined (__EMX__) || defined (MSDOS)
558 return 'p';
559 #else
560 return '1';
561 #endif
564 /* Return the current working directory. */
566 void
567 __gnat_get_current_dir (char *dir, int *length)
569 #if defined (__MINGW32__)
570 TCHAR wdir[GNAT_MAX_PATH_LEN];
572 _tgetcwd (wdir, *length);
574 WS2SU (dir, wdir, GNAT_MAX_PATH_LEN);
576 #elif defined (VMS)
577 /* Force Unix style, which is what GNAT uses internally. */
578 getcwd (dir, *length, 0);
579 #else
580 getcwd (dir, *length);
581 #endif
583 *length = strlen (dir);
585 if (dir [*length - 1] != DIR_SEPARATOR)
587 dir [*length] = DIR_SEPARATOR;
588 ++(*length);
590 dir[*length] = '\0';
593 /* Return the suffix for object files. */
595 void
596 __gnat_get_object_suffix_ptr (int *len, const char **value)
598 *value = HOST_OBJECT_SUFFIX;
600 if (*value == 0)
601 *len = 0;
602 else
603 *len = strlen (*value);
605 return;
608 /* Return the suffix for executable files. */
610 void
611 __gnat_get_executable_suffix_ptr (int *len, const char **value)
613 *value = HOST_EXECUTABLE_SUFFIX;
614 if (!*value)
615 *len = 0;
616 else
617 *len = strlen (*value);
619 return;
622 /* Return the suffix for debuggable files. Usually this is the same as the
623 executable extension. */
625 void
626 __gnat_get_debuggable_suffix_ptr (int *len, const char **value)
628 #ifndef MSDOS
629 *value = HOST_EXECUTABLE_SUFFIX;
630 #else
631 /* On DOS, the extensionless COFF file is what gdb likes. */
632 *value = "";
633 #endif
635 if (*value == 0)
636 *len = 0;
637 else
638 *len = strlen (*value);
640 return;
643 /* Returns the OS filename and corresponding encoding. */
645 void
646 __gnat_os_filename (char *filename, char *w_filename,
647 char *os_name, int *o_length,
648 char *encoding, int *e_length)
650 #if defined (_WIN32) && ! defined (__vxworks) && ! defined (CROSS_DIRECTORY_STRUCTURE)
651 WS2SU (os_name, (TCHAR *)w_filename, o_length);
652 *o_length = strlen (os_name);
653 strcpy (encoding, "encoding=utf8");
654 *e_length = strlen (encoding);
655 #else
656 strcpy (os_name, filename);
657 *o_length = strlen (filename);
658 *e_length = 0;
659 #endif
662 FILE *
663 __gnat_fopen (char *path, char *mode, int encoding)
665 #if defined (_WIN32) && ! defined (__vxworks) && ! defined (CROSS_DIRECTORY_STRUCTURE)
666 TCHAR wpath[GNAT_MAX_PATH_LEN];
667 TCHAR wmode[10];
669 S2WS (wmode, mode, 10);
671 if (encoding == Encoding_UTF8)
672 S2WSU (wpath, path, GNAT_MAX_PATH_LEN);
673 else
674 S2WS (wpath, path, GNAT_MAX_PATH_LEN);
676 return _tfopen (wpath, wmode);
677 #elif defined (VMS)
678 return decc$fopen (path, mode);
679 #else
680 return fopen (path, mode);
681 #endif
684 FILE *
685 __gnat_freopen (char *path, char *mode, FILE *stream, int encoding)
687 #if defined (_WIN32) && ! defined (__vxworks) && ! defined (CROSS_DIRECTORY_STRUCTURE)
688 TCHAR wpath[GNAT_MAX_PATH_LEN];
689 TCHAR wmode[10];
691 S2WS (wmode, mode, 10);
693 if (encoding == Encoding_UTF8)
694 S2WSU (wpath, path, GNAT_MAX_PATH_LEN);
695 else
696 S2WS (wpath, path, GNAT_MAX_PATH_LEN);
698 return _tfreopen (wpath, wmode, stream);
699 #elif defined (VMS)
700 return decc$freopen (path, mode, stream);
701 #else
702 return freopen (path, mode, stream);
703 #endif
707 __gnat_open_read (char *path, int fmode)
709 int fd;
710 int o_fmode = O_BINARY;
712 if (fmode)
713 o_fmode = O_TEXT;
715 #if defined (VMS)
716 /* Optional arguments mbc,deq,fop increase read performance. */
717 fd = open (path, O_RDONLY | o_fmode, 0444,
718 "mbc=16", "deq=64", "fop=tef");
719 #elif defined (__vxworks)
720 fd = open (path, O_RDONLY | o_fmode, 0444);
721 #elif defined (__MINGW32__)
723 TCHAR wpath[GNAT_MAX_PATH_LEN];
725 S2WSU (wpath, path, GNAT_MAX_PATH_LEN);
726 fd = _topen (wpath, O_RDONLY | o_fmode, 0444);
728 #else
729 fd = open (path, O_RDONLY | o_fmode);
730 #endif
732 return fd < 0 ? -1 : fd;
735 #if defined (__EMX__) || defined (__MINGW32__)
736 #define PERM (S_IREAD | S_IWRITE)
737 #elif defined (VMS)
738 /* Excerpt from DECC C RTL Reference Manual:
739 To create files with OpenVMS RMS default protections using the UNIX
740 system-call functions umask, mkdir, creat, and open, call mkdir, creat,
741 and open with a file-protection mode argument of 0777 in a program
742 that never specifically calls umask. These default protections include
743 correctly establishing protections based on ACLs, previous versions of
744 files, and so on. */
745 #define PERM 0777
746 #else
747 #define PERM (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH)
748 #endif
751 __gnat_open_rw (char *path, int fmode)
753 int fd;
754 int o_fmode = O_BINARY;
756 if (fmode)
757 o_fmode = O_TEXT;
759 #if defined (VMS)
760 fd = open (path, O_RDWR | o_fmode, PERM,
761 "mbc=16", "deq=64", "fop=tef");
762 #elif defined (__MINGW32__)
764 TCHAR wpath[GNAT_MAX_PATH_LEN];
766 S2WSU (wpath, path, GNAT_MAX_PATH_LEN);
767 fd = _topen (wpath, O_RDWR | o_fmode, PERM);
769 #else
770 fd = open (path, O_RDWR | o_fmode, PERM);
771 #endif
773 return fd < 0 ? -1 : fd;
777 __gnat_open_create (char *path, int fmode)
779 int fd;
780 int o_fmode = O_BINARY;
782 if (fmode)
783 o_fmode = O_TEXT;
785 #if defined (VMS)
786 fd = open (path, O_WRONLY | O_CREAT | O_TRUNC | o_fmode, PERM,
787 "mbc=16", "deq=64", "fop=tef");
788 #elif defined (__MINGW32__)
790 TCHAR wpath[GNAT_MAX_PATH_LEN];
792 S2WSU (wpath, path, GNAT_MAX_PATH_LEN);
793 fd = _topen (wpath, O_WRONLY | O_CREAT | O_TRUNC | o_fmode, PERM);
795 #else
796 fd = open (path, O_WRONLY | O_CREAT | O_TRUNC | o_fmode, PERM);
797 #endif
799 return fd < 0 ? -1 : fd;
803 __gnat_create_output_file (char *path)
805 int fd;
806 #if defined (VMS)
807 fd = open (path, O_WRONLY | O_CREAT | O_TRUNC | O_TEXT, PERM,
808 "rfm=stmlf", "ctx=rec", "rat=none", "rop=nlk",
809 "shr=del,get,put,upd");
810 #elif defined (__MINGW32__)
812 TCHAR wpath[GNAT_MAX_PATH_LEN];
814 S2WSU (wpath, path, GNAT_MAX_PATH_LEN);
815 fd = _topen (wpath, O_WRONLY | O_CREAT | O_TRUNC | O_TEXT, PERM);
817 #else
818 fd = open (path, O_WRONLY | O_CREAT | O_TRUNC | O_TEXT, PERM);
819 #endif
821 return fd < 0 ? -1 : fd;
825 __gnat_open_append (char *path, int fmode)
827 int fd;
828 int o_fmode = O_BINARY;
830 if (fmode)
831 o_fmode = O_TEXT;
833 #if defined (VMS)
834 fd = open (path, O_WRONLY | O_CREAT | O_APPEND | o_fmode, PERM,
835 "mbc=16", "deq=64", "fop=tef");
836 #elif defined (__MINGW32__)
838 TCHAR wpath[GNAT_MAX_PATH_LEN];
840 S2WSU (wpath, path, GNAT_MAX_PATH_LEN);
841 fd = _topen (wpath, O_WRONLY | O_CREAT | O_APPEND | o_fmode, PERM);
843 #else
844 fd = open (path, O_WRONLY | O_CREAT | O_APPEND | o_fmode, PERM);
845 #endif
847 return fd < 0 ? -1 : fd;
850 /* Open a new file. Return error (-1) if the file already exists. */
853 __gnat_open_new (char *path, int fmode)
855 int fd;
856 int o_fmode = O_BINARY;
858 if (fmode)
859 o_fmode = O_TEXT;
861 #if defined (VMS)
862 fd = open (path, O_WRONLY | O_CREAT | O_EXCL | o_fmode, PERM,
863 "mbc=16", "deq=64", "fop=tef");
864 #elif defined (__MINGW32__)
866 TCHAR wpath[GNAT_MAX_PATH_LEN];
868 S2WSU (wpath, path, GNAT_MAX_PATH_LEN);
869 fd = _topen (wpath, O_WRONLY | O_CREAT | O_EXCL | o_fmode, PERM);
871 #else
872 fd = open (path, O_WRONLY | O_CREAT | O_EXCL | o_fmode, PERM);
873 #endif
875 return fd < 0 ? -1 : fd;
878 /* Open a new temp file. Return error (-1) if the file already exists.
879 Special options for VMS allow the file to be shared between parent and child
880 processes, however they really slow down output. Used in gnatchop. */
883 __gnat_open_new_temp (char *path, int fmode)
885 int fd;
886 int o_fmode = O_BINARY;
888 strcpy (path, "GNAT-XXXXXX");
890 #if (defined (__FreeBSD__) || defined (__NetBSD__) || defined (__OpenBSD__) \
891 || defined (linux)) && !defined (__vxworks)
892 return mkstemp (path);
893 #elif defined (__Lynx__)
894 mktemp (path);
895 #elif defined (__nucleus__)
896 return -1;
897 #else
898 if (mktemp (path) == NULL)
899 return -1;
900 #endif
902 if (fmode)
903 o_fmode = O_TEXT;
905 #if defined (VMS)
906 fd = open (path, O_WRONLY | O_CREAT | O_EXCL | o_fmode, PERM,
907 "rfm=stmlf", "ctx=rec", "rat=none", "shr=del,get,put,upd",
908 "mbc=16", "deq=64", "fop=tef");
909 #else
910 fd = open (path, O_WRONLY | O_CREAT | O_EXCL | o_fmode, PERM);
911 #endif
913 return fd < 0 ? -1 : fd;
916 /* Return the number of bytes in the specified file. */
918 long
919 __gnat_file_length (int fd)
921 int ret;
922 struct stat statbuf;
924 ret = fstat (fd, &statbuf);
925 if (ret || !S_ISREG (statbuf.st_mode))
926 return 0;
928 return (statbuf.st_size);
931 /* Return the number of bytes in the specified named file. */
933 long
934 __gnat_named_file_length (char *name)
936 int ret;
937 struct stat statbuf;
939 ret = __gnat_stat (name, &statbuf);
940 if (ret || !S_ISREG (statbuf.st_mode))
941 return 0;
943 return (statbuf.st_size);
946 /* Create a temporary filename and put it in string pointed to by
947 TMP_FILENAME. */
949 void
950 __gnat_tmp_name (char *tmp_filename)
952 #ifdef __MINGW32__
954 char *pname;
956 /* tempnam tries to create a temporary file in directory pointed to by
957 TMP environment variable, in c:\temp if TMP is not set, and in
958 directory specified by P_tmpdir in stdio.h if c:\temp does not
959 exist. The filename will be created with the prefix "gnat-". */
961 pname = (char *) tempnam ("c:\\temp", "gnat-");
963 /* if pname is NULL, the file was not created properly, the disk is full
964 or there is no more free temporary files */
966 if (pname == NULL)
967 *tmp_filename = '\0';
969 /* If pname start with a back slash and not path information it means that
970 the filename is valid for the current working directory. */
972 else if (pname[0] == '\\')
974 strcpy (tmp_filename, ".\\");
975 strcat (tmp_filename, pname+1);
977 else
978 strcpy (tmp_filename, pname);
980 free (pname);
983 #elif defined (linux) || defined (__FreeBSD__) || defined (__NetBSD__) \
984 || defined (__OpenBSD__)
985 #define MAX_SAFE_PATH 1000
986 char *tmpdir = getenv ("TMPDIR");
988 /* If tmpdir is longer than MAX_SAFE_PATH, revert to default value to avoid
989 a buffer overflow. */
990 if (tmpdir == NULL || strlen (tmpdir) > MAX_SAFE_PATH)
991 strcpy (tmp_filename, "/tmp/gnat-XXXXXX");
992 else
993 sprintf (tmp_filename, "%s/gnat-XXXXXX", tmpdir);
995 close (mkstemp(tmp_filename));
996 #else
997 tmpnam (tmp_filename);
998 #endif
1001 /* Open directory and returns a DIR pointer. */
1003 DIR* __gnat_opendir (char *name)
1005 #if defined (RTX)
1006 /* Not supported in RTX */
1008 return NULL;
1010 #elif defined (__MINGW32__)
1011 TCHAR wname[GNAT_MAX_PATH_LEN];
1013 S2WSU (wname, name, GNAT_MAX_PATH_LEN);
1014 return (DIR*)_topendir (wname);
1016 #else
1017 return opendir (name);
1018 #endif
1021 /* Read the next entry in a directory. The returned string points somewhere
1022 in the buffer. */
1024 char *
1025 __gnat_readdir (DIR *dirp, char *buffer, int *len)
1027 #if defined (RTX)
1028 /* Not supported in RTX */
1030 return NULL;
1031 #elif defined (__MINGW32__)
1032 struct _tdirent *dirent = _treaddir ((_TDIR*)dirp);
1034 if (dirent != NULL)
1036 WS2SU (buffer, dirent->d_name, GNAT_MAX_PATH_LEN);
1037 *len = strlen (buffer);
1039 return buffer;
1041 else
1042 return NULL;
1044 #elif defined (HAVE_READDIR_R)
1045 /* If possible, try to use the thread-safe version. */
1046 if (readdir_r (dirp, buffer) != NULL)
1048 *len = strlen (((struct dirent*) buffer)->d_name);
1049 return ((struct dirent*) buffer)->d_name;
1051 else
1052 return NULL;
1054 #else
1055 struct dirent *dirent = (struct dirent *) readdir (dirp);
1057 if (dirent != NULL)
1059 strcpy (buffer, dirent->d_name);
1060 *len = strlen (buffer);
1061 return buffer;
1063 else
1064 return NULL;
1066 #endif
1069 /* Close a directory entry. */
1071 int __gnat_closedir (DIR *dirp)
1073 #if defined (RTX)
1074 /* Not supported in RTX */
1076 return 0;
1078 #elif defined (__MINGW32__)
1079 return _tclosedir ((_TDIR*)dirp);
1081 #else
1082 return closedir (dirp);
1083 #endif
1086 /* Returns 1 if readdir is thread safe, 0 otherwise. */
1089 __gnat_readdir_is_thread_safe (void)
1091 #ifdef HAVE_READDIR_R
1092 return 1;
1093 #else
1094 return 0;
1095 #endif
1098 #if defined (_WIN32) && !defined (RTX)
1099 /* Number of seconds between <Jan 1st 1601> and <Jan 1st 1970>. */
1100 static const unsigned long long w32_epoch_offset = 11644473600ULL;
1102 /* Returns the file modification timestamp using Win32 routines which are
1103 immune against daylight saving time change. It is in fact not possible to
1104 use fstat for this purpose as the DST modify the st_mtime field of the
1105 stat structure. */
1107 static time_t
1108 win32_filetime (HANDLE h)
1110 union
1112 FILETIME ft_time;
1113 unsigned long long ull_time;
1114 } t_write;
1116 /* GetFileTime returns FILETIME data which are the number of 100 nanosecs
1117 since <Jan 1st 1601>. This function must return the number of seconds
1118 since <Jan 1st 1970>. */
1120 if (GetFileTime (h, NULL, NULL, &t_write.ft_time))
1121 return (time_t) (t_write.ull_time / 10000000ULL - w32_epoch_offset);
1122 return (time_t) 0;
1124 #endif
1126 /* Return a GNAT time stamp given a file name. */
1128 OS_Time
1129 __gnat_file_time_name (char *name)
1132 #if defined (__EMX__) || defined (MSDOS)
1133 int fd = open (name, O_RDONLY | O_BINARY);
1134 time_t ret = __gnat_file_time_fd (fd);
1135 close (fd);
1136 return (OS_Time)ret;
1138 #elif defined (_WIN32) && !defined (RTX)
1139 time_t ret = -1;
1140 TCHAR wname[GNAT_MAX_PATH_LEN];
1142 S2WSU (wname, name, GNAT_MAX_PATH_LEN);
1144 HANDLE h = CreateFile
1145 (wname, GENERIC_READ, FILE_SHARE_READ, 0,
1146 OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0);
1148 if (h != INVALID_HANDLE_VALUE)
1150 ret = win32_filetime (h);
1151 CloseHandle (h);
1153 return (OS_Time) ret;
1154 #else
1155 struct stat statbuf;
1156 if (__gnat_stat (name, &statbuf) != 0) {
1157 return (OS_Time)-1;
1158 } else {
1159 #ifdef VMS
1160 /* VMS has file versioning. */
1161 return (OS_Time)statbuf.st_ctime;
1162 #else
1163 return (OS_Time)statbuf.st_mtime;
1164 #endif
1166 #endif
1169 /* Return a GNAT time stamp given a file descriptor. */
1171 OS_Time
1172 __gnat_file_time_fd (int fd)
1174 /* The following workaround code is due to the fact that under EMX and
1175 DJGPP fstat attempts to convert time values to GMT rather than keep the
1176 actual OS timestamp of the file. By using the OS2/DOS functions directly
1177 the GNAT timestamp are independent of this behavior, which is desired to
1178 facilitate the distribution of GNAT compiled libraries. */
1180 #if defined (__EMX__) || defined (MSDOS)
1181 #ifdef __EMX__
1183 FILESTATUS fs;
1184 int ret = DosQueryFileInfo (fd, 1, (unsigned char *) &fs,
1185 sizeof (FILESTATUS));
1187 unsigned file_year = fs.fdateLastWrite.year;
1188 unsigned file_month = fs.fdateLastWrite.month;
1189 unsigned file_day = fs.fdateLastWrite.day;
1190 unsigned file_hour = fs.ftimeLastWrite.hours;
1191 unsigned file_min = fs.ftimeLastWrite.minutes;
1192 unsigned file_tsec = fs.ftimeLastWrite.twosecs;
1194 #else
1195 struct ftime fs;
1196 int ret = getftime (fd, &fs);
1198 unsigned file_year = fs.ft_year;
1199 unsigned file_month = fs.ft_month;
1200 unsigned file_day = fs.ft_day;
1201 unsigned file_hour = fs.ft_hour;
1202 unsigned file_min = fs.ft_min;
1203 unsigned file_tsec = fs.ft_tsec;
1204 #endif
1206 /* Calculate the seconds since epoch from the time components. First count
1207 the whole days passed. The value for years returned by the DOS and OS2
1208 functions count years from 1980, so to compensate for the UNIX epoch which
1209 begins in 1970 start with 10 years worth of days and add days for each
1210 four year period since then. */
1212 time_t tot_secs;
1213 int cum_days[12] = {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334};
1214 int days_passed = 3652 + (file_year / 4) * 1461;
1215 int years_since_leap = file_year % 4;
1217 if (years_since_leap == 1)
1218 days_passed += 366;
1219 else if (years_since_leap == 2)
1220 days_passed += 731;
1221 else if (years_since_leap == 3)
1222 days_passed += 1096;
1224 if (file_year > 20)
1225 days_passed -= 1;
1227 days_passed += cum_days[file_month - 1];
1228 if (years_since_leap == 0 && file_year != 20 && file_month > 2)
1229 days_passed++;
1231 days_passed += file_day - 1;
1233 /* OK - have whole days. Multiply -- then add in other parts. */
1235 tot_secs = days_passed * 86400;
1236 tot_secs += file_hour * 3600;
1237 tot_secs += file_min * 60;
1238 tot_secs += file_tsec * 2;
1239 return (OS_Time) tot_secs;
1241 #elif defined (_WIN32) && !defined (RTX)
1242 HANDLE h = (HANDLE) _get_osfhandle (fd);
1243 time_t ret = win32_filetime (h);
1244 return (OS_Time) ret;
1246 #else
1247 struct stat statbuf;
1249 if (fstat (fd, &statbuf) != 0) {
1250 return (OS_Time) -1;
1251 } else {
1252 #ifdef VMS
1253 /* VMS has file versioning. */
1254 return (OS_Time) statbuf.st_ctime;
1255 #else
1256 return (OS_Time) statbuf.st_mtime;
1257 #endif
1259 #endif
1262 /* Set the file time stamp. */
1264 void
1265 __gnat_set_file_time_name (char *name, time_t time_stamp)
1267 #if defined (__EMX__) || defined (MSDOS) || defined (__vxworks)
1269 /* Code to implement __gnat_set_file_time_name for these systems. */
1271 #elif defined (_WIN32) && !defined (RTX)
1272 union
1274 FILETIME ft_time;
1275 unsigned long long ull_time;
1276 } t_write;
1277 TCHAR wname[GNAT_MAX_PATH_LEN];
1279 S2WSU (wname, name, GNAT_MAX_PATH_LEN);
1281 HANDLE h = CreateFile
1282 (wname, GENERIC_WRITE, FILE_SHARE_WRITE, NULL,
1283 OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS,
1284 NULL);
1285 if (h == INVALID_HANDLE_VALUE)
1286 return;
1287 /* Add number of seconds between <Jan 1st 1601> and <Jan 1st 1970> */
1288 t_write.ull_time = ((unsigned long long)time_stamp + w32_epoch_offset);
1289 /* Convert to 100 nanosecond units */
1290 t_write.ull_time *= 10000000ULL;
1292 SetFileTime(h, NULL, NULL, &t_write.ft_time);
1293 CloseHandle (h);
1294 return;
1296 #elif defined (VMS)
1297 struct FAB fab;
1298 struct NAM nam;
1300 struct
1302 unsigned long long backup, create, expire, revise;
1303 unsigned int uic;
1304 union
1306 unsigned short value;
1307 struct
1309 unsigned system : 4;
1310 unsigned owner : 4;
1311 unsigned group : 4;
1312 unsigned world : 4;
1313 } bits;
1314 } prot;
1315 } Fat = { 0, 0, 0, 0, 0, { 0 }};
1317 ATRDEF atrlst[]
1319 { ATR$S_CREDATE, ATR$C_CREDATE, &Fat.create },
1320 { ATR$S_REVDATE, ATR$C_REVDATE, &Fat.revise },
1321 { ATR$S_EXPDATE, ATR$C_EXPDATE, &Fat.expire },
1322 { ATR$S_BAKDATE, ATR$C_BAKDATE, &Fat.backup },
1323 { ATR$S_FPRO, ATR$C_FPRO, &Fat.prot },
1324 { ATR$S_UIC, ATR$C_UIC, &Fat.uic },
1325 { 0, 0, 0}
1328 FIBDEF fib;
1329 struct dsc$descriptor_fib fibdsc = {sizeof (fib), (void *) &fib};
1331 struct IOSB iosb;
1333 unsigned long long newtime;
1334 unsigned long long revtime;
1335 long status;
1336 short chan;
1338 struct vstring file;
1339 struct dsc$descriptor_s filedsc
1340 = {NAM$C_MAXRSS, DSC$K_DTYPE_T, DSC$K_CLASS_S, (void *) file.string};
1341 struct vstring device;
1342 struct dsc$descriptor_s devicedsc
1343 = {NAM$C_MAXRSS, DSC$K_DTYPE_T, DSC$K_CLASS_S, (void *) device.string};
1344 struct vstring timev;
1345 struct dsc$descriptor_s timedsc
1346 = {NAM$C_MAXRSS, DSC$K_DTYPE_T, DSC$K_CLASS_S, (void *) timev.string};
1347 struct vstring result;
1348 struct dsc$descriptor_s resultdsc
1349 = {NAM$C_MAXRSS, DSC$K_DTYPE_VT, DSC$K_CLASS_VS, (void *) result.string};
1351 /* Convert parameter name (a file spec) to host file form. Note that this
1352 is needed on VMS to prepare for subsequent calls to VMS RMS library
1353 routines. Note that it would not work to call __gnat_to_host_dir_spec
1354 as was done in a previous version, since this fails silently unless
1355 the feature logical DECC$EFS_CHARSET is enabled, in which case a DNF
1356 (directory not found) condition is signalled. */
1357 tryfile = (char *) __gnat_to_host_file_spec (name);
1359 /* Allocate and initialize a FAB and NAM structures. */
1360 fab = cc$rms_fab;
1361 nam = cc$rms_nam;
1363 nam.nam$l_esa = file.string;
1364 nam.nam$b_ess = NAM$C_MAXRSS;
1365 nam.nam$l_rsa = result.string;
1366 nam.nam$b_rss = NAM$C_MAXRSS;
1367 fab.fab$l_fna = tryfile;
1368 fab.fab$b_fns = strlen (tryfile);
1369 fab.fab$l_nam = &nam;
1371 /* Validate filespec syntax and device existence. */
1372 status = SYS$PARSE (&fab, 0, 0);
1373 if ((status & 1) != 1)
1374 LIB$SIGNAL (status);
1376 file.string[nam.nam$b_esl] = 0;
1378 /* Find matching filespec. */
1379 status = SYS$SEARCH (&fab, 0, 0);
1380 if ((status & 1) != 1)
1381 LIB$SIGNAL (status);
1383 file.string[nam.nam$b_esl] = 0;
1384 result.string[result.length=nam.nam$b_rsl] = 0;
1386 /* Get the device name and assign an IO channel. */
1387 strncpy (device.string, nam.nam$l_dev, nam.nam$b_dev);
1388 devicedsc.dsc$w_length = nam.nam$b_dev;
1389 chan = 0;
1390 status = SYS$ASSIGN (&devicedsc, &chan, 0, 0, 0);
1391 if ((status & 1) != 1)
1392 LIB$SIGNAL (status);
1394 /* Initialize the FIB and fill in the directory id field. */
1395 memset (&fib, 0, sizeof (fib));
1396 fib.fib$w_did[0] = nam.nam$w_did[0];
1397 fib.fib$w_did[1] = nam.nam$w_did[1];
1398 fib.fib$w_did[2] = nam.nam$w_did[2];
1399 fib.fib$l_acctl = 0;
1400 fib.fib$l_wcc = 0;
1401 strcpy (file.string, (strrchr (result.string, ']') + 1));
1402 filedsc.dsc$w_length = strlen (file.string);
1403 result.string[result.length = 0] = 0;
1405 /* Open and close the file to fill in the attributes. */
1406 status
1407 = SYS$QIOW (0, chan, IO$_ACCESS|IO$M_ACCESS, &iosb, 0, 0,
1408 &fibdsc, &filedsc, &result.length, &resultdsc, &atrlst, 0);
1409 if ((status & 1) != 1)
1410 LIB$SIGNAL (status);
1411 if ((iosb.status & 1) != 1)
1412 LIB$SIGNAL (iosb.status);
1414 result.string[result.length] = 0;
1415 status = SYS$QIOW (0, chan, IO$_DEACCESS, &iosb, 0, 0, &fibdsc, 0, 0, 0,
1416 &atrlst, 0);
1417 if ((status & 1) != 1)
1418 LIB$SIGNAL (status);
1419 if ((iosb.status & 1) != 1)
1420 LIB$SIGNAL (iosb.status);
1423 time_t t;
1425 /* Set creation time to requested time. */
1426 unix_time_to_vms (time_stamp, newtime);
1428 t = time ((time_t) 0);
1430 /* Set revision time to now in local time. */
1431 unix_time_to_vms (t, revtime);
1434 /* Reopen the file, modify the times and then close. */
1435 fib.fib$l_acctl = FIB$M_WRITE;
1436 status
1437 = SYS$QIOW (0, chan, IO$_ACCESS|IO$M_ACCESS, &iosb, 0, 0,
1438 &fibdsc, &filedsc, &result.length, &resultdsc, &atrlst, 0);
1439 if ((status & 1) != 1)
1440 LIB$SIGNAL (status);
1441 if ((iosb.status & 1) != 1)
1442 LIB$SIGNAL (iosb.status);
1444 Fat.create = newtime;
1445 Fat.revise = revtime;
1447 status = SYS$QIOW (0, chan, IO$_DEACCESS, &iosb, 0, 0,
1448 &fibdsc, 0, 0, 0, &atrlst, 0);
1449 if ((status & 1) != 1)
1450 LIB$SIGNAL (status);
1451 if ((iosb.status & 1) != 1)
1452 LIB$SIGNAL (iosb.status);
1454 /* Deassign the channel and exit. */
1455 status = SYS$DASSGN (chan);
1456 if ((status & 1) != 1)
1457 LIB$SIGNAL (status);
1458 #else
1459 struct utimbuf utimbuf;
1460 time_t t;
1462 /* Set modification time to requested time. */
1463 utimbuf.modtime = time_stamp;
1465 /* Set access time to now in local time. */
1466 t = time ((time_t) 0);
1467 utimbuf.actime = mktime (localtime (&t));
1469 utime (name, &utimbuf);
1470 #endif
1473 #ifdef _WIN32
1474 #include <windows.h>
1475 #endif
1477 /* Get the list of installed standard libraries from the
1478 HKEY_LOCAL_MACHINE\SOFTWARE\Ada Core Technologies\GNAT\Standard Libraries
1479 key. */
1481 char *
1482 __gnat_get_libraries_from_registry (void)
1484 char *result = (char *) "";
1486 #if defined (_WIN32) && ! defined (__vxworks) && ! defined (CROSS_DIRECTORY_STRUCTURE) && ! defined (RTX)
1488 HKEY reg_key;
1489 DWORD name_size, value_size;
1490 char name[256];
1491 char value[256];
1492 DWORD type;
1493 DWORD index;
1494 LONG res;
1496 /* First open the key. */
1497 res = RegOpenKeyExA (HKEY_LOCAL_MACHINE, "SOFTWARE", 0, KEY_READ, &reg_key);
1499 if (res == ERROR_SUCCESS)
1500 res = RegOpenKeyExA (reg_key, "Ada Core Technologies", 0,
1501 KEY_READ, &reg_key);
1503 if (res == ERROR_SUCCESS)
1504 res = RegOpenKeyExA (reg_key, "GNAT", 0, KEY_READ, &reg_key);
1506 if (res == ERROR_SUCCESS)
1507 res = RegOpenKeyExA (reg_key, "Standard Libraries", 0, KEY_READ, &reg_key);
1509 /* If the key exists, read out all the values in it and concatenate them
1510 into a path. */
1511 for (index = 0; res == ERROR_SUCCESS; index++)
1513 value_size = name_size = 256;
1514 res = RegEnumValueA (reg_key, index, (TCHAR*)name, &name_size, 0,
1515 &type, (LPBYTE)value, &value_size);
1517 if (res == ERROR_SUCCESS && type == REG_SZ)
1519 char *old_result = result;
1521 result = (char *) xmalloc (strlen (old_result) + value_size + 2);
1522 strcpy (result, old_result);
1523 strcat (result, value);
1524 strcat (result, ";");
1528 /* Remove the trailing ";". */
1529 if (result[0] != 0)
1530 result[strlen (result) - 1] = 0;
1532 #endif
1533 return result;
1537 __gnat_stat (char *name, struct stat *statbuf)
1539 #ifdef __MINGW32__
1540 /* Under Windows the directory name for the stat function must not be
1541 terminated by a directory separator except if just after a drive name. */
1542 TCHAR wname [GNAT_MAX_PATH_LEN + 2];
1543 int name_len;
1544 TCHAR last_char;
1546 S2WSU (wname, name, GNAT_MAX_PATH_LEN + 2);
1547 name_len = _tcslen (wname);
1549 if (name_len > GNAT_MAX_PATH_LEN)
1550 return -1;
1552 last_char = wname[name_len - 1];
1554 while (name_len > 1 && (last_char == _T('\\') || last_char == _T('/')))
1556 wname[name_len - 1] = _T('\0');
1557 name_len--;
1558 last_char = wname[name_len - 1];
1561 /* Only a drive letter followed by ':', we must add a directory separator
1562 for the stat routine to work properly. */
1563 if (name_len == 2 && wname[1] == _T(':'))
1564 _tcscat (wname, _T("\\"));
1566 return _tstat (wname, statbuf);
1568 #else
1569 return stat (name, statbuf);
1570 #endif
1574 __gnat_file_exists (char *name)
1576 #if defined (__MINGW32__) && !defined (RTX)
1577 /* On Windows do not use __gnat_stat() because a bug in Microsoft
1578 _stat() routine. When the system time-zone is set with a negative
1579 offset the _stat() routine fails on specific files like CON: */
1580 TCHAR wname [GNAT_MAX_PATH_LEN + 2];
1582 S2WSU (wname, name, GNAT_MAX_PATH_LEN + 2);
1583 return GetFileAttributes (wname) != INVALID_FILE_ATTRIBUTES;
1584 #else
1585 struct stat statbuf;
1587 return !__gnat_stat (name, &statbuf);
1588 #endif
1592 __gnat_is_absolute_path (char *name, int length)
1594 #ifdef __vxworks
1595 /* On VxWorks systems, an absolute path can be represented (depending on
1596 the host platform) as either /dir/file, or device:/dir/file, or
1597 device:drive_letter:/dir/file. */
1599 int index;
1601 if (name[0] == '/')
1602 return 1;
1604 for (index = 0; index < length; index++)
1606 if (name[index] == ':' &&
1607 ((name[index + 1] == '/') ||
1608 (isalpha (name[index + 1]) && index + 2 <= length &&
1609 name[index + 2] == '/')))
1610 return 1;
1612 else if (name[index] == '/')
1613 return 0;
1615 return 0;
1616 #else
1617 return (length != 0) &&
1618 (*name == '/' || *name == DIR_SEPARATOR
1619 #if defined (__EMX__) || defined (MSDOS) || defined (WINNT)
1620 || (length > 1 && isalpha (name[0]) && name[1] == ':')
1621 #endif
1623 #endif
1627 __gnat_is_regular_file (char *name)
1629 int ret;
1630 struct stat statbuf;
1632 ret = __gnat_stat (name, &statbuf);
1633 return (!ret && S_ISREG (statbuf.st_mode));
1637 __gnat_is_directory (char *name)
1639 int ret;
1640 struct stat statbuf;
1642 ret = __gnat_stat (name, &statbuf);
1643 return (!ret && S_ISDIR (statbuf.st_mode));
1647 __gnat_is_readable_file (char *name)
1649 int ret;
1650 int mode;
1651 struct stat statbuf;
1653 ret = __gnat_stat (name, &statbuf);
1654 mode = statbuf.st_mode & S_IRUSR;
1655 return (!ret && mode);
1659 __gnat_is_writable_file (char *name)
1661 int ret;
1662 int mode;
1663 struct stat statbuf;
1665 ret = __gnat_stat (name, &statbuf);
1666 mode = statbuf.st_mode & S_IWUSR;
1667 return (!ret && mode);
1670 void
1671 __gnat_set_writable (char *name)
1673 #if ! defined (__vxworks) && ! defined(__nucleus__)
1674 struct stat statbuf;
1676 if (stat (name, &statbuf) == 0)
1678 statbuf.st_mode = statbuf.st_mode | S_IWUSR;
1679 chmod (name, statbuf.st_mode);
1681 #endif
1684 void
1685 __gnat_set_executable (char *name)
1687 #if ! defined (__vxworks) && ! defined(__nucleus__)
1688 struct stat statbuf;
1690 if (stat (name, &statbuf) == 0)
1692 statbuf.st_mode = statbuf.st_mode | S_IXUSR;
1693 chmod (name, statbuf.st_mode);
1695 #endif
1698 void
1699 __gnat_set_readonly (char *name)
1701 #if ! defined (__vxworks) && ! defined(__nucleus__)
1702 struct stat statbuf;
1704 if (stat (name, &statbuf) == 0)
1706 statbuf.st_mode = statbuf.st_mode & 07577;
1707 chmod (name, statbuf.st_mode);
1709 #endif
1713 __gnat_is_symbolic_link (char *name ATTRIBUTE_UNUSED)
1715 #if defined (__vxworks) || defined (__nucleus__)
1716 return 0;
1718 #elif defined (_AIX) || defined (__APPLE__) || defined (__unix__)
1719 int ret;
1720 struct stat statbuf;
1722 ret = lstat (name, &statbuf);
1723 return (!ret && S_ISLNK (statbuf.st_mode));
1725 #else
1726 return 0;
1727 #endif
1730 #if defined (sun) && defined (__SVR4)
1731 /* Using fork on Solaris will duplicate all the threads. fork1, which
1732 duplicates only the active thread, must be used instead, or spawning
1733 subprocess from a program with tasking will lead into numerous problems. */
1734 #define fork fork1
1735 #endif
1738 __gnat_portable_spawn (char *args[])
1740 int status = 0;
1741 int finished ATTRIBUTE_UNUSED;
1742 int pid ATTRIBUTE_UNUSED;
1744 #if defined (__vxworks) || defined(__nucleus__) || defined(RTX)
1745 return -1;
1747 #elif defined (MSDOS) || defined (_WIN32)
1748 /* args[0] must be quotes as it could contain a full pathname with spaces */
1749 char *args_0 = args[0];
1750 args[0] = (char *)xmalloc (strlen (args_0) + 3);
1751 strcpy (args[0], "\"");
1752 strcat (args[0], args_0);
1753 strcat (args[0], "\"");
1755 status = spawnvp (P_WAIT, args_0, (const char* const*)args);
1757 /* restore previous value */
1758 free (args[0]);
1759 args[0] = (char *)args_0;
1761 if (status < 0)
1762 return -1;
1763 else
1764 return status;
1766 #else
1768 #ifdef __EMX__
1769 pid = spawnvp (P_NOWAIT, args[0], args);
1770 if (pid == -1)
1771 return -1;
1773 #else
1774 pid = fork ();
1775 if (pid < 0)
1776 return -1;
1778 if (pid == 0)
1780 /* The child. */
1781 if (execv (args[0], MAYBE_TO_PTR32 (args)) != 0)
1782 #if defined (VMS)
1783 return -1; /* execv is in parent context on VMS. */
1784 #else
1785 _exit (1);
1786 #endif
1788 #endif
1790 /* The parent. */
1791 finished = waitpid (pid, &status, 0);
1793 if (finished != pid || WIFEXITED (status) == 0)
1794 return -1;
1796 return WEXITSTATUS (status);
1797 #endif
1799 return 0;
1802 /* Create a copy of the given file descriptor.
1803 Return -1 if an error occurred. */
1806 __gnat_dup (int oldfd)
1808 #if defined (__vxworks) && !defined (__RTP__)
1809 /* Not supported on VxWorks 5.x, but supported on VxWorks 6.0 when using
1810 RTPs. */
1811 return -1;
1812 #else
1813 return dup (oldfd);
1814 #endif
1817 /* Make newfd be the copy of oldfd, closing newfd first if necessary.
1818 Return -1 if an error occurred. */
1821 __gnat_dup2 (int oldfd, int newfd)
1823 #if defined (__vxworks) && !defined (__RTP__)
1824 /* Not supported on VxWorks 5.x, but supported on VxWorks 6.0 when using
1825 RTPs. */
1826 return -1;
1827 #else
1828 return dup2 (oldfd, newfd);
1829 #endif
1832 /* WIN32 code to implement a wait call that wait for any child process. */
1834 #if defined (_WIN32) && !defined (RTX)
1836 /* Synchronization code, to be thread safe. */
1838 static CRITICAL_SECTION plist_cs;
1840 void
1841 __gnat_plist_init (void)
1843 InitializeCriticalSection (&plist_cs);
1846 static void
1847 plist_enter (void)
1849 EnterCriticalSection (&plist_cs);
1852 static void
1853 plist_leave (void)
1855 LeaveCriticalSection (&plist_cs);
1858 typedef struct _process_list
1860 HANDLE h;
1861 struct _process_list *next;
1862 } Process_List;
1864 static Process_List *PLIST = NULL;
1866 static int plist_length = 0;
1868 static void
1869 add_handle (HANDLE h)
1871 Process_List *pl;
1873 pl = (Process_List *) xmalloc (sizeof (Process_List));
1875 plist_enter();
1877 /* -------------------- critical section -------------------- */
1878 pl->h = h;
1879 pl->next = PLIST;
1880 PLIST = pl;
1881 ++plist_length;
1882 /* -------------------- critical section -------------------- */
1884 plist_leave();
1887 static void
1888 remove_handle (HANDLE h)
1890 Process_List *pl;
1891 Process_List *prev = NULL;
1893 plist_enter();
1895 /* -------------------- critical section -------------------- */
1896 pl = PLIST;
1897 while (pl)
1899 if (pl->h == h)
1901 if (pl == PLIST)
1902 PLIST = pl->next;
1903 else
1904 prev->next = pl->next;
1905 free (pl);
1906 break;
1908 else
1910 prev = pl;
1911 pl = pl->next;
1915 --plist_length;
1916 /* -------------------- critical section -------------------- */
1918 plist_leave();
1921 static int
1922 win32_no_block_spawn (char *command, char *args[])
1924 BOOL result;
1925 STARTUPINFO SI;
1926 PROCESS_INFORMATION PI;
1927 SECURITY_ATTRIBUTES SA;
1928 int csize = 1;
1929 char *full_command;
1930 int k;
1932 /* compute the total command line length */
1933 k = 0;
1934 while (args[k])
1936 csize += strlen (args[k]) + 1;
1937 k++;
1940 full_command = (char *) xmalloc (csize);
1942 /* Startup info. */
1943 SI.cb = sizeof (STARTUPINFO);
1944 SI.lpReserved = NULL;
1945 SI.lpReserved2 = NULL;
1946 SI.lpDesktop = NULL;
1947 SI.cbReserved2 = 0;
1948 SI.lpTitle = NULL;
1949 SI.dwFlags = 0;
1950 SI.wShowWindow = SW_HIDE;
1952 /* Security attributes. */
1953 SA.nLength = sizeof (SECURITY_ATTRIBUTES);
1954 SA.bInheritHandle = TRUE;
1955 SA.lpSecurityDescriptor = NULL;
1957 /* Prepare the command string. */
1958 strcpy (full_command, command);
1959 strcat (full_command, " ");
1961 k = 1;
1962 while (args[k])
1964 strcat (full_command, args[k]);
1965 strcat (full_command, " ");
1966 k++;
1970 int wsize = csize * 2;
1971 TCHAR *wcommand = (TCHAR *) xmalloc (wsize);
1973 S2WSU (wcommand, full_command, wsize);
1975 free (full_command);
1977 result = CreateProcess
1978 (NULL, wcommand, &SA, NULL, TRUE,
1979 GetPriorityClass (GetCurrentProcess()), NULL, NULL, &SI, &PI);
1981 free (wcommand);
1984 if (result == TRUE)
1986 add_handle (PI.hProcess);
1987 CloseHandle (PI.hThread);
1988 return (int) PI.hProcess;
1990 else
1991 return -1;
1994 static int
1995 win32_wait (int *status)
1997 DWORD exitcode;
1998 HANDLE *hl;
1999 HANDLE h;
2000 DWORD res;
2001 int k;
2002 Process_List *pl;
2004 if (plist_length == 0)
2006 errno = ECHILD;
2007 return -1;
2010 hl = (HANDLE *) xmalloc (sizeof (HANDLE) * plist_length);
2012 k = 0;
2013 plist_enter();
2015 /* -------------------- critical section -------------------- */
2016 pl = PLIST;
2017 while (pl)
2019 hl[k++] = pl->h;
2020 pl = pl->next;
2022 /* -------------------- critical section -------------------- */
2024 plist_leave();
2026 res = WaitForMultipleObjects (plist_length, hl, FALSE, INFINITE);
2027 h = hl[res - WAIT_OBJECT_0];
2028 free (hl);
2030 remove_handle (h);
2032 GetExitCodeProcess (h, &exitcode);
2033 CloseHandle (h);
2035 *status = (int) exitcode;
2036 return (int) h;
2039 #endif
2042 __gnat_portable_no_block_spawn (char *args[])
2044 int pid = 0;
2046 #if defined (__vxworks) || defined (__nucleus__) || defined (RTX)
2047 return -1;
2049 #elif defined (__EMX__) || defined (MSDOS)
2051 /* ??? For PC machines I (Franco) don't know the system calls to implement
2052 this routine. So I'll fake it as follows. This routine will behave
2053 exactly like the blocking portable_spawn and will systematically return
2054 a pid of 0 unless the spawned task did not complete successfully, in
2055 which case we return a pid of -1. To synchronize with this the
2056 portable_wait below systematically returns a pid of 0 and reports that
2057 the subprocess terminated successfully. */
2059 if (spawnvp (P_WAIT, args[0], args) != 0)
2060 return -1;
2062 #elif defined (_WIN32)
2064 pid = win32_no_block_spawn (args[0], args);
2065 return pid;
2067 #else
2068 pid = fork ();
2070 if (pid == 0)
2072 /* The child. */
2073 if (execv (args[0], MAYBE_TO_PTR32 (args)) != 0)
2074 #if defined (VMS)
2075 return -1; /* execv is in parent context on VMS. */
2076 #else
2077 _exit (1);
2078 #endif
2081 #endif
2083 return pid;
2087 __gnat_portable_wait (int *process_status)
2089 int status = 0;
2090 int pid = 0;
2092 #if defined (__vxworks) || defined (__nucleus__) || defined (RTX)
2093 /* Not sure what to do here, so do same as __EMX__ case, i.e., nothing but
2094 return zero. */
2096 #elif defined (_WIN32)
2098 pid = win32_wait (&status);
2100 #elif defined (__EMX__) || defined (MSDOS)
2101 /* ??? See corresponding comment in portable_no_block_spawn. */
2103 #else
2105 pid = waitpid (-1, &status, 0);
2106 status = status & 0xffff;
2107 #endif
2109 *process_status = status;
2110 return pid;
2113 void
2114 __gnat_os_exit (int status)
2116 exit (status);
2119 /* Locate a regular file, give a Path value. */
2121 char *
2122 __gnat_locate_regular_file (char *file_name, char *path_val)
2124 char *ptr;
2125 char *file_path = alloca (strlen (file_name) + 1);
2126 int absolute;
2128 /* Return immediately if file_name is empty */
2130 if (*file_name == '\0')
2131 return 0;
2133 /* Remove quotes around file_name if present */
2135 ptr = file_name;
2136 if (*ptr == '"')
2137 ptr++;
2139 strcpy (file_path, ptr);
2141 ptr = file_path + strlen (file_path) - 1;
2143 if (*ptr == '"')
2144 *ptr = '\0';
2146 /* Handle absolute pathnames. */
2148 absolute = __gnat_is_absolute_path (file_path, strlen (file_name));
2150 if (absolute)
2152 if (__gnat_is_regular_file (file_path))
2153 return xstrdup (file_path);
2155 return 0;
2158 /* If file_name include directory separator(s), try it first as
2159 a path name relative to the current directory */
2160 for (ptr = file_name; *ptr && *ptr != '/' && *ptr != DIR_SEPARATOR; ptr++)
2163 if (*ptr != 0)
2165 if (__gnat_is_regular_file (file_name))
2166 return xstrdup (file_name);
2169 if (path_val == 0)
2170 return 0;
2173 /* The result has to be smaller than path_val + file_name. */
2174 char *file_path = alloca (strlen (path_val) + strlen (file_name) + 2);
2176 for (;;)
2178 for (; *path_val == PATH_SEPARATOR; path_val++)
2181 if (*path_val == 0)
2182 return 0;
2184 /* Skip the starting quote */
2186 if (*path_val == '"')
2187 path_val++;
2189 for (ptr = file_path; *path_val && *path_val != PATH_SEPARATOR; )
2190 *ptr++ = *path_val++;
2192 ptr--;
2194 /* Skip the ending quote */
2196 if (*ptr == '"')
2197 ptr--;
2199 if (*ptr != '/' && *ptr != DIR_SEPARATOR)
2200 *++ptr = DIR_SEPARATOR;
2202 strcpy (++ptr, file_name);
2204 if (__gnat_is_regular_file (file_path))
2205 return xstrdup (file_path);
2209 return 0;
2212 /* Locate an executable given a Path argument. This routine is only used by
2213 gnatbl and should not be used otherwise. Use locate_exec_on_path
2214 instead. */
2216 char *
2217 __gnat_locate_exec (char *exec_name, char *path_val)
2219 char *ptr;
2220 if (!strstr (exec_name, HOST_EXECUTABLE_SUFFIX))
2222 char *full_exec_name
2223 = alloca (strlen (exec_name) + strlen (HOST_EXECUTABLE_SUFFIX) + 1);
2225 strcpy (full_exec_name, exec_name);
2226 strcat (full_exec_name, HOST_EXECUTABLE_SUFFIX);
2227 ptr = __gnat_locate_regular_file (full_exec_name, path_val);
2229 if (ptr == 0)
2230 return __gnat_locate_regular_file (exec_name, path_val);
2231 return ptr;
2233 else
2234 return __gnat_locate_regular_file (exec_name, path_val);
2237 /* Locate an executable using the Systems default PATH. */
2239 char *
2240 __gnat_locate_exec_on_path (char *exec_name)
2242 char *apath_val;
2244 #if defined (_WIN32) && !defined (RTX)
2245 TCHAR *wpath_val = _tgetenv (_T("PATH"));
2246 TCHAR *wapath_val;
2247 /* In Win32 systems we expand the PATH as for XP environment
2248 variables are not automatically expanded. We also prepend the
2249 ".;" to the path to match normal NT path search semantics */
2251 #define EXPAND_BUFFER_SIZE 32767
2253 wapath_val = alloca (EXPAND_BUFFER_SIZE);
2255 wapath_val [0] = '.';
2256 wapath_val [1] = ';';
2258 DWORD res = ExpandEnvironmentStrings
2259 (wpath_val, &wapath_val[2], EXPAND_BUFFER_SIZE - 2);
2261 if (!res) wapath_val [0] = _T('\0');
2263 apath_val = alloca (EXPAND_BUFFER_SIZE);
2265 WS2SU (apath_val, wapath_val, EXPAND_BUFFER_SIZE);
2266 return __gnat_locate_exec (exec_name, apath_val);
2268 #else
2270 #ifdef VMS
2271 char *path_val = "/VAXC$PATH";
2272 #else
2273 char *path_val = getenv ("PATH");
2274 #endif
2275 if (path_val == NULL) return NULL;
2276 apath_val = alloca (strlen (path_val) + 1);
2277 strcpy (apath_val, path_val);
2278 return __gnat_locate_exec (exec_name, apath_val);
2279 #endif
2282 #ifdef VMS
2284 /* These functions are used to translate to and from VMS and Unix syntax
2285 file, directory and path specifications. */
2287 #define MAXPATH 256
2288 #define MAXNAMES 256
2289 #define NEW_CANONICAL_FILELIST_INCREMENT 64
2291 static char new_canonical_dirspec [MAXPATH];
2292 static char new_canonical_filespec [MAXPATH];
2293 static char new_canonical_pathspec [MAXNAMES*MAXPATH];
2294 static unsigned new_canonical_filelist_index;
2295 static unsigned new_canonical_filelist_in_use;
2296 static unsigned new_canonical_filelist_allocated;
2297 static char **new_canonical_filelist;
2298 static char new_host_pathspec [MAXNAMES*MAXPATH];
2299 static char new_host_dirspec [MAXPATH];
2300 static char new_host_filespec [MAXPATH];
2302 /* Routine is called repeatedly by decc$from_vms via
2303 __gnat_to_canonical_file_list_init until it returns 0 or the expansion
2304 runs out. */
2306 static int
2307 wildcard_translate_unix (char *name)
2309 char *ver;
2310 char buff [MAXPATH];
2312 strncpy (buff, name, MAXPATH);
2313 buff [MAXPATH - 1] = (char) 0;
2314 ver = strrchr (buff, '.');
2316 /* Chop off the version. */
2317 if (ver)
2318 *ver = 0;
2320 /* Dynamically extend the allocation by the increment. */
2321 if (new_canonical_filelist_in_use == new_canonical_filelist_allocated)
2323 new_canonical_filelist_allocated += NEW_CANONICAL_FILELIST_INCREMENT;
2324 new_canonical_filelist = (char **) xrealloc
2325 (new_canonical_filelist,
2326 new_canonical_filelist_allocated * sizeof (char *));
2329 new_canonical_filelist[new_canonical_filelist_in_use++] = xstrdup (buff);
2331 return 1;
2334 /* Translate a wildcard VMS file spec into a list of Unix file specs. First do
2335 full translation and copy the results into a list (_init), then return them
2336 one at a time (_next). If onlydirs set, only expand directory files. */
2339 __gnat_to_canonical_file_list_init (char *filespec, int onlydirs)
2341 int len;
2342 char buff [MAXPATH];
2344 len = strlen (filespec);
2345 strncpy (buff, filespec, MAXPATH);
2347 /* Only look for directories */
2348 if (onlydirs && !strstr (&buff [len-5], "*.dir"))
2349 strncat (buff, "*.dir", MAXPATH);
2351 buff [MAXPATH - 1] = (char) 0;
2353 decc$from_vms (buff, wildcard_translate_unix, 1);
2355 /* Remove the .dir extension. */
2356 if (onlydirs)
2358 int i;
2359 char *ext;
2361 for (i = 0; i < new_canonical_filelist_in_use; i++)
2363 ext = strstr (new_canonical_filelist[i], ".dir");
2364 if (ext)
2365 *ext = 0;
2369 return new_canonical_filelist_in_use;
2372 /* Return the next filespec in the list. */
2374 char *
2375 __gnat_to_canonical_file_list_next ()
2377 return new_canonical_filelist[new_canonical_filelist_index++];
2380 /* Free storage used in the wildcard expansion. */
2382 void
2383 __gnat_to_canonical_file_list_free ()
2385 int i;
2387 for (i = 0; i < new_canonical_filelist_in_use; i++)
2388 free (new_canonical_filelist[i]);
2390 free (new_canonical_filelist);
2392 new_canonical_filelist_in_use = 0;
2393 new_canonical_filelist_allocated = 0;
2394 new_canonical_filelist_index = 0;
2395 new_canonical_filelist = 0;
2398 /* The functional equivalent of decc$translate_vms routine.
2399 Designed to produce the same output, but is protected against
2400 malformed paths (original version ACCVIOs in this case) and
2401 does not require VMS-specific DECC RTL */
2403 #define NAM$C_MAXRSS 1024
2405 char *
2406 __gnat_translate_vms (char *src)
2408 static char retbuf [NAM$C_MAXRSS+1];
2409 char *srcendpos, *pos1, *pos2, *retpos;
2410 int disp, path_present = 0;
2412 if (!src) return NULL;
2414 srcendpos = strchr (src, '\0');
2415 retpos = retbuf;
2417 /* Look for the node and/or device in front of the path */
2418 pos1 = src;
2419 pos2 = strchr (pos1, ':');
2421 if (pos2 && (pos2 < srcendpos) && (*(pos2 + 1) == ':')) {
2422 /* There is a node name. "node_name::" becomes "node_name!" */
2423 disp = pos2 - pos1;
2424 strncpy (retbuf, pos1, disp);
2425 retpos [disp] = '!';
2426 retpos = retpos + disp + 1;
2427 pos1 = pos2 + 2;
2428 pos2 = strchr (pos1, ':');
2431 if (pos2) {
2432 /* There is a device name. "dev_name:" becomes "/dev_name/" */
2433 *(retpos++) = '/';
2434 disp = pos2 - pos1;
2435 strncpy (retpos, pos1, disp);
2436 retpos = retpos + disp;
2437 pos1 = pos2 + 1;
2438 *(retpos++) = '/';
2440 else
2441 /* No explicit device; we must look ahead and prepend /sys$disk/ if
2442 the path is absolute */
2443 if ((*pos1 == '[' || *pos1 == '<') && (pos1 < srcendpos)
2444 && !strchr (".-]>", *(pos1 + 1))) {
2445 strncpy (retpos, "/sys$disk/", 10);
2446 retpos += 10;
2449 /* Process the path part */
2450 while (*pos1 == '[' || *pos1 == '<') {
2451 path_present++;
2452 pos1++;
2453 if (*pos1 == ']' || *pos1 == '>') {
2454 /* Special case, [] translates to '.' */
2455 *(retpos++) = '.';
2456 pos1++;
2458 else {
2459 /* '[000000' means root dir. It can be present in the middle of
2460 the path due to expansion of logical devices, in which case
2461 we skip it */
2462 if (!strncmp (pos1, "000000", 6) && path_present > 1 &&
2463 (*(pos1 + 6) == ']' || *(pos1 + 6) == '>' || *(pos1 + 6) == '.')) {
2464 pos1 += 6;
2465 if (*pos1 == '.') pos1++;
2467 else if (*pos1 == '.') {
2468 /* Relative path */
2469 *(retpos++) = '.';
2472 /* There is a qualified path */
2473 while (*pos1 && *pos1 != ']' && *pos1 != '>') {
2474 switch (*pos1) {
2475 case '.':
2476 /* '.' is used to separate directories. Replace it with '/' but
2477 only if there isn't already '/' just before */
2478 if (*(retpos - 1) != '/') *(retpos++) = '/';
2479 pos1++;
2480 if (pos1 + 1 < srcendpos && *pos1 == '.' && *(pos1 + 1) == '.') {
2481 /* ellipsis refers to entire subtree; replace with '**' */
2482 *(retpos++) = '*'; *(retpos++) = '*'; *(retpos++) = '/';
2483 pos1 += 2;
2485 break;
2486 case '-' :
2487 /* When after '.' '[' '<' is equivalent to Unix ".." but there
2488 may be several in a row */
2489 if (*(pos1 - 1) == '.' || *(pos1 - 1) == '[' ||
2490 *(pos1 - 1) == '<') {
2491 while (*pos1 == '-') {
2492 pos1++;
2493 *(retpos++) = '.'; *(retpos++) = '.'; *(retpos++) = '/';
2495 retpos--;
2496 break;
2498 /* otherwise fall through to default */
2499 default:
2500 *(retpos++) = *(pos1++);
2503 pos1++;
2507 if (pos1 < srcendpos) {
2508 /* Now add the actual file name, until the version suffix if any */
2509 if (path_present) *(retpos++) = '/';
2510 pos2 = strchr (pos1, ';');
2511 disp = pos2? (pos2 - pos1) : (srcendpos - pos1);
2512 strncpy (retpos, pos1, disp);
2513 retpos += disp;
2514 if (pos2 && pos2 < srcendpos) {
2515 /* There is a non-empty version suffix. ";<ver>" becomes ".<ver>" */
2516 *retpos++ = '.';
2517 disp = srcendpos - pos2 - 1;
2518 strncpy (retpos, pos2 + 1, disp);
2519 retpos += disp;
2523 *retpos = '\0';
2525 return retbuf;
2529 /* Translate a VMS syntax directory specification in to Unix syntax. If
2530 PREFIXFLAG is set, append an underscore "/". If no indicators of VMS syntax
2531 found, return input string. Also translate a dirname that contains no
2532 slashes, in case it's a logical name. */
2534 char *
2535 __gnat_to_canonical_dir_spec (char *dirspec, int prefixflag)
2537 int len;
2539 strcpy (new_canonical_dirspec, "");
2540 if (strlen (dirspec))
2542 char *dirspec1;
2544 if (strchr (dirspec, ']') || strchr (dirspec, ':'))
2546 strncpy (new_canonical_dirspec,
2547 __gnat_translate_vms (dirspec),
2548 MAXPATH);
2550 else if (!strchr (dirspec, '/') && (dirspec1 = getenv (dirspec)) != 0)
2552 strncpy (new_canonical_dirspec,
2553 __gnat_translate_vms (dirspec1),
2554 MAXPATH);
2556 else
2558 strncpy (new_canonical_dirspec, dirspec, MAXPATH);
2562 len = strlen (new_canonical_dirspec);
2563 if (prefixflag && new_canonical_dirspec [len-1] != '/')
2564 strncat (new_canonical_dirspec, "/", MAXPATH);
2566 new_canonical_dirspec [MAXPATH - 1] = (char) 0;
2568 return new_canonical_dirspec;
2572 /* Translate a VMS syntax file specification into Unix syntax.
2573 If no indicators of VMS syntax found, check if it's an uppercase
2574 alphanumeric_ name and if so try it out as an environment
2575 variable (logical name). If all else fails return the
2576 input string. */
2578 char *
2579 __gnat_to_canonical_file_spec (char *filespec)
2581 char *filespec1;
2583 strncpy (new_canonical_filespec, "", MAXPATH);
2585 if (strchr (filespec, ']') || strchr (filespec, ':'))
2587 char *tspec = (char *) __gnat_translate_vms (filespec);
2589 if (tspec != (char *) -1)
2590 strncpy (new_canonical_filespec, tspec, MAXPATH);
2592 else if ((strlen (filespec) == strspn (filespec,
2593 "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_"))
2594 && (filespec1 = getenv (filespec)))
2596 char *tspec = (char *) __gnat_translate_vms (filespec1);
2598 if (tspec != (char *) -1)
2599 strncpy (new_canonical_filespec, tspec, MAXPATH);
2601 else
2603 strncpy (new_canonical_filespec, filespec, MAXPATH);
2606 new_canonical_filespec [MAXPATH - 1] = (char) 0;
2608 return new_canonical_filespec;
2611 /* Translate a VMS syntax path specification into Unix syntax.
2612 If no indicators of VMS syntax found, return input string. */
2614 char *
2615 __gnat_to_canonical_path_spec (char *pathspec)
2617 char *curr, *next, buff [MAXPATH];
2619 if (pathspec == 0)
2620 return pathspec;
2622 /* If there are /'s, assume it's a Unix path spec and return. */
2623 if (strchr (pathspec, '/'))
2624 return pathspec;
2626 new_canonical_pathspec[0] = 0;
2627 curr = pathspec;
2629 for (;;)
2631 next = strchr (curr, ',');
2632 if (next == 0)
2633 next = strchr (curr, 0);
2635 strncpy (buff, curr, next - curr);
2636 buff[next - curr] = 0;
2638 /* Check for wildcards and expand if present. */
2639 if (strchr (buff, '*') || strchr (buff, '%') || strstr (buff, "..."))
2641 int i, dirs;
2643 dirs = __gnat_to_canonical_file_list_init (buff, 1);
2644 for (i = 0; i < dirs; i++)
2646 char *next_dir;
2648 next_dir = __gnat_to_canonical_file_list_next ();
2649 strncat (new_canonical_pathspec, next_dir, MAXPATH);
2651 /* Don't append the separator after the last expansion. */
2652 if (i+1 < dirs)
2653 strncat (new_canonical_pathspec, ":", MAXPATH);
2656 __gnat_to_canonical_file_list_free ();
2658 else
2659 strncat (new_canonical_pathspec,
2660 __gnat_to_canonical_dir_spec (buff, 0), MAXPATH);
2662 if (*next == 0)
2663 break;
2665 strncat (new_canonical_pathspec, ":", MAXPATH);
2666 curr = next + 1;
2669 new_canonical_pathspec [MAXPATH - 1] = (char) 0;
2671 return new_canonical_pathspec;
2674 static char filename_buff [MAXPATH];
2676 static int
2677 translate_unix (char *name, int type)
2679 strncpy (filename_buff, name, MAXPATH);
2680 filename_buff [MAXPATH - 1] = (char) 0;
2681 return 0;
2684 /* Translate a Unix syntax path spec into a VMS style (comma separated list of
2685 directories. */
2687 static char *
2688 to_host_path_spec (char *pathspec)
2690 char *curr, *next, buff [MAXPATH];
2692 if (pathspec == 0)
2693 return pathspec;
2695 /* Can't very well test for colons, since that's the Unix separator! */
2696 if (strchr (pathspec, ']') || strchr (pathspec, ','))
2697 return pathspec;
2699 new_host_pathspec[0] = 0;
2700 curr = pathspec;
2702 for (;;)
2704 next = strchr (curr, ':');
2705 if (next == 0)
2706 next = strchr (curr, 0);
2708 strncpy (buff, curr, next - curr);
2709 buff[next - curr] = 0;
2711 strncat (new_host_pathspec, __gnat_to_host_dir_spec (buff, 0), MAXPATH);
2712 if (*next == 0)
2713 break;
2714 strncat (new_host_pathspec, ",", MAXPATH);
2715 curr = next + 1;
2718 new_host_pathspec [MAXPATH - 1] = (char) 0;
2720 return new_host_pathspec;
2723 /* Translate a Unix syntax directory specification into VMS syntax. The
2724 PREFIXFLAG has no effect, but is kept for symmetry with
2725 to_canonical_dir_spec. If indicators of VMS syntax found, return input
2726 string. */
2728 char *
2729 __gnat_to_host_dir_spec (char *dirspec, int prefixflag ATTRIBUTE_UNUSED)
2731 int len = strlen (dirspec);
2733 strncpy (new_host_dirspec, dirspec, MAXPATH);
2734 new_host_dirspec [MAXPATH - 1] = (char) 0;
2736 if (strchr (new_host_dirspec, ']') || strchr (new_host_dirspec, ':'))
2737 return new_host_dirspec;
2739 while (len > 1 && new_host_dirspec[len - 1] == '/')
2741 new_host_dirspec[len - 1] = 0;
2742 len--;
2745 decc$to_vms (new_host_dirspec, translate_unix, 1, 2);
2746 strncpy (new_host_dirspec, filename_buff, MAXPATH);
2747 new_host_dirspec [MAXPATH - 1] = (char) 0;
2749 return new_host_dirspec;
2752 /* Translate a Unix syntax file specification into VMS syntax.
2753 If indicators of VMS syntax found, return input string. */
2755 char *
2756 __gnat_to_host_file_spec (char *filespec)
2758 strncpy (new_host_filespec, "", MAXPATH);
2759 if (strchr (filespec, ']') || strchr (filespec, ':'))
2761 strncpy (new_host_filespec, filespec, MAXPATH);
2763 else
2765 decc$to_vms (filespec, translate_unix, 1, 1);
2766 strncpy (new_host_filespec, filename_buff, MAXPATH);
2769 new_host_filespec [MAXPATH - 1] = (char) 0;
2771 return new_host_filespec;
2774 void
2775 __gnat_adjust_os_resource_limits ()
2777 SYS$ADJWSL (131072, 0);
2780 #else /* VMS */
2782 /* Dummy functions for Osint import for non-VMS systems. */
2785 __gnat_to_canonical_file_list_init
2786 (char *dirspec ATTRIBUTE_UNUSED, int onlydirs ATTRIBUTE_UNUSED)
2788 return 0;
2791 char *
2792 __gnat_to_canonical_file_list_next (void)
2794 return (char *) "";
2797 void
2798 __gnat_to_canonical_file_list_free (void)
2802 char *
2803 __gnat_to_canonical_dir_spec (char *dirspec, int prefixflag ATTRIBUTE_UNUSED)
2805 return dirspec;
2808 char *
2809 __gnat_to_canonical_file_spec (char *filespec)
2811 return filespec;
2814 char *
2815 __gnat_to_canonical_path_spec (char *pathspec)
2817 return pathspec;
2820 char *
2821 __gnat_to_host_dir_spec (char *dirspec, int prefixflag ATTRIBUTE_UNUSED)
2823 return dirspec;
2826 char *
2827 __gnat_to_host_file_spec (char *filespec)
2829 return filespec;
2832 void
2833 __gnat_adjust_os_resource_limits (void)
2837 #endif
2839 /* For EMX, we cannot include dummy in libgcc, since it is too difficult
2840 to coordinate this with the EMX distribution. Consequently, we put the
2841 definition of dummy which is used for exception handling, here. */
2843 #if defined (__EMX__)
2844 void __dummy () {}
2845 #endif
2847 #if defined (__mips_vxworks)
2849 _flush_cache()
2851 CACHE_USER_FLUSH (0, ENTIRE_CACHE);
2853 #endif
2855 #if defined (CROSS_DIRECTORY_STRUCTURE) \
2856 || (! ((defined (sparc) || defined (i386)) && defined (sun) \
2857 && defined (__SVR4)) \
2858 && ! (defined (linux) && (defined (i386) || defined (__x86_64__))) \
2859 && ! (defined (linux) && defined (__ia64__)) \
2860 && ! defined (__FreeBSD__) \
2861 && ! defined (__hpux__) \
2862 && ! defined (__APPLE__) \
2863 && ! defined (_AIX) \
2864 && ! (defined (__alpha__) && defined (__osf__)) \
2865 && ! defined (VMS) \
2866 && ! defined (__MINGW32__) \
2867 && ! (defined (__mips) && defined (__sgi)))
2869 /* Dummy function to satisfy g-trasym.o. See the preprocessor conditional
2870 just above for a list of native platforms that provide a non-dummy
2871 version of this procedure in libaddr2line.a. */
2873 void
2874 convert_addresses (const char *file_name ATTRIBUTE_UNUSED,
2875 void *addrs ATTRIBUTE_UNUSED,
2876 int n_addr ATTRIBUTE_UNUSED,
2877 void *buf ATTRIBUTE_UNUSED,
2878 int *len ATTRIBUTE_UNUSED)
2880 *len = 0;
2882 #endif
2884 #if defined (_WIN32)
2885 int __gnat_argument_needs_quote = 1;
2886 #else
2887 int __gnat_argument_needs_quote = 0;
2888 #endif
2890 /* This option is used to enable/disable object files handling from the
2891 binder file by the GNAT Project module. For example, this is disabled on
2892 Windows (prior to GCC 3.4) as it is already done by the mdll module.
2893 Stating with GCC 3.4 the shared libraries are not based on mdll
2894 anymore as it uses the GCC's -shared option */
2895 #if defined (_WIN32) \
2896 && ((__GNUC__ < 3) || ((__GNUC__ == 3) && (__GNUC_MINOR__ < 4)))
2897 int __gnat_prj_add_obj_files = 0;
2898 #else
2899 int __gnat_prj_add_obj_files = 1;
2900 #endif
2902 /* char used as prefix/suffix for environment variables */
2903 #if defined (_WIN32)
2904 char __gnat_environment_char = '%';
2905 #else
2906 char __gnat_environment_char = '$';
2907 #endif
2909 /* This functions copy the file attributes from a source file to a
2910 destination file.
2912 mode = 0 : In this mode copy only the file time stamps (last access and
2913 last modification time stamps).
2915 mode = 1 : In this mode, time stamps and read/write/execute attributes are
2916 copied.
2918 Returns 0 if operation was successful and -1 in case of error. */
2921 __gnat_copy_attribs (char *from, char *to, int mode)
2923 #if defined (VMS) || defined (__vxworks) || defined (__nucleus__)
2924 return -1;
2925 #else
2926 struct stat fbuf;
2927 struct utimbuf tbuf;
2929 if (stat (from, &fbuf) == -1)
2931 return -1;
2934 tbuf.actime = fbuf.st_atime;
2935 tbuf.modtime = fbuf.st_mtime;
2937 if (utime (to, &tbuf) == -1)
2939 return -1;
2942 if (mode == 1)
2944 if (chmod (to, fbuf.st_mode) == -1)
2946 return -1;
2950 return 0;
2951 #endif
2955 __gnat_lseek (int fd, long offset, int whence)
2957 return (int) lseek (fd, offset, whence);
2960 /* This function returns the major version number of GCC being used. */
2962 get_gcc_version (void)
2964 #ifdef IN_RTS
2965 return __GNUC__;
2966 #else
2967 return (int) (version_string[0] - '0');
2968 #endif
2972 __gnat_set_close_on_exec (int fd ATTRIBUTE_UNUSED,
2973 int close_on_exec_p ATTRIBUTE_UNUSED)
2975 #if defined (F_GETFD) && defined (FD_CLOEXEC) && ! defined (__vxworks)
2976 int flags = fcntl (fd, F_GETFD, 0);
2977 if (flags < 0)
2978 return flags;
2979 if (close_on_exec_p)
2980 flags |= FD_CLOEXEC;
2981 else
2982 flags &= ~FD_CLOEXEC;
2983 return fcntl (fd, F_SETFD, flags | FD_CLOEXEC);
2984 #else
2985 return -1;
2986 /* For the Windows case, we should use SetHandleInformation to remove
2987 the HANDLE_INHERIT property from fd. This is not implemented yet,
2988 but for our purposes (support of GNAT.Expect) this does not matter,
2989 as by default handles are *not* inherited. */
2990 #endif
2993 /* Indicates if platforms supports automatic initialization through the
2994 constructor mechanism */
2996 __gnat_binder_supports_auto_init ()
2998 #ifdef VMS
2999 return 0;
3000 #else
3001 return 1;
3002 #endif
3005 /* Indicates that Stand-Alone Libraries are automatically initialized through
3006 the constructor mechanism */
3008 __gnat_sals_init_using_constructors ()
3010 #if defined (__vxworks) || defined (__Lynx__) || defined (VMS)
3011 return 0;
3012 #else
3013 return 1;
3014 #endif
3017 /* In RTX mode, the procedure to get the time (as file time) is different
3018 in RTSS mode and Win32 mode. In order to avoid duplicating an Ada file,
3019 we introduce an intermediate procedure to link against the corresponding
3020 one in each situation. */
3021 #ifdef RTX
3023 void GetTimeAsFileTime(LPFILETIME pTime)
3025 #ifdef RTSS
3026 RtGetRtssTimeAsFileTime (pTime); /* RTSS interface */
3027 #else
3028 GetSystemTimeAsFileTime (pTime); /* w32 interface */
3029 #endif
3031 #endif
3033 #if defined (linux)
3034 /* pthread affinity support */
3036 #ifdef CPU_SETSIZE
3037 #include <pthread.h>
3039 __gnat_pthread_setaffinity_np (pthread_t th,
3040 size_t cpusetsize,
3041 const cpu_set_t *cpuset)
3043 return pthread_setaffinity_np (th, cpusetsize, cpuset);
3045 #else
3047 __gnat_pthread_setaffinity_np (pthread_t th,
3048 size_t cpusetsize,
3049 const void *cpuset)
3051 return 0;
3053 #endif
3054 #endif