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