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