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