]> git.ipfire.org Git - thirdparty/gcc.git/blame - gcc/ada/adaint.c
* gcc-interface/Make-lang.in: Update dependencies.
[thirdparty/gcc.git] / gcc / ada / adaint.c
CommitLineData
1fac938e 1/****************************************************************************
2 * *
3 * GNAT COMPILER COMPONENTS *
4 * *
5 * A D A I N T *
6 * *
1fac938e 7 * C Implementation File *
8 * *
6bc9506f 9 * Copyright (C) 1992-2009, Free Software Foundation, Inc. *
1fac938e 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- *
6bc9506f 13 * ware Foundation; either version 3, or (at your option) any later ver- *
1fac938e 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 *
6bc9506f 16 * or FITNESS FOR A PARTICULAR PURPOSE. *
17 * *
18 * As a special exception under Section 7 of GPL version 3, you are granted *
19 * additional permissions described in the GCC Runtime Library Exception, *
20 * version 3.1, as published by the Free Software Foundation. *
21 * *
22 * You should have received a copy of the GNU General Public License and *
23 * a copy of the GCC Runtime Library Exception along with this program; *
24 * see the files COPYING3 and COPYING.RUNTIME respectively. If not, see *
25 * <http://www.gnu.org/licenses/>. *
1fac938e 26 * *
27 * GNAT was originally developed by the GNAT team at New York University. *
e78e8c8e 28 * Extensive contributions were provided by Ada Core Technologies Inc. *
1fac938e 29 * *
30 ****************************************************************************/
31
f15731c4 32/* This file contains those routines named by Import pragmas in
33 packages in the GNAT hierarchy (especially GNAT.OS_Lib) and in
34 package Osint. Many of the subprograms in OS_Lib import standard
35 library calls directly. This file contains all other routines. */
1fac938e 36
37#ifdef __vxworks
f15731c4 38
39/* No need to redefine exit here. */
1fac938e 40#undef exit
f15731c4 41
1fac938e 42/* We want to use the POSIX variants of include files. */
43#define POSIX
44#include "vxWorks.h"
45
46#if defined (__mips_vxworks)
47#include "cacheLib.h"
48#endif /* __mips_vxworks */
49
50#endif /* VxWorks */
51
cafd02b3 52#ifdef VMS
53#define _POSIX_EXIT 1
ba706ed3 54#define HOST_EXECUTABLE_SUFFIX ".exe"
55#define HOST_OBJECT_SUFFIX ".obj"
cafd02b3 56#endif
57
1fac938e 58#ifdef IN_RTS
59#include "tconfig.h"
60#include "tsystem.h"
9dfe12ae 61
1fac938e 62#include <sys/stat.h>
63#include <fcntl.h>
64#include <time.h>
cafd02b3 65#ifdef VMS
66#include <unixio.h>
67#endif
1fac938e 68
f15731c4 69/* We don't have libiberty, so use malloc. */
1fac938e 70#define xmalloc(S) malloc (S)
f15731c4 71#define xrealloc(V,S) realloc (V,S)
1fac938e 72#else
73#include "config.h"
74#include "system.h"
e2c62f37 75#include "version.h"
1fac938e 76#endif
9dfe12ae 77
fa0b5df1 78#if defined (__MINGW32__)
79
e2a33c18 80#if defined (RTX)
81#include <windows.h>
82#include <Rtapi.h>
fa0b5df1 83#else
9dfe12ae 84#include "mingw32.h"
fa0b5df1 85#endif
86
9dfe12ae 87#include <sys/utime.h>
a4f295eb 88
89/* For isalpha-like tests in the compiler, we're expected to resort to
90 safe-ctype.h/ISALPHA. This isn't available for the runtime library
91 build, so we fallback on ctype.h/isalpha there. */
92
93#ifdef IN_RTS
f0a28ccb 94#include <ctype.h>
a4f295eb 95#define ISALPHA isalpha
96#endif
2359306a 97
98#elif defined (__Lynx__)
99
100/* Lynx utime.h only defines the entities of interest to us if
101 defined (VMOS_DEV), so ... */
102#define VMOS_DEV
103#include <utime.h>
104#undef VMOS_DEV
105
106#elif !defined (VMS)
9dfe12ae 107#include <utime.h>
9dfe12ae 108#endif
109
5091bc2f 110/* wait.h processing */
9dfe12ae 111#ifdef __MINGW32__
112#if OLD_MINGW
1fac938e 113#include <sys/wait.h>
9dfe12ae 114#endif
8ffbc401 115#elif defined (__vxworks) && defined (__RTP__)
116#include <wait.h>
2359306a 117#elif defined (__Lynx__)
118/* ??? We really need wait.h and it includes resource.h on Lynx. GCC
119 has a resource.h header as well, included instead of the lynx
120 version in our setup, causing lots of errors. We don't really need
121 the lynx contents of this file, so just workaround the issue by
122 preventing the inclusion of the GCC header from doing anything. */
123#define GCC_RESOURCE_H
124#include <sys/wait.h>
5091bc2f 125#elif defined (__nucleus__)
126/* No wait() or waitpid() calls available */
9dfe12ae 127#else
5091bc2f 128/* Default case */
9dfe12ae 129#include <sys/wait.h>
130#endif
1fac938e 131
d8dd2062 132#if defined (__EMX__) || defined (MSDOS) || defined (_WIN32)
133#elif defined (VMS)
71a3e619 134
f15731c4 135/* Header files and definitions for __gnat_set_file_time_name. */
71a3e619 136
8620a406 137#define __NEW_STARLET 1
ba706ed3 138#include <vms/rms.h>
139#include <vms/atrdef.h>
140#include <vms/fibdef.h>
141#include <vms/stsdef.h>
142#include <vms/iodef.h>
d8dd2062 143#include <errno.h>
ba706ed3 144#include <vms/descrip.h>
d8dd2062 145#include <string.h>
146#include <unixlib.h>
147
f15731c4 148/* Use native 64-bit arithmetic. */
d8dd2062 149#define unix_time_to_vms(X,Y) \
150 { unsigned long long reftime, tmptime = (X); \
151 $DESCRIPTOR (unixtime,"1-JAN-1970 0:00:00.00"); \
152 SYS$BINTIM (&unixtime, &reftime); \
153 Y = tmptime * 10000000 + reftime; }
154
155/* descrip.h doesn't have everything ... */
8620a406 156typedef struct fibdef* __fibdef_ptr32 __attribute__ (( mode (SI) ));
d8dd2062 157struct dsc$descriptor_fib
158{
8620a406 159 unsigned int fib$l_len;
160 __fibdef_ptr32 fib$l_addr;
d8dd2062 161};
162
71a3e619 163/* I/O Status Block. */
d8dd2062 164struct IOSB
9dfe12ae 165{
d8dd2062 166 unsigned short status, count;
8620a406 167 unsigned int devdep;
d8dd2062 168};
169
170static char *tryfile;
171
71a3e619 172/* Variable length string. */
d8dd2062 173struct vstring
174{
175 short length;
f15731c4 176 char string[NAM$C_MAXRSS+1];
d8dd2062 177};
178
d8dd2062 179#else
180#include <utime.h>
181#endif
182
1fac938e 183#if defined (__EMX__) || defined (MSDOS) || defined (_WIN32)
184#include <process.h>
185#endif
186
187#if defined (_WIN32)
188#include <dir.h>
189#include <windows.h>
7db1ef17 190#include <accctrl.h>
191#include <aclapi.h>
fef772a5 192#undef DIR_SEPARATOR
193#define DIR_SEPARATOR '\\'
1fac938e 194#endif
195
196#include "adaint.h"
197
198/* Define symbols O_BINARY and O_TEXT as harmless zeroes if they are not
199 defined in the current system. On DOS-like systems these flags control
200 whether the file is opened/created in text-translation mode (CR/LF in
201 external file mapped to LF in internal file), but in Unix-like systems,
202 no text translation is required, so these flags have no effect. */
203
204#if defined (__EMX__)
205#include <os2.h>
206#endif
207
208#if defined (MSDOS)
209#include <dos.h>
210#endif
211
212#ifndef O_BINARY
213#define O_BINARY 0
214#endif
215
216#ifndef O_TEXT
217#define O_TEXT 0
218#endif
219
220#ifndef HOST_EXECUTABLE_SUFFIX
221#define HOST_EXECUTABLE_SUFFIX ""
222#endif
223
224#ifndef HOST_OBJECT_SUFFIX
225#define HOST_OBJECT_SUFFIX ".o"
226#endif
227
228#ifndef PATH_SEPARATOR
229#define PATH_SEPARATOR ':'
230#endif
231
232#ifndef DIR_SEPARATOR
233#define DIR_SEPARATOR '/'
234#endif
235
a3b0f4f2 236/* Check for cross-compilation */
29d774d0 237#ifdef CROSS_DIRECTORY_STRUCTURE
a3b0f4f2 238int __gnat_is_cross_compiler = 1;
239#else
240int __gnat_is_cross_compiler = 0;
241#endif
242
1fac938e 243char __gnat_dir_separator = DIR_SEPARATOR;
244
245char __gnat_path_separator = PATH_SEPARATOR;
246
247/* The GNAT_LIBRARY_TEMPLATE contains a list of expressions that define
248 the base filenames that libraries specified with -lsomelib options
249 may have. This is used by GNATMAKE to check whether an executable
250 is up-to-date or not. The syntax is
251
252 library_template ::= { pattern ; } pattern NUL
253 pattern ::= [ prefix ] * [ postfix ]
254
255 These should only specify names of static libraries as it makes
256 no sense to determine at link time if dynamic-link libraries are
257 up to date or not. Any libraries that are not found are supposed
258 to be up-to-date:
259
260 * if they are needed but not present, the link
261 will fail,
262
263 * otherwise they are libraries in the system paths and so
264 they are considered part of the system and not checked
265 for that reason.
266
267 ??? This should be part of a GNAT host-specific compiler
268 file instead of being included in all user applications
f15731c4 269 as well. This is only a temporary work-around for 3.11b. */
1fac938e 270
271#ifndef GNAT_LIBRARY_TEMPLATE
f15731c4 272#if defined (__EMX__)
1fac938e 273#define GNAT_LIBRARY_TEMPLATE "*.a"
f15731c4 274#elif defined (VMS)
1fac938e 275#define GNAT_LIBRARY_TEMPLATE "*.olb"
276#else
277#define GNAT_LIBRARY_TEMPLATE "lib*.a"
278#endif
279#endif
280
281const char *__gnat_library_template = GNAT_LIBRARY_TEMPLATE;
282
f15731c4 283/* This variable is used in hostparm.ads to say whether the host is a VMS
284 system. */
285#ifdef VMS
286const int __gnat_vmsp = 1;
287#else
288const int __gnat_vmsp = 0;
289#endif
290
e633acdc 291#ifdef __EMX__
9dfe12ae 292#define GNAT_MAX_PATH_LEN MAX_PATH
e633acdc 293
294#elif defined (VMS)
9dfe12ae 295#define GNAT_MAX_PATH_LEN 256 /* PATH_MAX */
e633acdc 296
5091bc2f 297#elif defined (__vxworks) || defined (__OPENNT) || defined(__nucleus__)
9dfe12ae 298#define GNAT_MAX_PATH_LEN PATH_MAX
299
300#else
301
302#if defined (__MINGW32__)
303#include "mingw32.h"
304
305#if OLD_MINGW
306#include <sys/param.h>
307#endif
e633acdc 308
309#else
310#include <sys/param.h>
9dfe12ae 311#endif
312
8ae72cac 313#ifdef MAXPATHLEN
9dfe12ae 314#define GNAT_MAX_PATH_LEN MAXPATHLEN
8ae72cac 315#else
316#define GNAT_MAX_PATH_LEN 256
317#endif
e633acdc 318
319#endif
320
9dfe12ae 321/* The __gnat_max_path_len variable is used to export the maximum
322 length of a path name to Ada code. max_path_len is also provided
323 for compatibility with older GNAT versions, please do not use
324 it. */
325
326int __gnat_max_path_len = GNAT_MAX_PATH_LEN;
327int max_path_len = GNAT_MAX_PATH_LEN;
328
1fac938e 329/* The following macro HAVE_READDIR_R should be defined if the
f15731c4 330 system provides the routine readdir_r. */
1fac938e 331#undef HAVE_READDIR_R
332\f
6d9c3443 333#if defined(VMS) && defined (__LONG_POINTERS)
334
335/* Return a 32 bit pointer to an array of 32 bit pointers
336 given a 64 bit pointer to an array of 64 bit pointers */
337
338typedef __char_ptr32 *__char_ptr_char_ptr32 __attribute__ ((mode (SI)));
339
340static __char_ptr_char_ptr32
341to_ptr32 (char **ptr64)
342{
343 int argc;
344 __char_ptr_char_ptr32 short_argv;
345
346 for (argc=0; ptr64[argc]; argc++);
347
348 /* Reallocate argv with 32 bit pointers. */
349 short_argv = (__char_ptr_char_ptr32) decc$malloc
350 (sizeof (__char_ptr32) * (argc + 1));
351
352 for (argc=0; ptr64[argc]; argc++)
353 short_argv[argc] = (__char_ptr32) decc$strdup (ptr64[argc]);
354
355 short_argv[argc] = (__char_ptr32) 0;
356 return short_argv;
357
358}
359#define MAYBE_TO_PTR32(argv) to_ptr32 (argv)
360#else
361#define MAYBE_TO_PTR32(argv) argv
362#endif
363
1e622f0e 364OS_Time
365__gnat_current_time
366 (void)
367{
368 time_t res = time (NULL);
369 return (OS_Time) res;
370}
371
a17c817e 372/* Return the current local time as a string in the ISO 8601 format of
373 "YYYY-MM-DD HH:MM:SS.SS". The returned string is 22 + 1 (NULL) characters
374 long. */
375
376void
377__gnat_current_time_string
378 (char *result)
379{
380 const char *format = "%Y-%m-%d %H:%M:%S";
381 /* Format string necessary to describe the ISO 8601 format */
382
383 const time_t t_val = time (NULL);
384
385 strftime (result, 22, format, localtime (&t_val));
386 /* Convert the local time into a string following the ISO format, copying
387 at most 22 characters into the result string. */
388
389 result [19] = '.';
390 result [20] = '0';
391 result [21] = '0';
392 /* The sub-seconds are manually set to zero since type time_t lacks the
393 precision necessary for nanoseconds. */
394}
395
1fac938e 396void
9dfe12ae 397__gnat_to_gm_time
398 (OS_Time *p_time,
399 int *p_year,
400 int *p_month,
401 int *p_day,
402 int *p_hours,
403 int *p_mins,
404 int *p_secs)
1fac938e 405{
406 struct tm *res;
9dfe12ae 407 time_t time = (time_t) *p_time;
1fac938e 408
409#ifdef _WIN32
410 /* On Windows systems, the time is sometimes rounded up to the nearest
411 even second, so if the number of seconds is odd, increment it. */
412 if (time & 1)
413 time++;
414#endif
415
9dfe12ae 416#ifdef VMS
417 res = localtime (&time);
418#else
1fac938e 419 res = gmtime (&time);
9dfe12ae 420#endif
1fac938e 421
422 if (res)
423 {
424 *p_year = res->tm_year;
425 *p_month = res->tm_mon;
426 *p_day = res->tm_mday;
427 *p_hours = res->tm_hour;
428 *p_mins = res->tm_min;
429 *p_secs = res->tm_sec;
f15731c4 430 }
1fac938e 431 else
432 *p_year = *p_month = *p_day = *p_hours = *p_mins = *p_secs = 0;
433}
434
435/* Place the contents of the symbolic link named PATH in the buffer BUF,
436 which has size BUFSIZ. If PATH is a symbolic link, then return the number
5091bc2f 437 of characters of its content in BUF. Otherwise, return -1.
438 For systems not supporting symbolic links, always return -1. */
1fac938e 439
9dfe12ae 440int
f0a28ccb 441__gnat_readlink (char *path ATTRIBUTE_UNUSED,
442 char *buf ATTRIBUTE_UNUSED,
443 size_t bufsiz ATTRIBUTE_UNUSED)
1fac938e 444{
5091bc2f 445#if defined (MSDOS) || defined (_WIN32) || defined (__EMX__) \
acc10cf1 446 || defined (VMS) || defined(__vxworks) || defined (__nucleus__)
1fac938e 447 return -1;
448#else
449 return readlink (path, buf, bufsiz);
450#endif
451}
452
5091bc2f 453/* Creates a symbolic link named NEWPATH which contains the string OLDPATH.
454 If NEWPATH exists it will NOT be overwritten.
455 For systems not supporting symbolic links, always return -1. */
1fac938e 456
457int
f0a28ccb 458__gnat_symlink (char *oldpath ATTRIBUTE_UNUSED,
459 char *newpath ATTRIBUTE_UNUSED)
1fac938e 460{
5091bc2f 461#if defined (MSDOS) || defined (_WIN32) || defined (__EMX__) \
acc10cf1 462 || defined (VMS) || defined(__vxworks) || defined (__nucleus__)
1fac938e 463 return -1;
464#else
465 return symlink (oldpath, newpath);
466#endif
467}
468
f15731c4 469/* Try to lock a file, return 1 if success. */
1fac938e 470
a17c817e 471#if defined (__vxworks) || defined (__nucleus__) || defined (MSDOS) \
511d352a 472 || defined (_WIN32) || defined (__EMX__) || defined (VMS)
1fac938e 473
474/* Version that does not use link. */
475
476int
9dfe12ae 477__gnat_try_lock (char *dir, char *file)
1fac938e 478{
1fac938e 479 int fd;
3b18b370 480#ifdef __MINGW32__
481 TCHAR wfull_path[GNAT_MAX_PATH_LEN];
482 TCHAR wfile[GNAT_MAX_PATH_LEN];
483 TCHAR wdir[GNAT_MAX_PATH_LEN];
484
1e622f0e 485 S2WSU (wdir, dir, GNAT_MAX_PATH_LEN);
486 S2WSU (wfile, file, GNAT_MAX_PATH_LEN);
3b18b370 487
488 _stprintf (wfull_path, _T("%s%c%s"), wdir, _T(DIR_SEPARATOR), wfile);
489 fd = _topen (wfull_path, O_CREAT | O_EXCL, 0600);
490#else
491 char full_path[256];
1fac938e 492
493 sprintf (full_path, "%s%c%s", dir, DIR_SEPARATOR, file);
494 fd = open (full_path, O_CREAT | O_EXCL, 0600);
3b18b370 495#endif
496
f15731c4 497 if (fd < 0)
1fac938e 498 return 0;
f15731c4 499
1fac938e 500 close (fd);
501 return 1;
502}
503
1fac938e 504#else
f15731c4 505
1fac938e 506/* Version using link(), more secure over NFS. */
9dfe12ae 507/* See TN 6913-016 for discussion ??? */
1fac938e 508
509int
9dfe12ae 510__gnat_try_lock (char *dir, char *file)
1fac938e 511{
f15731c4 512 char full_path[256];
513 char temp_file[256];
1fac938e 514 struct stat stat_result;
515 int fd;
516
517 sprintf (full_path, "%s%c%s", dir, DIR_SEPARATOR, file);
4a3f445c 518 sprintf (temp_file, "%s%cTMP-%ld-%ld",
519 dir, DIR_SEPARATOR, (long)getpid(), (long)getppid ());
1fac938e 520
f15731c4 521 /* Create the temporary file and write the process number. */
1fac938e 522 fd = open (temp_file, O_CREAT | O_WRONLY, 0600);
523 if (fd < 0)
524 return 0;
525
526 close (fd);
527
f15731c4 528 /* Link it with the new file. */
1fac938e 529 link (temp_file, full_path);
530
531 /* Count the references on the old one. If we have a count of two, then
f15731c4 532 the link did succeed. Remove the temporary file before returning. */
1fac938e 533 __gnat_stat (temp_file, &stat_result);
534 unlink (temp_file);
535 return stat_result.st_nlink == 2;
536}
537#endif
538
539/* Return the maximum file name length. */
540
541int
6f2c2693 542__gnat_get_maximum_file_name_length (void)
1fac938e 543{
f15731c4 544#if defined (MSDOS)
1fac938e 545 return 8;
546#elif defined (VMS)
547 if (getenv ("GNAT$EXTENDED_FILE_SPECIFICATIONS"))
548 return -1;
549 else
550 return 39;
551#else
552 return -1;
553#endif
554}
555
1fac938e 556/* Return nonzero if file names are case sensitive. */
557
558int
6f2c2693 559__gnat_get_file_names_case_sensitive (void)
1fac938e 560{
f15731c4 561#if defined (__EMX__) || defined (MSDOS) || defined (VMS) || defined (WINNT)
1fac938e 562 return 0;
563#else
564 return 1;
565#endif
566}
567
568char
6f2c2693 569__gnat_get_default_identifier_character_set (void)
1fac938e 570{
571#if defined (__EMX__) || defined (MSDOS)
572 return 'p';
573#else
574 return '1';
575#endif
576}
577
f15731c4 578/* Return the current working directory. */
1fac938e 579
580void
9dfe12ae 581__gnat_get_current_dir (char *dir, int *length)
1fac938e 582{
3b18b370 583#if defined (__MINGW32__)
584 TCHAR wdir[GNAT_MAX_PATH_LEN];
585
586 _tgetcwd (wdir, *length);
587
1e622f0e 588 WS2SU (dir, wdir, GNAT_MAX_PATH_LEN);
3b18b370 589
590#elif defined (VMS)
1fac938e 591 /* Force Unix style, which is what GNAT uses internally. */
592 getcwd (dir, *length, 0);
593#else
594 getcwd (dir, *length);
595#endif
596
597 *length = strlen (dir);
598
9dfe12ae 599 if (dir [*length - 1] != DIR_SEPARATOR)
600 {
601 dir [*length] = DIR_SEPARATOR;
602 ++(*length);
603 }
f15731c4 604 dir[*length] = '\0';
1fac938e 605}
606
f15731c4 607/* Return the suffix for object files. */
1fac938e 608
609void
9dfe12ae 610__gnat_get_object_suffix_ptr (int *len, const char **value)
1fac938e 611{
612 *value = HOST_OBJECT_SUFFIX;
613
614 if (*value == 0)
615 *len = 0;
616 else
617 *len = strlen (*value);
618
619 return;
620}
621
f15731c4 622/* Return the suffix for executable files. */
1fac938e 623
624void
9dfe12ae 625__gnat_get_executable_suffix_ptr (int *len, const char **value)
1fac938e 626{
627 *value = HOST_EXECUTABLE_SUFFIX;
628 if (!*value)
629 *len = 0;
630 else
631 *len = strlen (*value);
632
633 return;
634}
635
636/* Return the suffix for debuggable files. Usually this is the same as the
f15731c4 637 executable extension. */
1fac938e 638
639void
9dfe12ae 640__gnat_get_debuggable_suffix_ptr (int *len, const char **value)
1fac938e 641{
642#ifndef MSDOS
643 *value = HOST_EXECUTABLE_SUFFIX;
644#else
f15731c4 645 /* On DOS, the extensionless COFF file is what gdb likes. */
1fac938e 646 *value = "";
647#endif
648
649 if (*value == 0)
650 *len = 0;
651 else
652 *len = strlen (*value);
653
654 return;
655}
656
1aa4b9ce 657/* Returns the OS filename and corresponding encoding. */
658
659void
c62e34a4 660__gnat_os_filename (char *filename, char *w_filename ATTRIBUTE_UNUSED,
1aa4b9ce 661 char *os_name, int *o_length,
c62e34a4 662 char *encoding ATTRIBUTE_UNUSED, int *e_length)
1aa4b9ce 663{
664#if defined (_WIN32) && ! defined (__vxworks) && ! defined (CROSS_DIRECTORY_STRUCTURE)
665 WS2SU (os_name, (TCHAR *)w_filename, o_length);
666 *o_length = strlen (os_name);
667 strcpy (encoding, "encoding=utf8");
668 *e_length = strlen (encoding);
669#else
670 strcpy (os_name, filename);
671 *o_length = strlen (filename);
672 *e_length = 0;
673#endif
674}
675
13320214 676/* Delete a file. */
677
678int
679__gnat_unlink (char *path)
680{
681#if defined (__MINGW32__) && ! defined (__vxworks) && ! defined (CROSS_COMPILE)
682 {
683 TCHAR wpath[GNAT_MAX_PATH_LEN];
684
685 S2WSU (wpath, path, GNAT_MAX_PATH_LEN);
686 return _tunlink (wpath);
687 }
688#else
689 return unlink (path);
690#endif
691}
692
693/* Rename a file. */
694
695int
696__gnat_rename (char *from, char *to)
697{
698#if defined (__MINGW32__) && ! defined (__vxworks) && ! defined (CROSS_COMPILE)
699 {
700 TCHAR wfrom[GNAT_MAX_PATH_LEN], wto[GNAT_MAX_PATH_LEN];
701
702 S2WSU (wfrom, from, GNAT_MAX_PATH_LEN);
703 S2WSU (wto, to, GNAT_MAX_PATH_LEN);
704 return _trename (wfrom, wto);
705 }
706#else
707 return rename (from, to);
708#endif
709}
710
a8d94a8f 711/* Changing directory. */
712
713int
714__gnat_chdir (char *path)
715{
716#if defined (__MINGW32__) && ! defined (__vxworks) && ! defined (CROSS_COMPILE)
717 {
718 TCHAR wpath[GNAT_MAX_PATH_LEN];
719
720 S2WSU (wpath, path, GNAT_MAX_PATH_LEN);
721 return _tchdir (wpath);
722 }
723#else
724 return chdir (path);
725#endif
726}
727
437991c2 728/* Removing a directory. */
729
730int
731__gnat_rmdir (char *path)
732{
733#if defined (__MINGW32__) && ! defined (__vxworks) && ! defined (CROSS_COMPILE)
734 {
735 TCHAR wpath[GNAT_MAX_PATH_LEN];
736
737 S2WSU (wpath, path, GNAT_MAX_PATH_LEN);
738 return _trmdir (wpath);
739 }
740#else
741 return rmdir (path);
742#endif
743}
744
e2c62f37 745FILE *
c62e34a4 746__gnat_fopen (char *path, char *mode, int encoding ATTRIBUTE_UNUSED)
e2c62f37 747{
29d774d0 748#if defined (_WIN32) && ! defined (__vxworks) && ! defined (CROSS_DIRECTORY_STRUCTURE)
e2c62f37 749 TCHAR wpath[GNAT_MAX_PATH_LEN];
750 TCHAR wmode[10];
751
e2c62f37 752 S2WS (wmode, mode, 10);
1e622f0e 753
754 if (encoding == Encoding_UTF8)
755 S2WSU (wpath, path, GNAT_MAX_PATH_LEN);
756 else
757 S2WS (wpath, path, GNAT_MAX_PATH_LEN);
758
e2c62f37 759 return _tfopen (wpath, wmode);
1e622f0e 760#elif defined (VMS)
761 return decc$fopen (path, mode);
e2c62f37 762#else
763 return fopen (path, mode);
764#endif
765}
766
e2c62f37 767FILE *
c62e34a4 768__gnat_freopen (char *path, char *mode, FILE *stream, int encoding ATTRIBUTE_UNUSED)
e2c62f37 769{
29d774d0 770#if defined (_WIN32) && ! defined (__vxworks) && ! defined (CROSS_DIRECTORY_STRUCTURE)
e2c62f37 771 TCHAR wpath[GNAT_MAX_PATH_LEN];
772 TCHAR wmode[10];
773
e2c62f37 774 S2WS (wmode, mode, 10);
1e622f0e 775
776 if (encoding == Encoding_UTF8)
777 S2WSU (wpath, path, GNAT_MAX_PATH_LEN);
778 else
779 S2WS (wpath, path, GNAT_MAX_PATH_LEN);
780
e2c62f37 781 return _tfreopen (wpath, wmode, stream);
1e622f0e 782#elif defined (VMS)
783 return decc$freopen (path, mode, stream);
e2c62f37 784#else
785 return freopen (path, mode, stream);
786#endif
787}
788
1fac938e 789int
9dfe12ae 790__gnat_open_read (char *path, int fmode)
1fac938e 791{
792 int fd;
793 int o_fmode = O_BINARY;
794
795 if (fmode)
796 o_fmode = O_TEXT;
797
f15731c4 798#if defined (VMS)
799 /* Optional arguments mbc,deq,fop increase read performance. */
1fac938e 800 fd = open (path, O_RDONLY | o_fmode, 0444,
801 "mbc=16", "deq=64", "fop=tef");
f15731c4 802#elif defined (__vxworks)
1fac938e 803 fd = open (path, O_RDONLY | o_fmode, 0444);
3b18b370 804#elif defined (__MINGW32__)
805 {
806 TCHAR wpath[GNAT_MAX_PATH_LEN];
807
1e622f0e 808 S2WSU (wpath, path, GNAT_MAX_PATH_LEN);
3b18b370 809 fd = _topen (wpath, O_RDONLY | o_fmode, 0444);
810 }
1fac938e 811#else
812 fd = open (path, O_RDONLY | o_fmode);
813#endif
f15731c4 814
1fac938e 815 return fd < 0 ? -1 : fd;
816}
817
9dfe12ae 818#if defined (__EMX__) || defined (__MINGW32__)
1fac938e 819#define PERM (S_IREAD | S_IWRITE)
9dfe12ae 820#elif defined (VMS)
821/* Excerpt from DECC C RTL Reference Manual:
822 To create files with OpenVMS RMS default protections using the UNIX
823 system-call functions umask, mkdir, creat, and open, call mkdir, creat,
824 and open with a file-protection mode argument of 0777 in a program
825 that never specifically calls umask. These default protections include
826 correctly establishing protections based on ACLs, previous versions of
827 files, and so on. */
828#define PERM 0777
1fac938e 829#else
830#define PERM (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH)
831#endif
832
833int
9dfe12ae 834__gnat_open_rw (char *path, int fmode)
1fac938e 835{
836 int fd;
837 int o_fmode = O_BINARY;
838
839 if (fmode)
840 o_fmode = O_TEXT;
841
f15731c4 842#if defined (VMS)
1fac938e 843 fd = open (path, O_RDWR | o_fmode, PERM,
844 "mbc=16", "deq=64", "fop=tef");
3b18b370 845#elif defined (__MINGW32__)
846 {
847 TCHAR wpath[GNAT_MAX_PATH_LEN];
848
1e622f0e 849 S2WSU (wpath, path, GNAT_MAX_PATH_LEN);
3b18b370 850 fd = _topen (wpath, O_RDWR | o_fmode, PERM);
851 }
1fac938e 852#else
853 fd = open (path, O_RDWR | o_fmode, PERM);
854#endif
855
856 return fd < 0 ? -1 : fd;
857}
858
859int
9dfe12ae 860__gnat_open_create (char *path, int fmode)
1fac938e 861{
862 int fd;
863 int o_fmode = O_BINARY;
864
865 if (fmode)
866 o_fmode = O_TEXT;
867
f15731c4 868#if defined (VMS)
1fac938e 869 fd = open (path, O_WRONLY | O_CREAT | O_TRUNC | o_fmode, PERM,
870 "mbc=16", "deq=64", "fop=tef");
3b18b370 871#elif defined (__MINGW32__)
872 {
873 TCHAR wpath[GNAT_MAX_PATH_LEN];
874
1e622f0e 875 S2WSU (wpath, path, GNAT_MAX_PATH_LEN);
3b18b370 876 fd = _topen (wpath, O_WRONLY | O_CREAT | O_TRUNC | o_fmode, PERM);
877 }
1fac938e 878#else
879 fd = open (path, O_WRONLY | O_CREAT | O_TRUNC | o_fmode, PERM);
880#endif
881
882 return fd < 0 ? -1 : fd;
28ed91d4 883}
884
885int
886__gnat_create_output_file (char *path)
887{
888 int fd;
889#if defined (VMS)
890 fd = open (path, O_WRONLY | O_CREAT | O_TRUNC | O_TEXT, PERM,
891 "rfm=stmlf", "ctx=rec", "rat=none", "rop=nlk",
892 "shr=del,get,put,upd");
3b18b370 893#elif defined (__MINGW32__)
894 {
895 TCHAR wpath[GNAT_MAX_PATH_LEN];
896
1e622f0e 897 S2WSU (wpath, path, GNAT_MAX_PATH_LEN);
3b18b370 898 fd = _topen (wpath, O_WRONLY | O_CREAT | O_TRUNC | O_TEXT, PERM);
899 }
28ed91d4 900#else
901 fd = open (path, O_WRONLY | O_CREAT | O_TRUNC | O_TEXT, PERM);
902#endif
903
904 return fd < 0 ? -1 : fd;
1fac938e 905}
906
907int
9dfe12ae 908__gnat_open_append (char *path, int fmode)
1fac938e 909{
910 int fd;
911 int o_fmode = O_BINARY;
912
913 if (fmode)
914 o_fmode = O_TEXT;
915
f15731c4 916#if defined (VMS)
1fac938e 917 fd = open (path, O_WRONLY | O_CREAT | O_APPEND | o_fmode, PERM,
918 "mbc=16", "deq=64", "fop=tef");
3b18b370 919#elif defined (__MINGW32__)
920 {
921 TCHAR wpath[GNAT_MAX_PATH_LEN];
922
1e622f0e 923 S2WSU (wpath, path, GNAT_MAX_PATH_LEN);
3b18b370 924 fd = _topen (wpath, O_WRONLY | O_CREAT | O_APPEND | o_fmode, PERM);
925 }
1fac938e 926#else
927 fd = open (path, O_WRONLY | O_CREAT | O_APPEND | o_fmode, PERM);
928#endif
929
930 return fd < 0 ? -1 : fd;
931}
932
f15731c4 933/* Open a new file. Return error (-1) if the file already exists. */
1fac938e 934
935int
9dfe12ae 936__gnat_open_new (char *path, int fmode)
1fac938e 937{
938 int fd;
939 int o_fmode = O_BINARY;
940
941 if (fmode)
942 o_fmode = O_TEXT;
943
f15731c4 944#if defined (VMS)
1fac938e 945 fd = open (path, O_WRONLY | O_CREAT | O_EXCL | o_fmode, PERM,
946 "mbc=16", "deq=64", "fop=tef");
3b18b370 947#elif defined (__MINGW32__)
948 {
949 TCHAR wpath[GNAT_MAX_PATH_LEN];
950
1e622f0e 951 S2WSU (wpath, path, GNAT_MAX_PATH_LEN);
3b18b370 952 fd = _topen (wpath, O_WRONLY | O_CREAT | O_EXCL | o_fmode, PERM);
953 }
1fac938e 954#else
955 fd = open (path, O_WRONLY | O_CREAT | O_EXCL | o_fmode, PERM);
956#endif
957
958 return fd < 0 ? -1 : fd;
959}
960
961/* Open a new temp file. Return error (-1) if the file already exists.
f15731c4 962 Special options for VMS allow the file to be shared between parent and child
963 processes, however they really slow down output. Used in gnatchop. */
1fac938e 964
965int
9dfe12ae 966__gnat_open_new_temp (char *path, int fmode)
1fac938e 967{
968 int fd;
969 int o_fmode = O_BINARY;
970
971 strcpy (path, "GNAT-XXXXXX");
972
e0324ff5 973#if (defined (__FreeBSD__) || defined (__NetBSD__) || defined (__OpenBSD__) \
9d093602 974 || defined (linux) || defined(__GLIBC__)) && !defined (__vxworks)
1fac938e 975 return mkstemp (path);
159eb63c 976#elif defined (__Lynx__)
977 mktemp (path);
5091bc2f 978#elif defined (__nucleus__)
979 return -1;
1fac938e 980#else
981 if (mktemp (path) == NULL)
982 return -1;
983#endif
984
985 if (fmode)
986 o_fmode = O_TEXT;
987
f15731c4 988#if defined (VMS)
1fac938e 989 fd = open (path, O_WRONLY | O_CREAT | O_EXCL | o_fmode, PERM,
990 "rfm=stmlf", "ctx=rec", "rat=none", "shr=del,get,put,upd",
991 "mbc=16", "deq=64", "fop=tef");
992#else
993 fd = open (path, O_WRONLY | O_CREAT | O_EXCL | o_fmode, PERM);
994#endif
995
996 return fd < 0 ? -1 : fd;
997}
998
f15731c4 999/* Return the number of bytes in the specified file. */
1fac938e 1000
1001long
9dfe12ae 1002__gnat_file_length (int fd)
1fac938e 1003{
1004 int ret;
1005 struct stat statbuf;
1006
1007 ret = fstat (fd, &statbuf);
1008 if (ret || !S_ISREG (statbuf.st_mode))
1009 return 0;
1010
1011 return (statbuf.st_size);
1012}
1013
d24d7e81 1014/* Return the number of bytes in the specified named file. */
1015
1016long
1017__gnat_named_file_length (char *name)
1018{
1019 int ret;
1020 struct stat statbuf;
1021
1022 ret = __gnat_stat (name, &statbuf);
1023 if (ret || !S_ISREG (statbuf.st_mode))
1024 return 0;
1025
1026 return (statbuf.st_size);
1027}
1028
1fac938e 1029/* Create a temporary filename and put it in string pointed to by
f15731c4 1030 TMP_FILENAME. */
1fac938e 1031
1032void
9dfe12ae 1033__gnat_tmp_name (char *tmp_filename)
1fac938e 1034{
72772d89 1035#ifdef RTX
f5099270 1036 /* Variable used to create a series of unique names */
1037 static int counter = 0;
1038
1039 /* RTX in RTSS mode does not support tempnam nor tmpnam so we emulate it */
1040 strcpy (tmp_filename, "c:\\WINDOWS\\Temp\\gnat-");
1041 sprintf (&tmp_filename[strlen (tmp_filename)], "%d\0", counter++);
72772d89 1042
1043#elif defined (__MINGW32__)
1fac938e 1044 {
1045 char *pname;
1046
1047 /* tempnam tries to create a temporary file in directory pointed to by
1048 TMP environment variable, in c:\temp if TMP is not set, and in
1049 directory specified by P_tmpdir in stdio.h if c:\temp does not
1050 exist. The filename will be created with the prefix "gnat-". */
1051
1052 pname = (char *) tempnam ("c:\\temp", "gnat-");
1053
9dfe12ae 1054 /* if pname is NULL, the file was not created properly, the disk is full
1055 or there is no more free temporary files */
1056
1057 if (pname == NULL)
1058 *tmp_filename = '\0';
1059
f15731c4 1060 /* If pname start with a back slash and not path information it means that
1061 the filename is valid for the current working directory. */
1fac938e 1062
9dfe12ae 1063 else if (pname[0] == '\\')
1fac938e 1064 {
1065 strcpy (tmp_filename, ".\\");
1066 strcat (tmp_filename, pname+1);
1067 }
1068 else
1069 strcpy (tmp_filename, pname);
1070
1071 free (pname);
1072 }
f15731c4 1073
e0324ff5 1074#elif defined (linux) || defined (__FreeBSD__) || defined (__NetBSD__) \
9d093602 1075 || defined (__OpenBSD__) || defined(__GLIBC__)
9dfe12ae 1076#define MAX_SAFE_PATH 1000
1fac938e 1077 char *tmpdir = getenv ("TMPDIR");
1078
9dfe12ae 1079 /* If tmpdir is longer than MAX_SAFE_PATH, revert to default value to avoid
1080 a buffer overflow. */
1081 if (tmpdir == NULL || strlen (tmpdir) > MAX_SAFE_PATH)
1fac938e 1082 strcpy (tmp_filename, "/tmp/gnat-XXXXXX");
1083 else
9dfe12ae 1084 sprintf (tmp_filename, "%s/gnat-XXXXXX", tmpdir);
1fac938e 1085
1086 close (mkstemp(tmp_filename));
1087#else
1088 tmpnam (tmp_filename);
1089#endif
1090}
1091
3b18b370 1092/* Open directory and returns a DIR pointer. */
1093
1094DIR* __gnat_opendir (char *name)
1095{
e2a33c18 1096#if defined (RTX)
1097 /* Not supported in RTX */
1098
1099 return NULL;
1100
1101#elif defined (__MINGW32__)
3b18b370 1102 TCHAR wname[GNAT_MAX_PATH_LEN];
1103
1e622f0e 1104 S2WSU (wname, name, GNAT_MAX_PATH_LEN);
3b18b370 1105 return (DIR*)_topendir (wname);
1106
1107#else
1108 return opendir (name);
1109#endif
1110}
1111
1fac938e 1112/* Read the next entry in a directory. The returned string points somewhere
1113 in the buffer. */
1114
1115char *
3b18b370 1116__gnat_readdir (DIR *dirp, char *buffer, int *len)
1fac938e 1117{
e2a33c18 1118#if defined (RTX)
1119 /* Not supported in RTX */
1120
1121 return NULL;
8e726ab4 1122
e2a33c18 1123#elif defined (__MINGW32__)
3b18b370 1124 struct _tdirent *dirent = _treaddir ((_TDIR*)dirp);
1125
1126 if (dirent != NULL)
1127 {
1e622f0e 1128 WS2SU (buffer, dirent->d_name, GNAT_MAX_PATH_LEN);
3b18b370 1129 *len = strlen (buffer);
1130
1131 return buffer;
1132 }
1133 else
1134 return NULL;
1135
1136#elif defined (HAVE_READDIR_R)
1fac938e 1137 /* If possible, try to use the thread-safe version. */
1fac938e 1138 if (readdir_r (dirp, buffer) != NULL)
1aa4b9ce 1139 {
1140 *len = strlen (((struct dirent*) buffer)->d_name);
1141 return ((struct dirent*) buffer)->d_name;
1142 }
1fac938e 1143 else
1144 return NULL;
1145
1146#else
5b941af6 1147 struct dirent *dirent = (struct dirent *) readdir (dirp);
1fac938e 1148
1149 if (dirent != NULL)
1150 {
1151 strcpy (buffer, dirent->d_name);
3b18b370 1152 *len = strlen (buffer);
1fac938e 1153 return buffer;
1154 }
1155 else
1156 return NULL;
1157
1158#endif
1159}
1160
3b18b370 1161/* Close a directory entry. */
1162
1163int __gnat_closedir (DIR *dirp)
1164{
e2a33c18 1165#if defined (RTX)
1166 /* Not supported in RTX */
1167
1168 return 0;
1169
1170#elif defined (__MINGW32__)
3b18b370 1171 return _tclosedir ((_TDIR*)dirp);
1172
1173#else
1174 return closedir (dirp);
1175#endif
1176}
1177
1fac938e 1178/* Returns 1 if readdir is thread safe, 0 otherwise. */
1179
1180int
6f2c2693 1181__gnat_readdir_is_thread_safe (void)
1fac938e 1182{
1183#ifdef HAVE_READDIR_R
1184 return 1;
1185#else
1186 return 0;
1187#endif
1188}
1189
e2a33c18 1190#if defined (_WIN32) && !defined (RTX)
982e2721 1191/* Number of seconds between <Jan 1st 1601> and <Jan 1st 1970>. */
1192static const unsigned long long w32_epoch_offset = 11644473600ULL;
1fac938e 1193
1194/* Returns the file modification timestamp using Win32 routines which are
1195 immune against daylight saving time change. It is in fact not possible to
1196 use fstat for this purpose as the DST modify the st_mtime field of the
1197 stat structure. */
1198
1199static time_t
9dfe12ae 1200win32_filetime (HANDLE h)
1fac938e 1201{
982e2721 1202 union
1203 {
1204 FILETIME ft_time;
1205 unsigned long long ull_time;
1206 } t_write;
1fac938e 1207
1208 /* GetFileTime returns FILETIME data which are the number of 100 nanosecs
1209 since <Jan 1st 1601>. This function must return the number of seconds
1210 since <Jan 1st 1970>. */
1211
982e2721 1212 if (GetFileTime (h, NULL, NULL, &t_write.ft_time))
3b18b370 1213 return (time_t) (t_write.ull_time / 10000000ULL - w32_epoch_offset);
982e2721 1214 return (time_t) 0;
1fac938e 1215}
1216#endif
1217
1218/* Return a GNAT time stamp given a file name. */
1219
1bbc9831 1220OS_Time
9dfe12ae 1221__gnat_file_time_name (char *name)
1fac938e 1222{
1fac938e 1223
1224#if defined (__EMX__) || defined (MSDOS)
1225 int fd = open (name, O_RDONLY | O_BINARY);
1226 time_t ret = __gnat_file_time_fd (fd);
1227 close (fd);
1bbc9831 1228 return (OS_Time)ret;
1fac938e 1229
e2a33c18 1230#elif defined (_WIN32) && !defined (RTX)
e2c62f37 1231 time_t ret = -1;
3b18b370 1232 TCHAR wname[GNAT_MAX_PATH_LEN];
1233
1e622f0e 1234 S2WSU (wname, name, GNAT_MAX_PATH_LEN);
3b18b370 1235
1236 HANDLE h = CreateFile
1237 (wname, GENERIC_READ, FILE_SHARE_READ, 0,
1238 OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0);
fabb7dc5 1239
982e2721 1240 if (h != INVALID_HANDLE_VALUE)
1241 {
1242 ret = win32_filetime (h);
1243 CloseHandle (h);
1244 }
1bbc9831 1245 return (OS_Time) ret;
1fac938e 1246#else
f0a28ccb 1247 struct stat statbuf;
1bbc9831 1248 if (__gnat_stat (name, &statbuf) != 0) {
1249 return (OS_Time)-1;
1250 } else {
1fac938e 1251#ifdef VMS
1bbc9831 1252 /* VMS has file versioning. */
1253 return (OS_Time)statbuf.st_ctime;
1fac938e 1254#else
1bbc9831 1255 return (OS_Time)statbuf.st_mtime;
1fac938e 1256#endif
1bbc9831 1257 }
1fac938e 1258#endif
1259}
1260
1261/* Return a GNAT time stamp given a file descriptor. */
1262
1bbc9831 1263OS_Time
9dfe12ae 1264__gnat_file_time_fd (int fd)
1fac938e 1265{
1266 /* The following workaround code is due to the fact that under EMX and
1267 DJGPP fstat attempts to convert time values to GMT rather than keep the
1268 actual OS timestamp of the file. By using the OS2/DOS functions directly
1269 the GNAT timestamp are independent of this behavior, which is desired to
f15731c4 1270 facilitate the distribution of GNAT compiled libraries. */
1fac938e 1271
1272#if defined (__EMX__) || defined (MSDOS)
1273#ifdef __EMX__
1274
1275 FILESTATUS fs;
1276 int ret = DosQueryFileInfo (fd, 1, (unsigned char *) &fs,
1277 sizeof (FILESTATUS));
1278
1279 unsigned file_year = fs.fdateLastWrite.year;
1280 unsigned file_month = fs.fdateLastWrite.month;
1281 unsigned file_day = fs.fdateLastWrite.day;
1282 unsigned file_hour = fs.ftimeLastWrite.hours;
1283 unsigned file_min = fs.ftimeLastWrite.minutes;
1284 unsigned file_tsec = fs.ftimeLastWrite.twosecs;
1285
1286#else
1287 struct ftime fs;
1288 int ret = getftime (fd, &fs);
1289
1290 unsigned file_year = fs.ft_year;
1291 unsigned file_month = fs.ft_month;
1292 unsigned file_day = fs.ft_day;
1293 unsigned file_hour = fs.ft_hour;
1294 unsigned file_min = fs.ft_min;
1295 unsigned file_tsec = fs.ft_tsec;
1296#endif
1297
1298 /* Calculate the seconds since epoch from the time components. First count
1299 the whole days passed. The value for years returned by the DOS and OS2
1300 functions count years from 1980, so to compensate for the UNIX epoch which
1301 begins in 1970 start with 10 years worth of days and add days for each
f15731c4 1302 four year period since then. */
1fac938e 1303
1304 time_t tot_secs;
f15731c4 1305 int cum_days[12] = {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334};
1fac938e 1306 int days_passed = 3652 + (file_year / 4) * 1461;
1307 int years_since_leap = file_year % 4;
1308
1309 if (years_since_leap == 1)
1310 days_passed += 366;
1311 else if (years_since_leap == 2)
1312 days_passed += 731;
1313 else if (years_since_leap == 3)
1314 days_passed += 1096;
1315
1316 if (file_year > 20)
1317 days_passed -= 1;
1318
f15731c4 1319 days_passed += cum_days[file_month - 1];
1fac938e 1320 if (years_since_leap == 0 && file_year != 20 && file_month > 2)
1321 days_passed++;
1322
1323 days_passed += file_day - 1;
1324
f15731c4 1325 /* OK - have whole days. Multiply -- then add in other parts. */
1fac938e 1326
1327 tot_secs = days_passed * 86400;
1328 tot_secs += file_hour * 3600;
1329 tot_secs += file_min * 60;
1330 tot_secs += file_tsec * 2;
1bbc9831 1331 return (OS_Time) tot_secs;
1fac938e 1332
e2a33c18 1333#elif defined (_WIN32) && !defined (RTX)
1fac938e 1334 HANDLE h = (HANDLE) _get_osfhandle (fd);
1335 time_t ret = win32_filetime (h);
1bbc9831 1336 return (OS_Time) ret;
1fac938e 1337
1338#else
1339 struct stat statbuf;
1340
1bbc9831 1341 if (fstat (fd, &statbuf) != 0) {
1342 return (OS_Time) -1;
1343 } else {
1fac938e 1344#ifdef VMS
1bbc9831 1345 /* VMS has file versioning. */
1346 return (OS_Time) statbuf.st_ctime;
1fac938e 1347#else
1bbc9831 1348 return (OS_Time) statbuf.st_mtime;
1fac938e 1349#endif
1bbc9831 1350 }
1fac938e 1351#endif
1352}
1353
f15731c4 1354/* Set the file time stamp. */
d8dd2062 1355
1356void
9dfe12ae 1357__gnat_set_file_time_name (char *name, time_t time_stamp)
d8dd2062 1358{
982e2721 1359#if defined (__EMX__) || defined (MSDOS) || defined (__vxworks)
71a3e619 1360
f15731c4 1361/* Code to implement __gnat_set_file_time_name for these systems. */
71a3e619 1362
e2a33c18 1363#elif defined (_WIN32) && !defined (RTX)
982e2721 1364 union
1365 {
1366 FILETIME ft_time;
1367 unsigned long long ull_time;
1368 } t_write;
3b18b370 1369 TCHAR wname[GNAT_MAX_PATH_LEN];
fabb7dc5 1370
1e622f0e 1371 S2WSU (wname, name, GNAT_MAX_PATH_LEN);
3b18b370 1372
1373 HANDLE h = CreateFile
1374 (wname, GENERIC_WRITE, FILE_SHARE_WRITE, NULL,
1375 OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS,
1376 NULL);
982e2721 1377 if (h == INVALID_HANDLE_VALUE)
1378 return;
1379 /* Add number of seconds between <Jan 1st 1601> and <Jan 1st 1970> */
1380 t_write.ull_time = ((unsigned long long)time_stamp + w32_epoch_offset);
1381 /* Convert to 100 nanosecond units */
1382 t_write.ull_time *= 10000000ULL;
1383
1384 SetFileTime(h, NULL, NULL, &t_write.ft_time);
1385 CloseHandle (h);
1386 return;
1387
d8dd2062 1388#elif defined (VMS)
1389 struct FAB fab;
1390 struct NAM nam;
1391
1392 struct
1393 {
1394 unsigned long long backup, create, expire, revise;
8620a406 1395 unsigned int uic;
d8dd2062 1396 union
1397 {
1398 unsigned short value;
1399 struct
1400 {
1401 unsigned system : 4;
1402 unsigned owner : 4;
1403 unsigned group : 4;
1404 unsigned world : 4;
1405 } bits;
1406 } prot;
f15731c4 1407 } Fat = { 0, 0, 0, 0, 0, { 0 }};
d8dd2062 1408
f15731c4 1409 ATRDEF atrlst[]
d8dd2062 1410 = {
1411 { ATR$S_CREDATE, ATR$C_CREDATE, &Fat.create },
1412 { ATR$S_REVDATE, ATR$C_REVDATE, &Fat.revise },
1413 { ATR$S_EXPDATE, ATR$C_EXPDATE, &Fat.expire },
1414 { ATR$S_BAKDATE, ATR$C_BAKDATE, &Fat.backup },
f15731c4 1415 { ATR$S_FPRO, ATR$C_FPRO, &Fat.prot },
d8dd2062 1416 { ATR$S_UIC, ATR$C_UIC, &Fat.uic },
1417 { 0, 0, 0}
1418 };
1419
1420 FIBDEF fib;
1421 struct dsc$descriptor_fib fibdsc = {sizeof (fib), (void *) &fib};
1422
1423 struct IOSB iosb;
1424
1425 unsigned long long newtime;
1426 unsigned long long revtime;
1427 long status;
1428 short chan;
1429
1430 struct vstring file;
1431 struct dsc$descriptor_s filedsc
1432 = {NAM$C_MAXRSS, DSC$K_DTYPE_T, DSC$K_CLASS_S, (void *) file.string};
1433 struct vstring device;
1434 struct dsc$descriptor_s devicedsc
1435 = {NAM$C_MAXRSS, DSC$K_DTYPE_T, DSC$K_CLASS_S, (void *) device.string};
1436 struct vstring timev;
1437 struct dsc$descriptor_s timedsc
1438 = {NAM$C_MAXRSS, DSC$K_DTYPE_T, DSC$K_CLASS_S, (void *) timev.string};
1439 struct vstring result;
1440 struct dsc$descriptor_s resultdsc
1441 = {NAM$C_MAXRSS, DSC$K_DTYPE_VT, DSC$K_CLASS_VS, (void *) result.string};
1442
3b18b370 1443 /* Convert parameter name (a file spec) to host file form. Note that this
1444 is needed on VMS to prepare for subsequent calls to VMS RMS library
1445 routines. Note that it would not work to call __gnat_to_host_dir_spec
1446 as was done in a previous version, since this fails silently unless
1447 the feature logical DECC$EFS_CHARSET is enabled, in which case a DNF
1448 (directory not found) condition is signalled. */
1449 tryfile = (char *) __gnat_to_host_file_spec (name);
d8dd2062 1450
f15731c4 1451 /* Allocate and initialize a FAB and NAM structures. */
d8dd2062 1452 fab = cc$rms_fab;
1453 nam = cc$rms_nam;
1454
1455 nam.nam$l_esa = file.string;
1456 nam.nam$b_ess = NAM$C_MAXRSS;
1457 nam.nam$l_rsa = result.string;
1458 nam.nam$b_rss = NAM$C_MAXRSS;
1459 fab.fab$l_fna = tryfile;
1460 fab.fab$b_fns = strlen (tryfile);
1461 fab.fab$l_nam = &nam;
1462
f15731c4 1463 /* Validate filespec syntax and device existence. */
d8dd2062 1464 status = SYS$PARSE (&fab, 0, 0);
1465 if ((status & 1) != 1)
1466 LIB$SIGNAL (status);
1467
f15731c4 1468 file.string[nam.nam$b_esl] = 0;
d8dd2062 1469
f15731c4 1470 /* Find matching filespec. */
d8dd2062 1471 status = SYS$SEARCH (&fab, 0, 0);
1472 if ((status & 1) != 1)
1473 LIB$SIGNAL (status);
1474
f15731c4 1475 file.string[nam.nam$b_esl] = 0;
1476 result.string[result.length=nam.nam$b_rsl] = 0;
d8dd2062 1477
f15731c4 1478 /* Get the device name and assign an IO channel. */
d8dd2062 1479 strncpy (device.string, nam.nam$l_dev, nam.nam$b_dev);
1480 devicedsc.dsc$w_length = nam.nam$b_dev;
1481 chan = 0;
1482 status = SYS$ASSIGN (&devicedsc, &chan, 0, 0, 0);
1483 if ((status & 1) != 1)
1484 LIB$SIGNAL (status);
1485
f15731c4 1486 /* Initialize the FIB and fill in the directory id field. */
1487 memset (&fib, 0, sizeof (fib));
1488 fib.fib$w_did[0] = nam.nam$w_did[0];
1489 fib.fib$w_did[1] = nam.nam$w_did[1];
1490 fib.fib$w_did[2] = nam.nam$w_did[2];
d8dd2062 1491 fib.fib$l_acctl = 0;
1492 fib.fib$l_wcc = 0;
1493 strcpy (file.string, (strrchr (result.string, ']') + 1));
1494 filedsc.dsc$w_length = strlen (file.string);
f15731c4 1495 result.string[result.length = 0] = 0;
d8dd2062 1496
1497 /* Open and close the file to fill in the attributes. */
1498 status
1499 = SYS$QIOW (0, chan, IO$_ACCESS|IO$M_ACCESS, &iosb, 0, 0,
1500 &fibdsc, &filedsc, &result.length, &resultdsc, &atrlst, 0);
1501 if ((status & 1) != 1)
1502 LIB$SIGNAL (status);
1503 if ((iosb.status & 1) != 1)
1504 LIB$SIGNAL (iosb.status);
1505
f15731c4 1506 result.string[result.length] = 0;
1507 status = SYS$QIOW (0, chan, IO$_DEACCESS, &iosb, 0, 0, &fibdsc, 0, 0, 0,
1508 &atrlst, 0);
d8dd2062 1509 if ((status & 1) != 1)
1510 LIB$SIGNAL (status);
1511 if ((iosb.status & 1) != 1)
1512 LIB$SIGNAL (iosb.status);
1513
d8dd2062 1514 {
1515 time_t t;
f15731c4 1516
1517 /* Set creation time to requested time. */
9dfe12ae 1518 unix_time_to_vms (time_stamp, newtime);
f15731c4 1519
d8dd2062 1520 t = time ((time_t) 0);
d8dd2062 1521
f15731c4 1522 /* Set revision time to now in local time. */
9dfe12ae 1523 unix_time_to_vms (t, revtime);
d8dd2062 1524 }
1525
f15731c4 1526 /* Reopen the file, modify the times and then close. */
d8dd2062 1527 fib.fib$l_acctl = FIB$M_WRITE;
1528 status
1529 = SYS$QIOW (0, chan, IO$_ACCESS|IO$M_ACCESS, &iosb, 0, 0,
1530 &fibdsc, &filedsc, &result.length, &resultdsc, &atrlst, 0);
1531 if ((status & 1) != 1)
1532 LIB$SIGNAL (status);
1533 if ((iosb.status & 1) != 1)
1534 LIB$SIGNAL (iosb.status);
1535
1536 Fat.create = newtime;
1537 Fat.revise = revtime;
1538
1539 status = SYS$QIOW (0, chan, IO$_DEACCESS, &iosb, 0, 0,
1540 &fibdsc, 0, 0, 0, &atrlst, 0);
1541 if ((status & 1) != 1)
1542 LIB$SIGNAL (status);
1543 if ((iosb.status & 1) != 1)
1544 LIB$SIGNAL (iosb.status);
1545
f15731c4 1546 /* Deassign the channel and exit. */
d8dd2062 1547 status = SYS$DASSGN (chan);
1548 if ((status & 1) != 1)
1549 LIB$SIGNAL (status);
1550#else
1551 struct utimbuf utimbuf;
1552 time_t t;
1553
f15731c4 1554 /* Set modification time to requested time. */
d8dd2062 1555 utimbuf.modtime = time_stamp;
1556
f15731c4 1557 /* Set access time to now in local time. */
d8dd2062 1558 t = time ((time_t) 0);
1559 utimbuf.actime = mktime (localtime (&t));
1560
1561 utime (name, &utimbuf);
1562#endif
1563}
1564
1fac938e 1565/* Get the list of installed standard libraries from the
1566 HKEY_LOCAL_MACHINE\SOFTWARE\Ada Core Technologies\GNAT\Standard Libraries
1567 key. */
1568
1569char *
6f2c2693 1570__gnat_get_libraries_from_registry (void)
1fac938e 1571{
1572 char *result = (char *) "";
1573
e2a33c18 1574#if defined (_WIN32) && ! defined (__vxworks) && ! defined (CROSS_DIRECTORY_STRUCTURE) && ! defined (RTX)
1fac938e 1575
1576 HKEY reg_key;
1577 DWORD name_size, value_size;
1578 char name[256];
1579 char value[256];
1580 DWORD type;
1581 DWORD index;
1582 LONG res;
1583
1584 /* First open the key. */
1585 res = RegOpenKeyExA (HKEY_LOCAL_MACHINE, "SOFTWARE", 0, KEY_READ, &reg_key);
1586
1587 if (res == ERROR_SUCCESS)
1588 res = RegOpenKeyExA (reg_key, "Ada Core Technologies", 0,
1589 KEY_READ, &reg_key);
1590
1591 if (res == ERROR_SUCCESS)
1592 res = RegOpenKeyExA (reg_key, "GNAT", 0, KEY_READ, &reg_key);
1593
1594 if (res == ERROR_SUCCESS)
1595 res = RegOpenKeyExA (reg_key, "Standard Libraries", 0, KEY_READ, &reg_key);
1596
1597 /* If the key exists, read out all the values in it and concatenate them
1598 into a path. */
1599 for (index = 0; res == ERROR_SUCCESS; index++)
1600 {
1601 value_size = name_size = 256;
e2c62f37 1602 res = RegEnumValueA (reg_key, index, (TCHAR*)name, &name_size, 0,
1603 &type, (LPBYTE)value, &value_size);
1fac938e 1604
1605 if (res == ERROR_SUCCESS && type == REG_SZ)
1606 {
1607 char *old_result = result;
1608
1609 result = (char *) xmalloc (strlen (old_result) + value_size + 2);
1610 strcpy (result, old_result);
1611 strcat (result, value);
1612 strcat (result, ";");
1613 }
1614 }
1615
1616 /* Remove the trailing ";". */
1617 if (result[0] != 0)
1618 result[strlen (result) - 1] = 0;
1619
1620#endif
1621 return result;
1622}
1623
1624int
9dfe12ae 1625__gnat_stat (char *name, struct stat *statbuf)
1fac938e 1626{
3b18b370 1627#ifdef __MINGW32__
1fac938e 1628 /* Under Windows the directory name for the stat function must not be
1629 terminated by a directory separator except if just after a drive name. */
3b18b370 1630 TCHAR wname [GNAT_MAX_PATH_LEN + 2];
1631 int name_len;
1632 TCHAR last_char;
1633
1e622f0e 1634 S2WSU (wname, name, GNAT_MAX_PATH_LEN + 2);
3b18b370 1635 name_len = _tcslen (wname);
e7b2d6bc 1636
1637 if (name_len > GNAT_MAX_PATH_LEN)
1638 return -1;
1fac938e 1639
3b18b370 1640 last_char = wname[name_len - 1];
1fac938e 1641
3b18b370 1642 while (name_len > 1 && (last_char == _T('\\') || last_char == _T('/')))
1fac938e 1643 {
3b18b370 1644 wname[name_len - 1] = _T('\0');
1fac938e 1645 name_len--;
3b18b370 1646 last_char = wname[name_len - 1];
1fac938e 1647 }
1648
3b18b370 1649 /* Only a drive letter followed by ':', we must add a directory separator
1650 for the stat routine to work properly. */
1651 if (name_len == 2 && wname[1] == _T(':'))
1652 _tcscat (wname, _T("\\"));
1fac938e 1653
3b18b370 1654 return _tstat (wname, statbuf);
1fac938e 1655
1656#else
1657 return stat (name, statbuf);
1658#endif
1659}
1660
1661int
9dfe12ae 1662__gnat_file_exists (char *name)
1fac938e 1663{
8e726ab4 1664#ifdef __MINGW32__
1aa4b9ce 1665 /* On Windows do not use __gnat_stat() because a bug in Microsoft
1666 _stat() routine. When the system time-zone is set with a negative
1667 offset the _stat() routine fails on specific files like CON: */
1668 TCHAR wname [GNAT_MAX_PATH_LEN + 2];
1669
1670 S2WSU (wname, name, GNAT_MAX_PATH_LEN + 2);
1671 return GetFileAttributes (wname) != INVALID_FILE_ATTRIBUTES;
1672#else
1fac938e 1673 struct stat statbuf;
1674
1675 return !__gnat_stat (name, &statbuf);
1aa4b9ce 1676#endif
1fac938e 1677}
1678
9dfe12ae 1679int
4a3f445c 1680__gnat_is_absolute_path (char *name, int length)
1fac938e 1681{
8620a406 1682#ifdef __vxworks
1683 /* On VxWorks systems, an absolute path can be represented (depending on
1684 the host platform) as either /dir/file, or device:/dir/file, or
1685 device:drive_letter:/dir/file. */
1686
1687 int index;
1688
1689 if (name[0] == '/')
1690 return 1;
1691
1692 for (index = 0; index < length; index++)
1693 {
1694 if (name[index] == ':' &&
1695 ((name[index + 1] == '/') ||
1696 (isalpha (name[index + 1]) && index + 2 <= length &&
1697 name[index + 2] == '/')))
1698 return 1;
1699
1700 else if (name[index] == '/')
1701 return 0;
1702 }
1703 return 0;
1704#else
4a3f445c 1705 return (length != 0) &&
1706 (*name == '/' || *name == DIR_SEPARATOR
f15731c4 1707#if defined (__EMX__) || defined (MSDOS) || defined (WINNT)
a4f295eb 1708 || (length > 1 && ISALPHA (name[0]) && name[1] == ':')
1fac938e 1709#endif
1710 );
8620a406 1711#endif
1fac938e 1712}
1713
1714int
9dfe12ae 1715__gnat_is_regular_file (char *name)
1fac938e 1716{
1717 int ret;
1718 struct stat statbuf;
1719
1720 ret = __gnat_stat (name, &statbuf);
1721 return (!ret && S_ISREG (statbuf.st_mode));
1722}
1723
1724int
9dfe12ae 1725__gnat_is_directory (char *name)
1fac938e 1726{
1727 int ret;
1728 struct stat statbuf;
1729
1730 ret = __gnat_stat (name, &statbuf);
1731 return (!ret && S_ISDIR (statbuf.st_mode));
1732}
1733
7db1ef17 1734#if defined (_WIN32) && !defined (RTX)
1735/* This MingW section contains code to work with ACL. */
1736static int
1737__gnat_check_OWNER_ACL
3855c659 1738(TCHAR *wname,
7db1ef17 1739 DWORD CheckAccessDesired,
1740 GENERIC_MAPPING CheckGenericMapping)
1741{
7db1ef17 1742 DWORD dwAccessDesired, dwAccessAllowed;
1743 PRIVILEGE_SET PrivilegeSet;
1744 DWORD dwPrivSetSize = sizeof (PRIVILEGE_SET);
1745 BOOL fAccessGranted = FALSE;
1746 HANDLE hToken;
1747 DWORD nLength;
1748 SECURITY_DESCRIPTOR* pSD = NULL;
1749
7db1ef17 1750 GetFileSecurity
1751 (wname, OWNER_SECURITY_INFORMATION |
1752 GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION,
1753 NULL, 0, &nLength);
1754
1755 if ((pSD = (PSECURITY_DESCRIPTOR) HeapAlloc
1756 (GetProcessHeap (), HEAP_ZERO_MEMORY, nLength)) == NULL)
1757 return 0;
1758
1759 /* Obtain the security descriptor. */
1760
1761 if (!GetFileSecurity
1762 (wname, OWNER_SECURITY_INFORMATION |
1763 GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION,
1764 pSD, nLength, &nLength))
1765 return 0;
1766
1767 if (!ImpersonateSelf (SecurityImpersonation))
1768 return 0;
1769
1770 if (!OpenThreadToken
1771 (GetCurrentThread(), TOKEN_DUPLICATE | TOKEN_QUERY, FALSE, &hToken))
1772 return 0;
1773
1774 /* Undoes the effect of ImpersonateSelf. */
1775
1776 RevertToSelf ();
1777
1778 /* We want to test for write permissions. */
1779
1780 dwAccessDesired = CheckAccessDesired;
1781
1782 MapGenericMask (&dwAccessDesired, &CheckGenericMapping);
1783
1784 if (!AccessCheck
1785 (pSD , /* security descriptor to check */
1786 hToken, /* impersonation token */
1787 dwAccessDesired, /* requested access rights */
1788 &CheckGenericMapping, /* pointer to GENERIC_MAPPING */
1789 &PrivilegeSet, /* receives privileges used in check */
1790 &dwPrivSetSize, /* size of PrivilegeSet buffer */
1791 &dwAccessAllowed, /* receives mask of allowed access rights */
1792 &fAccessGranted))
1793 return 0;
1794
1795 return fAccessGranted;
1796}
1797
1798static void
1799__gnat_set_OWNER_ACL
3855c659 1800(TCHAR *wname,
7db1ef17 1801 DWORD AccessMode,
1802 DWORD AccessPermissions)
1803{
1804 ACL* pOldDACL = NULL;
1805 ACL* pNewDACL = NULL;
1806 SECURITY_DESCRIPTOR* pSD = NULL;
1807 EXPLICIT_ACCESS ea;
1808 TCHAR username [100];
1809 DWORD unsize = 100;
1810
7db1ef17 1811 /* Get current user, he will act as the owner */
1812
1813 if (!GetUserName (username, &unsize))
1814 return;
1815
0b3929a6 1816 if (GetNamedSecurityInfo
1817 (wname,
7db1ef17 1818 SE_FILE_OBJECT,
1819 DACL_SECURITY_INFORMATION,
1820 NULL, NULL, &pOldDACL, NULL, &pSD) != ERROR_SUCCESS)
1821 return;
1822
0b3929a6 1823 BuildExplicitAccessWithName
1824 (&ea, username, AccessPermissions, AccessMode, NO_INHERITANCE);
7db1ef17 1825
1826 if (AccessMode == SET_ACCESS)
1827 {
1828 /* SET_ACCESS, we want to set an explicte set of permissions, do not
1829 merge with current DACL. */
1830 if (SetEntriesInAcl (1, &ea, NULL, &pNewDACL) != ERROR_SUCCESS)
1831 return;
1832 }
1833 else
1834 if (SetEntriesInAcl (1, &ea, pOldDACL, &pNewDACL) != ERROR_SUCCESS)
1835 return;
1836
0b3929a6 1837 if (SetNamedSecurityInfo
1838 (wname, SE_FILE_OBJECT,
7db1ef17 1839 DACL_SECURITY_INFORMATION, NULL, NULL, pNewDACL, NULL) != ERROR_SUCCESS)
1840 return;
1841
1842 LocalFree (pSD);
1843 LocalFree (pNewDACL);
7db1ef17 1844}
1845#endif /* defined (_WIN32) && !defined (RTX) */
1846
1fac938e 1847int
9dfe12ae 1848__gnat_is_readable_file (char *name)
1849{
7db1ef17 1850#if defined (_WIN32) && !defined (RTX)
3855c659 1851 TCHAR wname [GNAT_MAX_PATH_LEN + 2];
7db1ef17 1852 GENERIC_MAPPING GenericMapping;
3855c659 1853
1854 S2WSU (wname, name, GNAT_MAX_PATH_LEN + 2);
1855
7db1ef17 1856 ZeroMemory (&GenericMapping, sizeof (GENERIC_MAPPING));
1857 GenericMapping.GenericRead = GENERIC_READ;
1858
3855c659 1859 return __gnat_check_OWNER_ACL (wname, FILE_READ_DATA, GenericMapping);
7db1ef17 1860#else
9dfe12ae 1861 int ret;
1862 int mode;
1863 struct stat statbuf;
1864
0e9e8338 1865 ret = stat (name, &statbuf);
9dfe12ae 1866 mode = statbuf.st_mode & S_IRUSR;
1867 return (!ret && mode);
7db1ef17 1868#endif
9dfe12ae 1869}
1870
1871int
1872__gnat_is_writable_file (char *name)
1fac938e 1873{
7db1ef17 1874#if defined (_WIN32) && !defined (RTX)
3855c659 1875 TCHAR wname [GNAT_MAX_PATH_LEN + 2];
7db1ef17 1876 GENERIC_MAPPING GenericMapping;
3855c659 1877
1878 S2WSU (wname, name, GNAT_MAX_PATH_LEN + 2);
1879
7db1ef17 1880 ZeroMemory (&GenericMapping, sizeof (GENERIC_MAPPING));
1881 GenericMapping.GenericWrite = GENERIC_WRITE;
1882
1883 return __gnat_check_OWNER_ACL
3855c659 1884 (wname, FILE_WRITE_DATA | FILE_APPEND_DATA, GenericMapping)
1885 && !(GetFileAttributes (wname) & FILE_ATTRIBUTE_READONLY);
7db1ef17 1886#else
1fac938e 1887 int ret;
1888 int mode;
1889 struct stat statbuf;
1890
0e9e8338 1891 ret = stat (name, &statbuf);
1fac938e 1892 mode = statbuf.st_mode & S_IWUSR;
1893 return (!ret && mode);
7db1ef17 1894#endif
1895}
1896
1897int
1898__gnat_is_executable_file (char *name)
1899{
1900#if defined (_WIN32) && !defined (RTX)
3855c659 1901 TCHAR wname [GNAT_MAX_PATH_LEN + 2];
7db1ef17 1902 GENERIC_MAPPING GenericMapping;
3855c659 1903
1904 S2WSU (wname, name, GNAT_MAX_PATH_LEN + 2);
1905
7db1ef17 1906 ZeroMemory (&GenericMapping, sizeof (GENERIC_MAPPING));
1907 GenericMapping.GenericExecute = GENERIC_EXECUTE;
1908
3855c659 1909 return __gnat_check_OWNER_ACL (wname, FILE_EXECUTE, GenericMapping);
7db1ef17 1910#else
1911 int ret;
1912 int mode;
1913 struct stat statbuf;
1914
0e9e8338 1915 ret = stat (name, &statbuf);
7db1ef17 1916 mode = statbuf.st_mode & S_IXUSR;
1917 return (!ret && mode);
1918#endif
1fac938e 1919}
1920
9dfe12ae 1921void
1922__gnat_set_writable (char *name)
1923{
7db1ef17 1924#if defined (_WIN32) && !defined (RTX)
3855c659 1925 TCHAR wname [GNAT_MAX_PATH_LEN + 2];
1926
1927 S2WSU (wname, name, GNAT_MAX_PATH_LEN + 2);
1928
0b3929a6 1929 __gnat_set_OWNER_ACL (wname, GRANT_ACCESS, FILE_GENERIC_WRITE);
3855c659 1930 SetFileAttributes
1931 (wname, GetFileAttributes (wname) & ~FILE_ATTRIBUTE_READONLY);
7db1ef17 1932#elif ! defined (__vxworks) && ! defined(__nucleus__)
9dfe12ae 1933 struct stat statbuf;
1934
1935 if (stat (name, &statbuf) == 0)
0e9e8338 1936 {
1937 statbuf.st_mode = statbuf.st_mode | S_IWUSR;
1938 chmod (name, statbuf.st_mode);
1939 }
9dfe12ae 1940#endif
1941}
1942
5329ca64 1943void
1944__gnat_set_executable (char *name)
1945{
7db1ef17 1946#if defined (_WIN32) && !defined (RTX)
3855c659 1947 TCHAR wname [GNAT_MAX_PATH_LEN + 2];
1948
1949 S2WSU (wname, name, GNAT_MAX_PATH_LEN + 2);
1950
0b3929a6 1951 __gnat_set_OWNER_ACL (wname, GRANT_ACCESS, FILE_GENERIC_EXECUTE);
7db1ef17 1952#elif ! defined (__vxworks) && ! defined(__nucleus__)
5329ca64 1953 struct stat statbuf;
1954
1955 if (stat (name, &statbuf) == 0)
0e9e8338 1956 {
1957 statbuf.st_mode = statbuf.st_mode | S_IXUSR;
1958 chmod (name, statbuf.st_mode);
1959 }
5329ca64 1960#endif
1961}
1962
9dfe12ae 1963void
2ab009c7 1964__gnat_set_non_writable (char *name)
9dfe12ae 1965{
7db1ef17 1966#if defined (_WIN32) && !defined (RTX)
3855c659 1967 TCHAR wname [GNAT_MAX_PATH_LEN + 2];
1968
1969 S2WSU (wname, name, GNAT_MAX_PATH_LEN + 2);
1970
b23dd297 1971 __gnat_set_OWNER_ACL
1972 (wname, DENY_ACCESS,
1973 FILE_WRITE_DATA | FILE_APPEND_DATA |
64d569f5 1974 FILE_WRITE_EA | FILE_WRITE_ATTRIBUTES);
3855c659 1975 SetFileAttributes
1976 (wname, GetFileAttributes (wname) | FILE_ATTRIBUTE_READONLY);
7db1ef17 1977#elif ! defined (__vxworks) && ! defined(__nucleus__)
9dfe12ae 1978 struct stat statbuf;
1979
1980 if (stat (name, &statbuf) == 0)
0b3929a6 1981 {
1982 statbuf.st_mode = statbuf.st_mode & 07577;
1983 chmod (name, statbuf.st_mode);
1984 }
1985#endif
1986}
1987
1988void
1989__gnat_set_readable (char *name)
1990{
1991#if defined (_WIN32) && !defined (RTX)
1992 TCHAR wname [GNAT_MAX_PATH_LEN + 2];
1993
1994 S2WSU (wname, name, GNAT_MAX_PATH_LEN + 2);
1995
1996 __gnat_set_OWNER_ACL (wname, GRANT_ACCESS, FILE_GENERIC_READ);
e31ad175 1997#elif ! defined (__vxworks) && ! defined(__nucleus__)
0b3929a6 1998 struct stat statbuf;
1999
2000 if (stat (name, &statbuf) == 0)
2001 {
2002 chmod (name, statbuf.st_mode | S_IREAD);
2003 }
2004#endif
2005}
2006
2007void
2008__gnat_set_non_readable (char *name)
2009{
2010#if defined (_WIN32) && !defined (RTX)
2011 TCHAR wname [GNAT_MAX_PATH_LEN + 2];
2012
2013 S2WSU (wname, name, GNAT_MAX_PATH_LEN + 2);
2014
2015 __gnat_set_OWNER_ACL (wname, DENY_ACCESS, FILE_GENERIC_READ);
e31ad175 2016#elif ! defined (__vxworks) && ! defined(__nucleus__)
0b3929a6 2017 struct stat statbuf;
2018
2019 if (stat (name, &statbuf) == 0)
2020 {
2021 chmod (name, statbuf.st_mode & (~S_IREAD));
2022 }
9dfe12ae 2023#endif
2024}
2025
2026int
f0a28ccb 2027__gnat_is_symbolic_link (char *name ATTRIBUTE_UNUSED)
9dfe12ae 2028{
5091bc2f 2029#if defined (__vxworks) || defined (__nucleus__)
9dfe12ae 2030 return 0;
2031
8e761191 2032#elif defined (_AIX) || defined (__APPLE__) || defined (__unix__)
9dfe12ae 2033 int ret;
2034 struct stat statbuf;
2035
2036 ret = lstat (name, &statbuf);
2037 return (!ret && S_ISLNK (statbuf.st_mode));
2038
2039#else
2040 return 0;
2041#endif
2042}
2043
1fac938e 2044#if defined (sun) && defined (__SVR4)
2045/* Using fork on Solaris will duplicate all the threads. fork1, which
2046 duplicates only the active thread, must be used instead, or spawning
2047 subprocess from a program with tasking will lead into numerous problems. */
2048#define fork fork1
2049#endif
2050
2051int
9dfe12ae 2052__gnat_portable_spawn (char *args[])
1fac938e 2053{
2054 int status = 0;
f0a28ccb 2055 int finished ATTRIBUTE_UNUSED;
2056 int pid ATTRIBUTE_UNUSED;
1fac938e 2057
e2a33c18 2058#if defined (__vxworks) || defined(__nucleus__) || defined(RTX)
2059 return -1;
2060
2061#elif defined (MSDOS) || defined (_WIN32)
f270dc82 2062 /* args[0] must be quotes as it could contain a full pathname with spaces */
38750fcd 2063 char *args_0 = args[0];
f270dc82 2064 args[0] = (char *)xmalloc (strlen (args_0) + 3);
2065 strcpy (args[0], "\"");
2066 strcat (args[0], args_0);
2067 strcat (args[0], "\"");
2068
0b9eca83 2069 status = spawnvp (P_WAIT, args_0, (const char* const*)args);
f270dc82 2070
2071 /* restore previous value */
2072 free (args[0]);
8e761191 2073 args[0] = (char *)args_0;
f270dc82 2074
1fac938e 2075 if (status < 0)
f15731c4 2076 return -1;
1fac938e 2077 else
2078 return status;
2079
1fac938e 2080#else
2081
2082#ifdef __EMX__
f15731c4 2083 pid = spawnvp (P_NOWAIT, args[0], args);
1fac938e 2084 if (pid == -1)
f15731c4 2085 return -1;
2086
1fac938e 2087#else
2088 pid = fork ();
f15731c4 2089 if (pid < 0)
2090 return -1;
1fac938e 2091
f15731c4 2092 if (pid == 0)
2093 {
2094 /* The child. */
6d9c3443 2095 if (execv (args[0], MAYBE_TO_PTR32 (args)) != 0)
f15731c4 2096#if defined (VMS)
2097 return -1; /* execv is in parent context on VMS. */
2098#else
2099 _exit (1);
2100#endif
2101 }
1fac938e 2102#endif
2103
f15731c4 2104 /* The parent. */
1fac938e 2105 finished = waitpid (pid, &status, 0);
2106
2107 if (finished != pid || WIFEXITED (status) == 0)
f15731c4 2108 return -1;
1fac938e 2109
2110 return WEXITSTATUS (status);
2111#endif
f15731c4 2112
1fac938e 2113 return 0;
2114}
2115
8e761191 2116/* Create a copy of the given file descriptor.
2117 Return -1 if an error occurred. */
2118
2119int
2120__gnat_dup (int oldfd)
2121{
8ffbc401 2122#if defined (__vxworks) && !defined (__RTP__)
2123 /* Not supported on VxWorks 5.x, but supported on VxWorks 6.0 when using
2124 RTPs. */
2125 return -1;
8e761191 2126#else
8ffbc401 2127 return dup (oldfd);
8e761191 2128#endif
2129}
2130
2131/* Make newfd be the copy of oldfd, closing newfd first if necessary.
5e947a95 2132 Return -1 if an error occurred. */
8e761191 2133
2134int
2135__gnat_dup2 (int oldfd, int newfd)
2136{
8ffbc401 2137#if defined (__vxworks) && !defined (__RTP__)
2138 /* Not supported on VxWorks 5.x, but supported on VxWorks 6.0 when using
2139 RTPs. */
8e761191 2140 return -1;
2141#else
2142 return dup2 (oldfd, newfd);
2143#endif
2144}
2145
f15731c4 2146/* WIN32 code to implement a wait call that wait for any child process. */
2147
e2a33c18 2148#if defined (_WIN32) && !defined (RTX)
1fac938e 2149
2150/* Synchronization code, to be thread safe. */
2151
51fa65dc 2152#ifdef CERT
1fac938e 2153
51fa65dc 2154/* For the Cert run times on native Windows we use dummy functions
2155 for locking and unlocking tasks since we do not support multiple
2156 threads on this configuration (Cert run time on native Windows). */
1fac938e 2157
51fa65dc 2158void dummy (void) {}
1fac938e 2159
51fa65dc 2160void (*Lock_Task) () = &dummy;
2161void (*Unlock_Task) () = &dummy;
2162
2163#else
2164
2165#define Lock_Task system__soft_links__lock_task
2166extern void (*Lock_Task) (void);
2167
2168#define Unlock_Task system__soft_links__unlock_task
2169extern void (*Unlock_Task) (void);
2170
2171#endif
1fac938e 2172
2173typedef struct _process_list
2174{
2175 HANDLE h;
2176 struct _process_list *next;
2177} Process_List;
2178
2179static Process_List *PLIST = NULL;
2180
2181static int plist_length = 0;
2182
2183static void
9dfe12ae 2184add_handle (HANDLE h)
1fac938e 2185{
2186 Process_List *pl;
2187
2188 pl = (Process_List *) xmalloc (sizeof (Process_List));
2189
1fac938e 2190 /* -------------------- critical section -------------------- */
51fa65dc 2191 (*Lock_Task) ();
2192
1fac938e 2193 pl->h = h;
2194 pl->next = PLIST;
2195 PLIST = pl;
2196 ++plist_length;
1fac938e 2197
51fa65dc 2198 (*Unlock_Task) ();
2199 /* -------------------- critical section -------------------- */
1fac938e 2200}
2201
f0a28ccb 2202static void
2203remove_handle (HANDLE h)
1fac938e 2204{
f0a28ccb 2205 Process_List *pl;
2206 Process_List *prev = NULL;
1fac938e 2207
1fac938e 2208 /* -------------------- critical section -------------------- */
51fa65dc 2209 (*Lock_Task) ();
2210
1fac938e 2211 pl = PLIST;
2212 while (pl)
2213 {
2214 if (pl->h == h)
2215 {
2216 if (pl == PLIST)
2217 PLIST = pl->next;
2218 else
2219 prev->next = pl->next;
2220 free (pl);
2221 break;
2222 }
2223 else
2224 {
2225 prev = pl;
2226 pl = pl->next;
2227 }
2228 }
2229
2230 --plist_length;
1fac938e 2231
51fa65dc 2232 (*Unlock_Task) ();
2233 /* -------------------- critical section -------------------- */
1fac938e 2234}
2235
2236static int
9dfe12ae 2237win32_no_block_spawn (char *command, char *args[])
1fac938e 2238{
2239 BOOL result;
2240 STARTUPINFO SI;
2241 PROCESS_INFORMATION PI;
2242 SECURITY_ATTRIBUTES SA;
f15731c4 2243 int csize = 1;
2244 char *full_command;
1fac938e 2245 int k;
2246
f15731c4 2247 /* compute the total command line length */
2248 k = 0;
2249 while (args[k])
2250 {
2251 csize += strlen (args[k]) + 1;
2252 k++;
2253 }
2254
2255 full_command = (char *) xmalloc (csize);
2256
1fac938e 2257 /* Startup info. */
2258 SI.cb = sizeof (STARTUPINFO);
2259 SI.lpReserved = NULL;
2260 SI.lpReserved2 = NULL;
2261 SI.lpDesktop = NULL;
2262 SI.cbReserved2 = 0;
2263 SI.lpTitle = NULL;
2264 SI.dwFlags = 0;
2265 SI.wShowWindow = SW_HIDE;
2266
2267 /* Security attributes. */
2268 SA.nLength = sizeof (SECURITY_ATTRIBUTES);
2269 SA.bInheritHandle = TRUE;
2270 SA.lpSecurityDescriptor = NULL;
2271
2272 /* Prepare the command string. */
2273 strcpy (full_command, command);
2274 strcat (full_command, " ");
2275
2276 k = 1;
2277 while (args[k])
2278 {
2279 strcat (full_command, args[k]);
2280 strcat (full_command, " ");
2281 k++;
2282 }
2283
3b18b370 2284 {
2285 int wsize = csize * 2;
2286 TCHAR *wcommand = (TCHAR *) xmalloc (wsize);
2287
1e622f0e 2288 S2WSU (wcommand, full_command, wsize);
3b18b370 2289
2290 free (full_command);
1fac938e 2291
3b18b370 2292 result = CreateProcess
2293 (NULL, wcommand, &SA, NULL, TRUE,
2294 GetPriorityClass (GetCurrentProcess()), NULL, NULL, &SI, &PI);
2295
2296 free (wcommand);
2297 }
f15731c4 2298
1fac938e 2299 if (result == TRUE)
2300 {
2301 add_handle (PI.hProcess);
2302 CloseHandle (PI.hThread);
2303 return (int) PI.hProcess;
2304 }
2305 else
2306 return -1;
2307}
2308
2309static int
9dfe12ae 2310win32_wait (int *status)
1fac938e 2311{
2312 DWORD exitcode;
2313 HANDLE *hl;
2314 HANDLE h;
2315 DWORD res;
2316 int k;
2317 Process_List *pl;
e41b023d 2318 int hl_len;
1fac938e 2319
2320 if (plist_length == 0)
2321 {
2322 errno = ECHILD;
2323 return -1;
2324 }
2325
1fac938e 2326 k = 0;
51fa65dc 2327
2328 /* -------------------- critical section -------------------- */
2329 (*Lock_Task) ();
1fac938e 2330
e41b023d 2331 hl_len = plist_length;
2332
e41b023d 2333 hl = (HANDLE *) xmalloc (sizeof (HANDLE) * hl_len);
2334
1fac938e 2335 pl = PLIST;
2336 while (pl)
2337 {
2338 hl[k++] = pl->h;
2339 pl = pl->next;
2340 }
1fac938e 2341
51fa65dc 2342 (*Unlock_Task) ();
2343 /* -------------------- critical section -------------------- */
1fac938e 2344
e41b023d 2345 res = WaitForMultipleObjects (hl_len, hl, FALSE, INFINITE);
f15731c4 2346 h = hl[res - WAIT_OBJECT_0];
1fac938e 2347 free (hl);
2348
2349 remove_handle (h);
2350
2351 GetExitCodeProcess (h, &exitcode);
2352 CloseHandle (h);
2353
2354 *status = (int) exitcode;
2355 return (int) h;
2356}
2357
2358#endif
2359
2360int
9dfe12ae 2361__gnat_portable_no_block_spawn (char *args[])
1fac938e 2362{
2363 int pid = 0;
2364
e2a33c18 2365#if defined (__vxworks) || defined (__nucleus__) || defined (RTX)
2366 return -1;
2367
2368#elif defined (__EMX__) || defined (MSDOS)
1fac938e 2369
2370 /* ??? For PC machines I (Franco) don't know the system calls to implement
2371 this routine. So I'll fake it as follows. This routine will behave
2372 exactly like the blocking portable_spawn and will systematically return
2373 a pid of 0 unless the spawned task did not complete successfully, in
2374 which case we return a pid of -1. To synchronize with this the
2375 portable_wait below systematically returns a pid of 0 and reports that
2376 the subprocess terminated successfully. */
2377
f15731c4 2378 if (spawnvp (P_WAIT, args[0], args) != 0)
1fac938e 2379 return -1;
2380
2381#elif defined (_WIN32)
2382
2383 pid = win32_no_block_spawn (args[0], args);
2384 return pid;
2385
1fac938e 2386#else
2387 pid = fork ();
2388
f15731c4 2389 if (pid == 0)
2390 {
2391 /* The child. */
6d9c3443 2392 if (execv (args[0], MAYBE_TO_PTR32 (args)) != 0)
f15731c4 2393#if defined (VMS)
2394 return -1; /* execv is in parent context on VMS. */
9dfe12ae 2395#else
f15731c4 2396 _exit (1);
2397#endif
2398 }
2399
1fac938e 2400#endif
2401
2402 return pid;
2403}
2404
2405int
9dfe12ae 2406__gnat_portable_wait (int *process_status)
1fac938e 2407{
2408 int status = 0;
2409 int pid = 0;
2410
e2a33c18 2411#if defined (__vxworks) || defined (__nucleus__) || defined (RTX)
2412 /* Not sure what to do here, so do same as __EMX__ case, i.e., nothing but
2413 return zero. */
2414
2415#elif defined (_WIN32)
1fac938e 2416
2417 pid = win32_wait (&status);
2418
2419#elif defined (__EMX__) || defined (MSDOS)
f15731c4 2420 /* ??? See corresponding comment in portable_no_block_spawn. */
1fac938e 2421
1fac938e 2422#else
2423
1fac938e 2424 pid = waitpid (-1, &status, 0);
1fac938e 2425 status = status & 0xffff;
2426#endif
2427
2428 *process_status = status;
2429 return pid;
2430}
2431
2432void
9dfe12ae 2433__gnat_os_exit (int status)
1fac938e 2434{
1fac938e 2435 exit (status);
1fac938e 2436}
2437
f15731c4 2438/* Locate a regular file, give a Path value. */
1fac938e 2439
2440char *
9dfe12ae 2441__gnat_locate_regular_file (char *file_name, char *path_val)
1fac938e 2442{
2443 char *ptr;
5703e222 2444 char *file_path = (char *) alloca (strlen (file_name) + 1);
c69ba469 2445 int absolute;
2446
b51bcb1c 2447 /* Return immediately if file_name is empty */
2448
2449 if (*file_name == '\0')
2450 return 0;
2451
c69ba469 2452 /* Remove quotes around file_name if present */
2453
2454 ptr = file_name;
2455 if (*ptr == '"')
2456 ptr++;
2457
2458 strcpy (file_path, ptr);
2459
2460 ptr = file_path + strlen (file_path) - 1;
2461
2462 if (*ptr == '"')
2463 *ptr = '\0';
1fac938e 2464
f15731c4 2465 /* Handle absolute pathnames. */
c69ba469 2466
2467 absolute = __gnat_is_absolute_path (file_path, strlen (file_name));
2468
9dfe12ae 2469 if (absolute)
2470 {
c69ba469 2471 if (__gnat_is_regular_file (file_path))
2472 return xstrdup (file_path);
9dfe12ae 2473
2474 return 0;
2475 }
2476
2477 /* If file_name include directory separator(s), try it first as
2478 a path name relative to the current directory */
1fac938e 2479 for (ptr = file_name; *ptr && *ptr != '/' && *ptr != DIR_SEPARATOR; ptr++)
2480 ;
2481
9dfe12ae 2482 if (*ptr != 0)
1fac938e 2483 {
2484 if (__gnat_is_regular_file (file_name))
2485 return xstrdup (file_name);
1fac938e 2486 }
2487
2488 if (path_val == 0)
2489 return 0;
2490
2491 {
2492 /* The result has to be smaller than path_val + file_name. */
5703e222 2493 char *file_path = (char *) alloca (strlen (path_val) + strlen (file_name) + 2);
1fac938e 2494
2495 for (;;)
2496 {
2497 for (; *path_val == PATH_SEPARATOR; path_val++)
2498 ;
2499
2500 if (*path_val == 0)
2501 return 0;
2502
c69ba469 2503 /* Skip the starting quote */
2504
2505 if (*path_val == '"')
2506 path_val++;
2507
1fac938e 2508 for (ptr = file_path; *path_val && *path_val != PATH_SEPARATOR; )
c69ba469 2509 *ptr++ = *path_val++;
1fac938e 2510
2511 ptr--;
c69ba469 2512
2513 /* Skip the ending quote */
2514
2515 if (*ptr == '"')
2516 ptr--;
2517
1fac938e 2518 if (*ptr != '/' && *ptr != DIR_SEPARATOR)
2519 *++ptr = DIR_SEPARATOR;
2520
2521 strcpy (++ptr, file_name);
2522
2523 if (__gnat_is_regular_file (file_path))
2524 return xstrdup (file_path);
2525 }
2526 }
2527
2528 return 0;
2529}
2530
1fac938e 2531/* Locate an executable given a Path argument. This routine is only used by
2532 gnatbl and should not be used otherwise. Use locate_exec_on_path
f15731c4 2533 instead. */
1fac938e 2534
2535char *
9dfe12ae 2536__gnat_locate_exec (char *exec_name, char *path_val)
1fac938e 2537{
fb31b465 2538 char *ptr;
1fac938e 2539 if (!strstr (exec_name, HOST_EXECUTABLE_SUFFIX))
2540 {
2541 char *full_exec_name
5703e222 2542 = (char *) alloca (strlen (exec_name) + strlen (HOST_EXECUTABLE_SUFFIX) + 1);
1fac938e 2543
2544 strcpy (full_exec_name, exec_name);
2545 strcat (full_exec_name, HOST_EXECUTABLE_SUFFIX);
fb31b465 2546 ptr = __gnat_locate_regular_file (full_exec_name, path_val);
2547
2548 if (ptr == 0)
2549 return __gnat_locate_regular_file (exec_name, path_val);
2550 return ptr;
1fac938e 2551 }
2552 else
2553 return __gnat_locate_regular_file (exec_name, path_val);
2554}
2555
f15731c4 2556/* Locate an executable using the Systems default PATH. */
1fac938e 2557
2558char *
9dfe12ae 2559__gnat_locate_exec_on_path (char *exec_name)
1fac938e 2560{
9dfe12ae 2561 char *apath_val;
3b18b370 2562
e2a33c18 2563#if defined (_WIN32) && !defined (RTX)
3b18b370 2564 TCHAR *wpath_val = _tgetenv (_T("PATH"));
2565 TCHAR *wapath_val;
9dfe12ae 2566 /* In Win32 systems we expand the PATH as for XP environment
c69ba469 2567 variables are not automatically expanded. We also prepend the
2568 ".;" to the path to match normal NT path search semantics */
9dfe12ae 2569
c69ba469 2570 #define EXPAND_BUFFER_SIZE 32767
9dfe12ae 2571
3b18b370 2572 wapath_val = alloca (EXPAND_BUFFER_SIZE);
c69ba469 2573
3b18b370 2574 wapath_val [0] = '.';
2575 wapath_val [1] = ';';
1fac938e 2576
c69ba469 2577 DWORD res = ExpandEnvironmentStrings
3b18b370 2578 (wpath_val, &wapath_val[2], EXPAND_BUFFER_SIZE - 2);
2579
2580 if (!res) wapath_val [0] = _T('\0');
2581
2582 apath_val = alloca (EXPAND_BUFFER_SIZE);
2583
1e622f0e 2584 WS2SU (apath_val, wapath_val, EXPAND_BUFFER_SIZE);
3b18b370 2585 return __gnat_locate_exec (exec_name, apath_val);
c69ba469 2586
c69ba469 2587#else
3b18b370 2588
2589#ifdef VMS
2590 char *path_val = "/VAXC$PATH";
2591#else
2592 char *path_val = getenv ("PATH");
2593#endif
e2c62f37 2594 if (path_val == NULL) return NULL;
5703e222 2595 apath_val = (char *) alloca (strlen (path_val) + 1);
1fac938e 2596 strcpy (apath_val, path_val);
2597 return __gnat_locate_exec (exec_name, apath_val);
3b18b370 2598#endif
1fac938e 2599}
2600
2601#ifdef VMS
2602
2603/* These functions are used to translate to and from VMS and Unix syntax
f15731c4 2604 file, directory and path specifications. */
1fac938e 2605
9dfe12ae 2606#define MAXPATH 256
1fac938e 2607#define MAXNAMES 256
2608#define NEW_CANONICAL_FILELIST_INCREMENT 64
2609
9dfe12ae 2610static char new_canonical_dirspec [MAXPATH];
2611static char new_canonical_filespec [MAXPATH];
2612static char new_canonical_pathspec [MAXNAMES*MAXPATH];
1fac938e 2613static unsigned new_canonical_filelist_index;
2614static unsigned new_canonical_filelist_in_use;
2615static unsigned new_canonical_filelist_allocated;
2616static char **new_canonical_filelist;
9dfe12ae 2617static char new_host_pathspec [MAXNAMES*MAXPATH];
2618static char new_host_dirspec [MAXPATH];
2619static char new_host_filespec [MAXPATH];
1fac938e 2620
2621/* Routine is called repeatedly by decc$from_vms via
9dfe12ae 2622 __gnat_to_canonical_file_list_init until it returns 0 or the expansion
2623 runs out. */
1fac938e 2624
2625static int
9dfe12ae 2626wildcard_translate_unix (char *name)
1fac938e 2627{
2628 char *ver;
9dfe12ae 2629 char buff [MAXPATH];
1fac938e 2630
9dfe12ae 2631 strncpy (buff, name, MAXPATH);
2632 buff [MAXPATH - 1] = (char) 0;
1fac938e 2633 ver = strrchr (buff, '.');
2634
f15731c4 2635 /* Chop off the version. */
1fac938e 2636 if (ver)
2637 *ver = 0;
2638
f15731c4 2639 /* Dynamically extend the allocation by the increment. */
1fac938e 2640 if (new_canonical_filelist_in_use == new_canonical_filelist_allocated)
2641 {
2642 new_canonical_filelist_allocated += NEW_CANONICAL_FILELIST_INCREMENT;
f15731c4 2643 new_canonical_filelist = (char **) xrealloc
1fac938e 2644 (new_canonical_filelist,
2645 new_canonical_filelist_allocated * sizeof (char *));
2646 }
2647
2648 new_canonical_filelist[new_canonical_filelist_in_use++] = xstrdup (buff);
2649
2650 return 1;
2651}
2652
f15731c4 2653/* Translate a wildcard VMS file spec into a list of Unix file specs. First do
2654 full translation and copy the results into a list (_init), then return them
2655 one at a time (_next). If onlydirs set, only expand directory files. */
1fac938e 2656
2657int
9dfe12ae 2658__gnat_to_canonical_file_list_init (char *filespec, int onlydirs)
1fac938e 2659{
2660 int len;
9dfe12ae 2661 char buff [MAXPATH];
1fac938e 2662
2663 len = strlen (filespec);
9dfe12ae 2664 strncpy (buff, filespec, MAXPATH);
2665
2666 /* Only look for directories */
2667 if (onlydirs && !strstr (&buff [len-5], "*.dir"))
2668 strncat (buff, "*.dir", MAXPATH);
1fac938e 2669
9dfe12ae 2670 buff [MAXPATH - 1] = (char) 0;
1fac938e 2671
2672 decc$from_vms (buff, wildcard_translate_unix, 1);
2673
f15731c4 2674 /* Remove the .dir extension. */
1fac938e 2675 if (onlydirs)
2676 {
2677 int i;
2678 char *ext;
2679
2680 for (i = 0; i < new_canonical_filelist_in_use; i++)
2681 {
f15731c4 2682 ext = strstr (new_canonical_filelist[i], ".dir");
1fac938e 2683 if (ext)
2684 *ext = 0;
2685 }
2686 }
2687
2688 return new_canonical_filelist_in_use;
2689}
2690
f15731c4 2691/* Return the next filespec in the list. */
1fac938e 2692
2693char *
2694__gnat_to_canonical_file_list_next ()
2695{
f15731c4 2696 return new_canonical_filelist[new_canonical_filelist_index++];
1fac938e 2697}
2698
f15731c4 2699/* Free storage used in the wildcard expansion. */
1fac938e 2700
2701void
2702__gnat_to_canonical_file_list_free ()
2703{
2704 int i;
2705
2706 for (i = 0; i < new_canonical_filelist_in_use; i++)
f15731c4 2707 free (new_canonical_filelist[i]);
1fac938e 2708
2709 free (new_canonical_filelist);
2710
2711 new_canonical_filelist_in_use = 0;
2712 new_canonical_filelist_allocated = 0;
2713 new_canonical_filelist_index = 0;
2714 new_canonical_filelist = 0;
2715}
2716
b12d3a0b 2717/* The functional equivalent of decc$translate_vms routine.
2718 Designed to produce the same output, but is protected against
2719 malformed paths (original version ACCVIOs in this case) and
2720 does not require VMS-specific DECC RTL */
2721
2722#define NAM$C_MAXRSS 1024
2723
2724char *
2725__gnat_translate_vms (char *src)
2726{
2727 static char retbuf [NAM$C_MAXRSS+1];
2728 char *srcendpos, *pos1, *pos2, *retpos;
2729 int disp, path_present = 0;
2730
2731 if (!src) return NULL;
2732
2733 srcendpos = strchr (src, '\0');
2734 retpos = retbuf;
2735
2736 /* Look for the node and/or device in front of the path */
2737 pos1 = src;
2738 pos2 = strchr (pos1, ':');
2739
2740 if (pos2 && (pos2 < srcendpos) && (*(pos2 + 1) == ':')) {
2741 /* There is a node name. "node_name::" becomes "node_name!" */
2742 disp = pos2 - pos1;
2743 strncpy (retbuf, pos1, disp);
2744 retpos [disp] = '!';
2745 retpos = retpos + disp + 1;
2746 pos1 = pos2 + 2;
2747 pos2 = strchr (pos1, ':');
2748 }
2749
2750 if (pos2) {
2751 /* There is a device name. "dev_name:" becomes "/dev_name/" */
2752 *(retpos++) = '/';
2753 disp = pos2 - pos1;
2754 strncpy (retpos, pos1, disp);
2755 retpos = retpos + disp;
2756 pos1 = pos2 + 1;
2757 *(retpos++) = '/';
2758 }
2759 else
2760 /* No explicit device; we must look ahead and prepend /sys$disk/ if
2761 the path is absolute */
2762 if ((*pos1 == '[' || *pos1 == '<') && (pos1 < srcendpos)
2763 && !strchr (".-]>", *(pos1 + 1))) {
2764 strncpy (retpos, "/sys$disk/", 10);
2765 retpos += 10;
2766 }
2767
2768 /* Process the path part */
2769 while (*pos1 == '[' || *pos1 == '<') {
2770 path_present++;
2771 pos1++;
2772 if (*pos1 == ']' || *pos1 == '>') {
2773 /* Special case, [] translates to '.' */
2774 *(retpos++) = '.';
2775 pos1++;
2776 }
2777 else {
2778 /* '[000000' means root dir. It can be present in the middle of
2779 the path due to expansion of logical devices, in which case
2780 we skip it */
2781 if (!strncmp (pos1, "000000", 6) && path_present > 1 &&
2782 (*(pos1 + 6) == ']' || *(pos1 + 6) == '>' || *(pos1 + 6) == '.')) {
2783 pos1 += 6;
2784 if (*pos1 == '.') pos1++;
2785 }
2786 else if (*pos1 == '.') {
2787 /* Relative path */
2788 *(retpos++) = '.';
2789 }
2790
2359306a 2791 /* There is a qualified path */
2792 while (*pos1 && *pos1 != ']' && *pos1 != '>') {
b12d3a0b 2793 switch (*pos1) {
2794 case '.':
2795 /* '.' is used to separate directories. Replace it with '/' but
2796 only if there isn't already '/' just before */
2797 if (*(retpos - 1) != '/') *(retpos++) = '/';
2798 pos1++;
2799 if (pos1 + 1 < srcendpos && *pos1 == '.' && *(pos1 + 1) == '.') {
2800 /* ellipsis refers to entire subtree; replace with '**' */
2801 *(retpos++) = '*'; *(retpos++) = '*'; *(retpos++) = '/';
2802 pos1 += 2;
2803 }
2804 break;
2805 case '-' :
2359306a 2806 /* When after '.' '[' '<' is equivalent to Unix ".." but there
2807 may be several in a row */
2808 if (*(pos1 - 1) == '.' || *(pos1 - 1) == '[' ||
2809 *(pos1 - 1) == '<') {
2810 while (*pos1 == '-') {
2811 pos1++;
2812 *(retpos++) = '.'; *(retpos++) = '.'; *(retpos++) = '/';
2813 }
2814 retpos--;
2815 break;
b12d3a0b 2816 }
2359306a 2817 /* otherwise fall through to default */
b12d3a0b 2818 default:
2819 *(retpos++) = *(pos1++);
2820 }
2821 }
2822 pos1++;
2823 }
2824 }
2825
2826 if (pos1 < srcendpos) {
2827 /* Now add the actual file name, until the version suffix if any */
2828 if (path_present) *(retpos++) = '/';
2829 pos2 = strchr (pos1, ';');
2830 disp = pos2? (pos2 - pos1) : (srcendpos - pos1);
2831 strncpy (retpos, pos1, disp);
2832 retpos += disp;
2833 if (pos2 && pos2 < srcendpos) {
2834 /* There is a non-empty version suffix. ";<ver>" becomes ".<ver>" */
2835 *retpos++ = '.';
2836 disp = srcendpos - pos2 - 1;
2837 strncpy (retpos, pos2 + 1, disp);
2838 retpos += disp;
2839 }
2840 }
2841
2842 *retpos = '\0';
2843
2844 return retbuf;
2845
2846}
2847
f15731c4 2848/* Translate a VMS syntax directory specification in to Unix syntax. If
2849 PREFIXFLAG is set, append an underscore "/". If no indicators of VMS syntax
2850 found, return input string. Also translate a dirname that contains no
2851 slashes, in case it's a logical name. */
1fac938e 2852
2853char *
9dfe12ae 2854__gnat_to_canonical_dir_spec (char *dirspec, int prefixflag)
1fac938e 2855{
2856 int len;
2857
2858 strcpy (new_canonical_dirspec, "");
2859 if (strlen (dirspec))
2860 {
2861 char *dirspec1;
2862
2863 if (strchr (dirspec, ']') || strchr (dirspec, ':'))
9dfe12ae 2864 {
2865 strncpy (new_canonical_dirspec,
b12d3a0b 2866 __gnat_translate_vms (dirspec),
9dfe12ae 2867 MAXPATH);
2868 }
1fac938e 2869 else if (!strchr (dirspec, '/') && (dirspec1 = getenv (dirspec)) != 0)
9dfe12ae 2870 {
2871 strncpy (new_canonical_dirspec,
b12d3a0b 2872 __gnat_translate_vms (dirspec1),
9dfe12ae 2873 MAXPATH);
2874 }
1fac938e 2875 else
9dfe12ae 2876 {
2877 strncpy (new_canonical_dirspec, dirspec, MAXPATH);
2878 }
1fac938e 2879 }
2880
2881 len = strlen (new_canonical_dirspec);
9dfe12ae 2882 if (prefixflag && new_canonical_dirspec [len-1] != '/')
2883 strncat (new_canonical_dirspec, "/", MAXPATH);
2884
2885 new_canonical_dirspec [MAXPATH - 1] = (char) 0;
1fac938e 2886
2887 return new_canonical_dirspec;
2888
2889}
2890
2891/* Translate a VMS syntax file specification into Unix syntax.
3cc2671a 2892 If no indicators of VMS syntax found, check if it's an uppercase
23c6b287 2893 alphanumeric_ name and if so try it out as an environment
2894 variable (logical name). If all else fails return the
2895 input string. */
1fac938e 2896
2897char *
9dfe12ae 2898__gnat_to_canonical_file_spec (char *filespec)
1fac938e 2899{
23c6b287 2900 char *filespec1;
2901
9dfe12ae 2902 strncpy (new_canonical_filespec, "", MAXPATH);
2903
1fac938e 2904 if (strchr (filespec, ']') || strchr (filespec, ':'))
9dfe12ae 2905 {
2359306a 2906 char *tspec = (char *) __gnat_translate_vms (filespec);
c69ba469 2907
2908 if (tspec != (char *) -1)
2909 strncpy (new_canonical_filespec, tspec, MAXPATH);
23c6b287 2910 }
2911 else if ((strlen (filespec) == strspn (filespec,
2912 "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_"))
2913 && (filespec1 = getenv (filespec)))
2914 {
2359306a 2915 char *tspec = (char *) __gnat_translate_vms (filespec1);
c69ba469 2916
2917 if (tspec != (char *) -1)
2918 strncpy (new_canonical_filespec, tspec, MAXPATH);
9dfe12ae 2919 }
1fac938e 2920 else
9dfe12ae 2921 {
2922 strncpy (new_canonical_filespec, filespec, MAXPATH);
2923 }
2924
2925 new_canonical_filespec [MAXPATH - 1] = (char) 0;
1fac938e 2926
2927 return new_canonical_filespec;
2928}
2929
2930/* Translate a VMS syntax path specification into Unix syntax.
f15731c4 2931 If no indicators of VMS syntax found, return input string. */
1fac938e 2932
2933char *
9dfe12ae 2934__gnat_to_canonical_path_spec (char *pathspec)
1fac938e 2935{
9dfe12ae 2936 char *curr, *next, buff [MAXPATH];
1fac938e 2937
2938 if (pathspec == 0)
2939 return pathspec;
2940
f15731c4 2941 /* If there are /'s, assume it's a Unix path spec and return. */
1fac938e 2942 if (strchr (pathspec, '/'))
2943 return pathspec;
2944
f15731c4 2945 new_canonical_pathspec[0] = 0;
1fac938e 2946 curr = pathspec;
2947
2948 for (;;)
2949 {
2950 next = strchr (curr, ',');
2951 if (next == 0)
2952 next = strchr (curr, 0);
2953
2954 strncpy (buff, curr, next - curr);
f15731c4 2955 buff[next - curr] = 0;
1fac938e 2956
f15731c4 2957 /* Check for wildcards and expand if present. */
1fac938e 2958 if (strchr (buff, '*') || strchr (buff, '%') || strstr (buff, "..."))
2959 {
2960 int i, dirs;
2961
2962 dirs = __gnat_to_canonical_file_list_init (buff, 1);
2963 for (i = 0; i < dirs; i++)
2964 {
2965 char *next_dir;
2966
2967 next_dir = __gnat_to_canonical_file_list_next ();
9dfe12ae 2968 strncat (new_canonical_pathspec, next_dir, MAXPATH);
1fac938e 2969
f15731c4 2970 /* Don't append the separator after the last expansion. */
1fac938e 2971 if (i+1 < dirs)
9dfe12ae 2972 strncat (new_canonical_pathspec, ":", MAXPATH);
1fac938e 2973 }
2974
2975 __gnat_to_canonical_file_list_free ();
2976 }
2977 else
9dfe12ae 2978 strncat (new_canonical_pathspec,
2979 __gnat_to_canonical_dir_spec (buff, 0), MAXPATH);
1fac938e 2980
2981 if (*next == 0)
2982 break;
2983
9dfe12ae 2984 strncat (new_canonical_pathspec, ":", MAXPATH);
1fac938e 2985 curr = next + 1;
2986 }
2987
9dfe12ae 2988 new_canonical_pathspec [MAXPATH - 1] = (char) 0;
2989
1fac938e 2990 return new_canonical_pathspec;
2991}
2992
9dfe12ae 2993static char filename_buff [MAXPATH];
1fac938e 2994
2995static int
9dfe12ae 2996translate_unix (char *name, int type)
1fac938e 2997{
9dfe12ae 2998 strncpy (filename_buff, name, MAXPATH);
2999 filename_buff [MAXPATH - 1] = (char) 0;
1fac938e 3000 return 0;
3001}
3002
f15731c4 3003/* Translate a Unix syntax path spec into a VMS style (comma separated list of
3004 directories. */
1fac938e 3005
3006static char *
9dfe12ae 3007to_host_path_spec (char *pathspec)
1fac938e 3008{
9dfe12ae 3009 char *curr, *next, buff [MAXPATH];
1fac938e 3010
3011 if (pathspec == 0)
3012 return pathspec;
3013
f15731c4 3014 /* Can't very well test for colons, since that's the Unix separator! */
1fac938e 3015 if (strchr (pathspec, ']') || strchr (pathspec, ','))
3016 return pathspec;
3017
f15731c4 3018 new_host_pathspec[0] = 0;
1fac938e 3019 curr = pathspec;
3020
3021 for (;;)
3022 {
3023 next = strchr (curr, ':');
3024 if (next == 0)
3025 next = strchr (curr, 0);
3026
3027 strncpy (buff, curr, next - curr);
f15731c4 3028 buff[next - curr] = 0;
1fac938e 3029
9dfe12ae 3030 strncat (new_host_pathspec, __gnat_to_host_dir_spec (buff, 0), MAXPATH);
1fac938e 3031 if (*next == 0)
3032 break;
9dfe12ae 3033 strncat (new_host_pathspec, ",", MAXPATH);
1fac938e 3034 curr = next + 1;
3035 }
3036
9dfe12ae 3037 new_host_pathspec [MAXPATH - 1] = (char) 0;
3038
1fac938e 3039 return new_host_pathspec;
3040}
3041
f15731c4 3042/* Translate a Unix syntax directory specification into VMS syntax. The
3043 PREFIXFLAG has no effect, but is kept for symmetry with
3044 to_canonical_dir_spec. If indicators of VMS syntax found, return input
3045 string. */
1fac938e 3046
3047char *
9dfe12ae 3048__gnat_to_host_dir_spec (char *dirspec, int prefixflag ATTRIBUTE_UNUSED)
1fac938e 3049{
3050 int len = strlen (dirspec);
3051
9dfe12ae 3052 strncpy (new_host_dirspec, dirspec, MAXPATH);
3053 new_host_dirspec [MAXPATH - 1] = (char) 0;
1fac938e 3054
3055 if (strchr (new_host_dirspec, ']') || strchr (new_host_dirspec, ':'))
3056 return new_host_dirspec;
3057
f15731c4 3058 while (len > 1 && new_host_dirspec[len - 1] == '/')
1fac938e 3059 {
f15731c4 3060 new_host_dirspec[len - 1] = 0;
1fac938e 3061 len--;
3062 }
3063
3064 decc$to_vms (new_host_dirspec, translate_unix, 1, 2);
9dfe12ae 3065 strncpy (new_host_dirspec, filename_buff, MAXPATH);
3066 new_host_dirspec [MAXPATH - 1] = (char) 0;
1fac938e 3067
3068 return new_host_dirspec;
1fac938e 3069}
3070
3071/* Translate a Unix syntax file specification into VMS syntax.
f15731c4 3072 If indicators of VMS syntax found, return input string. */
1fac938e 3073
3074char *
9dfe12ae 3075__gnat_to_host_file_spec (char *filespec)
1fac938e 3076{
9dfe12ae 3077 strncpy (new_host_filespec, "", MAXPATH);
1fac938e 3078 if (strchr (filespec, ']') || strchr (filespec, ':'))
9dfe12ae 3079 {
3080 strncpy (new_host_filespec, filespec, MAXPATH);
3081 }
1fac938e 3082 else
3083 {
3084 decc$to_vms (filespec, translate_unix, 1, 1);
9dfe12ae 3085 strncpy (new_host_filespec, filename_buff, MAXPATH);
1fac938e 3086 }
3087
9dfe12ae 3088 new_host_filespec [MAXPATH - 1] = (char) 0;
3089
1fac938e 3090 return new_host_filespec;
3091}
3092
3093void
3094__gnat_adjust_os_resource_limits ()
3095{
3096 SYS$ADJWSL (131072, 0);
3097}
3098
9dfe12ae 3099#else /* VMS */
1fac938e 3100
f15731c4 3101/* Dummy functions for Osint import for non-VMS systems. */
1fac938e 3102
3103int
9dfe12ae 3104__gnat_to_canonical_file_list_init
3105 (char *dirspec ATTRIBUTE_UNUSED, int onlydirs ATTRIBUTE_UNUSED)
1fac938e 3106{
3107 return 0;
3108}
3109
3110char *
6f2c2693 3111__gnat_to_canonical_file_list_next (void)
1fac938e 3112{
3113 return (char *) "";
3114}
3115
3116void
6f2c2693 3117__gnat_to_canonical_file_list_free (void)
1fac938e 3118{
3119}
3120
3121char *
9dfe12ae 3122__gnat_to_canonical_dir_spec (char *dirspec, int prefixflag ATTRIBUTE_UNUSED)
1fac938e 3123{
3124 return dirspec;
3125}
3126
3127char *
9dfe12ae 3128__gnat_to_canonical_file_spec (char *filespec)
1fac938e 3129{
3130 return filespec;
3131}
3132
3133char *
9dfe12ae 3134__gnat_to_canonical_path_spec (char *pathspec)
1fac938e 3135{
3136 return pathspec;
3137}
3138
3139char *
9dfe12ae 3140__gnat_to_host_dir_spec (char *dirspec, int prefixflag ATTRIBUTE_UNUSED)
1fac938e 3141{
3142 return dirspec;
3143}
3144
3145char *
9dfe12ae 3146__gnat_to_host_file_spec (char *filespec)
1fac938e 3147{
3148 return filespec;
3149}
3150
3151void
6f2c2693 3152__gnat_adjust_os_resource_limits (void)
1fac938e 3153{
3154}
3155
3156#endif
3157
f15731c4 3158/* For EMX, we cannot include dummy in libgcc, since it is too difficult
1fac938e 3159 to coordinate this with the EMX distribution. Consequently, we put the
f15731c4 3160 definition of dummy which is used for exception handling, here. */
1fac938e 3161
3162#if defined (__EMX__)
3163void __dummy () {}
3164#endif
3165
3166#if defined (__mips_vxworks)
9dfe12ae 3167int
3168_flush_cache()
1fac938e 3169{
3170 CACHE_USER_FLUSH (0, ENTIRE_CACHE);
3171}
3172#endif
3173
29d774d0 3174#if defined (CROSS_DIRECTORY_STRUCTURE) \
a3b0f4f2 3175 || (! ((defined (sparc) || defined (i386)) && defined (sun) \
3176 && defined (__SVR4)) \
c69ba469 3177 && ! (defined (linux) && (defined (i386) || defined (__x86_64__))) \
a3b0f4f2 3178 && ! (defined (linux) && defined (__ia64__)) \
547371fa 3179 && ! (defined (linux) && defined (powerpc)) \
40a4417a 3180 && ! defined (__FreeBSD__) \
21a87c1d 3181 && ! defined (__hpux__) \
ba706ed3 3182 && ! defined (__APPLE__) \
9dfe12ae 3183 && ! defined (_AIX) \
1fac938e 3184 && ! (defined (__alpha__) && defined (__osf__)) \
3b18b370 3185 && ! defined (VMS) \
80d4fec4 3186 && ! defined (__MINGW32__) \
3187 && ! (defined (__mips) && defined (__sgi)))
f15731c4 3188
a3b0f4f2 3189/* Dummy function to satisfy g-trasym.o. See the preprocessor conditional
3190 just above for a list of native platforms that provide a non-dummy
3191 version of this procedure in libaddr2line.a. */
1fac938e 3192
3193void
1e622f0e 3194convert_addresses (const char *file_name ATTRIBUTE_UNUSED,
3195 void *addrs ATTRIBUTE_UNUSED,
9dfe12ae 3196 int n_addr ATTRIBUTE_UNUSED,
3197 void *buf ATTRIBUTE_UNUSED,
3198 int *len ATTRIBUTE_UNUSED)
1fac938e 3199{
3200 *len = 0;
3201}
3202#endif
f15731c4 3203
3204#if defined (_WIN32)
3205int __gnat_argument_needs_quote = 1;
3206#else
3207int __gnat_argument_needs_quote = 0;
3208#endif
9dfe12ae 3209
3210/* This option is used to enable/disable object files handling from the
3211 binder file by the GNAT Project module. For example, this is disabled on
e0f42093 3212 Windows (prior to GCC 3.4) as it is already done by the mdll module.
3213 Stating with GCC 3.4 the shared libraries are not based on mdll
3214 anymore as it uses the GCC's -shared option */
3215#if defined (_WIN32) \
3216 && ((__GNUC__ < 3) || ((__GNUC__ == 3) && (__GNUC_MINOR__ < 4)))
9dfe12ae 3217int __gnat_prj_add_obj_files = 0;
3218#else
3219int __gnat_prj_add_obj_files = 1;
3220#endif
3221
3222/* char used as prefix/suffix for environment variables */
3223#if defined (_WIN32)
3224char __gnat_environment_char = '%';
3225#else
3226char __gnat_environment_char = '$';
3227#endif
3228
3229/* This functions copy the file attributes from a source file to a
3230 destination file.
3231
3232 mode = 0 : In this mode copy only the file time stamps (last access and
3233 last modification time stamps).
3234
3235 mode = 1 : In this mode, time stamps and read/write/execute attributes are
3236 copied.
3237
3238 Returns 0 if operation was successful and -1 in case of error. */
3239
3240int
3241__gnat_copy_attribs (char *from, char *to, int mode)
3242{
5091bc2f 3243#if defined (VMS) || defined (__vxworks) || defined (__nucleus__)
9dfe12ae 3244 return -1;
3245#else
3246 struct stat fbuf;
3247 struct utimbuf tbuf;
3248
3249 if (stat (from, &fbuf) == -1)
3250 {
3251 return -1;
3252 }
3253
3254 tbuf.actime = fbuf.st_atime;
3255 tbuf.modtime = fbuf.st_mtime;
3256
3257 if (utime (to, &tbuf) == -1)
3258 {
3259 return -1;
3260 }
3261
3262 if (mode == 1)
3263 {
3264 if (chmod (to, fbuf.st_mode) == -1)
3265 {
3266 return -1;
3267 }
3268 }
3269
3270 return 0;
3271#endif
3272}
3273
cf6d853e 3274int
3275__gnat_lseek (int fd, long offset, int whence)
3276{
3277 return (int) lseek (fd, offset, whence);
3278}
0914a918 3279
e2c62f37 3280/* This function returns the major version number of GCC being used. */
0914a918 3281int
3282get_gcc_version (void)
3283{
e2c62f37 3284#ifdef IN_RTS
3285 return __GNUC__;
3286#else
3287 return (int) (version_string[0] - '0');
3288#endif
0914a918 3289}
6d9c3443 3290
3291int
de10c095 3292__gnat_set_close_on_exec (int fd ATTRIBUTE_UNUSED,
0e9e8338 3293 int close_on_exec_p ATTRIBUTE_UNUSED)
6d9c3443 3294{
3295#if defined (F_GETFD) && defined (FD_CLOEXEC) && ! defined (__vxworks)
3296 int flags = fcntl (fd, F_GETFD, 0);
3297 if (flags < 0)
3298 return flags;
3299 if (close_on_exec_p)
3300 flags |= FD_CLOEXEC;
3301 else
3302 flags &= ~FD_CLOEXEC;
3303 return fcntl (fd, F_SETFD, flags | FD_CLOEXEC);
07f34887 3304#elif defined(_WIN32)
3305 HANDLE h = (HANDLE) _get_osfhandle (fd);
3306 if (h == (HANDLE) -1)
3307 return -1;
3308 if (close_on_exec_p)
3309 return ! SetHandleInformation (h, HANDLE_FLAG_INHERIT, 0);
3310 return ! SetHandleInformation (h, HANDLE_FLAG_INHERIT,
3311 HANDLE_FLAG_INHERIT);
6d9c3443 3312#else
07f34887 3313 /* TODO: Unimplemented. */
6d9c3443 3314 return -1;
6d9c3443 3315#endif
3316}
fb31b465 3317
3318/* Indicates if platforms supports automatic initialization through the
3319 constructor mechanism */
3320int
3321__gnat_binder_supports_auto_init ()
3322{
3323#ifdef VMS
3324 return 0;
3325#else
3326 return 1;
3327#endif
3328}
3329
3330/* Indicates that Stand-Alone Libraries are automatically initialized through
3331 the constructor mechanism */
3332int
3333__gnat_sals_init_using_constructors ()
3334{
3335#if defined (__vxworks) || defined (__Lynx__) || defined (VMS)
3336 return 0;
3337#else
3338 return 1;
3339#endif
3340}
e2a33c18 3341
8e726ab4 3342#ifdef RTX
3343
e2a33c18 3344/* In RTX mode, the procedure to get the time (as file time) is different
3345 in RTSS mode and Win32 mode. In order to avoid duplicating an Ada file,
3346 we introduce an intermediate procedure to link against the corresponding
3347 one in each situation. */
8e726ab4 3348
3349extern void GetTimeAsFileTime(LPFILETIME pTime);
e2a33c18 3350
3351void GetTimeAsFileTime(LPFILETIME pTime)
3352{
3353#ifdef RTSS
3354 RtGetRtssTimeAsFileTime (pTime); /* RTSS interface */
3355#else
3356 GetSystemTimeAsFileTime (pTime); /* w32 interface */
3357#endif
3358}
8e726ab4 3359
3360#ifdef RTSS
3361/* Add symbol that is required to link. It would otherwise be taken from
3362 libgcc.a and it would try to use the gcc constructors that are not
3363 supported by Microsoft linker. */
3364
3365extern void __main (void);
3366
3367void __main (void) {}
3368#endif
e2a33c18 3369#endif
3370
9d093602 3371#if defined (linux) || defined(__GLIBC__)
e2a33c18 3372/* pthread affinity support */
3373
c62e34a4 3374int __gnat_pthread_setaffinity_np (pthread_t th,
3375 size_t cpusetsize,
3376 const void *cpuset);
3377
e2a33c18 3378#ifdef CPU_SETSIZE
3379#include <pthread.h>
3380int
3381__gnat_pthread_setaffinity_np (pthread_t th,
3382 size_t cpusetsize,
3383 const cpu_set_t *cpuset)
3384{
3385 return pthread_setaffinity_np (th, cpusetsize, cpuset);
3386}
3387#else
3388int
c62e34a4 3389__gnat_pthread_setaffinity_np (pthread_t th ATTRIBUTE_UNUSED,
3390 size_t cpusetsize ATTRIBUTE_UNUSED,
3391 const void *cpuset ATTRIBUTE_UNUSED)
e2a33c18 3392{
3393 return 0;
3394}
3395#endif
3396#endif
a0d9619f 3397
3398#if defined (linux)
3399/* There is no function in the glibc to retrieve the LWP of the current
3400 thread. We need to do a system call in order to retrieve this
3401 information. */
3402#include <sys/syscall.h>
3403void *__gnat_lwp_self (void) {
3404 return (void *) syscall (__NR_gettid);
3405}
3406#endif