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