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