OSDN Git Service

2011-10-13 Robert Dewar <dewar@adacore.com>
[pf3gnuchains/gcc-fork.git] / gcc / ada / sysdep.c
1 /****************************************************************************
2  *                                                                          *
3  *                         GNAT COMPILER COMPONENTS                         *
4  *                                                                          *
5  *                                S Y S D E P                               *
6  *                                                                          *
7  *                          C Implementation File                           *
8  *                                                                          *
9  *         Copyright (C) 1992-2011, Free Software Foundation, Inc.          *
10  *                                                                          *
11  * GNAT is free software;  you can  redistribute it  and/or modify it under *
12  * terms of the  GNU General Public License as published  by the Free Soft- *
13  * ware  Foundation;  either version 3,  or (at your option) any later ver- *
14  * sion.  GNAT is distributed in the hope that it will be useful, but WITH- *
15  * OUT ANY WARRANTY;  without even the  implied warranty of MERCHANTABILITY *
16  * or FITNESS FOR A PARTICULAR PURPOSE.                                     *
17  *                                                                          *
18  * As a special exception under Section 7 of GPL version 3, you are granted *
19  * additional permissions described in the GCC Runtime Library Exception,   *
20  * version 3.1, as published by the Free Software Foundation.               *
21  *                                                                          *
22  * You should have received a copy of the GNU General Public License and    *
23  * a copy of the GCC Runtime Library Exception along with this program;     *
24  * see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see    *
25  * <http://www.gnu.org/licenses/>.                                          *
26  *                                                                          *
27  * GNAT was originally developed  by the GNAT team at  New York University. *
28  * Extensive contributions were provided by Ada Core Technologies Inc.      *
29  *                                                                          *
30  ****************************************************************************/
31
32 /* This file contains system dependent symbols that are referenced in the
33    GNAT Run Time Library */
34
35 #ifdef __vxworks
36 #include "ioLib.h"
37 #if ! defined (VTHREADS)
38 #include "dosFsLib.h"
39 #endif
40 #if ! defined (__RTP__) && (! defined (VTHREADS) || defined (__VXWORKSMILS__))
41 # include "nfsLib.h"
42 #endif
43 #include "selectLib.h"
44 #include "vxWorks.h"
45 #endif
46
47 #ifdef IN_RTS
48 #define POSIX
49 #include "tconfig.h"
50 #include "tsystem.h"
51 #include <fcntl.h>
52 #include <sys/stat.h>
53 #ifdef VMS
54 #include <unixio.h>
55 #endif
56 #else
57 #include "config.h"
58 #include "system.h"
59 #endif
60
61 #include <time.h>
62 #include <errno.h>
63
64 #if defined (sun) && defined (__SVR4) && !defined (__vxworks)
65 /* The declaration is present in <time.h> but conditionalized
66    on a couple of macros we don't define.  */
67 extern struct tm *localtime_r(const time_t *, struct tm *);
68 #endif
69
70 #include "adaint.h"
71
72 /* Don't use macros versions of this functions on VxWorks since they cause
73    imcompatible changes in some VxWorks versions */
74 #ifdef __vxworks
75 #undef getchar
76 #undef putchar
77 #undef feof
78 #undef ferror
79 #undef fileno
80 #endif
81
82 /*
83    mode_read_text
84    open text file for reading
85    rt for DOS and Windows NT, r for Unix
86
87    mode_write_text
88    truncate to zero length or create text file for writing
89    wt for DOS and Windows NT, w for Unix
90
91    mode_append_text
92    append; open or create text file for writing at end-of-file
93    at for DOS and Windows NT, a for Unix
94
95    mode_read_binary
96    open binary file for reading
97    rb for DOS and Windows NT, r for Unix
98
99    mode_write_binary
100    truncate to zero length or create binary file for writing
101    wb for DOS and Windows NT, w for Unix
102
103    mode_append_binary
104    append; open or create binary file for writing at end-of-file
105    ab for DOS and Windows NT, a for Unix
106
107    mode_read_text_plus
108    open text file for update (reading and writing)
109    r+t for DOS and Windows NT, r+ for Unix
110
111    mode_write_text_plus
112    truncate to zero length or create text file for update
113    w+t for DOS and Windows NT, w+ for Unix
114
115    mode_append_text_plus
116    append; open or create text file for update, writing at end-of-file
117    a+t for DOS and Windows NT, a+ for Unix
118
119    mode_read_binary_plus
120    open binary file for update (reading and writing)
121    r+b for DOS and Windows NT, r+ for Unix
122
123    mode_write_binary_plus
124    truncate to zero length or create binary file for update
125    w+b for DOS and Windows NT, w+ for Unix
126
127    mode_append_binary_plus
128    append; open or create binary file for update, writing at end-of-file
129    a+b for DOS and Windows NT, a+ for Unix
130
131    Notes:
132
133    (1) Opening a file with read mode fails if the file does not exist or
134    cannot be read.
135
136    (2) Opening a file with append mode causes all subsequent writes to the
137    file to be forced to the then current end-of-file, regardless of
138    intervening calls to the fseek function.
139
140    (3) When a file is opened with update mode, both input and output may be
141    performed on the associated stream.  However, output may not be directly
142    followed by input without an intervening call to the fflush function or
143    to a file positioning function (fseek, fsetpos, or rewind), and input
144    may not be directly followed by output without an intervening call to a
145    file positioning function, unless the input operation encounters
146    end-of-file.
147
148    The other target dependent declarations here are for the two functions
149    __gnat_set_binary_mode and __gnat_set_text_mode:
150
151       void __gnat_set_binary_mode (int handle);
152       void __gnat_set_text_mode   (int handle);
153
154    These functions have no effect in Unix (or similar systems where there is
155    no distinction between binary and text files), but in DOS (and similar
156    systems where text mode does CR/LF translation), these functions allow
157    the mode of the stream with the given handle (fileno can be used to get
158    the handle of a stream) to be changed dynamically. The returned result
159    is 0 if no error occurs and -1 if an error occurs.
160
161    Finally there is a boolean (character) variable
162
163       char __gnat_text_translation_required;
164
165    which is zero (false) in Unix mode, and one (true) in DOS mode, with a
166    true value indicating that text translation is required on text files
167    and that fopen supports the trailing t and b modifiers.
168
169 */
170
171 #if defined(WINNT)
172 static const char *mode_read_text = "rt";
173 static const char *mode_write_text = "wt";
174 static const char *mode_append_text = "at";
175 static const char *mode_read_binary = "rb";
176 static const char *mode_write_binary = "wb";
177 static const char *mode_append_binary = "ab";
178 static const char *mode_read_text_plus = "r+t";
179 static const char *mode_write_text_plus = "w+t";
180 static const char *mode_append_text_plus = "a+t";
181 static const char *mode_read_binary_plus = "r+b";
182 static const char *mode_write_binary_plus = "w+b";
183 static const char *mode_append_binary_plus = "a+b";
184 const char __gnat_text_translation_required = 1;
185
186 void
187 __gnat_set_binary_mode (int handle)
188 {
189   _setmode (handle, O_BINARY);
190 }
191
192 void
193 __gnat_set_text_mode (int handle)
194 {
195   _setmode (handle, O_TEXT);
196 }
197
198 #ifdef __MINGW32__
199 #include <windows.h>
200
201 /* Return the name of the tty.   Under windows there is no name for
202    the tty, so this function, if connected to a tty, returns the generic name
203    "console".  */
204
205 char *
206 __gnat_ttyname (int filedes)
207 {
208   if (isatty (filedes))
209     return "console";
210   else
211     return NULL;
212 }
213
214 #ifndef RTX
215
216 int __gnat_is_windows_xp (void);
217
218 int
219 __gnat_is_windows_xp (void)
220 {
221   static int is_win_xp=0, is_win_xp_checked=0;
222
223   if (!is_win_xp_checked)
224     {
225       OSVERSIONINFO version;
226
227       is_win_xp_checked = 1;
228
229       memset (&version, 0, sizeof (version));
230       version.dwOSVersionInfoSize = sizeof (version);
231
232       is_win_xp = GetVersionEx (&version)
233         && version.dwPlatformId == VER_PLATFORM_WIN32_NT
234         && (version.dwMajorVersion > 5
235             || (version.dwMajorVersion == 5 && version.dwMinorVersion >= 1));
236     }
237   return is_win_xp;
238 }
239
240 #endif
241
242 /* Get the bounds of the stack.  The stack pointer is supposed to be
243    initialized to BASE when a thread is created and the stack can be extended
244    to LIMIT before reaching a guard page.
245    Note: for the main thread, the system automatically extend the stack, so
246    LIMIT is only the current limit.  */
247
248 void
249 __gnat_get_stack_bounds (void **base, void **limit)
250 {
251   NT_TIB *tib;
252
253   /* We know that the first field of the TEB is the TIB.  */
254   tib = (NT_TIB *)NtCurrentTeb ();
255
256   *base = tib->StackBase;
257   *limit = tib->StackLimit;
258 }
259
260 #endif /* !__MINGW32__ */
261
262 #else
263
264 static const char *mode_read_text = "r";
265 static const char *mode_write_text = "w";
266 static const char *mode_append_text = "a";
267 static const char *mode_read_binary = "r";
268 static const char *mode_write_binary = "w";
269 static const char *mode_append_binary = "a";
270 static const char *mode_read_text_plus = "r+";
271 static const char *mode_write_text_plus = "w+";
272 static const char *mode_append_text_plus = "a+";
273 static const char *mode_read_binary_plus = "r+";
274 static const char *mode_write_binary_plus = "w+";
275 static const char *mode_append_binary_plus = "a+";
276 const char __gnat_text_translation_required = 0;
277
278 /* These functions do nothing in non-DOS systems. */
279
280 void
281 __gnat_set_binary_mode (int handle ATTRIBUTE_UNUSED)
282 {
283 }
284
285 void
286 __gnat_set_text_mode (int handle ATTRIBUTE_UNUSED)
287 {
288 }
289 char *
290 __gnat_ttyname (int filedes)
291 {
292 #if defined (__vxworks) || defined (__nucleus)
293   return "";
294 #else
295   extern char *ttyname (int);
296
297   return ttyname (filedes);
298 #endif /* defined (__vxworks) || defined (__nucleus) */
299 }
300 #endif
301 \f
302 #if defined (linux) || defined (sun) || defined (sgi) \
303   || (defined (__osf__) && ! defined (__alpha_vxworks)) || defined (WINNT) \
304   || defined (__MACHTEN__) || defined (__hpux__) || defined (_AIX) \
305   || (defined (__svr4__) && defined (i386)) || defined (__Lynx__) \
306   || defined (__CYGWIN__) || defined (__FreeBSD__) || defined (__OpenBSD__) \
307   || defined (__GLIBC__) || defined (__APPLE__)
308
309 #ifdef __MINGW32__
310 #if OLD_MINGW
311 #include <termios.h>
312 #else
313 #include <conio.h>  /* for getch(), kbhit() */
314 #endif
315 #else
316 #include <termios.h>
317 #endif
318
319 #else
320 #if defined (VMS)
321 extern char *decc$ga_stdscr;
322 static int initted = 0;
323 #endif
324 #endif
325
326 /* Implements the common processing for getc_immediate and
327    getc_immediate_nowait. */
328
329 extern void getc_immediate (FILE *, int *, int *);
330 extern void getc_immediate_nowait (FILE *, int *, int *, int *);
331 extern void getc_immediate_common (FILE *, int *, int *, int *, int);
332
333 /* Called by Get_Immediate (Foo); */
334
335 void
336 getc_immediate (FILE *stream, int *ch, int *end_of_file)
337 {
338   int avail;
339
340   getc_immediate_common (stream, ch, end_of_file, &avail, 1);
341 }
342
343 /* Called by Get_Immediate (Foo, Available); */
344
345 void
346 getc_immediate_nowait (FILE *stream, int *ch, int *end_of_file, int *avail)
347 {
348   getc_immediate_common (stream, ch, end_of_file, avail, 0);
349 }
350
351 /* Called by getc_immediate () and getc_immediate_nowait () */
352
353 void
354 getc_immediate_common (FILE *stream,
355                        int *ch,
356                        int *end_of_file,
357                        int *avail,
358                        int waiting)
359 {
360 #if defined (linux) || defined (sun) || defined (sgi) \
361     || (defined (__osf__) && ! defined (__alpha_vxworks)) \
362     || defined (__CYGWIN32__) || defined (__MACHTEN__) || defined (__hpux__) \
363     || defined (_AIX) || (defined (__svr4__) && defined (i386)) \
364     || defined (__Lynx__) || defined (__FreeBSD__) || defined (__OpenBSD__) \
365     || defined (__GLIBC__) || defined (__APPLE__)
366   char c;
367   int nread;
368   int good_one = 0;
369   int eof_ch = 4; /* Ctrl-D */
370   int fd = fileno (stream);
371   struct termios otermios_rec, termios_rec;
372
373   if (isatty (fd))
374     {
375       tcgetattr (fd, &termios_rec);
376       memcpy (&otermios_rec, &termios_rec, sizeof (struct termios));
377
378       /* Set RAW mode, with no echo */
379       termios_rec.c_lflag = termios_rec.c_lflag & ~ICANON & ~ECHO;
380
381 #if defined(linux) || defined (sun) || defined (sgi) \
382     || defined (__osf__) || defined (__MACHTEN__) || defined (__hpux__) \
383     || defined (_AIX) || (defined (__svr4__) && defined (i386)) \
384     || defined (__Lynx__) || defined (__FreeBSD__) || defined (__OpenBSD__) \
385     || defined (__GLIBC__) || defined (__APPLE__)
386       eof_ch = termios_rec.c_cc[VEOF];
387
388       /* If waiting (i.e. Get_Immediate (Char)), set MIN = 1 and wait for
389          a character forever. This doesn't seem to effect Ctrl-Z or
390          Ctrl-C processing.
391          If not waiting (i.e. Get_Immediate (Char, Available)),
392          don't wait for anything but timeout immediately. */
393       termios_rec.c_cc[VMIN] = waiting;
394       termios_rec.c_cc[VTIME] = 0;
395 #endif
396       tcsetattr (fd, TCSANOW, &termios_rec);
397
398       while (! good_one)
399         {
400           /* Read is used here instead of fread, because fread doesn't
401              work on Solaris5 and Sunos4 in this situation.  Maybe because we
402              are mixing calls that use file descriptors and streams. */
403           nread = read (fd, &c, 1);
404           if (nread > 0)
405             {
406               /* On Unix terminals, Ctrl-D (EOT) is an End of File. */
407               if (c == eof_ch)
408                 {
409                   *avail = 0;
410                   *end_of_file = 1;
411                   good_one = 1;
412                 }
413
414               /* Everything else is ok */
415               else if (c != eof_ch)
416                 {
417                   *avail = 1;
418                   *end_of_file = 0;
419                   good_one = 1;
420                 }
421             }
422
423           else if (! waiting)
424             {
425               *avail = 0;
426               *end_of_file = 0;
427               good_one = 1;
428             }
429           else
430             good_one = 0;
431         }
432
433       tcsetattr (fd, TCSANOW, &otermios_rec);
434       *ch = c;
435     }
436
437   else
438 #elif defined (VMS)
439   int fd = fileno (stream);
440
441   if (isatty (fd))
442     {
443       if (initted == 0)
444         {
445           decc$bsd_initscr ();
446           initted = 1;
447         }
448
449       decc$bsd_cbreak ();
450       *ch = decc$bsd_wgetch (decc$ga_stdscr);
451
452       if (*ch == 4)
453         *end_of_file = 1;
454       else
455         *end_of_file = 0;
456
457       *avail = 1;
458       decc$bsd_nocbreak ();
459     }
460   else
461 #elif defined (__MINGW32__)
462   int fd = fileno (stream);
463   int char_waiting;
464   int eot_ch = 4; /* Ctrl-D */
465
466   if (isatty (fd))
467     {
468       if (waiting)
469         {
470           *ch = getch ();
471
472           if (*ch == eot_ch)
473             *end_of_file = 1;
474           else
475             *end_of_file = 0;
476
477           *avail = 1;
478         }
479       else /* ! waiting */
480         {
481           char_waiting = kbhit();
482
483           if (char_waiting == 1)
484             {
485               *avail = 1;
486               *ch = getch ();
487
488               if (*ch == eot_ch)
489                 *end_of_file = 1;
490               else
491                 *end_of_file = 0;
492             }
493           else
494             {
495               *avail = 0;
496               *end_of_file = 0;
497             }
498         }
499     }
500   else
501 #elif defined (__vxworks)
502   /* Bit masks of file descriptors to read from.  */
503   struct fd_set readFds;
504   /* Timeout before select returns if nothing can be read.  */
505   struct timeval timeOut;
506   char c;
507   int fd = fileno (stream);
508   int nread;
509   int option;
510   int readable;
511   int status;
512   int width;
513
514   if (isatty (fd))
515     {
516       /* If we do not want to wait, we have to set up fd in RAW mode. This
517          should be done outside this function as setting fd in RAW mode under
518          vxWorks flushes the buffer of fd. If the RAW mode was set here, the
519          buffer would be empty and we would always return that no character
520          is available */
521       if (! waiting)
522         {
523           /* Initialization of timeOut for its use with select.  */
524           timeOut.tv_sec  = 0;
525           timeOut.tv_usec = 0;
526
527           /* Initialization of readFds for its use with select;
528              FD is the only file descriptor to be monitored */
529           FD_ZERO (&readFds);
530           FD_SET (fd, &readFds);
531           width = 2;
532
533           /* We do all this processing to emulate a non blocking read.  */
534           readable = select (width, &readFds, NULL, NULL, &timeOut);
535           if (readable == ERROR)
536             *avail = -1, *end_of_file = -1;
537           /* No character available in input.  */
538           else if (readable == 0)
539             *avail = 0, *end_of_file = 0;
540           else
541             {
542               nread = read (fd, &c, 1);
543               if (nread > 0)
544                 *avail = 1, *end_of_file = 0;
545               /* End Of File. */
546               else if (nread == 0)
547                 *avail = 0, *end_of_file = 1;
548               /* Error.  */
549               else
550                 *avail = -1, *end_of_file = -1;
551             }
552         }
553
554       /* We have to wait until we get a character */
555       else
556         {
557           *avail = -1;
558           *end_of_file = -1;
559
560           /* Save the current mode of FD.  */
561           option = ioctl (fd, FIOGETOPTIONS, 0);
562
563           /* Set FD in RAW mode.  */
564           status = ioctl (fd, FIOSETOPTIONS, OPT_RAW);
565           if (status != -1)
566             {
567               nread = read (fd, &c, 1);
568               if (nread > 0)
569                 *avail = 1, *end_of_file = 0;
570               /* End of file.  */
571               else if (nread == 0)
572                 *avail = 0, *end_of_file = 1;
573               /* Else there is an ERROR.  */
574             }
575
576           /* Revert FD to its previous mode. */
577           status = ioctl (fd, FIOSETOPTIONS, option);
578         }
579
580       *ch = c;
581     }
582   else
583 #endif
584     {
585       /* If we're not on a terminal, then we don't need any fancy processing.
586          Also this is the only thing that's left if we're not on one of the
587          supported systems; which means that for non supported systems,
588          get_immediate may wait for a carriage return on terminals. */
589       *ch = fgetc (stream);
590       if (feof (stream))
591         {
592           *end_of_file = 1;
593           *avail = 0;
594         }
595       else
596         {
597           *end_of_file = 0;
598           *avail = 1;
599         }
600     }
601 }
602
603 /* The following definitions are provided in NT to support Windows based
604    Ada programs.  */
605
606 #ifdef WINNT
607 #include <windows.h>
608
609 /* Provide functions to echo the values passed to WinMain (windows bindings
610    will want to import these).  We use the same names as the routines used
611    by AdaMagic for compatibility.  */
612
613 char *rts_get_hInstance (void);
614 char *rts_get_hPrevInstance (void);
615 char *rts_get_lpCommandLine (void);
616 int   rts_get_nShowCmd (void);
617
618 char *
619 rts_get_hInstance (void)
620 {
621   return (char *)GetModuleHandleA (0);
622 }
623
624 char *
625 rts_get_hPrevInstance (void)
626 {
627   return 0;
628 }
629
630 char *
631 rts_get_lpCommandLine (void)
632 {
633   return GetCommandLineA ();
634 }
635
636 int
637 rts_get_nShowCmd (void)
638 {
639   return 1;
640 }
641
642 #endif /* WINNT */
643 #ifdef VMS
644
645 /* This gets around a problem with using the old threads library on VMS 7.0. */
646
647 extern long get_gmtoff (void);
648
649 long
650 get_gmtoff (void)
651 {
652   time_t t;
653   struct tm *ts;
654
655   t = time ((time_t) 0);
656   ts = localtime (&t);
657   return ts->tm_gmtoff;
658 }
659 #endif
660
661 /* This value is returned as the time zone offset when a valid value
662    cannot be determined. It is simply a bizarre value that will never
663    occur. It is 3 days plus 73 seconds (offset is in seconds). */
664
665 long __gnat_invalid_tzoff = 259273;
666
667 /* Definition of __gnat_localtime_r used by a-calend.adb */
668
669 #if defined (__MINGW32__)
670
671 #ifdef CERT
672
673 /* For the Cert run times on native Windows we use dummy functions
674    for locking and unlocking tasks since we do not support multiple
675    threads on this configuration (Cert run time on native Windows). */
676
677 void dummy (void) {}
678
679 void (*Lock_Task) ()   = &dummy;
680 void (*Unlock_Task) () = &dummy;
681
682 #else
683
684 #define Lock_Task system__soft_links__lock_task
685 extern void (*Lock_Task) (void);
686
687 #define Unlock_Task system__soft_links__unlock_task
688 extern void (*Unlock_Task) (void);
689
690 #endif
691
692 /* Reentrant localtime for Windows. */
693
694 extern void
695 __gnat_localtime_tzoff (const time_t *, long *);
696
697 static const unsigned long long w32_epoch_offset = 11644473600ULL;
698 void
699 __gnat_localtime_tzoff (const time_t *timer, long *off)
700 {
701   union
702   {
703     FILETIME ft_time;
704     unsigned long long ull_time;
705   } utc_time, local_time;
706
707   SYSTEMTIME utc_sys_time, local_sys_time;
708   TIME_ZONE_INFORMATION tzi;
709
710   BOOL  status = 1;
711   DWORD tzi_status;
712
713   (*Lock_Task) ();
714
715 #ifdef RTX
716
717   tzi_status = GetTimeZoneInformation (&tzi);
718   *off = tzi.Bias;
719   if (tzi_status == TIME_ZONE_ID_STANDARD)
720      /* The system is operating in the range covered by the StandardDate
721         member. */
722      *off = *off + tzi.StandardBias;
723   else if (tzi_status == TIME_ZONE_ID_DAYLIGHT)
724      /* The system is operating in the range covered by the DaylightDate
725         member. */
726      *off = *off + tzi.DaylightBias;
727   *off = *off * -60;
728
729 #else
730
731   /* First convert unix time_t structure to windows FILETIME format.  */
732   utc_time.ull_time = ((unsigned long long) *timer + w32_epoch_offset)
733                       * 10000000ULL;
734
735   tzi_status = GetTimeZoneInformation (&tzi);
736
737   /* If GetTimeZoneInformation does not return a value between 0 and 2 then
738      it means that we were not able to retrieve timezone informations.
739      Note that we cannot use here FileTimeToLocalFileTime as Windows will use
740      in always in this case the current timezone setting. As suggested on
741      MSDN we use the following three system calls to get the right information.
742      Note also that starting with Windows Vista new functions are provided to
743      get timezone settings that depend on the year. We cannot use them as we
744      still support Windows XP and Windows 2003.  */
745   status = (tzi_status >= 0 && tzi_status <= 2)
746      && FileTimeToSystemTime (&utc_time.ft_time, &utc_sys_time)
747      && SystemTimeToTzSpecificLocalTime (&tzi, &utc_sys_time, &local_sys_time)
748      && SystemTimeToFileTime (&local_sys_time, &local_time.ft_time);
749
750   if (!status)
751      /* An error occurs so return invalid_tzoff.  */
752      *off = __gnat_invalid_tzoff;
753   else
754      if (local_time.ull_time > utc_time.ull_time)
755         *off = (long) ((local_time.ull_time - utc_time.ull_time) / 10000000ULL);
756      else
757         *off = - (long) ((utc_time.ull_time - local_time.ull_time) / 10000000ULL);
758
759 #endif
760
761   (*Unlock_Task) ();
762 }
763
764 #else
765
766 /* On Lynx, all time values are treated in GMT */
767
768 #if defined (__Lynx__)
769
770 /* As of LynxOS 3.1.0a patch level 040, LynuxWorks changes the
771    prototype to the C library function localtime_r from the POSIX.4
772    Draft 9 to the POSIX 1.c version. Before this change the following
773    spec is required. Only use when ___THREADS_POSIX4ad4__ is defined,
774    the Lynx convention when building against the legacy API. */
775
776 extern void
777 __gnat_localtime_tzoff (const time_t *, long *);
778
779 void
780 __gnat_localtime_tzoff (const time_t *timer, long *off)
781 {
782   *off = 0;
783 }
784
785 #else
786
787 /* VMS does not need __gnat_localtime_tzoff */
788
789 #if defined (VMS)
790
791 /* Other targets except Lynx, VMS and Windows provide a standard localtime_r */
792
793 #else
794
795 #define Lock_Task system__soft_links__lock_task
796 extern void (*Lock_Task) (void);
797
798 #define Unlock_Task system__soft_links__unlock_task
799 extern void (*Unlock_Task) (void);
800
801 extern void
802 __gnat_localtime_tzoff (const time_t *, long *);
803
804 void
805 __gnat_localtime_tzoff (const time_t *timer, long *off)
806 {
807   struct tm tp;
808
809 /* AIX, HPUX, SGI Irix, Sun Solaris */
810 #if defined (_AIX) || defined (__hpux__) || defined (sgi) || defined (sun)
811 {
812   (*Lock_Task) ();
813
814   localtime_r (timer, &tp);
815   *off = (long) -timezone;
816
817   (*Unlock_Task) ();
818
819   /* Correct the offset if Daylight Saving Time is in effect */
820
821   if (tp.tm_isdst > 0)
822     *off = *off + 3600;
823 }
824
825 /* VxWorks */
826 #elif defined (__vxworks)
827 #include <stdlib.h>
828 {
829   (*Lock_Task) ();
830
831   localtime_r (timer, &tp);
832
833   /* Try to read the environment variable TIMEZONE. The variable may not have
834      been initialize, in that case return an offset of zero (0) for UTC. */
835
836   char *tz_str = getenv ("TIMEZONE");
837
838   if ((tz_str == NULL) || (*tz_str == '\0'))
839     *off = 0;
840   else
841   {
842     char *tz_start, *tz_end;
843
844     /* The format of the data contained in TIMEZONE is N::U:S:E where N is the
845        name of the time zone, U are the minutes difference from UTC, S is the
846        start of DST in mmddhh and E is the end of DST in mmddhh. Extracting
847        the value of U involves setting two pointers, one at the beginning and
848        one at the end of the value. The end pointer is then set to null in
849        order to delimit a string slice for atol to process. */
850
851     tz_start = index (tz_str, ':') + 2;
852     tz_end = index (tz_start, ':');
853     tz_end = '\0';
854
855     /* The Ada layer expects an offset in seconds. Note that we must reverse
856        the sign of the result since west is positive and east is negative on
857        VxWorks targets. */
858
859     *off = -atol (tz_start) * 60;
860
861     /* Correct the offset if Daylight Saving Time is in effect */
862
863     if (tp.tm_isdst > 0)
864       *off = *off + 3600;
865   }
866
867   (*Unlock_Task) ();
868 }
869
870 /* Darwin, Free BSD, Linux, Tru64, where component tm_gmtoff is present in
871    struct tm */
872
873 #elif defined (__APPLE__) || defined (__FreeBSD__) || defined (linux) ||\
874      (defined (__alpha__) && defined (__osf__)) || defined (__GLIBC__)
875 {
876   localtime_r (timer, &tp);
877   *off = tp.tm_gmtoff;
878 }
879
880 /* Default: treat all time values in GMT */
881
882 #else
883   *off = 0;
884
885 #endif
886 }
887
888 #endif
889 #endif
890 #endif
891
892 #ifdef __vxworks
893
894 #include <taskLib.h>
895
896 /* __gnat_get_task_options is used by s-taprop.adb only for VxWorks. This
897    function returns the options to be set when creating a new task. It fetches
898    the options assigned to the current task (parent), so offering some user
899    level control over the options for a task hierarchy. It forces VX_FP_TASK
900    because it is almost always required. On processors with the SPE
901    category, VX_SPE_TASK is needed to enable the SPE. */
902 extern int __gnat_get_task_options (void);
903
904 int
905 __gnat_get_task_options (void)
906 {
907   int options;
908
909   /* Get the options for the task creator */
910   taskOptionsGet (taskIdSelf (), &options);
911
912   /* Force VX_FP_TASK because it is almost always required */
913   options |= VX_FP_TASK;
914 #if defined (__SPE__) && (! defined (__VXWORKSMILS__))
915   options |= VX_SPE_TASK;
916 #endif
917
918   /* Mask those bits that are not under user control */
919 #ifdef VX_USR_TASK_OPTIONS
920   return options & VX_USR_TASK_OPTIONS;
921 #else
922   return options;
923 #endif
924 }
925
926 #endif
927
928 int
929 __gnat_is_file_not_found_error (int errno_val) {
930    switch (errno_val) {
931       case ENOENT:
932 #ifdef __vxworks
933       /* In the case of VxWorks, we also have to take into account various
934        * filesystem-specific variants of this error.
935        */
936 #if ! defined (VTHREADS)
937       case S_dosFsLib_FILE_NOT_FOUND:
938 #endif
939 #if ! defined (__RTP__) && (! defined (VTHREADS) || defined (__VXWORKSMILS__))
940       case S_nfsLib_NFSERR_NOENT:
941 #endif
942 #endif
943          return 1;
944
945       default:
946          return 0;
947    }
948 }