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