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