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