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