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