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