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