OSDN Git Service

* approved by rth
[pf3gnuchains/gcc-fork.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  * It is now maintained by Ada Core Technologies Inc (http://www.gnat.com). *
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, "%s/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