[multiple changes]
[gcc.git] / gcc / ada / adaint.c
1 /****************************************************************************
2 * *
3 * GNAT COMPILER COMPONENTS *
4 * *
5 * A D A I N T *
6 * *
7 * C Implementation File *
8 * *
9 * Copyright (C) 1992-2004, Free Software Foundation, Inc. *
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. *
29 * Extensive contributions were provided by Ada Core Technologies Inc. *
30 * *
31 ****************************************************************************/
32
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. */
37
38 #ifdef __vxworks
39
40 /* No need to redefine exit here. */
41 #undef exit
42
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
53 #ifdef VMS
54 #define _POSIX_EXIT 1
55 #endif
56
57 #ifdef IN_RTS
58 #include "tconfig.h"
59 #include "tsystem.h"
60
61 #include <sys/stat.h>
62 #include <fcntl.h>
63 #include <time.h>
64 #ifdef VMS
65 #include <unixio.h>
66 #endif
67
68 /* We don't have libiberty, so use malloc. */
69 #define xmalloc(S) malloc (S)
70 #define xrealloc(V,S) realloc (V,S)
71 #else
72 #include "config.h"
73 #include "system.h"
74 #endif
75
76 #ifdef __MINGW32__
77 #include "mingw32.h"
78 #include <sys/utime.h>
79 #include <ctype.h>
80 #else
81 #ifndef VMS
82 #include <utime.h>
83 #endif
84 #endif
85
86 #ifdef __MINGW32__
87 #if OLD_MINGW
88 #include <sys/wait.h>
89 #endif
90 #else
91 #include <sys/wait.h>
92 #endif
93
94 #if defined (__EMX__) || defined (MSDOS) || defined (_WIN32)
95 #elif defined (VMS)
96
97 /* Header files and definitions for __gnat_set_file_time_name. */
98
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
109 /* Use native 64-bit arithmetic. */
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 ... */
117 struct dsc$descriptor_fib
118 {
119 unsigned long fib$l_len;
120 struct fibdef *fib$l_addr;
121 };
122
123 /* I/O Status Block. */
124 struct IOSB
125 {
126 unsigned short status, count;
127 unsigned long devdep;
128 };
129
130 static char *tryfile;
131
132 /* Variable length string. */
133 struct vstring
134 {
135 short length;
136 char string[NAM$C_MAXRSS+1];
137 };
138
139 #else
140 #include <utime.h>
141 #endif
142
143 #if defined (__EMX__) || defined (MSDOS) || defined (_WIN32)
144 #include <process.h>
145 #endif
146
147 #if defined (_WIN32)
148 #include <dir.h>
149 #include <windows.h>
150 #undef DIR_SEPARATOR
151 #define DIR_SEPARATOR '\\'
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
194 char __gnat_dir_separator = DIR_SEPARATOR;
195
196 char __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
220 as well. This is only a temporary work-around for 3.11b. */
221
222 #ifndef GNAT_LIBRARY_TEMPLATE
223 #if defined (__EMX__)
224 #define GNAT_LIBRARY_TEMPLATE "*.a"
225 #elif defined (VMS)
226 #define GNAT_LIBRARY_TEMPLATE "*.olb"
227 #else
228 #define GNAT_LIBRARY_TEMPLATE "lib*.a"
229 #endif
230 #endif
231
232 const char *__gnat_library_template = GNAT_LIBRARY_TEMPLATE;
233
234 /* This variable is used in hostparm.ads to say whether the host is a VMS
235 system. */
236 #ifdef VMS
237 const int __gnat_vmsp = 1;
238 #else
239 const int __gnat_vmsp = 0;
240 #endif
241
242 #ifdef __EMX__
243 #define GNAT_MAX_PATH_LEN MAX_PATH
244
245 #elif defined (VMS)
246 #define GNAT_MAX_PATH_LEN 256 /* PATH_MAX */
247
248 #elif defined (__vxworks) || defined (__OPENNT)
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
259
260 #else
261 #include <sys/param.h>
262 #endif
263
264 #define GNAT_MAX_PATH_LEN MAXPATHLEN
265
266 #endif
267
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
273 int __gnat_max_path_len = GNAT_MAX_PATH_LEN;
274 int max_path_len = GNAT_MAX_PATH_LEN;
275
276 /* The following macro HAVE_READDIR_R should be defined if the
277 system provides the routine readdir_r. */
278 #undef HAVE_READDIR_R
279 \f
280 void
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)
289 {
290 struct tm *res;
291 time_t time = (time_t) *p_time;
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
300 #ifdef VMS
301 res = localtime (&time);
302 #else
303 res = gmtime (&time);
304 #endif
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;
314 }
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
324 int
325 __gnat_readlink (char *path ATTRIBUTE_UNUSED,
326 char *buf ATTRIBUTE_UNUSED,
327 size_t bufsiz ATTRIBUTE_UNUSED)
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
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. */
343
344 int
345 __gnat_symlink (char *oldpath ATTRIBUTE_UNUSED,
346 char *newpath ATTRIBUTE_UNUSED)
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
359 /* Try to lock a file, return 1 if success. */
360
361 #if defined (__vxworks) || defined (MSDOS) || defined (_WIN32)
362
363 /* Version that does not use link. */
364
365 int
366 __gnat_try_lock (char *dir, char *file)
367 {
368 char full_path[256];
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);
373 if (fd < 0)
374 return 0;
375
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
385 int
386 __gnat_try_lock (char *dir, char *file)
387 {
388 char full_path[256];
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
401
402 /* Version using link(), more secure over NFS. */
403 /* See TN 6913-016 for discussion ??? */
404
405 int
406 __gnat_try_lock (char *dir, char *file)
407 {
408 char full_path[256];
409 char temp_file[256];
410 struct stat stat_result;
411 int fd;
412
413 sprintf (full_path, "%s%c%s", dir, DIR_SEPARATOR, file);
414 sprintf (temp_file, "%s%cTMP-%ld-%ld",
415 dir, DIR_SEPARATOR, (long)getpid(), (long)getppid ());
416
417 /* Create the temporary file and write the process number. */
418 fd = open (temp_file, O_CREAT | O_WRONLY, 0600);
419 if (fd < 0)
420 return 0;
421
422 close (fd);
423
424 /* Link it with the new file. */
425 link (temp_file, full_path);
426
427 /* Count the references on the old one. If we have a count of two, then
428 the link did succeed. Remove the temporary file before returning. */
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
437 int
438 __gnat_get_maximum_file_name_length (void)
439 {
440 #if defined (MSDOS)
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
452 /* Return nonzero if file names are case sensitive. */
453
454 int
455 __gnat_get_file_names_case_sensitive (void)
456 {
457 #if defined (__EMX__) || defined (MSDOS) || defined (VMS) || defined (WINNT)
458 return 0;
459 #else
460 return 1;
461 #endif
462 }
463
464 char
465 __gnat_get_default_identifier_character_set (void)
466 {
467 #if defined (__EMX__) || defined (MSDOS)
468 return 'p';
469 #else
470 return '1';
471 #endif
472 }
473
474 /* Return the current working directory. */
475
476 void
477 __gnat_get_current_dir (char *dir, int *length)
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
488 if (dir [*length - 1] != DIR_SEPARATOR)
489 {
490 dir [*length] = DIR_SEPARATOR;
491 ++(*length);
492 }
493 dir[*length] = '\0';
494 }
495
496 /* Return the suffix for object files. */
497
498 void
499 __gnat_get_object_suffix_ptr (int *len, const char **value)
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
511 /* Return the suffix for executable files. */
512
513 void
514 __gnat_get_executable_suffix_ptr (int *len, const char **value)
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
526 executable extension. */
527
528 void
529 __gnat_get_debuggable_suffix_ptr (int *len, const char **value)
530 {
531 #ifndef MSDOS
532 *value = HOST_EXECUTABLE_SUFFIX;
533 #else
534 /* On DOS, the extensionless COFF file is what gdb likes. */
535 *value = "";
536 #endif
537
538 if (*value == 0)
539 *len = 0;
540 else
541 *len = strlen (*value);
542
543 return;
544 }
545
546 int
547 __gnat_open_read (char *path, int fmode)
548 {
549 int fd;
550 int o_fmode = O_BINARY;
551
552 if (fmode)
553 o_fmode = O_TEXT;
554
555 #if defined (VMS)
556 /* Optional arguments mbc,deq,fop increase read performance. */
557 fd = open (path, O_RDONLY | o_fmode, 0444,
558 "mbc=16", "deq=64", "fop=tef");
559 #elif defined (__vxworks)
560 fd = open (path, O_RDONLY | o_fmode, 0444);
561 #else
562 fd = open (path, O_RDONLY | o_fmode);
563 #endif
564
565 return fd < 0 ? -1 : fd;
566 }
567
568 #if defined (__EMX__) || defined (__MINGW32__)
569 #define PERM (S_IREAD | S_IWRITE)
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
579 #else
580 #define PERM (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH)
581 #endif
582
583 int
584 __gnat_open_rw (char *path, int fmode)
585 {
586 int fd;
587 int o_fmode = O_BINARY;
588
589 if (fmode)
590 o_fmode = O_TEXT;
591
592 #if defined (VMS)
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
602 int
603 __gnat_open_create (char *path, int fmode)
604 {
605 int fd;
606 int o_fmode = O_BINARY;
607
608 if (fmode)
609 o_fmode = O_TEXT;
610
611 #if defined (VMS)
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;
619 }
620
621 int
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;
634 }
635
636 int
637 __gnat_open_append (char *path, int fmode)
638 {
639 int fd;
640 int o_fmode = O_BINARY;
641
642 if (fmode)
643 o_fmode = O_TEXT;
644
645 #if defined (VMS)
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
655 /* Open a new file. Return error (-1) if the file already exists. */
656
657 int
658 __gnat_open_new (char *path, int fmode)
659 {
660 int fd;
661 int o_fmode = O_BINARY;
662
663 if (fmode)
664 o_fmode = O_TEXT;
665
666 #if defined (VMS)
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.
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. */
679
680 int
681 __gnat_open_new_temp (char *path, int fmode)
682 {
683 int fd;
684 int o_fmode = O_BINARY;
685
686 strcpy (path, "GNAT-XXXXXX");
687
688 #if (defined (__FreeBSD__) || defined (linux)) && !defined (__vxworks)
689 return mkstemp (path);
690 #elif defined (__Lynx__)
691 mktemp (path);
692 #else
693 if (mktemp (path) == NULL)
694 return -1;
695 #endif
696
697 if (fmode)
698 o_fmode = O_TEXT;
699
700 #if defined (VMS)
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
711 /* Return the number of bytes in the specified file. */
712
713 long
714 __gnat_file_length (int fd)
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
726 /* Return the number of bytes in the specified named file. */
727
728 long
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
741 /* Create a temporary filename and put it in string pointed to by
742 TMP_FILENAME. */
743
744 void
745 __gnat_tmp_name (char *tmp_filename)
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
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
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. */
766
767 else if (pname[0] == '\\')
768 {
769 strcpy (tmp_filename, ".\\");
770 strcat (tmp_filename, pname+1);
771 }
772 else
773 strcpy (tmp_filename, pname);
774
775 free (pname);
776 }
777
778 #elif defined (linux) || defined (__FreeBSD__)
779 #define MAX_SAFE_PATH 1000
780 char *tmpdir = getenv ("TMPDIR");
781
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)
785 strcpy (tmp_filename, "/tmp/gnat-XXXXXX");
786 else
787 sprintf (tmp_filename, "%s/gnat-XXXXXX", tmpdir);
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
798 char *
799 __gnat_readdir (DIR *dirp, char *buffer)
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
809 struct dirent *dirent = readdir (dirp);
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
824 int
825 __gnat_readdir_is_thread_safe (void)
826 {
827 #ifdef HAVE_READDIR_R
828 return 1;
829 #else
830 return 0;
831 #endif
832 }
833
834 #ifdef _WIN32
835 /* Number of seconds between <Jan 1st 1601> and <Jan 1st 1970>. */
836 static const unsigned long long w32_epoch_offset = 11644473600ULL;
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
843 static time_t
844 win32_filetime (HANDLE h)
845 {
846 union
847 {
848 FILETIME ft_time;
849 unsigned long long ull_time;
850 } t_write;
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
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;
860 }
861 #endif
862
863 /* Return a GNAT time stamp given a file name. */
864
865 OS_Time
866 __gnat_file_time_name (char *name)
867 {
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);
873 return (OS_Time)ret;
874
875 #elif defined (_WIN32)
876 time_t ret = 0;
877 HANDLE h = CreateFile (name, GENERIC_READ, FILE_SHARE_READ, 0,
878 OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0);
879
880 if (h != INVALID_HANDLE_VALUE)
881 {
882 ret = win32_filetime (h);
883 CloseHandle (h);
884 }
885 return (OS_Time) ret;
886 #else
887 struct stat statbuf;
888 if (__gnat_stat (name, &statbuf) != 0) {
889 return (OS_Time)-1;
890 } else {
891 #ifdef VMS
892 /* VMS has file versioning. */
893 return (OS_Time)statbuf.st_ctime;
894 #else
895 return (OS_Time)statbuf.st_mtime;
896 #endif
897 }
898 #endif
899 }
900
901 /* Return a GNAT time stamp given a file descriptor. */
902
903 OS_Time
904 __gnat_file_time_fd (int fd)
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
910 facilitate the distribution of GNAT compiled libraries. */
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
942 four year period since then. */
943
944 time_t tot_secs;
945 int cum_days[12] = {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334};
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
959 days_passed += cum_days[file_month - 1];
960 if (years_since_leap == 0 && file_year != 20 && file_month > 2)
961 days_passed++;
962
963 days_passed += file_day - 1;
964
965 /* OK - have whole days. Multiply -- then add in other parts. */
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;
971 return (OS_Time) tot_secs;
972
973 #elif defined (_WIN32)
974 HANDLE h = (HANDLE) _get_osfhandle (fd);
975 time_t ret = win32_filetime (h);
976 return (OS_Time) ret;
977
978 #else
979 struct stat statbuf;
980
981 if (fstat (fd, &statbuf) != 0) {
982 return (OS_Time) -1;
983 } else {
984 #ifdef VMS
985 /* VMS has file versioning. */
986 return (OS_Time) statbuf.st_ctime;
987 #else
988 return (OS_Time) statbuf.st_mtime;
989 #endif
990 }
991 #endif
992 }
993
994 /* Set the file time stamp. */
995
996 void
997 __gnat_set_file_time_name (char *name, time_t time_stamp)
998 {
999 #if defined (__EMX__) || defined (MSDOS) || defined (__vxworks)
1000
1001 /* Code to implement __gnat_set_file_time_name for these systems. */
1002
1003 #elif defined (_WIN32)
1004 union
1005 {
1006 FILETIME ft_time;
1007 unsigned long long ull_time;
1008 } t_write;
1009
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
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;
1043 } Fat = { 0, 0, 0, 0, 0, { 0 }};
1044
1045 ATRDEF atrlst[]
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 },
1051 { ATR$S_FPRO, ATR$C_FPRO, &Fat.prot },
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
1081 /* Allocate and initialize a FAB and NAM structures. */
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
1093 /* Validate filespec syntax and device existence. */
1094 status = SYS$PARSE (&fab, 0, 0);
1095 if ((status & 1) != 1)
1096 LIB$SIGNAL (status);
1097
1098 file.string[nam.nam$b_esl] = 0;
1099
1100 /* Find matching filespec. */
1101 status = SYS$SEARCH (&fab, 0, 0);
1102 if ((status & 1) != 1)
1103 LIB$SIGNAL (status);
1104
1105 file.string[nam.nam$b_esl] = 0;
1106 result.string[result.length=nam.nam$b_rsl] = 0;
1107
1108 /* Get the device name and assign an IO channel. */
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
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];
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);
1125 result.string[result.length = 0] = 0;
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
1136 result.string[result.length] = 0;
1137 status = SYS$QIOW (0, chan, IO$_DEACCESS, &iosb, 0, 0, &fibdsc, 0, 0, 0,
1138 &atrlst, 0);
1139 if ((status & 1) != 1)
1140 LIB$SIGNAL (status);
1141 if ((iosb.status & 1) != 1)
1142 LIB$SIGNAL (iosb.status);
1143
1144 {
1145 time_t t;
1146
1147 /* Set creation time to requested time. */
1148 unix_time_to_vms (time_stamp, newtime);
1149
1150 t = time ((time_t) 0);
1151
1152 /* Set revision time to now in local time. */
1153 unix_time_to_vms (t, revtime);
1154 }
1155
1156 /* Reopen the file, modify the times and then close. */
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
1176 /* Deassign the channel and exit. */
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
1184 /* Set modification time to requested time. */
1185 utimbuf.modtime = time_stamp;
1186
1187 /* Set access time to now in local time. */
1188 t = time ((time_t) 0);
1189 utimbuf.actime = mktime (localtime (&t));
1190
1191 utime (name, &utimbuf);
1192 #endif
1193 }
1194
1195 void
1196 __gnat_get_env_value_ptr (char *name, int *len, char **value)
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
1211 static char *to_host_path_spec (char *);
1212
1213 struct descriptor_s
1214 {
1215 unsigned short len, mbz;
1216 char *adr;
1217 };
1218
1219 typedef struct _ile3
1220 {
1221 unsigned short len, code;
1222 char *adr;
1223 unsigned short *retlen_adr;
1224 } ile_s;
1225
1226 #endif
1227
1228 void
1229 __gnat_set_env_value (char *name, char *value)
1230 {
1231 #ifdef MSDOS
1232
1233 #elif defined (VMS)
1234 struct descriptor_s name_desc;
1235 /* Put in JOB table for now, so that the project stuff at least works. */
1236 struct descriptor_s table_desc = {7, 0, "LNM$JOB"};
1237 char *host_pathspec = value;
1238 char *copy_pathspec;
1239 int num_dirs_in_pathspec = 1;
1240 char *ptr;
1241 long status;
1242
1243 name_desc.len = strlen (name);
1244 name_desc.mbz = 0;
1245 name_desc.adr = name;
1246
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
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;
1276 ile_array[i].len = strlen (curr);
1277
1278 /* Code 2 from lnmdef.h means its a string. */
1279 ile_array[i].code = 2;
1280 ile_array[i].adr = curr;
1281
1282 /* retlen_adr is ignored. */
1283 ile_array[i].retlen_adr = 0;
1284 curr = next + 1;
1285 }
1286
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;
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
1317 char *
1318 __gnat_get_libraries_from_registry (void)
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
1372 int
1373 __gnat_stat (char *name, struct stat *statbuf)
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);
1379 char last_char = name[name_len - 1];
1380 char win32_name[GNAT_MAX_PATH_LEN + 2];
1381
1382 if (name_len > GNAT_MAX_PATH_LEN)
1383 return -1;
1384
1385 strcpy (win32_name, name);
1386
1387 while (name_len > 1 && (last_char == '\\' || last_char == '/'))
1388 {
1389 win32_name[name_len - 1] = '\0';
1390 name_len--;
1391 last_char = win32_name[name_len - 1];
1392 }
1393
1394 if (name_len == 2 && win32_name[1] == ':')
1395 strcat (win32_name, "\\");
1396
1397 return stat (win32_name, statbuf);
1398
1399 #else
1400 return stat (name, statbuf);
1401 #endif
1402 }
1403
1404 int
1405 __gnat_file_exists (char *name)
1406 {
1407 struct stat statbuf;
1408
1409 return !__gnat_stat (name, &statbuf);
1410 }
1411
1412 int
1413 __gnat_is_absolute_path (char *name, int length)
1414 {
1415 return (length != 0) &&
1416 (*name == '/' || *name == DIR_SEPARATOR
1417 #if defined (__EMX__) || defined (MSDOS) || defined (WINNT)
1418 || (length > 1 && isalpha (name[0]) && name[1] == ':')
1419 #endif
1420 );
1421 }
1422
1423 int
1424 __gnat_is_regular_file (char *name)
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
1433 int
1434 __gnat_is_directory (char *name)
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
1443 int
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
1455 int
1456 __gnat_is_writable_file (char *name)
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
1467 void
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
1481 void
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
1495 void
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
1509 int
1510 __gnat_is_symbolic_link (char *name ATTRIBUTE_UNUSED)
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
1527 #ifdef VMS
1528 /* Defined in VMS header files. */
1529 #if defined (__ALPHA)
1530 #define fork() (decc$$alloc_vfork_blocks() >= 0 ? \
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
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
1545 int
1546 __gnat_portable_spawn (char *args[])
1547 {
1548 int status = 0;
1549 int finished ATTRIBUTE_UNUSED;
1550 int pid ATTRIBUTE_UNUSED;
1551
1552 #if defined (MSDOS) || defined (_WIN32)
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
1566 if (status < 0)
1567 return -1;
1568 else
1569 return status;
1570
1571 #elif defined (__vxworks)
1572 return -1;
1573 #else
1574
1575 #ifdef __EMX__
1576 pid = spawnvp (P_NOWAIT, args[0], args);
1577 if (pid == -1)
1578 return -1;
1579
1580 #else
1581 pid = fork ();
1582 if (pid < 0)
1583 return -1;
1584
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 }
1595 #endif
1596
1597 /* The parent. */
1598 finished = waitpid (pid, &status, 0);
1599
1600 if (finished != pid || WIFEXITED (status) == 0)
1601 return -1;
1602
1603 return WEXITSTATUS (status);
1604 #endif
1605
1606 return 0;
1607 }
1608
1609 /* WIN32 code to implement a wait call that wait for any child process. */
1610
1611 #ifdef _WIN32
1612
1613 /* Synchronization code, to be thread safe. */
1614
1615 static CRITICAL_SECTION plist_cs;
1616
1617 void
1618 __gnat_plist_init (void)
1619 {
1620 InitializeCriticalSection (&plist_cs);
1621 }
1622
1623 static void
1624 plist_enter (void)
1625 {
1626 EnterCriticalSection (&plist_cs);
1627 }
1628
1629 static void
1630 plist_leave (void)
1631 {
1632 LeaveCriticalSection (&plist_cs);
1633 }
1634
1635 typedef struct _process_list
1636 {
1637 HANDLE h;
1638 struct _process_list *next;
1639 } Process_List;
1640
1641 static Process_List *PLIST = NULL;
1642
1643 static int plist_length = 0;
1644
1645 static void
1646 add_handle (HANDLE h)
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
1664 static void
1665 remove_handle (HANDLE h)
1666 {
1667 Process_List *pl;
1668 Process_List *prev = NULL;
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
1698 static int
1699 win32_no_block_spawn (char *command, char *args[])
1700 {
1701 BOOL result;
1702 STARTUPINFO SI;
1703 PROCESS_INFORMATION PI;
1704 SECURITY_ATTRIBUTES SA;
1705 int csize = 1;
1706 char *full_command;
1707 int k;
1708
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
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
1749 free (full_command);
1750
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
1761 static int
1762 win32_wait (int *status)
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);
1794 h = hl[res - WAIT_OBJECT_0];
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
1808 int
1809 __gnat_portable_no_block_spawn (char *args[])
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
1823 if (spawnvp (P_WAIT, args[0], args) != 0)
1824 return -1;
1825
1826 #elif defined (_WIN32)
1827
1828 pid = win32_no_block_spawn (args[0], args);
1829 return pid;
1830
1831 #elif defined (__vxworks)
1832 return -1;
1833
1834 #else
1835 pid = fork ();
1836
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. */
1843 #else
1844 _exit (1);
1845 #endif
1846 }
1847
1848 #endif
1849
1850 return pid;
1851 }
1852
1853 int
1854 __gnat_portable_wait (int *process_status)
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)
1864 /* ??? See corresponding comment in portable_no_block_spawn. */
1865
1866 #elif defined (__vxworks)
1867 /* Not sure what to do here, so do same as __EMX__ case, i.e., nothing but
1868 return zero. */
1869 #else
1870
1871 pid = waitpid (-1, &status, 0);
1872 status = status & 0xffff;
1873 #endif
1874
1875 *process_status = status;
1876 return pid;
1877 }
1878
1879 int
1880 __gnat_waitpid (int pid)
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
1896 void
1897 __gnat_os_exit (int status)
1898 {
1899 exit (status);
1900 }
1901
1902 /* Locate a regular file, give a Path value. */
1903
1904 char *
1905 __gnat_locate_regular_file (char *file_name, char *path_val)
1906 {
1907 char *ptr;
1908 int absolute = __gnat_is_absolute_path (file_name, strlen (file_name));
1909
1910 /* Handle absolute pathnames. */
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 */
1921 for (ptr = file_name; *ptr && *ptr != '/' && *ptr != DIR_SEPARATOR; ptr++)
1922 ;
1923
1924 if (*ptr != 0)
1925 {
1926 if (__gnat_is_regular_file (file_name))
1927 return xstrdup (file_name);
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
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
1964 instead. */
1965
1966 char *
1967 __gnat_locate_exec (char *exec_name, char *path_val)
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
1982 /* Locate an executable using the Systems default PATH. */
1983
1984 char *
1985 __gnat_locate_exec_on_path (char *exec_name)
1986 {
1987 char *apath_val;
1988 #ifdef VMS
1989 char *path_val = "/VAXC$PATH";
1990 #else
1991 char *path_val = getenv ("PATH");
1992 #endif
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
2006
2007 apath_val = alloca (strlen (path_val) + 1);
2008 strcpy (apath_val, path_val);
2009
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
2016 file, directory and path specifications. */
2017
2018 #define MAXPATH 256
2019 #define MAXNAMES 256
2020 #define NEW_CANONICAL_FILELIST_INCREMENT 64
2021
2022 static char new_canonical_dirspec [MAXPATH];
2023 static char new_canonical_filespec [MAXPATH];
2024 static char new_canonical_pathspec [MAXNAMES*MAXPATH];
2025 static unsigned new_canonical_filelist_index;
2026 static unsigned new_canonical_filelist_in_use;
2027 static unsigned new_canonical_filelist_allocated;
2028 static char **new_canonical_filelist;
2029 static char new_host_pathspec [MAXNAMES*MAXPATH];
2030 static char new_host_dirspec [MAXPATH];
2031 static char new_host_filespec [MAXPATH];
2032
2033 /* Routine is called repeatedly by decc$from_vms via
2034 __gnat_to_canonical_file_list_init until it returns 0 or the expansion
2035 runs out. */
2036
2037 static int
2038 wildcard_translate_unix (char *name)
2039 {
2040 char *ver;
2041 char buff [MAXPATH];
2042
2043 strncpy (buff, name, MAXPATH);
2044 buff [MAXPATH - 1] = (char) 0;
2045 ver = strrchr (buff, '.');
2046
2047 /* Chop off the version. */
2048 if (ver)
2049 *ver = 0;
2050
2051 /* Dynamically extend the allocation by the increment. */
2052 if (new_canonical_filelist_in_use == new_canonical_filelist_allocated)
2053 {
2054 new_canonical_filelist_allocated += NEW_CANONICAL_FILELIST_INCREMENT;
2055 new_canonical_filelist = (char **) xrealloc
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
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. */
2068
2069 int
2070 __gnat_to_canonical_file_list_init (char *filespec, int onlydirs)
2071 {
2072 int len;
2073 char buff [MAXPATH];
2074
2075 len = strlen (filespec);
2076 strncpy (buff, filespec, MAXPATH);
2077
2078 /* Only look for directories */
2079 if (onlydirs && !strstr (&buff [len-5], "*.dir"))
2080 strncat (buff, "*.dir", MAXPATH);
2081
2082 buff [MAXPATH - 1] = (char) 0;
2083
2084 decc$from_vms (buff, wildcard_translate_unix, 1);
2085
2086 /* Remove the .dir extension. */
2087 if (onlydirs)
2088 {
2089 int i;
2090 char *ext;
2091
2092 for (i = 0; i < new_canonical_filelist_in_use; i++)
2093 {
2094 ext = strstr (new_canonical_filelist[i], ".dir");
2095 if (ext)
2096 *ext = 0;
2097 }
2098 }
2099
2100 return new_canonical_filelist_in_use;
2101 }
2102
2103 /* Return the next filespec in the list. */
2104
2105 char *
2106 __gnat_to_canonical_file_list_next ()
2107 {
2108 return new_canonical_filelist[new_canonical_filelist_index++];
2109 }
2110
2111 /* Free storage used in the wildcard expansion. */
2112
2113 void
2114 __gnat_to_canonical_file_list_free ()
2115 {
2116 int i;
2117
2118 for (i = 0; i < new_canonical_filelist_in_use; i++)
2119 free (new_canonical_filelist[i]);
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
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. */
2133
2134 char *
2135 __gnat_to_canonical_dir_spec (char *dirspec, int prefixflag)
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, ':'))
2145 {
2146 strncpy (new_canonical_dirspec,
2147 (char *) decc$translate_vms (dirspec),
2148 MAXPATH);
2149 }
2150 else if (!strchr (dirspec, '/') && (dirspec1 = getenv (dirspec)) != 0)
2151 {
2152 strncpy (new_canonical_dirspec,
2153 (char *) decc$translate_vms (dirspec1),
2154 MAXPATH);
2155 }
2156 else
2157 {
2158 strncpy (new_canonical_dirspec, dirspec, MAXPATH);
2159 }
2160 }
2161
2162 len = strlen (new_canonical_dirspec);
2163 if (prefixflag && new_canonical_dirspec [len-1] != '/')
2164 strncat (new_canonical_dirspec, "/", MAXPATH);
2165
2166 new_canonical_dirspec [MAXPATH - 1] = (char) 0;
2167
2168 return new_canonical_dirspec;
2169
2170 }
2171
2172 /* Translate a VMS syntax file specification into Unix syntax.
2173 If no indicators of VMS syntax found, return input string. */
2174
2175 char *
2176 __gnat_to_canonical_file_spec (char *filespec)
2177 {
2178 strncpy (new_canonical_filespec, "", MAXPATH);
2179
2180 if (strchr (filespec, ']') || strchr (filespec, ':'))
2181 {
2182 strncpy (new_canonical_filespec,
2183 (char *) decc$translate_vms (filespec),
2184 MAXPATH);
2185 }
2186 else
2187 {
2188 strncpy (new_canonical_filespec, filespec, MAXPATH);
2189 }
2190
2191 new_canonical_filespec [MAXPATH - 1] = (char) 0;
2192
2193 return new_canonical_filespec;
2194 }
2195
2196 /* Translate a VMS syntax path specification into Unix syntax.
2197 If no indicators of VMS syntax found, return input string. */
2198
2199 char *
2200 __gnat_to_canonical_path_spec (char *pathspec)
2201 {
2202 char *curr, *next, buff [MAXPATH];
2203
2204 if (pathspec == 0)
2205 return pathspec;
2206
2207 /* If there are /'s, assume it's a Unix path spec and return. */
2208 if (strchr (pathspec, '/'))
2209 return pathspec;
2210
2211 new_canonical_pathspec[0] = 0;
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);
2221 buff[next - curr] = 0;
2222
2223 /* Check for wildcards and expand if present. */
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 ();
2234 strncat (new_canonical_pathspec, next_dir, MAXPATH);
2235
2236 /* Don't append the separator after the last expansion. */
2237 if (i+1 < dirs)
2238 strncat (new_canonical_pathspec, ":", MAXPATH);
2239 }
2240
2241 __gnat_to_canonical_file_list_free ();
2242 }
2243 else
2244 strncat (new_canonical_pathspec,
2245 __gnat_to_canonical_dir_spec (buff, 0), MAXPATH);
2246
2247 if (*next == 0)
2248 break;
2249
2250 strncat (new_canonical_pathspec, ":", MAXPATH);
2251 curr = next + 1;
2252 }
2253
2254 new_canonical_pathspec [MAXPATH - 1] = (char) 0;
2255
2256 return new_canonical_pathspec;
2257 }
2258
2259 static char filename_buff [MAXPATH];
2260
2261 static int
2262 translate_unix (char *name, int type)
2263 {
2264 strncpy (filename_buff, name, MAXPATH);
2265 filename_buff [MAXPATH - 1] = (char) 0;
2266 return 0;
2267 }
2268
2269 /* Translate a Unix syntax path spec into a VMS style (comma separated list of
2270 directories. */
2271
2272 static char *
2273 to_host_path_spec (char *pathspec)
2274 {
2275 char *curr, *next, buff [MAXPATH];
2276
2277 if (pathspec == 0)
2278 return pathspec;
2279
2280 /* Can't very well test for colons, since that's the Unix separator! */
2281 if (strchr (pathspec, ']') || strchr (pathspec, ','))
2282 return pathspec;
2283
2284 new_host_pathspec[0] = 0;
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);
2294 buff[next - curr] = 0;
2295
2296 strncat (new_host_pathspec, __gnat_to_host_dir_spec (buff, 0), MAXPATH);
2297 if (*next == 0)
2298 break;
2299 strncat (new_host_pathspec, ",", MAXPATH);
2300 curr = next + 1;
2301 }
2302
2303 new_host_pathspec [MAXPATH - 1] = (char) 0;
2304
2305 return new_host_pathspec;
2306 }
2307
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. */
2312
2313 char *
2314 __gnat_to_host_dir_spec (char *dirspec, int prefixflag ATTRIBUTE_UNUSED)
2315 {
2316 int len = strlen (dirspec);
2317
2318 strncpy (new_host_dirspec, dirspec, MAXPATH);
2319 new_host_dirspec [MAXPATH - 1] = (char) 0;
2320
2321 if (strchr (new_host_dirspec, ']') || strchr (new_host_dirspec, ':'))
2322 return new_host_dirspec;
2323
2324 while (len > 1 && new_host_dirspec[len - 1] == '/')
2325 {
2326 new_host_dirspec[len - 1] = 0;
2327 len--;
2328 }
2329
2330 decc$to_vms (new_host_dirspec, translate_unix, 1, 2);
2331 strncpy (new_host_dirspec, filename_buff, MAXPATH);
2332 new_host_dirspec [MAXPATH - 1] = (char) 0;
2333
2334 return new_host_dirspec;
2335 }
2336
2337 /* Translate a Unix syntax file specification into VMS syntax.
2338 If indicators of VMS syntax found, return input string. */
2339
2340 char *
2341 __gnat_to_host_file_spec (char *filespec)
2342 {
2343 strncpy (new_host_filespec, "", MAXPATH);
2344 if (strchr (filespec, ']') || strchr (filespec, ':'))
2345 {
2346 strncpy (new_host_filespec, filespec, MAXPATH);
2347 }
2348 else
2349 {
2350 decc$to_vms (filespec, translate_unix, 1, 1);
2351 strncpy (new_host_filespec, filename_buff, MAXPATH);
2352 }
2353
2354 new_host_filespec [MAXPATH - 1] = (char) 0;
2355
2356 return new_host_filespec;
2357 }
2358
2359 void
2360 __gnat_adjust_os_resource_limits ()
2361 {
2362 SYS$ADJWSL (131072, 0);
2363 }
2364
2365 #else /* VMS */
2366
2367 /* Dummy functions for Osint import for non-VMS systems. */
2368
2369 int
2370 __gnat_to_canonical_file_list_init
2371 (char *dirspec ATTRIBUTE_UNUSED, int onlydirs ATTRIBUTE_UNUSED)
2372 {
2373 return 0;
2374 }
2375
2376 char *
2377 __gnat_to_canonical_file_list_next (void)
2378 {
2379 return (char *) "";
2380 }
2381
2382 void
2383 __gnat_to_canonical_file_list_free (void)
2384 {
2385 }
2386
2387 char *
2388 __gnat_to_canonical_dir_spec (char *dirspec, int prefixflag ATTRIBUTE_UNUSED)
2389 {
2390 return dirspec;
2391 }
2392
2393 char *
2394 __gnat_to_canonical_file_spec (char *filespec)
2395 {
2396 return filespec;
2397 }
2398
2399 char *
2400 __gnat_to_canonical_path_spec (char *pathspec)
2401 {
2402 return pathspec;
2403 }
2404
2405 char *
2406 __gnat_to_host_dir_spec (char *dirspec, int prefixflag ATTRIBUTE_UNUSED)
2407 {
2408 return dirspec;
2409 }
2410
2411 char *
2412 __gnat_to_host_file_spec (char *filespec)
2413 {
2414 return filespec;
2415 }
2416
2417 void
2418 __gnat_adjust_os_resource_limits (void)
2419 {
2420 }
2421
2422 #endif
2423
2424 /* For EMX, we cannot include dummy in libgcc, since it is too difficult
2425 to coordinate this with the EMX distribution. Consequently, we put the
2426 definition of dummy which is used for exception handling, here. */
2427
2428 #if defined (__EMX__)
2429 void __dummy () {}
2430 #endif
2431
2432 #if defined (__mips_vxworks)
2433 int
2434 _flush_cache()
2435 {
2436 CACHE_USER_FLUSH (0, ENTIRE_CACHE);
2437 }
2438 #endif
2439
2440 #if defined (CROSS_COMPILE) \
2441 || (! (defined (sparc) && defined (sun) && defined (__SVR4)) \
2442 && ! (defined (linux) && defined (i386)) \
2443 && ! defined (__FreeBSD__) \
2444 && ! defined (hpux) \
2445 && ! defined (_AIX) \
2446 && ! (defined (__alpha__) && defined (__osf__)) \
2447 && ! defined (__MINGW32__))
2448
2449 /* Dummy function to satisfy g-trasym.o. Currently Solaris sparc, HP/UX,
2450 GNU/Linux x86, Tru64 & Windows provide a non-dummy version of this
2451 procedure in libaddr2line.a. */
2452
2453 void
2454 convert_addresses (void *addrs ATTRIBUTE_UNUSED,
2455 int n_addr ATTRIBUTE_UNUSED,
2456 void *buf ATTRIBUTE_UNUSED,
2457 int *len ATTRIBUTE_UNUSED)
2458 {
2459 *len = 0;
2460 }
2461 #endif
2462
2463 #if defined (_WIN32)
2464 int __gnat_argument_needs_quote = 1;
2465 #else
2466 int __gnat_argument_needs_quote = 0;
2467 #endif
2468
2469 /* This option is used to enable/disable object files handling from the
2470 binder file by the GNAT Project module. For example, this is disabled on
2471 Windows as it is already done by the mdll module. */
2472 #if defined (_WIN32)
2473 int __gnat_prj_add_obj_files = 0;
2474 #else
2475 int __gnat_prj_add_obj_files = 1;
2476 #endif
2477
2478 /* char used as prefix/suffix for environment variables */
2479 #if defined (_WIN32)
2480 char __gnat_environment_char = '%';
2481 #else
2482 char __gnat_environment_char = '$';
2483 #endif
2484
2485 /* This functions copy the file attributes from a source file to a
2486 destination file.
2487
2488 mode = 0 : In this mode copy only the file time stamps (last access and
2489 last modification time stamps).
2490
2491 mode = 1 : In this mode, time stamps and read/write/execute attributes are
2492 copied.
2493
2494 Returns 0 if operation was successful and -1 in case of error. */
2495
2496 int
2497 __gnat_copy_attribs (char *from, char *to, int mode)
2498 {
2499 #if defined (VMS) || defined (__vxworks)
2500 return -1;
2501 #else
2502 struct stat fbuf;
2503 struct utimbuf tbuf;
2504
2505 if (stat (from, &fbuf) == -1)
2506 {
2507 return -1;
2508 }
2509
2510 tbuf.actime = fbuf.st_atime;
2511 tbuf.modtime = fbuf.st_mtime;
2512
2513 if (utime (to, &tbuf) == -1)
2514 {
2515 return -1;
2516 }
2517
2518 if (mode == 1)
2519 {
2520 if (chmod (to, fbuf.st_mode) == -1)
2521 {
2522 return -1;
2523 }
2524 }
2525
2526 return 0;
2527 #endif
2528 }
2529
2530 /* This function is installed in libgcc.a. */
2531 extern void __gnat_install_locks (void (*) (void), void (*) (void));
2532
2533 /* This function offers a hook for libgnarl to set the
2534 locking subprograms for libgcc_eh.
2535 This is only needed on OpenVMS, since other platforms use standard
2536 --enable-threads=posix option, or similar. */
2537
2538 void
2539 __gnatlib_install_locks (void (*lock) (void) ATTRIBUTE_UNUSED,
2540 void (*unlock) (void) ATTRIBUTE_UNUSED)
2541 {
2542 #if defined (IN_RTS) && defined (VMS)
2543 __gnat_install_locks (lock, unlock);
2544 /* There is a bootstrap path issue if adaint is build with this
2545 symbol unresolved for the stage1 compiler. Since the compiler
2546 does not use tasking, we simply make __gnatlib_install_locks
2547 a no-op in this case. */
2548 #endif
2549 }
2550
2551 int
2552 __gnat_lseek (int fd, long offset, int whence)
2553 {
2554 return (int) lseek (fd, offset, whence);
2555 }
2556
2557 /* This function returns the version of GCC being used. Here it's GCC 3. */
2558 int
2559 get_gcc_version (void)
2560 {
2561 return 3;
2562 }