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