init.c (__gnat_error_handler): Make msg const.
[official-gcc.git] / gcc / ada / adaint.c
blobd820d6d6d583a43d8ba9855a5bb16e2ff2a1c359
1 /****************************************************************************
2 * *
3 * GNAT COMPILER COMPONENTS *
4 * *
5 * A D A I N T *
6 * *
7 * *
8 * C Implementation File *
9 * *
10 * Copyright (C) 1992-2002, Free Software Foundation, Inc. *
11 * *
12 * GNAT is free software; you can redistribute it and/or modify it under *
13 * terms of the GNU General Public License as published by the Free Soft- *
14 * ware Foundation; either version 2, or (at your option) any later ver- *
15 * sion. GNAT is distributed in the hope that it will be useful, but WITH- *
16 * OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY *
17 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License *
18 * for more details. You should have received a copy of the GNU General *
19 * Public License distributed with GNAT; see file COPYING. If not, write *
20 * to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, *
21 * MA 02111-1307, USA. *
22 * *
23 * As a special exception, if you link this file with other files to *
24 * produce an executable, this file does not by itself cause the resulting *
25 * executable to be covered by the GNU General Public License. This except- *
26 * ion does not however invalidate any other reasons why the executable *
27 * file might be covered by the GNU Public License. *
28 * *
29 * GNAT was originally developed by the GNAT team at New York University. *
30 * Extensive contributions were provided by Ada Core Technologies Inc. *
31 * *
32 ****************************************************************************/
34 /* This file contains those routines named by Import pragmas in
35 packages in the GNAT hierarchy (especially GNAT.OS_Lib) and in
36 package Osint. Many of the subprograms in OS_Lib import standard
37 library calls directly. This file contains all other routines. */
39 #ifdef __vxworks
41 /* No need to redefine exit here. */
42 #undef exit
44 /* We want to use the POSIX variants of include files. */
45 #define POSIX
46 #include "vxWorks.h"
48 #if defined (__mips_vxworks)
49 #include "cacheLib.h"
50 #endif /* __mips_vxworks */
52 #endif /* VxWorks */
54 #ifdef IN_RTS
55 #include "tconfig.h"
56 #include "tsystem.h"
57 #include <sys/stat.h>
58 #include <fcntl.h>
59 #include <time.h>
61 /* We don't have libiberty, so use malloc. */
62 #define xmalloc(S) malloc (S)
63 #define xrealloc(V,S) realloc (V,S)
64 #else
65 #include "config.h"
66 #include "system.h"
67 #endif
68 #include <sys/wait.h>
70 #if defined (__EMX__) || defined (MSDOS) || defined (_WIN32)
71 #elif defined (VMS)
73 /* Header files and definitions for __gnat_set_file_time_name. */
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>
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; }
92 /* descrip.h doesn't have everything ... */
93 struct dsc$descriptor_fib
95 unsigned long fib$l_len;
96 struct fibdef *fib$l_addr;
99 /* I/O Status Block. */
100 struct IOSB
102 unsigned short status, count;
103 unsigned long devdep;
106 static char *tryfile;
108 /* Variable length string. */
109 struct vstring
111 short length;
112 char string[NAM$C_MAXRSS+1];
115 #else
116 #include <utime.h>
117 #endif
119 #if defined (__EMX__) || defined (MSDOS) || defined (_WIN32)
120 #include <process.h>
121 #endif
123 #if defined (_WIN32)
124 #include <dir.h>
125 #include <windows.h>
126 #endif
128 #include "adaint.h"
130 /* Define symbols O_BINARY and O_TEXT as harmless zeroes if they are not
131 defined in the current system. On DOS-like systems these flags control
132 whether the file is opened/created in text-translation mode (CR/LF in
133 external file mapped to LF in internal file), but in Unix-like systems,
134 no text translation is required, so these flags have no effect. */
136 #if defined (__EMX__)
137 #include <os2.h>
138 #endif
140 #if defined (MSDOS)
141 #include <dos.h>
142 #endif
144 #ifndef O_BINARY
145 #define O_BINARY 0
146 #endif
148 #ifndef O_TEXT
149 #define O_TEXT 0
150 #endif
152 #ifndef HOST_EXECUTABLE_SUFFIX
153 #define HOST_EXECUTABLE_SUFFIX ""
154 #endif
156 #ifndef HOST_OBJECT_SUFFIX
157 #define HOST_OBJECT_SUFFIX ".o"
158 #endif
160 #ifndef PATH_SEPARATOR
161 #define PATH_SEPARATOR ':'
162 #endif
164 #ifndef DIR_SEPARATOR
165 #define DIR_SEPARATOR '/'
166 #endif
168 char __gnat_dir_separator = DIR_SEPARATOR;
170 char __gnat_path_separator = PATH_SEPARATOR;
172 /* The GNAT_LIBRARY_TEMPLATE contains a list of expressions that define
173 the base filenames that libraries specified with -lsomelib options
174 may have. This is used by GNATMAKE to check whether an executable
175 is up-to-date or not. The syntax is
177 library_template ::= { pattern ; } pattern NUL
178 pattern ::= [ prefix ] * [ postfix ]
180 These should only specify names of static libraries as it makes
181 no sense to determine at link time if dynamic-link libraries are
182 up to date or not. Any libraries that are not found are supposed
183 to be up-to-date:
185 * if they are needed but not present, the link
186 will fail,
188 * otherwise they are libraries in the system paths and so
189 they are considered part of the system and not checked
190 for that reason.
192 ??? This should be part of a GNAT host-specific compiler
193 file instead of being included in all user applications
194 as well. This is only a temporary work-around for 3.11b. */
196 #ifndef GNAT_LIBRARY_TEMPLATE
197 #if defined (__EMX__)
198 #define GNAT_LIBRARY_TEMPLATE "*.a"
199 #elif defined (VMS)
200 #define GNAT_LIBRARY_TEMPLATE "*.olb"
201 #else
202 #define GNAT_LIBRARY_TEMPLATE "lib*.a"
203 #endif
204 #endif
206 const char *__gnat_library_template = GNAT_LIBRARY_TEMPLATE;
208 /* This variable is used in hostparm.ads to say whether the host is a VMS
209 system. */
210 #ifdef VMS
211 const int __gnat_vmsp = 1;
212 #else
213 const int __gnat_vmsp = 0;
214 #endif
216 /* This variable is used to export the maximum length of a path name to
217 Ada code. */
219 #ifdef __EMX__
220 int __gnat_max_path_len = _MAX_PATH;
222 #elif defined (VMS)
223 int __gnat_max_path_len = 4096; /* PATH_MAX */
225 #elif defined (__vxworks) || defined (__OPENNT)
226 int __gnat_max_path_len = PATH_MAX;
228 #else
229 #include <sys/param.h>
230 int __gnat_max_path_len = MAXPATHLEN;
232 #endif
234 /* The following macro HAVE_READDIR_R should be defined if the
235 system provides the routine readdir_r. */
236 #undef HAVE_READDIR_R
238 void
239 __gnat_to_gm_time (p_time, p_year, p_month, p_day, p_hours, p_mins, p_secs)
240 int *p_time, *p_year, *p_month, *p_day, *p_hours, *p_mins, *p_secs;
242 struct tm *res;
243 time_t time = *p_time;
245 #ifdef _WIN32
246 /* On Windows systems, the time is sometimes rounded up to the nearest
247 even second, so if the number of seconds is odd, increment it. */
248 if (time & 1)
249 time++;
250 #endif
252 res = gmtime (&time);
254 if (res)
256 *p_year = res->tm_year;
257 *p_month = res->tm_mon;
258 *p_day = res->tm_mday;
259 *p_hours = res->tm_hour;
260 *p_mins = res->tm_min;
261 *p_secs = res->tm_sec;
263 else
264 *p_year = *p_month = *p_day = *p_hours = *p_mins = *p_secs = 0;
267 /* Place the contents of the symbolic link named PATH in the buffer BUF,
268 which has size BUFSIZ. If PATH is a symbolic link, then return the number
269 of characters of its content in BUF. Otherwise, return -1. For Windows,
270 OS/2 and vxworks, always return -1. */
272 int
273 __gnat_readlink (path, buf, bufsiz)
274 char *path;
275 char *buf;
276 size_t bufsiz;
278 #if defined (MSDOS) || defined (_WIN32) || defined (__EMX__)
279 return -1;
280 #elif defined (__INTERIX) || defined (VMS)
281 return -1;
282 #elif defined (__vxworks)
283 return -1;
284 #else
285 return readlink (path, buf, bufsiz);
286 #endif
289 /* Creates a symbolic link named NEWPATH which contains the string OLDPATH. If
290 NEWPATH exists it will NOT be overwritten. For Windows, OS/2, VxWorks,
291 Interix and VMS, always return -1. */
294 __gnat_symlink (oldpath, newpath)
295 char *oldpath;
296 char *newpath;
298 #if defined (MSDOS) || defined (_WIN32) || defined (__EMX__)
299 return -1;
300 #elif defined (__INTERIX) || defined (VMS)
301 return -1;
302 #elif defined (__vxworks)
303 return -1;
304 #else
305 return symlink (oldpath, newpath);
306 #endif
309 /* Try to lock a file, return 1 if success. */
311 #if defined (__vxworks) || defined (MSDOS) || defined (_WIN32)
313 /* Version that does not use link. */
316 __gnat_try_lock (dir, file)
317 char *dir;
318 char *file;
320 char full_path[256];
321 int fd;
323 sprintf (full_path, "%s%c%s", dir, DIR_SEPARATOR, file);
324 fd = open (full_path, O_CREAT | O_EXCL, 0600);
325 if (fd < 0)
326 return 0;
328 close (fd);
329 return 1;
332 #elif defined (__EMX__) || defined (VMS)
334 /* More cases that do not use link; identical code, to solve too long
335 line problem ??? */
338 __gnat_try_lock (dir, file)
339 char *dir;
340 char *file;
342 char full_path[256];
343 int fd;
345 sprintf (full_path, "%s%c%s", dir, DIR_SEPARATOR, file);
346 fd = open (full_path, O_CREAT | O_EXCL, 0600);
347 if (fd < 0)
348 return 0;
350 close (fd);
351 return 1;
354 #else
356 /* Version using link(), more secure over NFS. */
359 __gnat_try_lock (dir, file)
360 char *dir;
361 char *file;
363 char full_path[256];
364 char temp_file[256];
365 struct stat stat_result;
366 int fd;
368 sprintf (full_path, "%s%c%s", dir, DIR_SEPARATOR, file);
369 sprintf (temp_file, "%s-%ld-%ld", dir, (long) getpid(), (long) getppid ());
371 /* Create the temporary file and write the process number. */
372 fd = open (temp_file, O_CREAT | O_WRONLY, 0600);
373 if (fd < 0)
374 return 0;
376 close (fd);
378 /* Link it with the new file. */
379 link (temp_file, full_path);
381 /* Count the references on the old one. If we have a count of two, then
382 the link did succeed. Remove the temporary file before returning. */
383 __gnat_stat (temp_file, &stat_result);
384 unlink (temp_file);
385 return stat_result.st_nlink == 2;
387 #endif
389 /* Return the maximum file name length. */
392 __gnat_get_maximum_file_name_length ()
394 #if defined (MSDOS)
395 return 8;
396 #elif defined (VMS)
397 if (getenv ("GNAT$EXTENDED_FILE_SPECIFICATIONS"))
398 return -1;
399 else
400 return 39;
401 #else
402 return -1;
403 #endif
406 /* Return nonzero if file names are case sensitive. */
409 __gnat_get_file_names_case_sensitive ()
411 #if defined (__EMX__) || defined (MSDOS) || defined (VMS) || defined (WINNT)
412 return 0;
413 #else
414 return 1;
415 #endif
418 char
419 __gnat_get_default_identifier_character_set ()
421 #if defined (__EMX__) || defined (MSDOS)
422 return 'p';
423 #else
424 return '1';
425 #endif
428 /* Return the current working directory. */
430 void
431 __gnat_get_current_dir (dir, length)
432 char *dir;
433 int *length;
435 #ifdef VMS
436 /* Force Unix style, which is what GNAT uses internally. */
437 getcwd (dir, *length, 0);
438 #else
439 getcwd (dir, *length);
440 #endif
442 *length = strlen (dir);
444 dir[*length] = DIR_SEPARATOR;
445 ++*length;
446 dir[*length] = '\0';
449 /* Return the suffix for object files. */
451 void
452 __gnat_get_object_suffix_ptr (len, value)
453 int *len;
454 const char **value;
456 *value = HOST_OBJECT_SUFFIX;
458 if (*value == 0)
459 *len = 0;
460 else
461 *len = strlen (*value);
463 return;
466 /* Return the suffix for executable files. */
468 void
469 __gnat_get_executable_suffix_ptr (len, value)
470 int *len;
471 const char **value;
473 *value = HOST_EXECUTABLE_SUFFIX;
474 if (!*value)
475 *len = 0;
476 else
477 *len = strlen (*value);
479 return;
482 /* Return the suffix for debuggable files. Usually this is the same as the
483 executable extension. */
485 void
486 __gnat_get_debuggable_suffix_ptr (len, value)
487 int *len;
488 const char **value;
490 #ifndef MSDOS
491 *value = HOST_EXECUTABLE_SUFFIX;
492 #else
493 /* On DOS, the extensionless COFF file is what gdb likes. */
494 *value = "";
495 #endif
497 if (*value == 0)
498 *len = 0;
499 else
500 *len = strlen (*value);
502 return;
506 __gnat_open_read (path, fmode)
507 char *path;
508 int fmode;
510 int fd;
511 int o_fmode = O_BINARY;
513 if (fmode)
514 o_fmode = O_TEXT;
516 #if defined (VMS)
517 /* Optional arguments mbc,deq,fop increase read performance. */
518 fd = open (path, O_RDONLY | o_fmode, 0444,
519 "mbc=16", "deq=64", "fop=tef");
520 #elif defined (__vxworks)
521 fd = open (path, O_RDONLY | o_fmode, 0444);
522 #else
523 fd = open (path, O_RDONLY | o_fmode);
524 #endif
526 return fd < 0 ? -1 : fd;
529 #if defined (__EMX__)
530 #define PERM (S_IREAD | S_IWRITE)
531 #else
532 #define PERM (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH)
533 #endif
536 __gnat_open_rw (path, fmode)
537 char *path;
538 int fmode;
540 int fd;
541 int o_fmode = O_BINARY;
543 if (fmode)
544 o_fmode = O_TEXT;
546 #if defined (VMS)
547 fd = open (path, O_RDWR | o_fmode, PERM,
548 "mbc=16", "deq=64", "fop=tef");
549 #else
550 fd = open (path, O_RDWR | o_fmode, PERM);
551 #endif
553 return fd < 0 ? -1 : fd;
557 __gnat_open_create (path, fmode)
558 char *path;
559 int fmode;
561 int fd;
562 int o_fmode = O_BINARY;
564 if (fmode)
565 o_fmode = O_TEXT;
567 #if defined (VMS)
568 fd = open (path, O_WRONLY | O_CREAT | O_TRUNC | o_fmode, PERM,
569 "mbc=16", "deq=64", "fop=tef");
570 #else
571 fd = open (path, O_WRONLY | O_CREAT | O_TRUNC | o_fmode, PERM);
572 #endif
574 return fd < 0 ? -1 : fd;
578 __gnat_open_append (path, fmode)
579 char *path;
580 int fmode;
582 int fd;
583 int o_fmode = O_BINARY;
585 if (fmode)
586 o_fmode = O_TEXT;
588 #if defined (VMS)
589 fd = open (path, O_WRONLY | O_CREAT | O_APPEND | o_fmode, PERM,
590 "mbc=16", "deq=64", "fop=tef");
591 #else
592 fd = open (path, O_WRONLY | O_CREAT | O_APPEND | o_fmode, PERM);
593 #endif
595 return fd < 0 ? -1 : fd;
598 /* Open a new file. Return error (-1) if the file already exists. */
601 __gnat_open_new (path, fmode)
602 char *path;
603 int fmode;
605 int fd;
606 int o_fmode = O_BINARY;
608 if (fmode)
609 o_fmode = O_TEXT;
611 #if defined (VMS)
612 fd = open (path, O_WRONLY | O_CREAT | O_EXCL | o_fmode, PERM,
613 "mbc=16", "deq=64", "fop=tef");
614 #else
615 fd = open (path, O_WRONLY | O_CREAT | O_EXCL | o_fmode, PERM);
616 #endif
618 return fd < 0 ? -1 : fd;
621 /* Open a new temp file. Return error (-1) if the file already exists.
622 Special options for VMS allow the file to be shared between parent and child
623 processes, however they really slow down output. Used in gnatchop. */
626 __gnat_open_new_temp (path, fmode)
627 char *path;
628 int fmode;
630 int fd;
631 int o_fmode = O_BINARY;
633 strcpy (path, "GNAT-XXXXXX");
635 #if defined (linux) && !defined (__vxworks)
636 return mkstemp (path);
637 #elif defined (__Lynx__)
638 mktemp (path);
639 #else
640 if (mktemp (path) == NULL)
641 return -1;
642 #endif
644 if (fmode)
645 o_fmode = O_TEXT;
647 #if defined (VMS)
648 fd = open (path, O_WRONLY | O_CREAT | O_EXCL | o_fmode, PERM,
649 "rfm=stmlf", "ctx=rec", "rat=none", "shr=del,get,put,upd",
650 "mbc=16", "deq=64", "fop=tef");
651 #else
652 fd = open (path, O_WRONLY | O_CREAT | O_EXCL | o_fmode, PERM);
653 #endif
655 return fd < 0 ? -1 : fd;
658 /* Return the number of bytes in the specified file. */
660 long
661 __gnat_file_length (fd)
662 int fd;
664 int ret;
665 struct stat statbuf;
667 ret = fstat (fd, &statbuf);
668 if (ret || !S_ISREG (statbuf.st_mode))
669 return 0;
671 return (statbuf.st_size);
674 /* Create a temporary filename and put it in string pointed to by
675 TMP_FILENAME. */
677 void
678 __gnat_tmp_name (tmp_filename)
679 char *tmp_filename;
681 #ifdef __MINGW32__
683 char *pname;
685 /* tempnam tries to create a temporary file in directory pointed to by
686 TMP environment variable, in c:\temp if TMP is not set, and in
687 directory specified by P_tmpdir in stdio.h if c:\temp does not
688 exist. The filename will be created with the prefix "gnat-". */
690 pname = (char *) tempnam ("c:\\temp", "gnat-");
692 /* If pname start with a back slash and not path information it means that
693 the filename is valid for the current working directory. */
695 if (pname[0] == '\\')
697 strcpy (tmp_filename, ".\\");
698 strcat (tmp_filename, pname+1);
700 else
701 strcpy (tmp_filename, pname);
703 free (pname);
706 #elif defined (linux)
707 char *tmpdir = getenv ("TMPDIR");
709 if (tmpdir == NULL)
710 strcpy (tmp_filename, "/tmp/gnat-XXXXXX");
711 else
712 sprintf (tmp_filename, "%.200s/gnat-XXXXXX", tmpdir);
714 close (mkstemp(tmp_filename));
715 #else
716 tmpnam (tmp_filename);
717 #endif
720 /* Read the next entry in a directory. The returned string points somewhere
721 in the buffer. */
723 char *
724 __gnat_readdir (dirp, buffer)
725 DIR *dirp;
726 char* buffer;
728 /* If possible, try to use the thread-safe version. */
729 #ifdef HAVE_READDIR_R
730 if (readdir_r (dirp, buffer) != NULL)
731 return ((struct dirent*) buffer)->d_name;
732 else
733 return NULL;
735 #else
736 struct dirent *dirent = readdir (dirp);
738 if (dirent != NULL)
740 strcpy (buffer, dirent->d_name);
741 return buffer;
743 else
744 return NULL;
746 #endif
749 /* Returns 1 if readdir is thread safe, 0 otherwise. */
752 __gnat_readdir_is_thread_safe ()
754 #ifdef HAVE_READDIR_R
755 return 1;
756 #else
757 return 0;
758 #endif
761 #ifdef _WIN32
763 /* Returns the file modification timestamp using Win32 routines which are
764 immune against daylight saving time change. It is in fact not possible to
765 use fstat for this purpose as the DST modify the st_mtime field of the
766 stat structure. */
768 static time_t
769 win32_filetime (h)
770 HANDLE h;
772 BOOL res;
773 FILETIME t_create;
774 FILETIME t_access;
775 FILETIME t_write;
776 unsigned long long timestamp;
778 /* Number of seconds between <Jan 1st 1601> and <Jan 1st 1970>. */
779 unsigned long long offset = 11644473600;
781 /* GetFileTime returns FILETIME data which are the number of 100 nanosecs
782 since <Jan 1st 1601>. This function must return the number of seconds
783 since <Jan 1st 1970>. */
785 res = GetFileTime (h, &t_create, &t_access, &t_write);
787 timestamp = (((long long) t_write.dwHighDateTime << 32)
788 + t_write.dwLowDateTime);
790 timestamp = timestamp / 10000000 - offset;
792 return (time_t) timestamp;
794 #endif
796 /* Return a GNAT time stamp given a file name. */
798 time_t
799 __gnat_file_time_name (name)
800 char *name;
802 struct stat statbuf;
804 #if defined (__EMX__) || defined (MSDOS)
805 int fd = open (name, O_RDONLY | O_BINARY);
806 time_t ret = __gnat_file_time_fd (fd);
807 close (fd);
808 return ret;
810 #elif defined (_WIN32)
811 HANDLE h = CreateFile (name, GENERIC_READ, FILE_SHARE_READ, 0,
812 OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0);
813 time_t ret = win32_filetime (h);
814 CloseHandle (h);
815 return ret;
816 #else
818 (void) __gnat_stat (name, &statbuf);
819 #ifdef VMS
820 /* VMS has file versioning. */
821 return statbuf.st_ctime;
822 #else
823 return statbuf.st_mtime;
824 #endif
825 #endif
828 /* Return a GNAT time stamp given a file descriptor. */
830 time_t
831 __gnat_file_time_fd (fd)
832 int fd;
834 /* The following workaround code is due to the fact that under EMX and
835 DJGPP fstat attempts to convert time values to GMT rather than keep the
836 actual OS timestamp of the file. By using the OS2/DOS functions directly
837 the GNAT timestamp are independent of this behavior, which is desired to
838 facilitate the distribution of GNAT compiled libraries. */
840 #if defined (__EMX__) || defined (MSDOS)
841 #ifdef __EMX__
843 FILESTATUS fs;
844 int ret = DosQueryFileInfo (fd, 1, (unsigned char *) &fs,
845 sizeof (FILESTATUS));
847 unsigned file_year = fs.fdateLastWrite.year;
848 unsigned file_month = fs.fdateLastWrite.month;
849 unsigned file_day = fs.fdateLastWrite.day;
850 unsigned file_hour = fs.ftimeLastWrite.hours;
851 unsigned file_min = fs.ftimeLastWrite.minutes;
852 unsigned file_tsec = fs.ftimeLastWrite.twosecs;
854 #else
855 struct ftime fs;
856 int ret = getftime (fd, &fs);
858 unsigned file_year = fs.ft_year;
859 unsigned file_month = fs.ft_month;
860 unsigned file_day = fs.ft_day;
861 unsigned file_hour = fs.ft_hour;
862 unsigned file_min = fs.ft_min;
863 unsigned file_tsec = fs.ft_tsec;
864 #endif
866 /* Calculate the seconds since epoch from the time components. First count
867 the whole days passed. The value for years returned by the DOS and OS2
868 functions count years from 1980, so to compensate for the UNIX epoch which
869 begins in 1970 start with 10 years worth of days and add days for each
870 four year period since then. */
872 time_t tot_secs;
873 int cum_days[12] = {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334};
874 int days_passed = 3652 + (file_year / 4) * 1461;
875 int years_since_leap = file_year % 4;
877 if (years_since_leap == 1)
878 days_passed += 366;
879 else if (years_since_leap == 2)
880 days_passed += 731;
881 else if (years_since_leap == 3)
882 days_passed += 1096;
884 if (file_year > 20)
885 days_passed -= 1;
887 days_passed += cum_days[file_month - 1];
888 if (years_since_leap == 0 && file_year != 20 && file_month > 2)
889 days_passed++;
891 days_passed += file_day - 1;
893 /* OK - have whole days. Multiply -- then add in other parts. */
895 tot_secs = days_passed * 86400;
896 tot_secs += file_hour * 3600;
897 tot_secs += file_min * 60;
898 tot_secs += file_tsec * 2;
899 return tot_secs;
901 #elif defined (_WIN32)
902 HANDLE h = (HANDLE) _get_osfhandle (fd);
903 time_t ret = win32_filetime (h);
904 return ret;
906 #else
907 struct stat statbuf;
909 (void) fstat (fd, &statbuf);
911 #ifdef VMS
912 /* VMS has file versioning. */
913 return statbuf.st_ctime;
914 #else
915 return statbuf.st_mtime;
916 #endif
917 #endif
920 /* Set the file time stamp. */
922 void
923 __gnat_set_file_time_name (name, time_stamp)
924 char *name;
925 time_t time_stamp;
927 #if defined (__EMX__) || defined (MSDOS) || defined (_WIN32) \
928 || defined (__vxworks)
930 /* Code to implement __gnat_set_file_time_name for these systems. */
932 #elif defined (VMS)
933 struct FAB fab;
934 struct NAM nam;
936 struct
938 unsigned long long backup, create, expire, revise;
939 unsigned long uic;
940 union
942 unsigned short value;
943 struct
945 unsigned system : 4;
946 unsigned owner : 4;
947 unsigned group : 4;
948 unsigned world : 4;
949 } bits;
950 } prot;
951 } Fat = { 0, 0, 0, 0, 0, { 0 }};
953 ATRDEF atrlst[]
955 { ATR$S_CREDATE, ATR$C_CREDATE, &Fat.create },
956 { ATR$S_REVDATE, ATR$C_REVDATE, &Fat.revise },
957 { ATR$S_EXPDATE, ATR$C_EXPDATE, &Fat.expire },
958 { ATR$S_BAKDATE, ATR$C_BAKDATE, &Fat.backup },
959 { ATR$S_FPRO, ATR$C_FPRO, &Fat.prot },
960 { ATR$S_UIC, ATR$C_UIC, &Fat.uic },
961 { 0, 0, 0}
964 FIBDEF fib;
965 struct dsc$descriptor_fib fibdsc = {sizeof (fib), (void *) &fib};
967 struct IOSB iosb;
969 unsigned long long newtime;
970 unsigned long long revtime;
971 long status;
972 short chan;
974 struct vstring file;
975 struct dsc$descriptor_s filedsc
976 = {NAM$C_MAXRSS, DSC$K_DTYPE_T, DSC$K_CLASS_S, (void *) file.string};
977 struct vstring device;
978 struct dsc$descriptor_s devicedsc
979 = {NAM$C_MAXRSS, DSC$K_DTYPE_T, DSC$K_CLASS_S, (void *) device.string};
980 struct vstring timev;
981 struct dsc$descriptor_s timedsc
982 = {NAM$C_MAXRSS, DSC$K_DTYPE_T, DSC$K_CLASS_S, (void *) timev.string};
983 struct vstring result;
984 struct dsc$descriptor_s resultdsc
985 = {NAM$C_MAXRSS, DSC$K_DTYPE_VT, DSC$K_CLASS_VS, (void *) result.string};
987 tryfile = (char *) __gnat_to_host_dir_spec (name, 0);
989 /* Allocate and initialize a FAB and NAM structures. */
990 fab = cc$rms_fab;
991 nam = cc$rms_nam;
993 nam.nam$l_esa = file.string;
994 nam.nam$b_ess = NAM$C_MAXRSS;
995 nam.nam$l_rsa = result.string;
996 nam.nam$b_rss = NAM$C_MAXRSS;
997 fab.fab$l_fna = tryfile;
998 fab.fab$b_fns = strlen (tryfile);
999 fab.fab$l_nam = &nam;
1001 /* Validate filespec syntax and device existence. */
1002 status = SYS$PARSE (&fab, 0, 0);
1003 if ((status & 1) != 1)
1004 LIB$SIGNAL (status);
1006 file.string[nam.nam$b_esl] = 0;
1008 /* Find matching filespec. */
1009 status = SYS$SEARCH (&fab, 0, 0);
1010 if ((status & 1) != 1)
1011 LIB$SIGNAL (status);
1013 file.string[nam.nam$b_esl] = 0;
1014 result.string[result.length=nam.nam$b_rsl] = 0;
1016 /* Get the device name and assign an IO channel. */
1017 strncpy (device.string, nam.nam$l_dev, nam.nam$b_dev);
1018 devicedsc.dsc$w_length = nam.nam$b_dev;
1019 chan = 0;
1020 status = SYS$ASSIGN (&devicedsc, &chan, 0, 0, 0);
1021 if ((status & 1) != 1)
1022 LIB$SIGNAL (status);
1024 /* Initialize the FIB and fill in the directory id field. */
1025 memset (&fib, 0, sizeof (fib));
1026 fib.fib$w_did[0] = nam.nam$w_did[0];
1027 fib.fib$w_did[1] = nam.nam$w_did[1];
1028 fib.fib$w_did[2] = nam.nam$w_did[2];
1029 fib.fib$l_acctl = 0;
1030 fib.fib$l_wcc = 0;
1031 strcpy (file.string, (strrchr (result.string, ']') + 1));
1032 filedsc.dsc$w_length = strlen (file.string);
1033 result.string[result.length = 0] = 0;
1035 /* Open and close the file to fill in the attributes. */
1036 status
1037 = SYS$QIOW (0, chan, IO$_ACCESS|IO$M_ACCESS, &iosb, 0, 0,
1038 &fibdsc, &filedsc, &result.length, &resultdsc, &atrlst, 0);
1039 if ((status & 1) != 1)
1040 LIB$SIGNAL (status);
1041 if ((iosb.status & 1) != 1)
1042 LIB$SIGNAL (iosb.status);
1044 result.string[result.length] = 0;
1045 status = SYS$QIOW (0, chan, IO$_DEACCESS, &iosb, 0, 0, &fibdsc, 0, 0, 0,
1046 &atrlst, 0);
1047 if ((status & 1) != 1)
1048 LIB$SIGNAL (status);
1049 if ((iosb.status & 1) != 1)
1050 LIB$SIGNAL (iosb.status);
1053 time_t t;
1054 struct tm *ts;
1056 ts = localtime (&time_stamp);
1058 /* Set creation time to requested time. */
1059 unix_time_to_vms (time_stamp + ts->tm_gmtoff, newtime);
1061 t = time ((time_t) 0);
1062 ts = localtime (&t);
1064 /* Set revision time to now in local time. */
1065 unix_time_to_vms (t + ts->tm_gmtoff, revtime);
1068 /* Reopen the file, modify the times and then close. */
1069 fib.fib$l_acctl = FIB$M_WRITE;
1070 status
1071 = SYS$QIOW (0, chan, IO$_ACCESS|IO$M_ACCESS, &iosb, 0, 0,
1072 &fibdsc, &filedsc, &result.length, &resultdsc, &atrlst, 0);
1073 if ((status & 1) != 1)
1074 LIB$SIGNAL (status);
1075 if ((iosb.status & 1) != 1)
1076 LIB$SIGNAL (iosb.status);
1078 Fat.create = newtime;
1079 Fat.revise = revtime;
1081 status = SYS$QIOW (0, chan, IO$_DEACCESS, &iosb, 0, 0,
1082 &fibdsc, 0, 0, 0, &atrlst, 0);
1083 if ((status & 1) != 1)
1084 LIB$SIGNAL (status);
1085 if ((iosb.status & 1) != 1)
1086 LIB$SIGNAL (iosb.status);
1088 /* Deassign the channel and exit. */
1089 status = SYS$DASSGN (chan);
1090 if ((status & 1) != 1)
1091 LIB$SIGNAL (status);
1092 #else
1093 struct utimbuf utimbuf;
1094 time_t t;
1096 /* Set modification time to requested time. */
1097 utimbuf.modtime = time_stamp;
1099 /* Set access time to now in local time. */
1100 t = time ((time_t) 0);
1101 utimbuf.actime = mktime (localtime (&t));
1103 utime (name, &utimbuf);
1104 #endif
1107 void
1108 __gnat_get_env_value_ptr (name, len, value)
1109 char *name;
1110 int *len;
1111 char **value;
1113 *value = getenv (name);
1114 if (!*value)
1115 *len = 0;
1116 else
1117 *len = strlen (*value);
1119 return;
1122 /* VMS specific declarations for set_env_value. */
1124 #ifdef VMS
1126 static char *to_host_path_spec PARAMS ((char *));
1128 struct descriptor_s
1130 unsigned short len, mbz;
1131 char *adr;
1134 typedef struct _ile3
1136 unsigned short len, code;
1137 char *adr;
1138 unsigned short *retlen_adr;
1139 } ile_s;
1141 #endif
1143 void
1144 __gnat_set_env_value (name, value)
1145 char *name;
1146 char *value;
1148 #ifdef MSDOS
1150 #elif defined (VMS)
1151 struct descriptor_s name_desc;
1152 /* Put in JOB table for now, so that the project stuff at least works. */
1153 struct descriptor_s table_desc = {7, 0, "LNM$JOB"};
1154 char *host_pathspec = to_host_path_spec (value);
1155 char *copy_pathspec;
1156 int num_dirs_in_pathspec = 1;
1157 char *ptr;
1159 if (*host_pathspec == 0)
1160 return;
1162 name_desc.len = strlen (name);
1163 name_desc.mbz = 0;
1164 name_desc.adr = name;
1166 ptr = host_pathspec;
1167 while (*ptr++)
1168 if (*ptr == ',')
1169 num_dirs_in_pathspec++;
1172 int i, status;
1173 ile_s *ile_array = alloca (sizeof (ile_s) * (num_dirs_in_pathspec + 1));
1174 char *copy_pathspec = alloca (strlen (host_pathspec) + 1);
1175 char *curr, *next;
1177 strcpy (copy_pathspec, host_pathspec);
1178 curr = copy_pathspec;
1179 for (i = 0; i < num_dirs_in_pathspec; i++)
1181 next = strchr (curr, ',');
1182 if (next == 0)
1183 next = strchr (curr, 0);
1185 *next = 0;
1186 ile_array[i].len = strlen (curr);
1188 /* Code 2 from lnmdef.h means its a string. */
1189 ile_array[i].code = 2;
1190 ile_array[i].adr = curr;
1192 /* retlen_adr is ignored. */
1193 ile_array[i].retlen_adr = 0;
1194 curr = next + 1;
1197 /* Terminating item must be zero. */
1198 ile_array[i].len = 0;
1199 ile_array[i].code = 0;
1200 ile_array[i].adr = 0;
1201 ile_array[i].retlen_adr = 0;
1203 status = LIB$SET_LOGICAL (&name_desc, 0, &table_desc, 0, ile_array);
1204 if ((status & 1) != 1)
1205 LIB$SIGNAL (status);
1208 #else
1209 int size = strlen (name) + strlen (value) + 2;
1210 char *expression;
1212 expression = (char *) xmalloc (size * sizeof (char));
1214 sprintf (expression, "%s=%s", name, value);
1215 putenv (expression);
1216 #endif
1219 #ifdef _WIN32
1220 #include <windows.h>
1221 #endif
1223 /* Get the list of installed standard libraries from the
1224 HKEY_LOCAL_MACHINE\SOFTWARE\Ada Core Technologies\GNAT\Standard Libraries
1225 key. */
1227 char *
1228 __gnat_get_libraries_from_registry ()
1230 char *result = (char *) "";
1232 #if defined (_WIN32) && ! defined (__vxworks) && ! defined (CROSS_COMPILE)
1234 HKEY reg_key;
1235 DWORD name_size, value_size;
1236 char name[256];
1237 char value[256];
1238 DWORD type;
1239 DWORD index;
1240 LONG res;
1242 /* First open the key. */
1243 res = RegOpenKeyExA (HKEY_LOCAL_MACHINE, "SOFTWARE", 0, KEY_READ, &reg_key);
1245 if (res == ERROR_SUCCESS)
1246 res = RegOpenKeyExA (reg_key, "Ada Core Technologies", 0,
1247 KEY_READ, &reg_key);
1249 if (res == ERROR_SUCCESS)
1250 res = RegOpenKeyExA (reg_key, "GNAT", 0, KEY_READ, &reg_key);
1252 if (res == ERROR_SUCCESS)
1253 res = RegOpenKeyExA (reg_key, "Standard Libraries", 0, KEY_READ, &reg_key);
1255 /* If the key exists, read out all the values in it and concatenate them
1256 into a path. */
1257 for (index = 0; res == ERROR_SUCCESS; index++)
1259 value_size = name_size = 256;
1260 res = RegEnumValue (reg_key, index, name, &name_size, 0,
1261 &type, value, &value_size);
1263 if (res == ERROR_SUCCESS && type == REG_SZ)
1265 char *old_result = result;
1267 result = (char *) xmalloc (strlen (old_result) + value_size + 2);
1268 strcpy (result, old_result);
1269 strcat (result, value);
1270 strcat (result, ";");
1274 /* Remove the trailing ";". */
1275 if (result[0] != 0)
1276 result[strlen (result) - 1] = 0;
1278 #endif
1279 return result;
1283 __gnat_stat (name, statbuf)
1284 char *name;
1285 struct stat *statbuf;
1287 #ifdef _WIN32
1288 /* Under Windows the directory name for the stat function must not be
1289 terminated by a directory separator except if just after a drive name. */
1290 int name_len = strlen (name);
1291 char last_char = name[name_len - 1];
1292 char win32_name[4096];
1294 strcpy (win32_name, name);
1296 while (name_len > 1 && (last_char == '\\' || last_char == '/'))
1298 win32_name[name_len - 1] = '\0';
1299 name_len--;
1300 last_char = win32_name[name_len - 1];
1303 if (name_len == 2 && win32_name[1] == ':')
1304 strcat (win32_name, "\\");
1306 return stat (win32_name, statbuf);
1308 #else
1309 return stat (name, statbuf);
1310 #endif
1314 __gnat_file_exists (name)
1315 char *name;
1317 struct stat statbuf;
1319 return !__gnat_stat (name, &statbuf);
1322 int
1323 __gnat_is_absolute_path (name)
1324 char *name;
1326 return (*name == '/' || *name == DIR_SEPARATOR
1327 #if defined (__EMX__) || defined (MSDOS) || defined (WINNT)
1328 || strlen (name) > 1 && isalpha (name[0]) && name[1] == ':'
1329 #endif
1334 __gnat_is_regular_file (name)
1335 char *name;
1337 int ret;
1338 struct stat statbuf;
1340 ret = __gnat_stat (name, &statbuf);
1341 return (!ret && S_ISREG (statbuf.st_mode));
1345 __gnat_is_directory (name)
1346 char *name;
1348 int ret;
1349 struct stat statbuf;
1351 ret = __gnat_stat (name, &statbuf);
1352 return (!ret && S_ISDIR (statbuf.st_mode));
1356 __gnat_is_writable_file (name)
1357 char *name;
1359 int ret;
1360 int mode;
1361 struct stat statbuf;
1363 ret = __gnat_stat (name, &statbuf);
1364 mode = statbuf.st_mode & S_IWUSR;
1365 return (!ret && mode);
1368 #ifdef VMS
1369 /* Defined in VMS header files. */
1370 #define fork() (decc$$alloc_vfork_blocks() >= 0 ? \
1371 LIB$GET_CURRENT_INVO_CONTEXT (decc$$get_vfork_jmpbuf()) : -1)
1372 #endif
1374 #if defined (sun) && defined (__SVR4)
1375 /* Using fork on Solaris will duplicate all the threads. fork1, which
1376 duplicates only the active thread, must be used instead, or spawning
1377 subprocess from a program with tasking will lead into numerous problems. */
1378 #define fork fork1
1379 #endif
1382 __gnat_portable_spawn (args)
1383 char *args[];
1385 int status = 0;
1386 int finished;
1387 int pid;
1389 #if defined (MSDOS) || defined (_WIN32)
1390 status = spawnvp (P_WAIT, args[0], args);
1391 if (status < 0)
1392 return -1;
1393 else
1394 return status;
1396 #elif defined (__vxworks)
1397 return -1;
1398 #else
1400 #ifdef __EMX__
1401 pid = spawnvp (P_NOWAIT, args[0], args);
1402 if (pid == -1)
1403 return -1;
1405 #else
1406 pid = fork ();
1407 if (pid < 0)
1408 return -1;
1410 if (pid == 0)
1412 /* The child. */
1413 if (execv (args[0], args) != 0)
1414 #if defined (VMS)
1415 return -1; /* execv is in parent context on VMS. */
1416 #else
1417 _exit (1);
1418 #endif
1420 #endif
1422 /* The parent. */
1423 finished = waitpid (pid, &status, 0);
1425 if (finished != pid || WIFEXITED (status) == 0)
1426 return -1;
1428 return WEXITSTATUS (status);
1429 #endif
1431 return 0;
1434 /* WIN32 code to implement a wait call that wait for any child process. */
1436 #ifdef _WIN32
1438 /* Synchronization code, to be thread safe. */
1440 static CRITICAL_SECTION plist_cs;
1442 void
1443 __gnat_plist_init ()
1445 InitializeCriticalSection (&plist_cs);
1448 static void
1449 plist_enter ()
1451 EnterCriticalSection (&plist_cs);
1454 static void
1455 plist_leave ()
1457 LeaveCriticalSection (&plist_cs);
1460 typedef struct _process_list
1462 HANDLE h;
1463 struct _process_list *next;
1464 } Process_List;
1466 static Process_List *PLIST = NULL;
1468 static int plist_length = 0;
1470 static void
1471 add_handle (h)
1472 HANDLE h;
1474 Process_List *pl;
1476 pl = (Process_List *) xmalloc (sizeof (Process_List));
1478 plist_enter();
1480 /* -------------------- critical section -------------------- */
1481 pl->h = h;
1482 pl->next = PLIST;
1483 PLIST = pl;
1484 ++plist_length;
1485 /* -------------------- critical section -------------------- */
1487 plist_leave();
1490 void remove_handle (h)
1491 HANDLE h;
1493 Process_List *pl, *prev;
1495 plist_enter();
1497 /* -------------------- critical section -------------------- */
1498 pl = PLIST;
1499 while (pl)
1501 if (pl->h == h)
1503 if (pl == PLIST)
1504 PLIST = pl->next;
1505 else
1506 prev->next = pl->next;
1507 free (pl);
1508 break;
1510 else
1512 prev = pl;
1513 pl = pl->next;
1517 --plist_length;
1518 /* -------------------- critical section -------------------- */
1520 plist_leave();
1523 static int
1524 win32_no_block_spawn (command, args)
1525 char *command;
1526 char *args[];
1528 BOOL result;
1529 STARTUPINFO SI;
1530 PROCESS_INFORMATION PI;
1531 SECURITY_ATTRIBUTES SA;
1532 int csize = 1;
1533 char *full_command;
1534 int k;
1536 /* compute the total command line length */
1537 k = 0;
1538 while (args[k])
1540 csize += strlen (args[k]) + 1;
1541 k++;
1544 full_command = (char *) xmalloc (csize);
1546 /* Startup info. */
1547 SI.cb = sizeof (STARTUPINFO);
1548 SI.lpReserved = NULL;
1549 SI.lpReserved2 = NULL;
1550 SI.lpDesktop = NULL;
1551 SI.cbReserved2 = 0;
1552 SI.lpTitle = NULL;
1553 SI.dwFlags = 0;
1554 SI.wShowWindow = SW_HIDE;
1556 /* Security attributes. */
1557 SA.nLength = sizeof (SECURITY_ATTRIBUTES);
1558 SA.bInheritHandle = TRUE;
1559 SA.lpSecurityDescriptor = NULL;
1561 /* Prepare the command string. */
1562 strcpy (full_command, command);
1563 strcat (full_command, " ");
1565 k = 1;
1566 while (args[k])
1568 strcat (full_command, args[k]);
1569 strcat (full_command, " ");
1570 k++;
1573 result = CreateProcess (NULL, (char *) full_command, &SA, NULL, TRUE,
1574 NORMAL_PRIORITY_CLASS, NULL, NULL, &SI, &PI);
1576 free (full_command);
1578 if (result == TRUE)
1580 add_handle (PI.hProcess);
1581 CloseHandle (PI.hThread);
1582 return (int) PI.hProcess;
1584 else
1585 return -1;
1588 static int
1589 win32_wait (status)
1590 int *status;
1592 DWORD exitcode;
1593 HANDLE *hl;
1594 HANDLE h;
1595 DWORD res;
1596 int k;
1597 Process_List *pl;
1599 if (plist_length == 0)
1601 errno = ECHILD;
1602 return -1;
1605 hl = (HANDLE *) xmalloc (sizeof (HANDLE) * plist_length);
1607 k = 0;
1608 plist_enter();
1610 /* -------------------- critical section -------------------- */
1611 pl = PLIST;
1612 while (pl)
1614 hl[k++] = pl->h;
1615 pl = pl->next;
1617 /* -------------------- critical section -------------------- */
1619 plist_leave();
1621 res = WaitForMultipleObjects (plist_length, hl, FALSE, INFINITE);
1622 h = hl[res - WAIT_OBJECT_0];
1623 free (hl);
1625 remove_handle (h);
1627 GetExitCodeProcess (h, &exitcode);
1628 CloseHandle (h);
1630 *status = (int) exitcode;
1631 return (int) h;
1634 #endif
1637 __gnat_portable_no_block_spawn (args)
1638 char *args[];
1640 int pid = 0;
1642 #if defined (__EMX__) || defined (MSDOS)
1644 /* ??? For PC machines I (Franco) don't know the system calls to implement
1645 this routine. So I'll fake it as follows. This routine will behave
1646 exactly like the blocking portable_spawn and will systematically return
1647 a pid of 0 unless the spawned task did not complete successfully, in
1648 which case we return a pid of -1. To synchronize with this the
1649 portable_wait below systematically returns a pid of 0 and reports that
1650 the subprocess terminated successfully. */
1652 if (spawnvp (P_WAIT, args[0], args) != 0)
1653 return -1;
1655 #elif defined (_WIN32)
1657 pid = win32_no_block_spawn (args[0], args);
1658 return pid;
1660 #elif defined (__vxworks)
1661 return -1;
1663 #else
1664 pid = fork ();
1666 if (pid == 0)
1668 /* The child. */
1669 if (execv (args[0], args) != 0)
1670 #if defined (VMS)
1671 return -1; /* execv is in parent context on VMS. */
1672 #else
1673 _exit (1);
1674 #endif
1677 #endif
1679 return pid;
1683 __gnat_portable_wait (process_status)
1684 int *process_status;
1686 int status = 0;
1687 int pid = 0;
1689 #if defined (_WIN32)
1691 pid = win32_wait (&status);
1693 #elif defined (__EMX__) || defined (MSDOS)
1694 /* ??? See corresponding comment in portable_no_block_spawn. */
1696 #elif defined (__vxworks)
1697 /* Not sure what to do here, so do same as __EMX__ case, i.e., nothing but
1698 return zero. */
1699 #else
1701 pid = waitpid (-1, &status, 0);
1702 status = status & 0xffff;
1703 #endif
1705 *process_status = status;
1706 return pid;
1710 __gnat_waitpid (pid)
1711 int pid;
1713 int status = 0;
1715 #if defined (_WIN32)
1716 cwait (&status, pid, _WAIT_CHILD);
1717 #elif defined (__EMX__) || defined (MSDOS) || defined (__vxworks)
1718 /* Status is already zero, so nothing to do. */
1719 #else
1720 waitpid (pid, &status, 0);
1721 status = WEXITSTATUS (status);
1722 #endif
1724 return status;
1727 void
1728 __gnat_os_exit (status)
1729 int status;
1731 #ifdef VMS
1732 /* Exit without changing 0 to 1. */
1733 __posix_exit (status);
1734 #else
1735 exit (status);
1736 #endif
1739 /* Locate a regular file, give a Path value. */
1741 char *
1742 __gnat_locate_regular_file (file_name, path_val)
1743 char *file_name;
1744 char *path_val;
1746 char *ptr;
1748 /* Handle absolute pathnames. */
1749 for (ptr = file_name; *ptr && *ptr != '/' && *ptr != DIR_SEPARATOR; ptr++)
1752 if (*ptr != 0
1753 #if defined (__EMX__) || defined (MSDOS) || defined (WINNT)
1754 || isalpha (file_name[0]) && file_name[1] == ':'
1755 #endif
1758 if (__gnat_is_regular_file (file_name))
1759 return xstrdup (file_name);
1761 return 0;
1764 if (path_val == 0)
1765 return 0;
1768 /* The result has to be smaller than path_val + file_name. */
1769 char *file_path = alloca (strlen (path_val) + strlen (file_name) + 2);
1771 for (;;)
1773 for (; *path_val == PATH_SEPARATOR; path_val++)
1776 if (*path_val == 0)
1777 return 0;
1779 for (ptr = file_path; *path_val && *path_val != PATH_SEPARATOR; )
1780 *ptr++ = *path_val++;
1782 ptr--;
1783 if (*ptr != '/' && *ptr != DIR_SEPARATOR)
1784 *++ptr = DIR_SEPARATOR;
1786 strcpy (++ptr, file_name);
1788 if (__gnat_is_regular_file (file_path))
1789 return xstrdup (file_path);
1793 return 0;
1796 /* Locate an executable given a Path argument. This routine is only used by
1797 gnatbl and should not be used otherwise. Use locate_exec_on_path
1798 instead. */
1800 char *
1801 __gnat_locate_exec (exec_name, path_val)
1802 char *exec_name;
1803 char *path_val;
1805 if (!strstr (exec_name, HOST_EXECUTABLE_SUFFIX))
1807 char *full_exec_name
1808 = alloca (strlen (exec_name) + strlen (HOST_EXECUTABLE_SUFFIX) + 1);
1810 strcpy (full_exec_name, exec_name);
1811 strcat (full_exec_name, HOST_EXECUTABLE_SUFFIX);
1812 return __gnat_locate_regular_file (full_exec_name, path_val);
1814 else
1815 return __gnat_locate_regular_file (exec_name, path_val);
1818 /* Locate an executable using the Systems default PATH. */
1820 char *
1821 __gnat_locate_exec_on_path (exec_name)
1822 char *exec_name;
1824 #ifdef VMS
1825 char *path_val = "/VAXC$PATH";
1826 #else
1827 char *path_val = getenv ("PATH");
1828 #endif
1829 char *apath_val = alloca (strlen (path_val) + 1);
1831 strcpy (apath_val, path_val);
1832 return __gnat_locate_exec (exec_name, apath_val);
1835 #ifdef VMS
1837 /* These functions are used to translate to and from VMS and Unix syntax
1838 file, directory and path specifications. */
1840 #define MAXNAMES 256
1841 #define NEW_CANONICAL_FILELIST_INCREMENT 64
1843 static char new_canonical_dirspec[255];
1844 static char new_canonical_filespec[255];
1845 static char new_canonical_pathspec[MAXNAMES*255];
1846 static unsigned new_canonical_filelist_index;
1847 static unsigned new_canonical_filelist_in_use;
1848 static unsigned new_canonical_filelist_allocated;
1849 static char **new_canonical_filelist;
1850 static char new_host_pathspec[MAXNAMES*255];
1851 static char new_host_dirspec[255];
1852 static char new_host_filespec[255];
1854 /* Routine is called repeatedly by decc$from_vms via
1855 __gnat_to_canonical_file_list_init until it returns 0 or the expansion runs
1856 out. */
1858 static int
1859 wildcard_translate_unix (name)
1860 char *name;
1862 char *ver;
1863 char buff[256];
1865 strcpy (buff, name);
1866 ver = strrchr (buff, '.');
1868 /* Chop off the version. */
1869 if (ver)
1870 *ver = 0;
1872 /* Dynamically extend the allocation by the increment. */
1873 if (new_canonical_filelist_in_use == new_canonical_filelist_allocated)
1875 new_canonical_filelist_allocated += NEW_CANONICAL_FILELIST_INCREMENT;
1876 new_canonical_filelist = (char **) xrealloc
1877 (new_canonical_filelist,
1878 new_canonical_filelist_allocated * sizeof (char *));
1881 new_canonical_filelist[new_canonical_filelist_in_use++] = xstrdup (buff);
1883 return 1;
1886 /* Translate a wildcard VMS file spec into a list of Unix file specs. First do
1887 full translation and copy the results into a list (_init), then return them
1888 one at a time (_next). If onlydirs set, only expand directory files. */
1891 __gnat_to_canonical_file_list_init (filespec, onlydirs)
1892 char *filespec;
1893 int onlydirs;
1895 int len;
1896 char buff[256];
1898 len = strlen (filespec);
1899 strcpy (buff, filespec);
1901 /* Only look for directories. */
1902 if (onlydirs && !strstr (&buff[len - 5], "*.dir"))
1903 strcat (buff, "*.dir");
1905 decc$from_vms (buff, wildcard_translate_unix, 1);
1907 /* Remove the .dir extension. */
1908 if (onlydirs)
1910 int i;
1911 char *ext;
1913 for (i = 0; i < new_canonical_filelist_in_use; i++)
1915 ext = strstr (new_canonical_filelist[i], ".dir");
1916 if (ext)
1917 *ext = 0;
1921 return new_canonical_filelist_in_use;
1924 /* Return the next filespec in the list. */
1926 char *
1927 __gnat_to_canonical_file_list_next ()
1929 return new_canonical_filelist[new_canonical_filelist_index++];
1932 /* Free storage used in the wildcard expansion. */
1934 void
1935 __gnat_to_canonical_file_list_free ()
1937 int i;
1939 for (i = 0; i < new_canonical_filelist_in_use; i++)
1940 free (new_canonical_filelist[i]);
1942 free (new_canonical_filelist);
1944 new_canonical_filelist_in_use = 0;
1945 new_canonical_filelist_allocated = 0;
1946 new_canonical_filelist_index = 0;
1947 new_canonical_filelist = 0;
1950 /* Translate a VMS syntax directory specification in to Unix syntax. If
1951 PREFIXFLAG is set, append an underscore "/". If no indicators of VMS syntax
1952 found, return input string. Also translate a dirname that contains no
1953 slashes, in case it's a logical name. */
1955 char *
1956 __gnat_to_canonical_dir_spec (dirspec, prefixflag)
1957 char *dirspec;
1958 int prefixflag;
1960 int len;
1962 strcpy (new_canonical_dirspec, "");
1963 if (strlen (dirspec))
1965 char *dirspec1;
1967 if (strchr (dirspec, ']') || strchr (dirspec, ':'))
1968 strcpy (new_canonical_dirspec, (char *) decc$translate_vms (dirspec));
1969 else if (!strchr (dirspec, '/') && (dirspec1 = getenv (dirspec)) != 0)
1970 strcpy (new_canonical_dirspec, (char *) decc$translate_vms (dirspec1));
1971 else
1972 strcpy (new_canonical_dirspec, dirspec);
1975 len = strlen (new_canonical_dirspec);
1976 if (prefixflag && new_canonical_dirspec[len - 1] != '/')
1977 strcat (new_canonical_dirspec, "/");
1979 return new_canonical_dirspec;
1983 /* Translate a VMS syntax file specification into Unix syntax.
1984 If no indicators of VMS syntax found, return input string. */
1986 char *
1987 __gnat_to_canonical_file_spec (filespec)
1988 char *filespec;
1990 strcpy (new_canonical_filespec, "");
1991 if (strchr (filespec, ']') || strchr (filespec, ':'))
1992 strcpy (new_canonical_filespec, (char *) decc$translate_vms (filespec));
1993 else
1994 strcpy (new_canonical_filespec, filespec);
1996 return new_canonical_filespec;
1999 /* Translate a VMS syntax path specification into Unix syntax.
2000 If no indicators of VMS syntax found, return input string. */
2002 char *
2003 __gnat_to_canonical_path_spec (pathspec)
2004 char *pathspec;
2006 char *curr, *next, buff[256];
2008 if (pathspec == 0)
2009 return pathspec;
2011 /* If there are /'s, assume it's a Unix path spec and return. */
2012 if (strchr (pathspec, '/'))
2013 return pathspec;
2015 new_canonical_pathspec[0] = 0;
2016 curr = pathspec;
2018 for (;;)
2020 next = strchr (curr, ',');
2021 if (next == 0)
2022 next = strchr (curr, 0);
2024 strncpy (buff, curr, next - curr);
2025 buff[next - curr] = 0;
2027 /* Check for wildcards and expand if present. */
2028 if (strchr (buff, '*') || strchr (buff, '%') || strstr (buff, "..."))
2030 int i, dirs;
2032 dirs = __gnat_to_canonical_file_list_init (buff, 1);
2033 for (i = 0; i < dirs; i++)
2035 char *next_dir;
2037 next_dir = __gnat_to_canonical_file_list_next ();
2038 strcat (new_canonical_pathspec, next_dir);
2040 /* Don't append the separator after the last expansion. */
2041 if (i+1 < dirs)
2042 strcat (new_canonical_pathspec, ":");
2045 __gnat_to_canonical_file_list_free ();
2047 else
2048 strcat (new_canonical_pathspec,
2049 __gnat_to_canonical_dir_spec (buff, 0));
2051 if (*next == 0)
2052 break;
2054 strcat (new_canonical_pathspec, ":");
2055 curr = next + 1;
2058 return new_canonical_pathspec;
2061 static char filename_buff[256];
2063 static int
2064 translate_unix (name, type)
2065 char *name;
2066 int type;
2068 strcpy (filename_buff, name);
2069 return 0;
2072 /* Translate a Unix syntax path spec into a VMS style (comma separated list of
2073 directories. */
2075 static char *
2076 to_host_path_spec (pathspec)
2077 char *pathspec;
2079 char *curr, *next, buff[256];
2081 if (pathspec == 0)
2082 return pathspec;
2084 /* Can't very well test for colons, since that's the Unix separator! */
2085 if (strchr (pathspec, ']') || strchr (pathspec, ','))
2086 return pathspec;
2088 new_host_pathspec[0] = 0;
2089 curr = pathspec;
2091 for (;;)
2093 next = strchr (curr, ':');
2094 if (next == 0)
2095 next = strchr (curr, 0);
2097 strncpy (buff, curr, next - curr);
2098 buff[next - curr] = 0;
2100 strcat (new_host_pathspec, __gnat_to_host_dir_spec (buff, 0));
2101 if (*next == 0)
2102 break;
2103 strcat (new_host_pathspec, ",");
2104 curr = next + 1;
2107 return new_host_pathspec;
2110 /* Translate a Unix syntax directory specification into VMS syntax. The
2111 PREFIXFLAG has no effect, but is kept for symmetry with
2112 to_canonical_dir_spec. If indicators of VMS syntax found, return input
2113 string. */
2115 char *
2116 __gnat_to_host_dir_spec (dirspec, prefixflag)
2117 char *dirspec;
2118 int prefixflag ATTRIBUTE_UNUSED;
2120 int len = strlen (dirspec);
2122 strcpy (new_host_dirspec, dirspec);
2124 if (strchr (new_host_dirspec, ']') || strchr (new_host_dirspec, ':'))
2125 return new_host_dirspec;
2127 while (len > 1 && new_host_dirspec[len - 1] == '/')
2129 new_host_dirspec[len - 1] = 0;
2130 len--;
2133 decc$to_vms (new_host_dirspec, translate_unix, 1, 2);
2134 strcpy (new_host_dirspec, filename_buff);
2136 return new_host_dirspec;
2140 /* Translate a Unix syntax file specification into VMS syntax.
2141 If indicators of VMS syntax found, return input string. */
2143 char *
2144 __gnat_to_host_file_spec (filespec)
2145 char *filespec;
2147 strcpy (new_host_filespec, "");
2148 if (strchr (filespec, ']') || strchr (filespec, ':'))
2149 strcpy (new_host_filespec, filespec);
2150 else
2152 decc$to_vms (filespec, translate_unix, 1, 1);
2153 strcpy (new_host_filespec, filename_buff);
2156 return new_host_filespec;
2159 void
2160 __gnat_adjust_os_resource_limits ()
2162 SYS$ADJWSL (131072, 0);
2165 #else
2167 /* Dummy functions for Osint import for non-VMS systems. */
2170 __gnat_to_canonical_file_list_init (dirspec, onlydirs)
2171 char *dirspec ATTRIBUTE_UNUSED;
2172 int onlydirs ATTRIBUTE_UNUSED;
2174 return 0;
2177 char *
2178 __gnat_to_canonical_file_list_next ()
2180 return (char *) "";
2183 void
2184 __gnat_to_canonical_file_list_free ()
2188 char *
2189 __gnat_to_canonical_dir_spec (dirspec, prefixflag)
2190 char *dirspec;
2191 int prefixflag ATTRIBUTE_UNUSED;
2193 return dirspec;
2196 char *
2197 __gnat_to_canonical_file_spec (filespec)
2198 char *filespec;
2200 return filespec;
2203 char *
2204 __gnat_to_canonical_path_spec (pathspec)
2205 char *pathspec;
2207 return pathspec;
2210 char *
2211 __gnat_to_host_dir_spec (dirspec, prefixflag)
2212 char *dirspec;
2213 int prefixflag ATTRIBUTE_UNUSED;
2215 return dirspec;
2218 char *
2219 __gnat_to_host_file_spec (filespec)
2220 char *filespec;
2222 return filespec;
2225 void
2226 __gnat_adjust_os_resource_limits ()
2230 #endif
2232 /* For EMX, we cannot include dummy in libgcc, since it is too difficult
2233 to coordinate this with the EMX distribution. Consequently, we put the
2234 definition of dummy which is used for exception handling, here. */
2236 #if defined (__EMX__)
2237 void __dummy () {}
2238 #endif
2240 #if defined (__mips_vxworks)
2241 int _flush_cache()
2243 CACHE_USER_FLUSH (0, ENTIRE_CACHE);
2245 #endif
2247 #if defined (CROSS_COMPILE) \
2248 || (! (defined (sparc) && defined (sun) && defined (__SVR4)) \
2249 && ! defined (linux) \
2250 && ! defined (hpux) \
2251 && ! (defined (__alpha__) && defined (__osf__)) \
2252 && ! defined (__MINGW32__))
2254 /* Dummy function to satisfy g-trasym.o. Currently Solaris sparc, HP/UX,
2255 GNU/Linux, Tru64 & Windows provide a non-dummy version of this procedure in
2256 libaddr2line.a. */
2258 void
2259 convert_addresses (addrs, n_addr, buf, len)
2260 char *addrs[] ATTRIBUTE_UNUSED;
2261 int n_addr ATTRIBUTE_UNUSED;
2262 void *buf ATTRIBUTE_UNUSED;
2263 int *len;
2265 *len = 0;
2267 #endif
2269 #if defined (_WIN32)
2270 int __gnat_argument_needs_quote = 1;
2271 #else
2272 int __gnat_argument_needs_quote = 0;
2273 #endif