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