]> git.ipfire.org Git - thirdparty/gcc.git/blame - gcc/ada/adaint.c
Remove obsolete IRIX 6.5 support
[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
becb63f5 37#ifdef __cplusplus
38extern "C" {
39#endif
40
1fac938e 41#ifdef __vxworks
f15731c4 42
43/* No need to redefine exit here. */
1fac938e 44#undef exit
f15731c4 45
1fac938e 46/* We want to use the POSIX variants of include files. */
47#define POSIX
48#include "vxWorks.h"
49
50#if defined (__mips_vxworks)
51#include "cacheLib.h"
52#endif /* __mips_vxworks */
53
0f4d3df5 54/* If SMP, access vxCpuConfiguredGet */
55#ifdef _WRS_CONFIG_SMP
56#include <vxCpuLib.h>
57#endif /* _WRS_CONFIG_SMP */
58
b07bcda8 59/* We need to know the VxWorks version because some file operations
60 (such as chmod) are only available on VxWorks 6. */
61#include "version.h"
62
1fac938e 63#endif /* VxWorks */
64
5641963c 65#if defined (__APPLE__)
90bc406c 66#include <unistd.h>
67#endif
68
69#if defined (__hpux__)
70#include <sys/param.h>
71#include <sys/pstat.h>
72#endif
73
cafd02b3 74#ifdef VMS
75#define _POSIX_EXIT 1
ba706ed3 76#define HOST_EXECUTABLE_SUFFIX ".exe"
77#define HOST_OBJECT_SUFFIX ".obj"
cafd02b3 78#endif
79
1fac938e 80#ifdef IN_RTS
81#include "tconfig.h"
82#include "tsystem.h"
9dfe12ae 83
1fac938e 84#include <sys/stat.h>
85#include <fcntl.h>
86#include <time.h>
cafd02b3 87#ifdef VMS
88#include <unixio.h>
89#endif
1fac938e 90
b07bcda8 91#ifdef __vxworks
92/* S_IREAD and S_IWRITE are not defined in VxWorks */
93#ifndef S_IREAD
94#define S_IREAD (S_IRUSR | S_IRGRP | S_IROTH)
95#endif
96
97#ifndef S_IWRITE
98#define S_IWRITE (S_IWUSR)
99#endif
100#endif
101
f15731c4 102/* We don't have libiberty, so use malloc. */
1fac938e 103#define xmalloc(S) malloc (S)
f15731c4 104#define xrealloc(V,S) realloc (V,S)
1fac938e 105#else
106#include "config.h"
107#include "system.h"
e2c62f37 108#include "version.h"
1fac938e 109#endif
9dfe12ae 110
fa0b5df1 111#if defined (__MINGW32__)
112
e2a33c18 113#if defined (RTX)
114#include <windows.h>
115#include <Rtapi.h>
fa0b5df1 116#else
9dfe12ae 117#include "mingw32.h"
f60cc57d 118
119/* Current code page to use, set in initialize.c. */
120UINT CurrentCodePage;
fa0b5df1 121#endif
122
9dfe12ae 123#include <sys/utime.h>
a4f295eb 124
125/* For isalpha-like tests in the compiler, we're expected to resort to
126 safe-ctype.h/ISALPHA. This isn't available for the runtime library
127 build, so we fallback on ctype.h/isalpha there. */
128
129#ifdef IN_RTS
f0a28ccb 130#include <ctype.h>
a4f295eb 131#define ISALPHA isalpha
132#endif
2359306a 133
134#elif defined (__Lynx__)
135
136/* Lynx utime.h only defines the entities of interest to us if
137 defined (VMOS_DEV), so ... */
138#define VMOS_DEV
139#include <utime.h>
140#undef VMOS_DEV
141
142#elif !defined (VMS)
9dfe12ae 143#include <utime.h>
9dfe12ae 144#endif
145
5091bc2f 146/* wait.h processing */
9dfe12ae 147#ifdef __MINGW32__
148#if OLD_MINGW
1fac938e 149#include <sys/wait.h>
9dfe12ae 150#endif
8ffbc401 151#elif defined (__vxworks) && defined (__RTP__)
152#include <wait.h>
2359306a 153#elif defined (__Lynx__)
154/* ??? We really need wait.h and it includes resource.h on Lynx. GCC
155 has a resource.h header as well, included instead of the lynx
156 version in our setup, causing lots of errors. We don't really need
157 the lynx contents of this file, so just workaround the issue by
158 preventing the inclusion of the GCC header from doing anything. */
159#define GCC_RESOURCE_H
160#include <sys/wait.h>
5091bc2f 161#elif defined (__nucleus__)
162/* No wait() or waitpid() calls available */
9dfe12ae 163#else
5091bc2f 164/* Default case */
9dfe12ae 165#include <sys/wait.h>
166#endif
1fac938e 167
30592778 168#if defined (_WIN32)
d8dd2062 169#elif defined (VMS)
71a3e619 170
f15731c4 171/* Header files and definitions for __gnat_set_file_time_name. */
71a3e619 172
8620a406 173#define __NEW_STARLET 1
ba706ed3 174#include <vms/rms.h>
175#include <vms/atrdef.h>
176#include <vms/fibdef.h>
177#include <vms/stsdef.h>
178#include <vms/iodef.h>
d8dd2062 179#include <errno.h>
ba706ed3 180#include <vms/descrip.h>
d8dd2062 181#include <string.h>
182#include <unixlib.h>
183
f15731c4 184/* Use native 64-bit arithmetic. */
d8dd2062 185#define unix_time_to_vms(X,Y) \
186 { unsigned long long reftime, tmptime = (X); \
187 $DESCRIPTOR (unixtime,"1-JAN-1970 0:00:00.00"); \
188 SYS$BINTIM (&unixtime, &reftime); \
189 Y = tmptime * 10000000 + reftime; }
190
191/* descrip.h doesn't have everything ... */
8620a406 192typedef struct fibdef* __fibdef_ptr32 __attribute__ (( mode (SI) ));
d8dd2062 193struct dsc$descriptor_fib
194{
8620a406 195 unsigned int fib$l_len;
196 __fibdef_ptr32 fib$l_addr;
d8dd2062 197};
198
71a3e619 199/* I/O Status Block. */
d8dd2062 200struct IOSB
9dfe12ae 201{
d8dd2062 202 unsigned short status, count;
8620a406 203 unsigned int devdep;
d8dd2062 204};
205
206static char *tryfile;
207
71a3e619 208/* Variable length string. */
d8dd2062 209struct vstring
210{
211 short length;
f15731c4 212 char string[NAM$C_MAXRSS+1];
d8dd2062 213};
214
9b1d6aeb 215#define SYI$_ACTIVECPU_CNT 0x111e
216extern int LIB$GETSYI (int *, unsigned int *);
217
d8dd2062 218#else
219#include <utime.h>
220#endif
221
30592778 222#if defined (_WIN32)
1fac938e 223#include <process.h>
224#endif
225
226#if defined (_WIN32)
4c4697b8 227
1fac938e 228#include <dir.h>
229#include <windows.h>
7db1ef17 230#include <accctrl.h>
231#include <aclapi.h>
fef772a5 232#undef DIR_SEPARATOR
233#define DIR_SEPARATOR '\\'
1fac938e 234#endif
235
236#include "adaint.h"
237
238/* Define symbols O_BINARY and O_TEXT as harmless zeroes if they are not
239 defined in the current system. On DOS-like systems these flags control
240 whether the file is opened/created in text-translation mode (CR/LF in
241 external file mapped to LF in internal file), but in Unix-like systems,
242 no text translation is required, so these flags have no effect. */
243
1fac938e 244#ifndef O_BINARY
245#define O_BINARY 0
246#endif
247
248#ifndef O_TEXT
249#define O_TEXT 0
250#endif
251
252#ifndef HOST_EXECUTABLE_SUFFIX
253#define HOST_EXECUTABLE_SUFFIX ""
254#endif
255
256#ifndef HOST_OBJECT_SUFFIX
257#define HOST_OBJECT_SUFFIX ".o"
258#endif
259
260#ifndef PATH_SEPARATOR
261#define PATH_SEPARATOR ':'
262#endif
263
264#ifndef DIR_SEPARATOR
265#define DIR_SEPARATOR '/'
266#endif
267
a3b0f4f2 268/* Check for cross-compilation */
8c7d3bad 269#if defined (CROSS_COMPILE) || defined (CROSS_DIRECTORY_STRUCTURE)
270#define IS_CROSS 1
a3b0f4f2 271int __gnat_is_cross_compiler = 1;
272#else
8c7d3bad 273#undef IS_CROSS
a3b0f4f2 274int __gnat_is_cross_compiler = 0;
275#endif
276
1fac938e 277char __gnat_dir_separator = DIR_SEPARATOR;
278
279char __gnat_path_separator = PATH_SEPARATOR;
280
281/* The GNAT_LIBRARY_TEMPLATE contains a list of expressions that define
282 the base filenames that libraries specified with -lsomelib options
283 may have. This is used by GNATMAKE to check whether an executable
284 is up-to-date or not. The syntax is
285
286 library_template ::= { pattern ; } pattern NUL
287 pattern ::= [ prefix ] * [ postfix ]
288
289 These should only specify names of static libraries as it makes
290 no sense to determine at link time if dynamic-link libraries are
291 up to date or not. Any libraries that are not found are supposed
292 to be up-to-date:
293
294 * if they are needed but not present, the link
295 will fail,
296
297 * otherwise they are libraries in the system paths and so
298 they are considered part of the system and not checked
299 for that reason.
300
301 ??? This should be part of a GNAT host-specific compiler
302 file instead of being included in all user applications
f15731c4 303 as well. This is only a temporary work-around for 3.11b. */
1fac938e 304
305#ifndef GNAT_LIBRARY_TEMPLATE
30592778 306#if defined (VMS)
1fac938e 307#define GNAT_LIBRARY_TEMPLATE "*.olb"
308#else
309#define GNAT_LIBRARY_TEMPLATE "lib*.a"
310#endif
311#endif
312
313const char *__gnat_library_template = GNAT_LIBRARY_TEMPLATE;
314
f15731c4 315/* This variable is used in hostparm.ads to say whether the host is a VMS
316 system. */
317#ifdef VMS
becb63f5 318int __gnat_vmsp = 1;
f15731c4 319#else
becb63f5 320int __gnat_vmsp = 0;
f15731c4 321#endif
322
30592778 323#if defined (VMS)
9dfe12ae 324#define GNAT_MAX_PATH_LEN 256 /* PATH_MAX */
e633acdc 325
5091bc2f 326#elif defined (__vxworks) || defined (__OPENNT) || defined(__nucleus__)
9dfe12ae 327#define GNAT_MAX_PATH_LEN PATH_MAX
328
329#else
330
331#if defined (__MINGW32__)
332#include "mingw32.h"
333
334#if OLD_MINGW
335#include <sys/param.h>
336#endif
e633acdc 337
338#else
339#include <sys/param.h>
9dfe12ae 340#endif
341
8ae72cac 342#ifdef MAXPATHLEN
9dfe12ae 343#define GNAT_MAX_PATH_LEN MAXPATHLEN
8ae72cac 344#else
345#define GNAT_MAX_PATH_LEN 256
346#endif
e633acdc 347
348#endif
349
5f93bcbf 350/* Used for Ada bindings */
becb63f5 351int __gnat_size_of_file_attributes = sizeof (struct file_attributes);
5f93bcbf 352
353/* Reset the file attributes as if no system call had been performed */
354void __gnat_stat_to_attr (int fd, char* name, struct file_attributes* attr);
355
9dfe12ae 356/* The __gnat_max_path_len variable is used to export the maximum
357 length of a path name to Ada code. max_path_len is also provided
358 for compatibility with older GNAT versions, please do not use
359 it. */
360
361int __gnat_max_path_len = GNAT_MAX_PATH_LEN;
362int max_path_len = GNAT_MAX_PATH_LEN;
363
2726b813 364/* Control whether we can use ACL on Windows. */
365
366int __gnat_use_acl = 1;
367
1fac938e 368/* The following macro HAVE_READDIR_R should be defined if the
f15731c4 369 system provides the routine readdir_r. */
1fac938e 370#undef HAVE_READDIR_R
371\f
6d9c3443 372#if defined(VMS) && defined (__LONG_POINTERS)
373
374/* Return a 32 bit pointer to an array of 32 bit pointers
375 given a 64 bit pointer to an array of 64 bit pointers */
376
377typedef __char_ptr32 *__char_ptr_char_ptr32 __attribute__ ((mode (SI)));
378
379static __char_ptr_char_ptr32
380to_ptr32 (char **ptr64)
381{
382 int argc;
383 __char_ptr_char_ptr32 short_argv;
384
385 for (argc=0; ptr64[argc]; argc++);
386
387 /* Reallocate argv with 32 bit pointers. */
388 short_argv = (__char_ptr_char_ptr32) decc$malloc
389 (sizeof (__char_ptr32) * (argc + 1));
390
391 for (argc=0; ptr64[argc]; argc++)
392 short_argv[argc] = (__char_ptr32) decc$strdup (ptr64[argc]);
393
394 short_argv[argc] = (__char_ptr32) 0;
395 return short_argv;
396
397}
398#define MAYBE_TO_PTR32(argv) to_ptr32 (argv)
399#else
400#define MAYBE_TO_PTR32(argv) argv
401#endif
402
44fef051 403static const char ATTR_UNSET = 127;
bce992c9 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
1985 if ((pSD = (PSECURITY_DESCRIPTOR) HeapAlloc
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
2062 (&ea, username, AccessPermissions, 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
0b9eca83 2387 status = spawnvp (P_WAIT, args_0, (const 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 =
2543 xrealloc (HANDLES_LIST, sizeof (HANDLE) * plist_max_length);
2544 PID_LIST =
2545 xrealloc (PID_LIST, sizeof (int) * plist_max_length);
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
3b18b370 2934 wapath_val = 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
2944 apath_val = alloca (EXPAND_BUFFER_SIZE);
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{
3089 static char retbuf [NAM$C_MAXRSS+1];
3090 char *srcendpos, *pos1, *pos2, *retpos;
3091 int disp, path_present = 0;
3092
3093 if (!src) return NULL;
3094
3095 srcendpos = strchr (src, '\0');
3096 retpos = retbuf;
3097
3098 /* Look for the node and/or device in front of the path */
3099 pos1 = src;
3100 pos2 = strchr (pos1, ':');
3101
3102 if (pos2 && (pos2 < srcendpos) && (*(pos2 + 1) == ':')) {
3103 /* There is a node name. "node_name::" becomes "node_name!" */
3104 disp = pos2 - pos1;
3105 strncpy (retbuf, pos1, disp);
3106 retpos [disp] = '!';
3107 retpos = retpos + disp + 1;
3108 pos1 = pos2 + 2;
3109 pos2 = strchr (pos1, ':');
3110 }
3111
3112 if (pos2) {
3113 /* There is a device name. "dev_name:" becomes "/dev_name/" */
3114 *(retpos++) = '/';
3115 disp = pos2 - pos1;
3116 strncpy (retpos, pos1, disp);
3117 retpos = retpos + disp;
3118 pos1 = pos2 + 1;
3119 *(retpos++) = '/';
3120 }
3121 else
3122 /* No explicit device; we must look ahead and prepend /sys$disk/ if
3123 the path is absolute */
3124 if ((*pos1 == '[' || *pos1 == '<') && (pos1 < srcendpos)
3125 && !strchr (".-]>", *(pos1 + 1))) {
3126 strncpy (retpos, "/sys$disk/", 10);
3127 retpos += 10;
3128 }
3129
3130 /* Process the path part */
3131 while (*pos1 == '[' || *pos1 == '<') {
3132 path_present++;
3133 pos1++;
3134 if (*pos1 == ']' || *pos1 == '>') {
3135 /* Special case, [] translates to '.' */
3136 *(retpos++) = '.';
3137 pos1++;
3138 }
3139 else {
3140 /* '[000000' means root dir. It can be present in the middle of
3141 the path due to expansion of logical devices, in which case
3142 we skip it */
3143 if (!strncmp (pos1, "000000", 6) && path_present > 1 &&
3144 (*(pos1 + 6) == ']' || *(pos1 + 6) == '>' || *(pos1 + 6) == '.')) {
3145 pos1 += 6;
3146 if (*pos1 == '.') pos1++;
3147 }
3148 else if (*pos1 == '.') {
3149 /* Relative path */
3150 *(retpos++) = '.';
3151 }
3152
2359306a 3153 /* There is a qualified path */
3154 while (*pos1 && *pos1 != ']' && *pos1 != '>') {
b12d3a0b 3155 switch (*pos1) {
3156 case '.':
3157 /* '.' is used to separate directories. Replace it with '/' but
3158 only if there isn't already '/' just before */
3159 if (*(retpos - 1) != '/') *(retpos++) = '/';
3160 pos1++;
3161 if (pos1 + 1 < srcendpos && *pos1 == '.' && *(pos1 + 1) == '.') {
3162 /* ellipsis refers to entire subtree; replace with '**' */
3163 *(retpos++) = '*'; *(retpos++) = '*'; *(retpos++) = '/';
3164 pos1 += 2;
3165 }
3166 break;
3167 case '-' :
2359306a 3168 /* When after '.' '[' '<' is equivalent to Unix ".." but there
3169 may be several in a row */
3170 if (*(pos1 - 1) == '.' || *(pos1 - 1) == '[' ||
3171 *(pos1 - 1) == '<') {
3172 while (*pos1 == '-') {
3173 pos1++;
3174 *(retpos++) = '.'; *(retpos++) = '.'; *(retpos++) = '/';
3175 }
3176 retpos--;
3177 break;
b12d3a0b 3178 }
2359306a 3179 /* otherwise fall through to default */
b12d3a0b 3180 default:
3181 *(retpos++) = *(pos1++);
3182 }
3183 }
3184 pos1++;
3185 }
3186 }
3187
3188 if (pos1 < srcendpos) {
3189 /* Now add the actual file name, until the version suffix if any */
3190 if (path_present) *(retpos++) = '/';
3191 pos2 = strchr (pos1, ';');
3192 disp = pos2? (pos2 - pos1) : (srcendpos - pos1);
3193 strncpy (retpos, pos1, disp);
3194 retpos += disp;
3195 if (pos2 && pos2 < srcendpos) {
3196 /* There is a non-empty version suffix. ";<ver>" becomes ".<ver>" */
3197 *retpos++ = '.';
3198 disp = srcendpos - pos2 - 1;
3199 strncpy (retpos, pos2 + 1, disp);
3200 retpos += disp;
3201 }
3202 }
3203
3204 *retpos = '\0';
3205
3206 return retbuf;
3207
3208}
3209
f15731c4 3210/* Translate a VMS syntax directory specification in to Unix syntax. If
3211 PREFIXFLAG is set, append an underscore "/". If no indicators of VMS syntax
3212 found, return input string. Also translate a dirname that contains no
3213 slashes, in case it's a logical name. */
1fac938e 3214
3215char *
9dfe12ae 3216__gnat_to_canonical_dir_spec (char *dirspec, int prefixflag)
1fac938e 3217{
3218 int len;
3219
3220 strcpy (new_canonical_dirspec, "");
3221 if (strlen (dirspec))
3222 {
3223 char *dirspec1;
3224
3225 if (strchr (dirspec, ']') || strchr (dirspec, ':'))
69d33a1d 3226 {
3227 strncpy (new_canonical_dirspec,
3228 __gnat_translate_vms (dirspec),
3229 MAXPATH);
3230 }
1fac938e 3231 else if (!strchr (dirspec, '/') && (dirspec1 = getenv (dirspec)) != 0)
69d33a1d 3232 {
3233 strncpy (new_canonical_dirspec,
3234 __gnat_translate_vms (dirspec1),
3235 MAXPATH);
3236 }
1fac938e 3237 else
69d33a1d 3238 {
3239 strncpy (new_canonical_dirspec, dirspec, MAXPATH);
3240 }
1fac938e 3241 }
3242
3243 len = strlen (new_canonical_dirspec);
9dfe12ae 3244 if (prefixflag && new_canonical_dirspec [len-1] != '/')
3245 strncat (new_canonical_dirspec, "/", MAXPATH);
3246
3247 new_canonical_dirspec [MAXPATH - 1] = (char) 0;
1fac938e 3248
3249 return new_canonical_dirspec;
3250
3251}
3252
3253/* Translate a VMS syntax file specification into Unix syntax.
3cc2671a 3254 If no indicators of VMS syntax found, check if it's an uppercase
23c6b287 3255 alphanumeric_ name and if so try it out as an environment
3256 variable (logical name). If all else fails return the
3257 input string. */
1fac938e 3258
3259char *
9dfe12ae 3260__gnat_to_canonical_file_spec (char *filespec)
1fac938e 3261{
23c6b287 3262 char *filespec1;
3263
9dfe12ae 3264 strncpy (new_canonical_filespec, "", MAXPATH);
3265
1fac938e 3266 if (strchr (filespec, ']') || strchr (filespec, ':'))
9dfe12ae 3267 {
2359306a 3268 char *tspec = (char *) __gnat_translate_vms (filespec);
c69ba469 3269
3270 if (tspec != (char *) -1)
69d33a1d 3271 strncpy (new_canonical_filespec, tspec, MAXPATH);
23c6b287 3272 }
3273 else if ((strlen (filespec) == strspn (filespec,
69d33a1d 3274 "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_"))
3275 && (filespec1 = getenv (filespec)))
23c6b287 3276 {
2359306a 3277 char *tspec = (char *) __gnat_translate_vms (filespec1);
c69ba469 3278
3279 if (tspec != (char *) -1)
69d33a1d 3280 strncpy (new_canonical_filespec, tspec, MAXPATH);
9dfe12ae 3281 }
1fac938e 3282 else
9dfe12ae 3283 {
3284 strncpy (new_canonical_filespec, filespec, MAXPATH);
3285 }
3286
3287 new_canonical_filespec [MAXPATH - 1] = (char) 0;
1fac938e 3288
3289 return new_canonical_filespec;
3290}
3291
3292/* Translate a VMS syntax path specification into Unix syntax.
f15731c4 3293 If no indicators of VMS syntax found, return input string. */
1fac938e 3294
3295char *
9dfe12ae 3296__gnat_to_canonical_path_spec (char *pathspec)
1fac938e 3297{
9dfe12ae 3298 char *curr, *next, buff [MAXPATH];
1fac938e 3299
3300 if (pathspec == 0)
3301 return pathspec;
3302
f15731c4 3303 /* If there are /'s, assume it's a Unix path spec and return. */
1fac938e 3304 if (strchr (pathspec, '/'))
3305 return pathspec;
3306
f15731c4 3307 new_canonical_pathspec[0] = 0;
1fac938e 3308 curr = pathspec;
3309
3310 for (;;)
3311 {
3312 next = strchr (curr, ',');
3313 if (next == 0)
3314 next = strchr (curr, 0);
3315
3316 strncpy (buff, curr, next - curr);
f15731c4 3317 buff[next - curr] = 0;
1fac938e 3318
f15731c4 3319 /* Check for wildcards and expand if present. */
1fac938e 3320 if (strchr (buff, '*') || strchr (buff, '%') || strstr (buff, "..."))
3321 {
3322 int i, dirs;
3323
3324 dirs = __gnat_to_canonical_file_list_init (buff, 1);
3325 for (i = 0; i < dirs; i++)
3326 {
3327 char *next_dir;
3328
3329 next_dir = __gnat_to_canonical_file_list_next ();
9dfe12ae 3330 strncat (new_canonical_pathspec, next_dir, MAXPATH);
1fac938e 3331
f15731c4 3332 /* Don't append the separator after the last expansion. */
1fac938e 3333 if (i+1 < dirs)
9dfe12ae 3334 strncat (new_canonical_pathspec, ":", MAXPATH);
1fac938e 3335 }
3336
69d33a1d 3337 __gnat_to_canonical_file_list_free ();
1fac938e 3338 }
3339 else
69d33a1d 3340 strncat (new_canonical_pathspec,
3341 __gnat_to_canonical_dir_spec (buff, 0), MAXPATH);
1fac938e 3342
3343 if (*next == 0)
3344 break;
3345
9dfe12ae 3346 strncat (new_canonical_pathspec, ":", MAXPATH);
1fac938e 3347 curr = next + 1;
3348 }
3349
9dfe12ae 3350 new_canonical_pathspec [MAXPATH - 1] = (char) 0;
3351
1fac938e 3352 return new_canonical_pathspec;
3353}
3354
9dfe12ae 3355static char filename_buff [MAXPATH];
1fac938e 3356
3357static int
9dfe12ae 3358translate_unix (char *name, int type)
1fac938e 3359{
9dfe12ae 3360 strncpy (filename_buff, name, MAXPATH);
3361 filename_buff [MAXPATH - 1] = (char) 0;
1fac938e 3362 return 0;
3363}
3364
f15731c4 3365/* Translate a Unix syntax path spec into a VMS style (comma separated list of
3366 directories. */
1fac938e 3367
3368static char *
9dfe12ae 3369to_host_path_spec (char *pathspec)
1fac938e 3370{
9dfe12ae 3371 char *curr, *next, buff [MAXPATH];
1fac938e 3372
3373 if (pathspec == 0)
3374 return pathspec;
3375
f15731c4 3376 /* Can't very well test for colons, since that's the Unix separator! */
1fac938e 3377 if (strchr (pathspec, ']') || strchr (pathspec, ','))
3378 return pathspec;
3379
f15731c4 3380 new_host_pathspec[0] = 0;
1fac938e 3381 curr = pathspec;
3382
3383 for (;;)
3384 {
3385 next = strchr (curr, ':');
3386 if (next == 0)
3387 next = strchr (curr, 0);
3388
3389 strncpy (buff, curr, next - curr);
f15731c4 3390 buff[next - curr] = 0;
1fac938e 3391
9dfe12ae 3392 strncat (new_host_pathspec, __gnat_to_host_dir_spec (buff, 0), MAXPATH);
1fac938e 3393 if (*next == 0)
3394 break;
9dfe12ae 3395 strncat (new_host_pathspec, ",", MAXPATH);
1fac938e 3396 curr = next + 1;
3397 }
3398
9dfe12ae 3399 new_host_pathspec [MAXPATH - 1] = (char) 0;
3400
1fac938e 3401 return new_host_pathspec;
3402}
3403
f15731c4 3404/* Translate a Unix syntax directory specification into VMS syntax. The
3405 PREFIXFLAG has no effect, but is kept for symmetry with
3406 to_canonical_dir_spec. If indicators of VMS syntax found, return input
3407 string. */
1fac938e 3408
3409char *
9dfe12ae 3410__gnat_to_host_dir_spec (char *dirspec, int prefixflag ATTRIBUTE_UNUSED)
1fac938e 3411{
3412 int len = strlen (dirspec);
3413
9dfe12ae 3414 strncpy (new_host_dirspec, dirspec, MAXPATH);
3415 new_host_dirspec [MAXPATH - 1] = (char) 0;
1fac938e 3416
3417 if (strchr (new_host_dirspec, ']') || strchr (new_host_dirspec, ':'))
3418 return new_host_dirspec;
3419
f15731c4 3420 while (len > 1 && new_host_dirspec[len - 1] == '/')
1fac938e 3421 {
f15731c4 3422 new_host_dirspec[len - 1] = 0;
1fac938e 3423 len--;
3424 }
3425
3426 decc$to_vms (new_host_dirspec, translate_unix, 1, 2);
9dfe12ae 3427 strncpy (new_host_dirspec, filename_buff, MAXPATH);
3428 new_host_dirspec [MAXPATH - 1] = (char) 0;
1fac938e 3429
3430 return new_host_dirspec;
1fac938e 3431}
3432
3433/* Translate a Unix syntax file specification into VMS syntax.
f15731c4 3434 If indicators of VMS syntax found, return input string. */
1fac938e 3435
3436char *
9dfe12ae 3437__gnat_to_host_file_spec (char *filespec)
1fac938e 3438{
9dfe12ae 3439 strncpy (new_host_filespec, "", MAXPATH);
1fac938e 3440 if (strchr (filespec, ']') || strchr (filespec, ':'))
9dfe12ae 3441 {
3442 strncpy (new_host_filespec, filespec, MAXPATH);
3443 }
1fac938e 3444 else
3445 {
3446 decc$to_vms (filespec, translate_unix, 1, 1);
9dfe12ae 3447 strncpy (new_host_filespec, filename_buff, MAXPATH);
1fac938e 3448 }
3449
9dfe12ae 3450 new_host_filespec [MAXPATH - 1] = (char) 0;
3451
1fac938e 3452 return new_host_filespec;
3453}
3454
3455void
3456__gnat_adjust_os_resource_limits ()
3457{
3458 SYS$ADJWSL (131072, 0);
3459}
3460
9dfe12ae 3461#else /* VMS */
1fac938e 3462
f15731c4 3463/* Dummy functions for Osint import for non-VMS systems. */
1fac938e 3464
3465int
9dfe12ae 3466__gnat_to_canonical_file_list_init
3467 (char *dirspec ATTRIBUTE_UNUSED, int onlydirs ATTRIBUTE_UNUSED)
1fac938e 3468{
3469 return 0;
3470}
3471
3472char *
6f2c2693 3473__gnat_to_canonical_file_list_next (void)
1fac938e 3474{
6b88f2fe 3475 static char empty[] = "";
4c4697b8 3476 return empty;
1fac938e 3477}
3478
3479void
6f2c2693 3480__gnat_to_canonical_file_list_free (void)
1fac938e 3481{
3482}
3483
3484char *
9dfe12ae 3485__gnat_to_canonical_dir_spec (char *dirspec, int prefixflag ATTRIBUTE_UNUSED)
1fac938e 3486{
3487 return dirspec;
3488}
3489
3490char *
9dfe12ae 3491__gnat_to_canonical_file_spec (char *filespec)
1fac938e 3492{
3493 return filespec;
3494}
3495
3496char *
9dfe12ae 3497__gnat_to_canonical_path_spec (char *pathspec)
1fac938e 3498{
3499 return pathspec;
3500}
3501
3502char *
9dfe12ae 3503__gnat_to_host_dir_spec (char *dirspec, int prefixflag ATTRIBUTE_UNUSED)
1fac938e 3504{
3505 return dirspec;
3506}
3507
3508char *
9dfe12ae 3509__gnat_to_host_file_spec (char *filespec)
1fac938e 3510{
3511 return filespec;
3512}
3513
3514void
6f2c2693 3515__gnat_adjust_os_resource_limits (void)
1fac938e 3516{
3517}
3518
3519#endif
3520
1fac938e 3521#if defined (__mips_vxworks)
9dfe12ae 3522int
3523_flush_cache()
1fac938e 3524{
3525 CACHE_USER_FLUSH (0, ENTIRE_CACHE);
3526}
3527#endif
3528
8c7d3bad 3529#if defined (IS_CROSS) \
a3b0f4f2 3530 || (! ((defined (sparc) || defined (i386)) && defined (sun) \
3531 && defined (__SVR4)) \
c69ba469 3532 && ! (defined (linux) && (defined (i386) || defined (__x86_64__))) \
a3b0f4f2 3533 && ! (defined (linux) && defined (__ia64__)) \
547371fa 3534 && ! (defined (linux) && defined (powerpc)) \
40a4417a 3535 && ! defined (__FreeBSD__) \
571e421a 3536 && ! defined (__Lynx__) \
21a87c1d 3537 && ! defined (__hpux__) \
ba706ed3 3538 && ! defined (__APPLE__) \
9dfe12ae 3539 && ! defined (_AIX) \
3b18b370 3540 && ! defined (VMS) \
5641963c 3541 && ! defined (__MINGW32__))
f15731c4 3542
a3b0f4f2 3543/* Dummy function to satisfy g-trasym.o. See the preprocessor conditional
3544 just above for a list of native platforms that provide a non-dummy
3545 version of this procedure in libaddr2line.a. */
1fac938e 3546
3547void
1e622f0e 3548convert_addresses (const char *file_name ATTRIBUTE_UNUSED,
3549 void *addrs ATTRIBUTE_UNUSED,
9dfe12ae 3550 int n_addr ATTRIBUTE_UNUSED,
3551 void *buf ATTRIBUTE_UNUSED,
3552 int *len ATTRIBUTE_UNUSED)
1fac938e 3553{
3554 *len = 0;
3555}
3556#endif
f15731c4 3557
3558#if defined (_WIN32)
3559int __gnat_argument_needs_quote = 1;
3560#else
3561int __gnat_argument_needs_quote = 0;
3562#endif
9dfe12ae 3563
3564/* This option is used to enable/disable object files handling from the
3565 binder file by the GNAT Project module. For example, this is disabled on
e0f42093 3566 Windows (prior to GCC 3.4) as it is already done by the mdll module.
3567 Stating with GCC 3.4 the shared libraries are not based on mdll
3568 anymore as it uses the GCC's -shared option */
3569#if defined (_WIN32) \
3570 && ((__GNUC__ < 3) || ((__GNUC__ == 3) && (__GNUC_MINOR__ < 4)))
9dfe12ae 3571int __gnat_prj_add_obj_files = 0;
3572#else
3573int __gnat_prj_add_obj_files = 1;
3574#endif
3575
3576/* char used as prefix/suffix for environment variables */
3577#if defined (_WIN32)
3578char __gnat_environment_char = '%';
3579#else
3580char __gnat_environment_char = '$';
3581#endif
3582
3583/* This functions copy the file attributes from a source file to a
3584 destination file.
3585
3586 mode = 0 : In this mode copy only the file time stamps (last access and
3587 last modification time stamps).
3588
3589 mode = 1 : In this mode, time stamps and read/write/execute attributes are
3590 copied.
3591
3592 Returns 0 if operation was successful and -1 in case of error. */
3593
3594int
3595__gnat_copy_attribs (char *from, char *to, int mode)
3596{
b07bcda8 3597#if defined (VMS) || (defined (__vxworks) && _WRS_VXWORKS_MAJOR < 6) || \
3598 defined (__nucleus__)
9dfe12ae 3599 return -1;
6a85c251 3600
3601#elif defined (_WIN32) && !defined (RTX)
3602 TCHAR wfrom [GNAT_MAX_PATH_LEN + 2];
3603 TCHAR wto [GNAT_MAX_PATH_LEN + 2];
3604 BOOL res;
3605 FILETIME fct, flat, flwt;
3606 HANDLE hfrom, hto;
3607
3608 S2WSC (wfrom, from, GNAT_MAX_PATH_LEN + 2);
3609 S2WSC (wto, to, GNAT_MAX_PATH_LEN + 2);
3610
3611 /* retrieve from times */
3612
3613 hfrom = CreateFile
3614 (wfrom, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
3615
3616 if (hfrom == INVALID_HANDLE_VALUE)
3617 return -1;
3618
3619 res = GetFileTime (hfrom, &fct, &flat, &flwt);
3620
3621 CloseHandle (hfrom);
3622
3623 if (res == 0)
3624 return -1;
3625
3626 /* retrieve from times */
3627
3628 hto = CreateFile
3629 (wto, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
3630
3631 if (hto == INVALID_HANDLE_VALUE)
3632 return -1;
3633
3634 res = SetFileTime (hto, NULL, &flat, &flwt);
3635
3636 CloseHandle (hto);
3637
3638 if (res == 0)
3639 return -1;
3640
3641 /* Set file attributes in full mode. */
3642
3643 if (mode == 1)
3644 {
3645 DWORD attribs = GetFileAttributes (wfrom);
3646
3647 if (attribs == INVALID_FILE_ATTRIBUTES)
3648 return -1;
3649
3650 res = SetFileAttributes (wto, attribs);
3651 if (res == 0)
3652 return -1;
3653 }
3654
3655 return 0;
3656
9dfe12ae 3657#else
8cb516d7 3658 GNAT_STRUCT_STAT fbuf;
9dfe12ae 3659 struct utimbuf tbuf;
3660
8cb516d7 3661 if (GNAT_STAT (from, &fbuf) == -1)
9dfe12ae 3662 {
3663 return -1;
3664 }
3665
3666 tbuf.actime = fbuf.st_atime;
3667 tbuf.modtime = fbuf.st_mtime;
3668
3669 if (utime (to, &tbuf) == -1)
3670 {
3671 return -1;
3672 }
3673
3674 if (mode == 1)
3675 {
3676 if (chmod (to, fbuf.st_mode) == -1)
3677 {
3678 return -1;
3679 }
3680 }
3681
3682 return 0;
3683#endif
3684}
3685
cf6d853e 3686int
3687__gnat_lseek (int fd, long offset, int whence)
3688{
3689 return (int) lseek (fd, offset, whence);
3690}
0914a918 3691
e2c62f37 3692/* This function returns the major version number of GCC being used. */
0914a918 3693int
3694get_gcc_version (void)
3695{
e2c62f37 3696#ifdef IN_RTS
3697 return __GNUC__;
3698#else
3699 return (int) (version_string[0] - '0');
3700#endif
0914a918 3701}
6d9c3443 3702
3703int
de10c095 3704__gnat_set_close_on_exec (int fd ATTRIBUTE_UNUSED,
0e9e8338 3705 int close_on_exec_p ATTRIBUTE_UNUSED)
6d9c3443 3706{
3707#if defined (F_GETFD) && defined (FD_CLOEXEC) && ! defined (__vxworks)
3708 int flags = fcntl (fd, F_GETFD, 0);
3709 if (flags < 0)
3710 return flags;
3711 if (close_on_exec_p)
3712 flags |= FD_CLOEXEC;
3713 else
3714 flags &= ~FD_CLOEXEC;
3715 return fcntl (fd, F_SETFD, flags | FD_CLOEXEC);
07f34887 3716#elif defined(_WIN32)
3717 HANDLE h = (HANDLE) _get_osfhandle (fd);
3718 if (h == (HANDLE) -1)
3719 return -1;
3720 if (close_on_exec_p)
3721 return ! SetHandleInformation (h, HANDLE_FLAG_INHERIT, 0);
bcf0a1b1 3722 return ! SetHandleInformation (h, HANDLE_FLAG_INHERIT,
07f34887 3723 HANDLE_FLAG_INHERIT);
6d9c3443 3724#else
07f34887 3725 /* TODO: Unimplemented. */
6d9c3443 3726 return -1;
6d9c3443 3727#endif
3728}
fb31b465 3729
3730/* Indicates if platforms supports automatic initialization through the
3731 constructor mechanism */
3732int
c88e6a4f 3733__gnat_binder_supports_auto_init (void)
fb31b465 3734{
3735#ifdef VMS
3736 return 0;
3737#else
3738 return 1;
3739#endif
3740}
3741
3742/* Indicates that Stand-Alone Libraries are automatically initialized through
3743 the constructor mechanism */
3744int
c88e6a4f 3745__gnat_sals_init_using_constructors (void)
fb31b465 3746{
3747#if defined (__vxworks) || defined (__Lynx__) || defined (VMS)
3748 return 0;
3749#else
3750 return 1;
3751#endif
3752}
e2a33c18 3753
8e726ab4 3754#ifdef RTX
3755
e2a33c18 3756/* In RTX mode, the procedure to get the time (as file time) is different
3757 in RTSS mode and Win32 mode. In order to avoid duplicating an Ada file,
3758 we introduce an intermediate procedure to link against the corresponding
3759 one in each situation. */
8e726ab4 3760
3761extern void GetTimeAsFileTime(LPFILETIME pTime);
e2a33c18 3762
3763void GetTimeAsFileTime(LPFILETIME pTime)
3764{
3765#ifdef RTSS
3766 RtGetRtssTimeAsFileTime (pTime); /* RTSS interface */
3767#else
3768 GetSystemTimeAsFileTime (pTime); /* w32 interface */
3769#endif
3770}
8e726ab4 3771
3772#ifdef RTSS
3773/* Add symbol that is required to link. It would otherwise be taken from
3774 libgcc.a and it would try to use the gcc constructors that are not
3775 supported by Microsoft linker. */
3776
3777extern void __main (void);
3778
3779void __main (void) {}
3780#endif
e2a33c18 3781#endif
3782
a0d9619f 3783#if defined (linux)
3784/* There is no function in the glibc to retrieve the LWP of the current
3785 thread. We need to do a system call in order to retrieve this
3786 information. */
3787#include <sys/syscall.h>
12e8797f 3788void *__gnat_lwp_self (void)
3789{
a0d9619f 3790 return (void *) syscall (__NR_gettid);
3791}
40d4441d 3792
3793#include <sched.h>
3794
38846e90 3795/* glibc versions earlier than 2.7 do not define the routines to handle
3796 dynamically allocated CPU sets. For these targets, we use the static
3797 versions. */
3798
3799#ifdef CPU_ALLOC
3800
3801/* Dynamic cpu sets */
3802
91965b95 3803cpu_set_t *__gnat_cpu_alloc (size_t count)
40d4441d 3804{
91965b95 3805 return CPU_ALLOC (count);
40d4441d 3806}
3807
91965b95 3808size_t __gnat_cpu_alloc_size (size_t count)
3809{
3810 return CPU_ALLOC_SIZE (count);
3811}
3812
3813void __gnat_cpu_free (cpu_set_t *set)
3814{
3815 CPU_FREE (set);
3816}
3817
3818void __gnat_cpu_zero (size_t count, cpu_set_t *set)
3819{
3820 CPU_ZERO_S (count, set);
3821}
3822
3823void __gnat_cpu_set (int cpu, size_t count, cpu_set_t *set)
40d4441d 3824{
3825 /* Ada handles CPU numbers starting from 1, while C identifies the first
3826 CPU by a 0, so we need to adjust. */
91965b95 3827 CPU_SET_S (cpu - 1, count, set);
40d4441d 3828}
38846e90 3829
3830#else
3831
3832/* Static cpu sets */
3833
3834cpu_set_t *__gnat_cpu_alloc (size_t count ATTRIBUTE_UNUSED)
3835{
3836 return (cpu_set_t *) xmalloc (sizeof (cpu_set_t));
3837}
3838
3839size_t __gnat_cpu_alloc_size (size_t count ATTRIBUTE_UNUSED)
3840{
3841 return sizeof (cpu_set_t);
3842}
3843
3844void __gnat_cpu_free (cpu_set_t *set)
3845{
3846 free (set);
3847}
3848
3849void __gnat_cpu_zero (size_t count ATTRIBUTE_UNUSED, cpu_set_t *set)
3850{
3851 CPU_ZERO (set);
3852}
3853
3854void __gnat_cpu_set (int cpu, size_t count ATTRIBUTE_UNUSED, cpu_set_t *set)
3855{
3856 /* Ada handles CPU numbers starting from 1, while C identifies the first
3857 CPU by a 0, so we need to adjust. */
3858 CPU_SET (cpu - 1, set);
3859}
a0d9619f 3860#endif
63b63ca2 3861#endif
becb63f5 3862
3863#ifdef __cplusplus
3864}
3865#endif