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