OSDN Git Service

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