]> git.ipfire.org Git - thirdparty/gcc.git/blame - gcc/ada/adaint.c
Remove obsolete Tru64 UNIX V5.1B 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
90bc406c 65#if (defined (__mips) && defined (__sgi)) || defined (__APPLE__)
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
2473#elif (defined (__mips) && defined (__sgi))
f7479d84 2474 cores = (int) sysconf (_SC_NPROC_ONLN);
90bc406c 2475
2476#elif defined (__hpux__)
f7479d84 2477 struct pst_dynamic psd;
2478 if (pstat_getdynamic (&psd, sizeof (psd), 1, 0) != -1)
2479 cores = (int) psd.psd_proc_cnt;
90bc406c 2480
ee0d6223 2481#elif defined (_WIN32)
2482 SYSTEM_INFO sysinfo;
2483 GetSystemInfo (&sysinfo);
2484 cores = (int) sysinfo.dwNumberOfProcessors;
9b1d6aeb 2485
2486#elif defined (VMS)
2487 int code = SYI$_ACTIVECPU_CNT;
2488 unsigned int res;
2489 int status;
2490
2491 status = LIB$GETSYI (&code, &res);
2492 if ((status & 1) != 0)
2493 cores = res;
0f4d3df5 2494
e423341f 2495#elif defined (_WRS_CONFIG_SMP)
0f4d3df5 2496 unsigned int vxCpuConfiguredGet (void);
2497
2498 cores = vxCpuConfiguredGet ();
2499
ed8e5b83 2500#endif
2501
2502 return cores;
2503}
2504
f15731c4 2505/* WIN32 code to implement a wait call that wait for any child process. */
2506
e2a33c18 2507#if defined (_WIN32) && !defined (RTX)
1fac938e 2508
2509/* Synchronization code, to be thread safe. */
2510
51fa65dc 2511#ifdef CERT
1fac938e 2512
51fa65dc 2513/* For the Cert run times on native Windows we use dummy functions
2514 for locking and unlocking tasks since we do not support multiple
2515 threads on this configuration (Cert run time on native Windows). */
1fac938e 2516
51fa65dc 2517void dummy (void) {}
1fac938e 2518
51fa65dc 2519void (*Lock_Task) () = &dummy;
2520void (*Unlock_Task) () = &dummy;
2521
2522#else
2523
2524#define Lock_Task system__soft_links__lock_task
2525extern void (*Lock_Task) (void);
2526
2527#define Unlock_Task system__soft_links__unlock_task
2528extern void (*Unlock_Task) (void);
2529
2530#endif
1fac938e 2531
4c4697b8 2532static HANDLE *HANDLES_LIST = NULL;
2533static int *PID_LIST = NULL, plist_length = 0, plist_max_length = 0;
1fac938e 2534
2535static void
14d22a3f 2536add_handle (HANDLE h, int pid)
1fac938e 2537{
1fac938e 2538
1fac938e 2539 /* -------------------- critical section -------------------- */
51fa65dc 2540 (*Lock_Task) ();
2541
4c4697b8 2542 if (plist_length == plist_max_length)
2543 {
2544 plist_max_length += 1000;
2545 HANDLES_LIST =
2546 xrealloc (HANDLES_LIST, sizeof (HANDLE) * plist_max_length);
2547 PID_LIST =
2548 xrealloc (PID_LIST, sizeof (int) * plist_max_length);
2549 }
2550
2551 HANDLES_LIST[plist_length] = h;
14d22a3f 2552 PID_LIST[plist_length] = pid;
1fac938e 2553 ++plist_length;
1fac938e 2554
51fa65dc 2555 (*Unlock_Task) ();
2556 /* -------------------- critical section -------------------- */
1fac938e 2557}
2558
4c4697b8 2559void
2560__gnat_win32_remove_handle (HANDLE h, int pid)
1fac938e 2561{
4c4697b8 2562 int j;
1fac938e 2563
1fac938e 2564 /* -------------------- critical section -------------------- */
51fa65dc 2565 (*Lock_Task) ();
2566
4c4697b8 2567 for (j = 0; j < plist_length; j++)
1fac938e 2568 {
4c4697b8 2569 if ((HANDLES_LIST[j] == h) || (PID_LIST[j] == pid))
1fac938e 2570 {
4c4697b8 2571 CloseHandle (h);
2572 --plist_length;
2573 HANDLES_LIST[j] = HANDLES_LIST[plist_length];
2574 PID_LIST[j] = PID_LIST[plist_length];
1fac938e 2575 break;
2576 }
1fac938e 2577 }
2578
51fa65dc 2579 (*Unlock_Task) ();
2580 /* -------------------- critical section -------------------- */
1fac938e 2581}
2582
14d22a3f 2583static void
2584win32_no_block_spawn (char *command, char *args[], HANDLE *h, int *pid)
1fac938e 2585{
2586 BOOL result;
2587 STARTUPINFO SI;
2588 PROCESS_INFORMATION PI;
2589 SECURITY_ATTRIBUTES SA;
f15731c4 2590 int csize = 1;
2591 char *full_command;
1fac938e 2592 int k;
2593
f15731c4 2594 /* compute the total command line length */
2595 k = 0;
2596 while (args[k])
2597 {
2598 csize += strlen (args[k]) + 1;
2599 k++;
2600 }
2601
2602 full_command = (char *) xmalloc (csize);
2603
1fac938e 2604 /* Startup info. */
2605 SI.cb = sizeof (STARTUPINFO);
2606 SI.lpReserved = NULL;
2607 SI.lpReserved2 = NULL;
2608 SI.lpDesktop = NULL;
2609 SI.cbReserved2 = 0;
2610 SI.lpTitle = NULL;
2611 SI.dwFlags = 0;
2612 SI.wShowWindow = SW_HIDE;
2613
2614 /* Security attributes. */
2615 SA.nLength = sizeof (SECURITY_ATTRIBUTES);
2616 SA.bInheritHandle = TRUE;
2617 SA.lpSecurityDescriptor = NULL;
2618
2619 /* Prepare the command string. */
2620 strcpy (full_command, command);
2621 strcat (full_command, " ");
2622
2623 k = 1;
2624 while (args[k])
2625 {
2626 strcat (full_command, args[k]);
2627 strcat (full_command, " ");
2628 k++;
2629 }
2630
3b18b370 2631 {
2632 int wsize = csize * 2;
2633 TCHAR *wcommand = (TCHAR *) xmalloc (wsize);
2634
f60cc57d 2635 S2WSC (wcommand, full_command, wsize);
3b18b370 2636
2637 free (full_command);
1fac938e 2638
3b18b370 2639 result = CreateProcess
2640 (NULL, wcommand, &SA, NULL, TRUE,
2641 GetPriorityClass (GetCurrentProcess()), NULL, NULL, &SI, &PI);
2642
2643 free (wcommand);
2644 }
f15731c4 2645
1fac938e 2646 if (result == TRUE)
2647 {
1fac938e 2648 CloseHandle (PI.hThread);
14d22a3f 2649 *h = PI.hProcess;
2650 *pid = PI.dwProcessId;
1fac938e 2651 }
2652 else
14d22a3f 2653 {
2654 *h = NULL;
2655 *pid = 0;
2656 }
1fac938e 2657}
2658
2659static int
9dfe12ae 2660win32_wait (int *status)
1fac938e 2661{
4c4697b8 2662 DWORD exitcode, pid;
1fac938e 2663 HANDLE *hl;
2664 HANDLE h;
2665 DWORD res;
2666 int k;
e41b023d 2667 int hl_len;
1fac938e 2668
2669 if (plist_length == 0)
2670 {
2671 errno = ECHILD;
2672 return -1;
2673 }
2674
1fac938e 2675 k = 0;
51fa65dc 2676
2677 /* -------------------- critical section -------------------- */
2678 (*Lock_Task) ();
1fac938e 2679
e41b023d 2680 hl_len = plist_length;
2681
e41b023d 2682 hl = (HANDLE *) xmalloc (sizeof (HANDLE) * hl_len);
2683
4c4697b8 2684 memmove (hl, HANDLES_LIST, sizeof (HANDLE) * hl_len);
1fac938e 2685
51fa65dc 2686 (*Unlock_Task) ();
2687 /* -------------------- critical section -------------------- */
1fac938e 2688
e41b023d 2689 res = WaitForMultipleObjects (hl_len, hl, FALSE, INFINITE);
f15731c4 2690 h = hl[res - WAIT_OBJECT_0];
1fac938e 2691
2692 GetExitCodeProcess (h, &exitcode);
14d22a3f 2693 pid = PID_LIST [res - WAIT_OBJECT_0];
4c4697b8 2694 __gnat_win32_remove_handle (h, -1);
2695
2696 free (hl);
1fac938e 2697
2698 *status = (int) exitcode;
4c4697b8 2699 return (int) pid;
1fac938e 2700}
2701
2702#endif
2703
2704int
9dfe12ae 2705__gnat_portable_no_block_spawn (char *args[])
1fac938e 2706{
1fac938e 2707
e2a33c18 2708#if defined (__vxworks) || defined (__nucleus__) || defined (RTX)
2709 return -1;
2710
1fac938e 2711#elif defined (_WIN32)
2712
4c4697b8 2713 HANDLE h = NULL;
14d22a3f 2714 int pid;
4c4697b8 2715
14d22a3f 2716 win32_no_block_spawn (args[0], args, &h, &pid);
4c4697b8 2717 if (h != NULL)
5d56d161 2718 {
14d22a3f 2719 add_handle (h, pid);
2720 return pid;
5d56d161 2721 }
2722 else
2723 return -1;
1fac938e 2724
1fac938e 2725#else
4c4697b8 2726
2727 int pid = fork ();
1fac938e 2728
f15731c4 2729 if (pid == 0)
2730 {
2731 /* The child. */
6d9c3443 2732 if (execv (args[0], MAYBE_TO_PTR32 (args)) != 0)
f15731c4 2733#if defined (VMS)
69d33a1d 2734 return -1; /* execv is in parent context on VMS. */
9dfe12ae 2735#else
69d33a1d 2736 _exit (1);
f15731c4 2737#endif
2738 }
2739
1fac938e 2740 return pid;
4c4697b8 2741
2742 #endif
1fac938e 2743}
2744
2745int
9dfe12ae 2746__gnat_portable_wait (int *process_status)
1fac938e 2747{
2748 int status = 0;
2749 int pid = 0;
2750
e2a33c18 2751#if defined (__vxworks) || defined (__nucleus__) || defined (RTX)
30592778 2752 /* Not sure what to do here, so do nothing but return zero. */
e2a33c18 2753
2754#elif defined (_WIN32)
1fac938e 2755
2756 pid = win32_wait (&status);
2757
1fac938e 2758#else
2759
1fac938e 2760 pid = waitpid (-1, &status, 0);
1fac938e 2761 status = status & 0xffff;
2762#endif
2763
2764 *process_status = status;
2765 return pid;
2766}
2767
2768void
9dfe12ae 2769__gnat_os_exit (int status)
1fac938e 2770{
1fac938e 2771 exit (status);
1fac938e 2772}
2773
b860aaec 2774/* Locate file on path, that matches a predicate */
1fac938e 2775
2776char *
b860aaec 2777__gnat_locate_file_with_predicate
2778 (char *file_name, char *path_val, int (*predicate)(char*))
1fac938e 2779{
2780 char *ptr;
5703e222 2781 char *file_path = (char *) alloca (strlen (file_name) + 1);
c69ba469 2782 int absolute;
2783
b51bcb1c 2784 /* Return immediately if file_name is empty */
2785
2786 if (*file_name == '\0')
2787 return 0;
2788
c69ba469 2789 /* Remove quotes around file_name if present */
2790
2791 ptr = file_name;
2792 if (*ptr == '"')
2793 ptr++;
2794
2795 strcpy (file_path, ptr);
2796
2797 ptr = file_path + strlen (file_path) - 1;
2798
2799 if (*ptr == '"')
2800 *ptr = '\0';
1fac938e 2801
f15731c4 2802 /* Handle absolute pathnames. */
c69ba469 2803
2804 absolute = __gnat_is_absolute_path (file_path, strlen (file_name));
2805
9dfe12ae 2806 if (absolute)
2807 {
b860aaec 2808 if (predicate (file_path))
c69ba469 2809 return xstrdup (file_path);
9dfe12ae 2810
2811 return 0;
2812 }
2813
2814 /* If file_name include directory separator(s), try it first as
2815 a path name relative to the current directory */
1fac938e 2816 for (ptr = file_name; *ptr && *ptr != '/' && *ptr != DIR_SEPARATOR; ptr++)
2817 ;
2818
9dfe12ae 2819 if (*ptr != 0)
1fac938e 2820 {
b860aaec 2821 if (predicate (file_name))
1fac938e 2822 return xstrdup (file_name);
1fac938e 2823 }
2824
2825 if (path_val == 0)
2826 return 0;
2827
2828 {
2829 /* The result has to be smaller than path_val + file_name. */
d9c927cc 2830 char *file_path =
2831 (char *) alloca (strlen (path_val) + strlen (file_name) + 2);
1fac938e 2832
2833 for (;;)
2834 {
c69ba469 2835 /* Skip the starting quote */
2836
2837 if (*path_val == '"')
69d33a1d 2838 path_val++;
c69ba469 2839
1fac938e 2840 for (ptr = file_path; *path_val && *path_val != PATH_SEPARATOR; )
69d33a1d 2841 *ptr++ = *path_val++;
1fac938e 2842
5c182b3b 2843 /* If directory is empty, it is the current directory*/
2844
2845 if (ptr == file_path)
2846 {
2847 *ptr = '.';
2848 }
2849 else
2850 ptr--;
c69ba469 2851
2852 /* Skip the ending quote */
2853
2854 if (*ptr == '"')
69d33a1d 2855 ptr--;
c69ba469 2856
1fac938e 2857 if (*ptr != '/' && *ptr != DIR_SEPARATOR)
2858 *++ptr = DIR_SEPARATOR;
2859
2860 strcpy (++ptr, file_name);
2861
b860aaec 2862 if (predicate (file_path))
1fac938e 2863 return xstrdup (file_path);
5c182b3b 2864
2865 if (*path_val == 0)
2866 return 0;
2867
2868 /* Skip path separator */
2869
2870 path_val++;
1fac938e 2871 }
2872 }
2873
2874 return 0;
2875}
2876
b860aaec 2877/* Locate an executable file, give a Path value. */
2878
2879char *
2880__gnat_locate_executable_file (char *file_name, char *path_val)
2881{
2882 return __gnat_locate_file_with_predicate
2883 (file_name, path_val, &__gnat_is_executable_file);
2884}
2885
2886/* Locate a regular file, give a Path value. */
2887
2888char *
2889__gnat_locate_regular_file (char *file_name, char *path_val)
2890{
2891 return __gnat_locate_file_with_predicate
2892 (file_name, path_val, &__gnat_is_regular_file);
2893}
2894
1fac938e 2895/* Locate an executable given a Path argument. This routine is only used by
2896 gnatbl and should not be used otherwise. Use locate_exec_on_path
f15731c4 2897 instead. */
1fac938e 2898
2899char *
9dfe12ae 2900__gnat_locate_exec (char *exec_name, char *path_val)
1fac938e 2901{
fb31b465 2902 char *ptr;
1fac938e 2903 if (!strstr (exec_name, HOST_EXECUTABLE_SUFFIX))
2904 {
d9c927cc 2905 char *full_exec_name =
2906 (char *) alloca
2907 (strlen (exec_name) + strlen (HOST_EXECUTABLE_SUFFIX) + 1);
1fac938e 2908
2909 strcpy (full_exec_name, exec_name);
2910 strcat (full_exec_name, HOST_EXECUTABLE_SUFFIX);
b860aaec 2911 ptr = __gnat_locate_executable_file (full_exec_name, path_val);
fb31b465 2912
2913 if (ptr == 0)
b860aaec 2914 return __gnat_locate_executable_file (exec_name, path_val);
fb31b465 2915 return ptr;
1fac938e 2916 }
2917 else
b860aaec 2918 return __gnat_locate_executable_file (exec_name, path_val);
1fac938e 2919}
2920
f15731c4 2921/* Locate an executable using the Systems default PATH. */
1fac938e 2922
2923char *
9dfe12ae 2924__gnat_locate_exec_on_path (char *exec_name)
1fac938e 2925{
9dfe12ae 2926 char *apath_val;
3b18b370 2927
e2a33c18 2928#if defined (_WIN32) && !defined (RTX)
3b18b370 2929 TCHAR *wpath_val = _tgetenv (_T("PATH"));
2930 TCHAR *wapath_val;
9dfe12ae 2931 /* In Win32 systems we expand the PATH as for XP environment
c69ba469 2932 variables are not automatically expanded. We also prepend the
2933 ".;" to the path to match normal NT path search semantics */
9dfe12ae 2934
c69ba469 2935 #define EXPAND_BUFFER_SIZE 32767
9dfe12ae 2936
3b18b370 2937 wapath_val = alloca (EXPAND_BUFFER_SIZE);
c69ba469 2938
3b18b370 2939 wapath_val [0] = '.';
2940 wapath_val [1] = ';';
1fac938e 2941
c69ba469 2942 DWORD res = ExpandEnvironmentStrings
3b18b370 2943 (wpath_val, &wapath_val[2], EXPAND_BUFFER_SIZE - 2);
2944
2945 if (!res) wapath_val [0] = _T('\0');
2946
2947 apath_val = alloca (EXPAND_BUFFER_SIZE);
2948
f60cc57d 2949 WS2SC (apath_val, wapath_val, EXPAND_BUFFER_SIZE);
3b18b370 2950 return __gnat_locate_exec (exec_name, apath_val);
c69ba469 2951
c69ba469 2952#else
3b18b370 2953
2954#ifdef VMS
2955 char *path_val = "/VAXC$PATH";
2956#else
2957 char *path_val = getenv ("PATH");
2958#endif
e2c62f37 2959 if (path_val == NULL) return NULL;
5703e222 2960 apath_val = (char *) alloca (strlen (path_val) + 1);
1fac938e 2961 strcpy (apath_val, path_val);
2962 return __gnat_locate_exec (exec_name, apath_val);
3b18b370 2963#endif
1fac938e 2964}
2965
2966#ifdef VMS
2967
2968/* These functions are used to translate to and from VMS and Unix syntax
f15731c4 2969 file, directory and path specifications. */
1fac938e 2970
9dfe12ae 2971#define MAXPATH 256
1fac938e 2972#define MAXNAMES 256
2973#define NEW_CANONICAL_FILELIST_INCREMENT 64
2974
9dfe12ae 2975static char new_canonical_dirspec [MAXPATH];
2976static char new_canonical_filespec [MAXPATH];
2977static char new_canonical_pathspec [MAXNAMES*MAXPATH];
1fac938e 2978static unsigned new_canonical_filelist_index;
2979static unsigned new_canonical_filelist_in_use;
2980static unsigned new_canonical_filelist_allocated;
2981static char **new_canonical_filelist;
9dfe12ae 2982static char new_host_pathspec [MAXNAMES*MAXPATH];
2983static char new_host_dirspec [MAXPATH];
2984static char new_host_filespec [MAXPATH];
1fac938e 2985
2986/* Routine is called repeatedly by decc$from_vms via
9dfe12ae 2987 __gnat_to_canonical_file_list_init until it returns 0 or the expansion
2988 runs out. */
1fac938e 2989
2990static int
9dfe12ae 2991wildcard_translate_unix (char *name)
1fac938e 2992{
2993 char *ver;
9dfe12ae 2994 char buff [MAXPATH];
1fac938e 2995
9dfe12ae 2996 strncpy (buff, name, MAXPATH);
2997 buff [MAXPATH - 1] = (char) 0;
1fac938e 2998 ver = strrchr (buff, '.');
2999
f15731c4 3000 /* Chop off the version. */
1fac938e 3001 if (ver)
3002 *ver = 0;
3003
f15731c4 3004 /* Dynamically extend the allocation by the increment. */
1fac938e 3005 if (new_canonical_filelist_in_use == new_canonical_filelist_allocated)
3006 {
3007 new_canonical_filelist_allocated += NEW_CANONICAL_FILELIST_INCREMENT;
f15731c4 3008 new_canonical_filelist = (char **) xrealloc
69d33a1d 3009 (new_canonical_filelist,
3010 new_canonical_filelist_allocated * sizeof (char *));
1fac938e 3011 }
3012
3013 new_canonical_filelist[new_canonical_filelist_in_use++] = xstrdup (buff);
3014
3015 return 1;
3016}
3017
f15731c4 3018/* Translate a wildcard VMS file spec into a list of Unix file specs. First do
3019 full translation and copy the results into a list (_init), then return them
3020 one at a time (_next). If onlydirs set, only expand directory files. */
1fac938e 3021
3022int
9dfe12ae 3023__gnat_to_canonical_file_list_init (char *filespec, int onlydirs)
1fac938e 3024{
3025 int len;
9dfe12ae 3026 char buff [MAXPATH];
1fac938e 3027
3028 len = strlen (filespec);
9dfe12ae 3029 strncpy (buff, filespec, MAXPATH);
3030
3031 /* Only look for directories */
3032 if (onlydirs && !strstr (&buff [len-5], "*.dir"))
3033 strncat (buff, "*.dir", MAXPATH);
1fac938e 3034
9dfe12ae 3035 buff [MAXPATH - 1] = (char) 0;
1fac938e 3036
3037 decc$from_vms (buff, wildcard_translate_unix, 1);
3038
f15731c4 3039 /* Remove the .dir extension. */
1fac938e 3040 if (onlydirs)
3041 {
3042 int i;
3043 char *ext;
3044
3045 for (i = 0; i < new_canonical_filelist_in_use; i++)
69d33a1d 3046 {
3047 ext = strstr (new_canonical_filelist[i], ".dir");
3048 if (ext)
3049 *ext = 0;
3050 }
1fac938e 3051 }
3052
3053 return new_canonical_filelist_in_use;
3054}
3055
f15731c4 3056/* Return the next filespec in the list. */
1fac938e 3057
3058char *
3059__gnat_to_canonical_file_list_next ()
3060{
f15731c4 3061 return new_canonical_filelist[new_canonical_filelist_index++];
1fac938e 3062}
3063
f15731c4 3064/* Free storage used in the wildcard expansion. */
1fac938e 3065
3066void
3067__gnat_to_canonical_file_list_free ()
3068{
3069 int i;
3070
3071 for (i = 0; i < new_canonical_filelist_in_use; i++)
f15731c4 3072 free (new_canonical_filelist[i]);
1fac938e 3073
3074 free (new_canonical_filelist);
3075
3076 new_canonical_filelist_in_use = 0;
3077 new_canonical_filelist_allocated = 0;
3078 new_canonical_filelist_index = 0;
3079 new_canonical_filelist = 0;
3080}
3081
b12d3a0b 3082/* The functional equivalent of decc$translate_vms routine.
3083 Designed to produce the same output, but is protected against
3084 malformed paths (original version ACCVIOs in this case) and
3085 does not require VMS-specific DECC RTL */
3086
3087#define NAM$C_MAXRSS 1024
3088
3089char *
3090__gnat_translate_vms (char *src)
3091{
3092 static char retbuf [NAM$C_MAXRSS+1];
3093 char *srcendpos, *pos1, *pos2, *retpos;
3094 int disp, path_present = 0;
3095
3096 if (!src) return NULL;
3097
3098 srcendpos = strchr (src, '\0');
3099 retpos = retbuf;
3100
3101 /* Look for the node and/or device in front of the path */
3102 pos1 = src;
3103 pos2 = strchr (pos1, ':');
3104
3105 if (pos2 && (pos2 < srcendpos) && (*(pos2 + 1) == ':')) {
3106 /* There is a node name. "node_name::" becomes "node_name!" */
3107 disp = pos2 - pos1;
3108 strncpy (retbuf, pos1, disp);
3109 retpos [disp] = '!';
3110 retpos = retpos + disp + 1;
3111 pos1 = pos2 + 2;
3112 pos2 = strchr (pos1, ':');
3113 }
3114
3115 if (pos2) {
3116 /* There is a device name. "dev_name:" becomes "/dev_name/" */
3117 *(retpos++) = '/';
3118 disp = pos2 - pos1;
3119 strncpy (retpos, pos1, disp);
3120 retpos = retpos + disp;
3121 pos1 = pos2 + 1;
3122 *(retpos++) = '/';
3123 }
3124 else
3125 /* No explicit device; we must look ahead and prepend /sys$disk/ if
3126 the path is absolute */
3127 if ((*pos1 == '[' || *pos1 == '<') && (pos1 < srcendpos)
3128 && !strchr (".-]>", *(pos1 + 1))) {
3129 strncpy (retpos, "/sys$disk/", 10);
3130 retpos += 10;
3131 }
3132
3133 /* Process the path part */
3134 while (*pos1 == '[' || *pos1 == '<') {
3135 path_present++;
3136 pos1++;
3137 if (*pos1 == ']' || *pos1 == '>') {
3138 /* Special case, [] translates to '.' */
3139 *(retpos++) = '.';
3140 pos1++;
3141 }
3142 else {
3143 /* '[000000' means root dir. It can be present in the middle of
3144 the path due to expansion of logical devices, in which case
3145 we skip it */
3146 if (!strncmp (pos1, "000000", 6) && path_present > 1 &&
3147 (*(pos1 + 6) == ']' || *(pos1 + 6) == '>' || *(pos1 + 6) == '.')) {
3148 pos1 += 6;
3149 if (*pos1 == '.') pos1++;
3150 }
3151 else if (*pos1 == '.') {
3152 /* Relative path */
3153 *(retpos++) = '.';
3154 }
3155
2359306a 3156 /* There is a qualified path */
3157 while (*pos1 && *pos1 != ']' && *pos1 != '>') {
b12d3a0b 3158 switch (*pos1) {
3159 case '.':
3160 /* '.' is used to separate directories. Replace it with '/' but
3161 only if there isn't already '/' just before */
3162 if (*(retpos - 1) != '/') *(retpos++) = '/';
3163 pos1++;
3164 if (pos1 + 1 < srcendpos && *pos1 == '.' && *(pos1 + 1) == '.') {
3165 /* ellipsis refers to entire subtree; replace with '**' */
3166 *(retpos++) = '*'; *(retpos++) = '*'; *(retpos++) = '/';
3167 pos1 += 2;
3168 }
3169 break;
3170 case '-' :
2359306a 3171 /* When after '.' '[' '<' is equivalent to Unix ".." but there
3172 may be several in a row */
3173 if (*(pos1 - 1) == '.' || *(pos1 - 1) == '[' ||
3174 *(pos1 - 1) == '<') {
3175 while (*pos1 == '-') {
3176 pos1++;
3177 *(retpos++) = '.'; *(retpos++) = '.'; *(retpos++) = '/';
3178 }
3179 retpos--;
3180 break;
b12d3a0b 3181 }
2359306a 3182 /* otherwise fall through to default */
b12d3a0b 3183 default:
3184 *(retpos++) = *(pos1++);
3185 }
3186 }
3187 pos1++;
3188 }
3189 }
3190
3191 if (pos1 < srcendpos) {
3192 /* Now add the actual file name, until the version suffix if any */
3193 if (path_present) *(retpos++) = '/';
3194 pos2 = strchr (pos1, ';');
3195 disp = pos2? (pos2 - pos1) : (srcendpos - pos1);
3196 strncpy (retpos, pos1, disp);
3197 retpos += disp;
3198 if (pos2 && pos2 < srcendpos) {
3199 /* There is a non-empty version suffix. ";<ver>" becomes ".<ver>" */
3200 *retpos++ = '.';
3201 disp = srcendpos - pos2 - 1;
3202 strncpy (retpos, pos2 + 1, disp);
3203 retpos += disp;
3204 }
3205 }
3206
3207 *retpos = '\0';
3208
3209 return retbuf;
3210
3211}
3212
f15731c4 3213/* Translate a VMS syntax directory specification in to Unix syntax. If
3214 PREFIXFLAG is set, append an underscore "/". If no indicators of VMS syntax
3215 found, return input string. Also translate a dirname that contains no
3216 slashes, in case it's a logical name. */
1fac938e 3217
3218char *
9dfe12ae 3219__gnat_to_canonical_dir_spec (char *dirspec, int prefixflag)
1fac938e 3220{
3221 int len;
3222
3223 strcpy (new_canonical_dirspec, "");
3224 if (strlen (dirspec))
3225 {
3226 char *dirspec1;
3227
3228 if (strchr (dirspec, ']') || strchr (dirspec, ':'))
69d33a1d 3229 {
3230 strncpy (new_canonical_dirspec,
3231 __gnat_translate_vms (dirspec),
3232 MAXPATH);
3233 }
1fac938e 3234 else if (!strchr (dirspec, '/') && (dirspec1 = getenv (dirspec)) != 0)
69d33a1d 3235 {
3236 strncpy (new_canonical_dirspec,
3237 __gnat_translate_vms (dirspec1),
3238 MAXPATH);
3239 }
1fac938e 3240 else
69d33a1d 3241 {
3242 strncpy (new_canonical_dirspec, dirspec, MAXPATH);
3243 }
1fac938e 3244 }
3245
3246 len = strlen (new_canonical_dirspec);
9dfe12ae 3247 if (prefixflag && new_canonical_dirspec [len-1] != '/')
3248 strncat (new_canonical_dirspec, "/", MAXPATH);
3249
3250 new_canonical_dirspec [MAXPATH - 1] = (char) 0;
1fac938e 3251
3252 return new_canonical_dirspec;
3253
3254}
3255
3256/* Translate a VMS syntax file specification into Unix syntax.
3cc2671a 3257 If no indicators of VMS syntax found, check if it's an uppercase
23c6b287 3258 alphanumeric_ name and if so try it out as an environment
3259 variable (logical name). If all else fails return the
3260 input string. */
1fac938e 3261
3262char *
9dfe12ae 3263__gnat_to_canonical_file_spec (char *filespec)
1fac938e 3264{
23c6b287 3265 char *filespec1;
3266
9dfe12ae 3267 strncpy (new_canonical_filespec, "", MAXPATH);
3268
1fac938e 3269 if (strchr (filespec, ']') || strchr (filespec, ':'))
9dfe12ae 3270 {
2359306a 3271 char *tspec = (char *) __gnat_translate_vms (filespec);
c69ba469 3272
3273 if (tspec != (char *) -1)
69d33a1d 3274 strncpy (new_canonical_filespec, tspec, MAXPATH);
23c6b287 3275 }
3276 else if ((strlen (filespec) == strspn (filespec,
69d33a1d 3277 "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_"))
3278 && (filespec1 = getenv (filespec)))
23c6b287 3279 {
2359306a 3280 char *tspec = (char *) __gnat_translate_vms (filespec1);
c69ba469 3281
3282 if (tspec != (char *) -1)
69d33a1d 3283 strncpy (new_canonical_filespec, tspec, MAXPATH);
9dfe12ae 3284 }
1fac938e 3285 else
9dfe12ae 3286 {
3287 strncpy (new_canonical_filespec, filespec, MAXPATH);
3288 }
3289
3290 new_canonical_filespec [MAXPATH - 1] = (char) 0;
1fac938e 3291
3292 return new_canonical_filespec;
3293}
3294
3295/* Translate a VMS syntax path specification into Unix syntax.
f15731c4 3296 If no indicators of VMS syntax found, return input string. */
1fac938e 3297
3298char *
9dfe12ae 3299__gnat_to_canonical_path_spec (char *pathspec)
1fac938e 3300{
9dfe12ae 3301 char *curr, *next, buff [MAXPATH];
1fac938e 3302
3303 if (pathspec == 0)
3304 return pathspec;
3305
f15731c4 3306 /* If there are /'s, assume it's a Unix path spec and return. */
1fac938e 3307 if (strchr (pathspec, '/'))
3308 return pathspec;
3309
f15731c4 3310 new_canonical_pathspec[0] = 0;
1fac938e 3311 curr = pathspec;
3312
3313 for (;;)
3314 {
3315 next = strchr (curr, ',');
3316 if (next == 0)
3317 next = strchr (curr, 0);
3318
3319 strncpy (buff, curr, next - curr);
f15731c4 3320 buff[next - curr] = 0;
1fac938e 3321
f15731c4 3322 /* Check for wildcards and expand if present. */
1fac938e 3323 if (strchr (buff, '*') || strchr (buff, '%') || strstr (buff, "..."))
3324 {
3325 int i, dirs;
3326
3327 dirs = __gnat_to_canonical_file_list_init (buff, 1);
3328 for (i = 0; i < dirs; i++)
3329 {
3330 char *next_dir;
3331
3332 next_dir = __gnat_to_canonical_file_list_next ();
9dfe12ae 3333 strncat (new_canonical_pathspec, next_dir, MAXPATH);
1fac938e 3334
f15731c4 3335 /* Don't append the separator after the last expansion. */
1fac938e 3336 if (i+1 < dirs)
9dfe12ae 3337 strncat (new_canonical_pathspec, ":", MAXPATH);
1fac938e 3338 }
3339
69d33a1d 3340 __gnat_to_canonical_file_list_free ();
1fac938e 3341 }
3342 else
69d33a1d 3343 strncat (new_canonical_pathspec,
3344 __gnat_to_canonical_dir_spec (buff, 0), MAXPATH);
1fac938e 3345
3346 if (*next == 0)
3347 break;
3348
9dfe12ae 3349 strncat (new_canonical_pathspec, ":", MAXPATH);
1fac938e 3350 curr = next + 1;
3351 }
3352
9dfe12ae 3353 new_canonical_pathspec [MAXPATH - 1] = (char) 0;
3354
1fac938e 3355 return new_canonical_pathspec;
3356}
3357
9dfe12ae 3358static char filename_buff [MAXPATH];
1fac938e 3359
3360static int
9dfe12ae 3361translate_unix (char *name, int type)
1fac938e 3362{
9dfe12ae 3363 strncpy (filename_buff, name, MAXPATH);
3364 filename_buff [MAXPATH - 1] = (char) 0;
1fac938e 3365 return 0;
3366}
3367
f15731c4 3368/* Translate a Unix syntax path spec into a VMS style (comma separated list of
3369 directories. */
1fac938e 3370
3371static char *
9dfe12ae 3372to_host_path_spec (char *pathspec)
1fac938e 3373{
9dfe12ae 3374 char *curr, *next, buff [MAXPATH];
1fac938e 3375
3376 if (pathspec == 0)
3377 return pathspec;
3378
f15731c4 3379 /* Can't very well test for colons, since that's the Unix separator! */
1fac938e 3380 if (strchr (pathspec, ']') || strchr (pathspec, ','))
3381 return pathspec;
3382
f15731c4 3383 new_host_pathspec[0] = 0;
1fac938e 3384 curr = pathspec;
3385
3386 for (;;)
3387 {
3388 next = strchr (curr, ':');
3389 if (next == 0)
3390 next = strchr (curr, 0);
3391
3392 strncpy (buff, curr, next - curr);
f15731c4 3393 buff[next - curr] = 0;
1fac938e 3394
9dfe12ae 3395 strncat (new_host_pathspec, __gnat_to_host_dir_spec (buff, 0), MAXPATH);
1fac938e 3396 if (*next == 0)
3397 break;
9dfe12ae 3398 strncat (new_host_pathspec, ",", MAXPATH);
1fac938e 3399 curr = next + 1;
3400 }
3401
9dfe12ae 3402 new_host_pathspec [MAXPATH - 1] = (char) 0;
3403
1fac938e 3404 return new_host_pathspec;
3405}
3406
f15731c4 3407/* Translate a Unix syntax directory specification into VMS syntax. The
3408 PREFIXFLAG has no effect, but is kept for symmetry with
3409 to_canonical_dir_spec. If indicators of VMS syntax found, return input
3410 string. */
1fac938e 3411
3412char *
9dfe12ae 3413__gnat_to_host_dir_spec (char *dirspec, int prefixflag ATTRIBUTE_UNUSED)
1fac938e 3414{
3415 int len = strlen (dirspec);
3416
9dfe12ae 3417 strncpy (new_host_dirspec, dirspec, MAXPATH);
3418 new_host_dirspec [MAXPATH - 1] = (char) 0;
1fac938e 3419
3420 if (strchr (new_host_dirspec, ']') || strchr (new_host_dirspec, ':'))
3421 return new_host_dirspec;
3422
f15731c4 3423 while (len > 1 && new_host_dirspec[len - 1] == '/')
1fac938e 3424 {
f15731c4 3425 new_host_dirspec[len - 1] = 0;
1fac938e 3426 len--;
3427 }
3428
3429 decc$to_vms (new_host_dirspec, translate_unix, 1, 2);
9dfe12ae 3430 strncpy (new_host_dirspec, filename_buff, MAXPATH);
3431 new_host_dirspec [MAXPATH - 1] = (char) 0;
1fac938e 3432
3433 return new_host_dirspec;
1fac938e 3434}
3435
3436/* Translate a Unix syntax file specification into VMS syntax.
f15731c4 3437 If indicators of VMS syntax found, return input string. */
1fac938e 3438
3439char *
9dfe12ae 3440__gnat_to_host_file_spec (char *filespec)
1fac938e 3441{
9dfe12ae 3442 strncpy (new_host_filespec, "", MAXPATH);
1fac938e 3443 if (strchr (filespec, ']') || strchr (filespec, ':'))
9dfe12ae 3444 {
3445 strncpy (new_host_filespec, filespec, MAXPATH);
3446 }
1fac938e 3447 else
3448 {
3449 decc$to_vms (filespec, translate_unix, 1, 1);
9dfe12ae 3450 strncpy (new_host_filespec, filename_buff, MAXPATH);
1fac938e 3451 }
3452
9dfe12ae 3453 new_host_filespec [MAXPATH - 1] = (char) 0;
3454
1fac938e 3455 return new_host_filespec;
3456}
3457
3458void
3459__gnat_adjust_os_resource_limits ()
3460{
3461 SYS$ADJWSL (131072, 0);
3462}
3463
9dfe12ae 3464#else /* VMS */
1fac938e 3465
f15731c4 3466/* Dummy functions for Osint import for non-VMS systems. */
1fac938e 3467
3468int
9dfe12ae 3469__gnat_to_canonical_file_list_init
3470 (char *dirspec ATTRIBUTE_UNUSED, int onlydirs ATTRIBUTE_UNUSED)
1fac938e 3471{
3472 return 0;
3473}
3474
3475char *
6f2c2693 3476__gnat_to_canonical_file_list_next (void)
1fac938e 3477{
6b88f2fe 3478 static char empty[] = "";
4c4697b8 3479 return empty;
1fac938e 3480}
3481
3482void
6f2c2693 3483__gnat_to_canonical_file_list_free (void)
1fac938e 3484{
3485}
3486
3487char *
9dfe12ae 3488__gnat_to_canonical_dir_spec (char *dirspec, int prefixflag ATTRIBUTE_UNUSED)
1fac938e 3489{
3490 return dirspec;
3491}
3492
3493char *
9dfe12ae 3494__gnat_to_canonical_file_spec (char *filespec)
1fac938e 3495{
3496 return filespec;
3497}
3498
3499char *
9dfe12ae 3500__gnat_to_canonical_path_spec (char *pathspec)
1fac938e 3501{
3502 return pathspec;
3503}
3504
3505char *
9dfe12ae 3506__gnat_to_host_dir_spec (char *dirspec, int prefixflag ATTRIBUTE_UNUSED)
1fac938e 3507{
3508 return dirspec;
3509}
3510
3511char *
9dfe12ae 3512__gnat_to_host_file_spec (char *filespec)
1fac938e 3513{
3514 return filespec;
3515}
3516
3517void
6f2c2693 3518__gnat_adjust_os_resource_limits (void)
1fac938e 3519{
3520}
3521
3522#endif
3523
1fac938e 3524#if defined (__mips_vxworks)
9dfe12ae 3525int
3526_flush_cache()
1fac938e 3527{
3528 CACHE_USER_FLUSH (0, ENTIRE_CACHE);
3529}
3530#endif
3531
8c7d3bad 3532#if defined (IS_CROSS) \
a3b0f4f2 3533 || (! ((defined (sparc) || defined (i386)) && defined (sun) \
3534 && defined (__SVR4)) \
c69ba469 3535 && ! (defined (linux) && (defined (i386) || defined (__x86_64__))) \
a3b0f4f2 3536 && ! (defined (linux) && defined (__ia64__)) \
547371fa 3537 && ! (defined (linux) && defined (powerpc)) \
40a4417a 3538 && ! defined (__FreeBSD__) \
571e421a 3539 && ! defined (__Lynx__) \
21a87c1d 3540 && ! defined (__hpux__) \
ba706ed3 3541 && ! defined (__APPLE__) \
9dfe12ae 3542 && ! defined (_AIX) \
3b18b370 3543 && ! defined (VMS) \
80d4fec4 3544 && ! defined (__MINGW32__) \
3545 && ! (defined (__mips) && defined (__sgi)))
f15731c4 3546
a3b0f4f2 3547/* Dummy function to satisfy g-trasym.o. See the preprocessor conditional
3548 just above for a list of native platforms that provide a non-dummy
3549 version of this procedure in libaddr2line.a. */
1fac938e 3550
3551void
1e622f0e 3552convert_addresses (const char *file_name ATTRIBUTE_UNUSED,
3553 void *addrs ATTRIBUTE_UNUSED,
9dfe12ae 3554 int n_addr ATTRIBUTE_UNUSED,
3555 void *buf ATTRIBUTE_UNUSED,
3556 int *len ATTRIBUTE_UNUSED)
1fac938e 3557{
3558 *len = 0;
3559}
3560#endif
f15731c4 3561
3562#if defined (_WIN32)
3563int __gnat_argument_needs_quote = 1;
3564#else
3565int __gnat_argument_needs_quote = 0;
3566#endif
9dfe12ae 3567
3568/* This option is used to enable/disable object files handling from the
3569 binder file by the GNAT Project module. For example, this is disabled on
e0f42093 3570 Windows (prior to GCC 3.4) as it is already done by the mdll module.
3571 Stating with GCC 3.4 the shared libraries are not based on mdll
3572 anymore as it uses the GCC's -shared option */
3573#if defined (_WIN32) \
3574 && ((__GNUC__ < 3) || ((__GNUC__ == 3) && (__GNUC_MINOR__ < 4)))
9dfe12ae 3575int __gnat_prj_add_obj_files = 0;
3576#else
3577int __gnat_prj_add_obj_files = 1;
3578#endif
3579
3580/* char used as prefix/suffix for environment variables */
3581#if defined (_WIN32)
3582char __gnat_environment_char = '%';
3583#else
3584char __gnat_environment_char = '$';
3585#endif
3586
3587/* This functions copy the file attributes from a source file to a
3588 destination file.
3589
3590 mode = 0 : In this mode copy only the file time stamps (last access and
3591 last modification time stamps).
3592
3593 mode = 1 : In this mode, time stamps and read/write/execute attributes are
3594 copied.
3595
3596 Returns 0 if operation was successful and -1 in case of error. */
3597
3598int
3599__gnat_copy_attribs (char *from, char *to, int mode)
3600{
b07bcda8 3601#if defined (VMS) || (defined (__vxworks) && _WRS_VXWORKS_MAJOR < 6) || \
3602 defined (__nucleus__)
9dfe12ae 3603 return -1;
6a85c251 3604
3605#elif defined (_WIN32) && !defined (RTX)
3606 TCHAR wfrom [GNAT_MAX_PATH_LEN + 2];
3607 TCHAR wto [GNAT_MAX_PATH_LEN + 2];
3608 BOOL res;
3609 FILETIME fct, flat, flwt;
3610 HANDLE hfrom, hto;
3611
3612 S2WSC (wfrom, from, GNAT_MAX_PATH_LEN + 2);
3613 S2WSC (wto, to, GNAT_MAX_PATH_LEN + 2);
3614
3615 /* retrieve from times */
3616
3617 hfrom = CreateFile
3618 (wfrom, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
3619
3620 if (hfrom == INVALID_HANDLE_VALUE)
3621 return -1;
3622
3623 res = GetFileTime (hfrom, &fct, &flat, &flwt);
3624
3625 CloseHandle (hfrom);
3626
3627 if (res == 0)
3628 return -1;
3629
3630 /* retrieve from times */
3631
3632 hto = CreateFile
3633 (wto, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
3634
3635 if (hto == INVALID_HANDLE_VALUE)
3636 return -1;
3637
3638 res = SetFileTime (hto, NULL, &flat, &flwt);
3639
3640 CloseHandle (hto);
3641
3642 if (res == 0)
3643 return -1;
3644
3645 /* Set file attributes in full mode. */
3646
3647 if (mode == 1)
3648 {
3649 DWORD attribs = GetFileAttributes (wfrom);
3650
3651 if (attribs == INVALID_FILE_ATTRIBUTES)
3652 return -1;
3653
3654 res = SetFileAttributes (wto, attribs);
3655 if (res == 0)
3656 return -1;
3657 }
3658
3659 return 0;
3660
9dfe12ae 3661#else
8cb516d7 3662 GNAT_STRUCT_STAT fbuf;
9dfe12ae 3663 struct utimbuf tbuf;
3664
8cb516d7 3665 if (GNAT_STAT (from, &fbuf) == -1)
9dfe12ae 3666 {
3667 return -1;
3668 }
3669
3670 tbuf.actime = fbuf.st_atime;
3671 tbuf.modtime = fbuf.st_mtime;
3672
3673 if (utime (to, &tbuf) == -1)
3674 {
3675 return -1;
3676 }
3677
3678 if (mode == 1)
3679 {
3680 if (chmod (to, fbuf.st_mode) == -1)
3681 {
3682 return -1;
3683 }
3684 }
3685
3686 return 0;
3687#endif
3688}
3689
cf6d853e 3690int
3691__gnat_lseek (int fd, long offset, int whence)
3692{
3693 return (int) lseek (fd, offset, whence);
3694}
0914a918 3695
e2c62f37 3696/* This function returns the major version number of GCC being used. */
0914a918 3697int
3698get_gcc_version (void)
3699{
e2c62f37 3700#ifdef IN_RTS
3701 return __GNUC__;
3702#else
3703 return (int) (version_string[0] - '0');
3704#endif
0914a918 3705}
6d9c3443 3706
3707int
de10c095 3708__gnat_set_close_on_exec (int fd ATTRIBUTE_UNUSED,
0e9e8338 3709 int close_on_exec_p ATTRIBUTE_UNUSED)
6d9c3443 3710{
3711#if defined (F_GETFD) && defined (FD_CLOEXEC) && ! defined (__vxworks)
3712 int flags = fcntl (fd, F_GETFD, 0);
3713 if (flags < 0)
3714 return flags;
3715 if (close_on_exec_p)
3716 flags |= FD_CLOEXEC;
3717 else
3718 flags &= ~FD_CLOEXEC;
3719 return fcntl (fd, F_SETFD, flags | FD_CLOEXEC);
07f34887 3720#elif defined(_WIN32)
3721 HANDLE h = (HANDLE) _get_osfhandle (fd);
3722 if (h == (HANDLE) -1)
3723 return -1;
3724 if (close_on_exec_p)
3725 return ! SetHandleInformation (h, HANDLE_FLAG_INHERIT, 0);
bcf0a1b1 3726 return ! SetHandleInformation (h, HANDLE_FLAG_INHERIT,
07f34887 3727 HANDLE_FLAG_INHERIT);
6d9c3443 3728#else
07f34887 3729 /* TODO: Unimplemented. */
6d9c3443 3730 return -1;
6d9c3443 3731#endif
3732}
fb31b465 3733
3734/* Indicates if platforms supports automatic initialization through the
3735 constructor mechanism */
3736int
c88e6a4f 3737__gnat_binder_supports_auto_init (void)
fb31b465 3738{
3739#ifdef VMS
3740 return 0;
3741#else
3742 return 1;
3743#endif
3744}
3745
3746/* Indicates that Stand-Alone Libraries are automatically initialized through
3747 the constructor mechanism */
3748int
c88e6a4f 3749__gnat_sals_init_using_constructors (void)
fb31b465 3750{
3751#if defined (__vxworks) || defined (__Lynx__) || defined (VMS)
3752 return 0;
3753#else
3754 return 1;
3755#endif
3756}
e2a33c18 3757
8e726ab4 3758#ifdef RTX
3759
e2a33c18 3760/* In RTX mode, the procedure to get the time (as file time) is different
3761 in RTSS mode and Win32 mode. In order to avoid duplicating an Ada file,
3762 we introduce an intermediate procedure to link against the corresponding
3763 one in each situation. */
8e726ab4 3764
3765extern void GetTimeAsFileTime(LPFILETIME pTime);
e2a33c18 3766
3767void GetTimeAsFileTime(LPFILETIME pTime)
3768{
3769#ifdef RTSS
3770 RtGetRtssTimeAsFileTime (pTime); /* RTSS interface */
3771#else
3772 GetSystemTimeAsFileTime (pTime); /* w32 interface */
3773#endif
3774}
8e726ab4 3775
3776#ifdef RTSS
3777/* Add symbol that is required to link. It would otherwise be taken from
3778 libgcc.a and it would try to use the gcc constructors that are not
3779 supported by Microsoft linker. */
3780
3781extern void __main (void);
3782
3783void __main (void) {}
3784#endif
e2a33c18 3785#endif
3786
a0d9619f 3787#if defined (linux)
3788/* There is no function in the glibc to retrieve the LWP of the current
3789 thread. We need to do a system call in order to retrieve this
3790 information. */
3791#include <sys/syscall.h>
12e8797f 3792void *__gnat_lwp_self (void)
3793{
a0d9619f 3794 return (void *) syscall (__NR_gettid);
3795}
40d4441d 3796
3797#include <sched.h>
3798
38846e90 3799/* glibc versions earlier than 2.7 do not define the routines to handle
3800 dynamically allocated CPU sets. For these targets, we use the static
3801 versions. */
3802
3803#ifdef CPU_ALLOC
3804
3805/* Dynamic cpu sets */
3806
91965b95 3807cpu_set_t *__gnat_cpu_alloc (size_t count)
40d4441d 3808{
91965b95 3809 return CPU_ALLOC (count);
40d4441d 3810}
3811
91965b95 3812size_t __gnat_cpu_alloc_size (size_t count)
3813{
3814 return CPU_ALLOC_SIZE (count);
3815}
3816
3817void __gnat_cpu_free (cpu_set_t *set)
3818{
3819 CPU_FREE (set);
3820}
3821
3822void __gnat_cpu_zero (size_t count, cpu_set_t *set)
3823{
3824 CPU_ZERO_S (count, set);
3825}
3826
3827void __gnat_cpu_set (int cpu, size_t count, cpu_set_t *set)
40d4441d 3828{
3829 /* Ada handles CPU numbers starting from 1, while C identifies the first
3830 CPU by a 0, so we need to adjust. */
91965b95 3831 CPU_SET_S (cpu - 1, count, set);
40d4441d 3832}
38846e90 3833
3834#else
3835
3836/* Static cpu sets */
3837
3838cpu_set_t *__gnat_cpu_alloc (size_t count ATTRIBUTE_UNUSED)
3839{
3840 return (cpu_set_t *) xmalloc (sizeof (cpu_set_t));
3841}
3842
3843size_t __gnat_cpu_alloc_size (size_t count ATTRIBUTE_UNUSED)
3844{
3845 return sizeof (cpu_set_t);
3846}
3847
3848void __gnat_cpu_free (cpu_set_t *set)
3849{
3850 free (set);
3851}
3852
3853void __gnat_cpu_zero (size_t count ATTRIBUTE_UNUSED, cpu_set_t *set)
3854{
3855 CPU_ZERO (set);
3856}
3857
3858void __gnat_cpu_set (int cpu, size_t count ATTRIBUTE_UNUSED, cpu_set_t *set)
3859{
3860 /* Ada handles CPU numbers starting from 1, while C identifies the first
3861 CPU by a 0, so we need to adjust. */
3862 CPU_SET (cpu - 1, set);
3863}
a0d9619f 3864#endif
63b63ca2 3865#endif
becb63f5 3866
3867#ifdef __cplusplus
3868}
3869#endif