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