adaint.c (__gnat_to_gm_time): First arg is int, not time_t.
[gcc.git] / gcc / ada / adaint.c
1 /****************************************************************************
2 * *
3 * GNAT COMPILER COMPONENTS *
4 * *
5 * A D A I N T *
6 * *
7 * $Revision: 1.6 $
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 int *p_time, *p_year, *p_month, *p_day, *p_hours, *p_mins, *p_secs;
216 {
217 struct tm *res;
218 time_t time = *p_time;
219
220 #ifdef _WIN32
221 /* On Windows systems, the time is sometimes rounded up to the nearest
222 even second, so if the number of seconds is odd, increment it. */
223 if (time & 1)
224 time++;
225 #endif
226
227 res = gmtime (&time);
228
229 if (res)
230 {
231 *p_year = res->tm_year;
232 *p_month = res->tm_mon;
233 *p_day = res->tm_mday;
234 *p_hours = res->tm_hour;
235 *p_mins = res->tm_min;
236 *p_secs = res->tm_sec;
237 }
238 else
239 *p_year = *p_month = *p_day = *p_hours = *p_mins = *p_secs = 0;
240 }
241
242 /* Place the contents of the symbolic link named PATH in the buffer BUF,
243 which has size BUFSIZ. If PATH is a symbolic link, then return the number
244 of characters of its content in BUF. Otherwise, return -1. For Windows,
245 OS/2 and vxworks, always return -1. */
246
247 int
248 __gnat_readlink (path, buf, bufsiz)
249 char *path;
250 char *buf;
251 size_t bufsiz;
252 {
253 #if defined (MSDOS) || defined (_WIN32) || defined (__EMX__)
254 return -1;
255 #elif defined (__INTERIX) || defined (VMS)
256 return -1;
257 #elif defined (__vxworks)
258 return -1;
259 #else
260 return readlink (path, buf, bufsiz);
261 #endif
262 }
263
264 /* Creates a symbolic link named newpath
265 which contains the string oldpath.
266 If newpath exists it will NOT be overwritten.
267 For Windows, OS/2, vxworks, Interix and VMS, always retur -1. */
268
269 int
270 __gnat_symlink (oldpath, newpath)
271 char *oldpath;
272 char *newpath;
273 {
274 #if defined (MSDOS) || defined (_WIN32) || defined (__EMX__)
275 return -1;
276 #elif defined (__INTERIX) || defined (VMS)
277 return -1;
278 #elif defined (__vxworks)
279 return -1;
280 #else
281 return symlink (oldpath, newpath);
282 #endif
283 }
284
285 /* Try to lock a file, return 1 if success */
286
287 #if defined (__vxworks) || defined (MSDOS) || defined (_WIN32)
288
289 /* Version that does not use link. */
290
291 int
292 __gnat_try_lock (dir, file)
293 char *dir;
294 char *file;
295 {
296 char full_path [256];
297 int fd;
298
299 sprintf (full_path, "%s%c%s", dir, DIR_SEPARATOR, file);
300 fd = open (full_path, O_CREAT | O_EXCL, 0600);
301 if (fd < 0) {
302 return 0;
303 }
304 close (fd);
305 return 1;
306 }
307
308 #elif defined (__EMX__) || defined (VMS)
309
310 /* More cases that do not use link; identical code, to solve too long
311 line problem ??? */
312
313 int
314 __gnat_try_lock (dir, file)
315 char *dir;
316 char *file;
317 {
318 char full_path [256];
319 int fd;
320
321 sprintf (full_path, "%s%c%s", dir, DIR_SEPARATOR, file);
322 fd = open (full_path, O_CREAT | O_EXCL, 0600);
323 if (fd < 0)
324 return 0;
325
326 close (fd);
327 return 1;
328 }
329
330 #else
331 /* Version using link(), more secure over NFS. */
332
333 int
334 __gnat_try_lock (dir, file)
335 char *dir;
336 char *file;
337 {
338 char full_path [256];
339 char temp_file [256];
340 struct stat stat_result;
341 int fd;
342
343 sprintf (full_path, "%s%c%s", dir, DIR_SEPARATOR, file);
344 sprintf (temp_file, "%s-%d-%d", dir, getpid(), getppid ());
345
346 /* Create the temporary file and write the process number */
347 fd = open (temp_file, O_CREAT | O_WRONLY, 0600);
348 if (fd < 0)
349 return 0;
350
351 close (fd);
352
353 /* Link it with the new file */
354 link (temp_file, full_path);
355
356 /* Count the references on the old one. If we have a count of two, then
357 the link did succeed. Remove the temporary file before returning. */
358 __gnat_stat (temp_file, &stat_result);
359 unlink (temp_file);
360 return stat_result.st_nlink == 2;
361 }
362 #endif
363
364 /* Return the maximum file name length. */
365
366 int
367 __gnat_get_maximum_file_name_length ()
368 {
369 #if defined(MSDOS)
370 return 8;
371 #elif defined (VMS)
372 if (getenv ("GNAT$EXTENDED_FILE_SPECIFICATIONS"))
373 return -1;
374 else
375 return 39;
376 #else
377 return -1;
378 #endif
379 }
380
381 /* Return the default switch character. */
382
383 char
384 __gnat_get_switch_character ()
385 {
386 /* Under MSDOS, the switch character is not normally a hyphen, but this is
387 the convention DJGPP uses. Similarly under OS2, the switch character is
388 not normally a hypen, but this is the convention EMX uses. */
389
390 return '-';
391 }
392
393 /* Return nonzero if file names are case sensitive. */
394
395 int
396 __gnat_get_file_names_case_sensitive ()
397 {
398 #if defined (__EMX__) || defined (MSDOS) || defined (VMS) || defined(WINNT)
399 return 0;
400 #else
401 return 1;
402 #endif
403 }
404
405 char
406 __gnat_get_default_identifier_character_set ()
407 {
408 #if defined (__EMX__) || defined (MSDOS)
409 return 'p';
410 #else
411 return '1';
412 #endif
413 }
414
415 /* Return the current working directory */
416
417 void
418 __gnat_get_current_dir (dir, length)
419 char *dir;
420 int *length;
421 {
422 #ifdef VMS
423 /* Force Unix style, which is what GNAT uses internally. */
424 getcwd (dir, *length, 0);
425 #else
426 getcwd (dir, *length);
427 #endif
428
429 *length = strlen (dir);
430
431 dir [*length] = DIR_SEPARATOR;
432 ++(*length);
433 dir [*length] = '\0';
434 }
435
436 /* Return the suffix for object files. */
437
438 void
439 __gnat_get_object_suffix_ptr (len, value)
440 int *len;
441 const char **value;
442 {
443 *value = HOST_OBJECT_SUFFIX;
444
445 if (*value == 0)
446 *len = 0;
447 else
448 *len = strlen (*value);
449
450 return;
451 }
452
453 /* Return the suffix for executable files */
454
455 void
456 __gnat_get_executable_suffix_ptr (len, value)
457 int *len;
458 const char **value;
459 {
460 *value = HOST_EXECUTABLE_SUFFIX;
461 if (!*value)
462 *len = 0;
463 else
464 *len = strlen (*value);
465
466 return;
467 }
468
469 /* Return the suffix for debuggable files. Usually this is the same as the
470 executable extension. */
471
472 void
473 __gnat_get_debuggable_suffix_ptr (len, value)
474 int *len;
475 const char **value;
476 {
477 #ifndef MSDOS
478 *value = HOST_EXECUTABLE_SUFFIX;
479 #else
480 /* On DOS, the extensionless COFF file is what gdb likes. */
481 *value = "";
482 #endif
483
484 if (*value == 0)
485 *len = 0;
486 else
487 *len = strlen (*value);
488
489 return;
490 }
491
492 int
493 __gnat_open_read (path, fmode)
494 char *path;
495 int fmode;
496 {
497 int fd;
498 int o_fmode = O_BINARY;
499
500 if (fmode)
501 o_fmode = O_TEXT;
502
503 #if defined(VMS)
504 /* Optional arguments mbc,deq,fop increase read performance */
505 fd = open (path, O_RDONLY | o_fmode, 0444,
506 "mbc=16", "deq=64", "fop=tef");
507 #elif defined(__vxworks)
508 fd = open (path, O_RDONLY | o_fmode, 0444);
509 #else
510 fd = open (path, O_RDONLY | o_fmode);
511 #endif
512 return fd < 0 ? -1 : fd;
513 }
514
515 #if defined (__EMX__)
516 #define PERM (S_IREAD | S_IWRITE)
517 #else
518 #define PERM (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH)
519 #endif
520
521 int
522 __gnat_open_rw (path, fmode)
523 char *path;
524 int fmode;
525 {
526 int fd;
527 int o_fmode = O_BINARY;
528
529 if (fmode)
530 o_fmode = O_TEXT;
531
532 #if defined(VMS)
533 fd = open (path, O_RDWR | o_fmode, PERM,
534 "mbc=16", "deq=64", "fop=tef");
535 #else
536 fd = open (path, O_RDWR | o_fmode, PERM);
537 #endif
538
539 return fd < 0 ? -1 : fd;
540 }
541
542 int
543 __gnat_open_create (path, fmode)
544 char *path;
545 int fmode;
546 {
547 int fd;
548 int o_fmode = O_BINARY;
549
550 if (fmode)
551 o_fmode = O_TEXT;
552
553 #if defined(VMS)
554 fd = open (path, O_WRONLY | O_CREAT | O_TRUNC | o_fmode, PERM,
555 "mbc=16", "deq=64", "fop=tef");
556 #else
557 fd = open (path, O_WRONLY | O_CREAT | O_TRUNC | o_fmode, PERM);
558 #endif
559
560 return fd < 0 ? -1 : fd;
561 }
562
563 int
564 __gnat_open_append (path, fmode)
565 char *path;
566 int fmode;
567 {
568 int fd;
569 int o_fmode = O_BINARY;
570
571 if (fmode)
572 o_fmode = O_TEXT;
573
574 #if defined(VMS)
575 fd = open (path, O_WRONLY | O_CREAT | O_APPEND | o_fmode, PERM,
576 "mbc=16", "deq=64", "fop=tef");
577 #else
578 fd = open (path, O_WRONLY | O_CREAT | O_APPEND | o_fmode, PERM);
579 #endif
580
581 return fd < 0 ? -1 : fd;
582 }
583
584 /* Open a new file. Return error (-1) if the file already exists. */
585
586 int
587 __gnat_open_new (path, fmode)
588 char *path;
589 int fmode;
590 {
591 int fd;
592 int o_fmode = O_BINARY;
593
594 if (fmode)
595 o_fmode = O_TEXT;
596
597 #if defined(VMS)
598 fd = open (path, O_WRONLY | O_CREAT | O_EXCL | o_fmode, PERM,
599 "mbc=16", "deq=64", "fop=tef");
600 #else
601 fd = open (path, O_WRONLY | O_CREAT | O_EXCL | o_fmode, PERM);
602 #endif
603
604 return fd < 0 ? -1 : fd;
605 }
606
607 /* Open a new temp file. Return error (-1) if the file already exists.
608 Special options for VMS allow the file to be shared between parent and
609 child processes, however they really slow down output. Used in
610 gnatchop. */
611
612 int
613 __gnat_open_new_temp (path, fmode)
614 char *path;
615 int fmode;
616 {
617 int fd;
618 int o_fmode = O_BINARY;
619
620 strcpy (path, "GNAT-XXXXXX");
621
622 #if defined (linux) && !defined (__vxworks)
623 return mkstemp (path);
624 #elif defined (__Lynx__)
625 mktemp (path);
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