19ddfb317f
gcc/ada/ * adaint.h (__gnat_expect_portable_execvp): Fix prototype. (__gnat_expect_poll): Likewise. * expect.c [_WIN32]: Include adaint.h file. (__gnat_waitpid): Remove useless variable. (__gnat_expect_portable_execvp): Add ATTRIBUTE_UNUSED on parameter. * raise-gcc.c [SEH] (__gnat_personality_v0): Add ATTRIBUTE_UNUSED. * socket.c [_WIN32] (__gnat_getservbyport): Add ATTRIBUTE_UNUSED on a couple of parameters. (__gnat_gethostbyname): Likewise. (__gnat_gethostbyaddr): Likewise. (__gnat_getservbyname): Likewise. (__gnat_last_socket_in_set): Use variables local to loops. (__gnat_socket_ioctl): Cast 3rd parameter to proper type if _WIN32. (__gnat_inet_pton): Cast 2nd parameter to proper type if _WIN32. * sysdep.c (__gnat_localtime_tzoff): Remove superfluous test. * terminals.c [_WIN32]: Include io.h file. (is_gui_app): Remove useless variables and fix unsigned comparison. (nt_spawnve): Add ATTRIBUTE_UNUSED on first parameter. Initialize a local variable and remove others that are useless. Add missing cast (__gnat_setup_child_communication): Remove useless variable and call Use proper formatting string in call to sprintf. (__gnat_setup_parent_communication): Cast to proper type. (find_child_console): Fix prototype and remove useless variable. (find_process_handle): Likewise. (_gnat_interrupt_process): Move to after __gnat_interrupt_pid. (__gnat_reset_tty): Add ATTRIBUTE_UNUSED on parameter, remove return (__gnat_setup_winsize): Add ATTRIBUTE_UNUSED on all parameters.
1075 lines
29 KiB
C
1075 lines
29 KiB
C
/****************************************************************************
|
||
* *
|
||
* GNAT COMPILER COMPONENTS *
|
||
* *
|
||
* S Y S D E P *
|
||
* *
|
||
* C Implementation File *
|
||
* *
|
||
* Copyright (C) 1992-2020, Free Software Foundation, Inc. *
|
||
* *
|
||
* GNAT is free software; you can redistribute it and/or modify it under *
|
||
* terms of the GNU General Public License as published by the Free Soft- *
|
||
* ware Foundation; either version 3, or (at your option) any later ver- *
|
||
* sion. GNAT is distributed in the hope that it will be useful, but WITH- *
|
||
* OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY *
|
||
* or FITNESS FOR A PARTICULAR PURPOSE. *
|
||
* *
|
||
* As a special exception under Section 7 of GPL version 3, you are granted *
|
||
* additional permissions described in the GCC Runtime Library Exception, *
|
||
* version 3.1, as published by the Free Software Foundation. *
|
||
* *
|
||
* You should have received a copy of the GNU General Public License and *
|
||
* a copy of the GCC Runtime Library Exception along with this program; *
|
||
* see the files COPYING3 and COPYING.RUNTIME respectively. If not, see *
|
||
* <http://www.gnu.org/licenses/>. *
|
||
* *
|
||
* GNAT was originally developed by the GNAT team at New York University. *
|
||
* Extensive contributions were provided by Ada Core Technologies Inc. *
|
||
* *
|
||
****************************************************************************/
|
||
|
||
/* This file contains system dependent symbols that are referenced in the
|
||
GNAT Run Time Library */
|
||
|
||
#ifdef __vxworks
|
||
#include "vxWorks.h"
|
||
#include "ioLib.h"
|
||
#if ! defined (VTHREADS)
|
||
#include "dosFsLib.h"
|
||
#endif
|
||
#if ! defined (__RTP__) && (! defined (VTHREADS) || defined (__VXWORKSMILS__))
|
||
# include "nfsLib.h"
|
||
#endif
|
||
#include "selectLib.h"
|
||
#include "version.h"
|
||
#if defined (__RTP__)
|
||
# include "vwModNum.h"
|
||
#endif /* __RTP__ */
|
||
#endif
|
||
|
||
#ifdef __ANDROID__
|
||
#undef __linux__
|
||
#endif
|
||
|
||
#ifdef IN_RTS
|
||
#define POSIX
|
||
#include "runtime.h"
|
||
#include <string.h>
|
||
#include <unistd.h>
|
||
|
||
#include <fcntl.h>
|
||
#include <sys/stat.h>
|
||
#else
|
||
#include "config.h"
|
||
#include "system.h"
|
||
#endif
|
||
|
||
#include <time.h>
|
||
#include <errno.h>
|
||
|
||
#if defined (__sun__) && !defined (__vxworks)
|
||
/* The declaration is present in <time.h> but conditionalized
|
||
on a couple of macros we don't define. */
|
||
extern struct tm *localtime_r(const time_t *, struct tm *);
|
||
#endif
|
||
|
||
#include "adaint.h"
|
||
|
||
/* Don't use macros versions of this functions on VxWorks since they cause
|
||
imcompatible changes in some VxWorks versions */
|
||
#ifdef __vxworks
|
||
#undef getchar
|
||
#undef putchar
|
||
#undef feof
|
||
#undef ferror
|
||
#undef fileno
|
||
#endif
|
||
|
||
/*
|
||
Notes:
|
||
|
||
(1) Opening a file with read mode fails if the file does not exist or
|
||
cannot be read.
|
||
|
||
(2) Opening a file with append mode causes all subsequent writes to the
|
||
file to be forced to the then current end-of-file, regardless of
|
||
intervening calls to the fseek function.
|
||
|
||
(3) When a file is opened with update mode, both input and output may be
|
||
performed on the associated stream. However, output may not be directly
|
||
followed by input without an intervening call to the fflush function or
|
||
to a file positioning function (fseek, fsetpos, or rewind), and input
|
||
may not be directly followed by output without an intervening call to a
|
||
file positioning function, unless the input operation encounters
|
||
end-of-file.
|
||
|
||
The other target dependent declarations here are for the three functions
|
||
__gnat_set_binary_mode, __gnat_set_text_mode and __gnat_set_mode:
|
||
|
||
void __gnat_set_binary_mode (int handle);
|
||
void __gnat_set_text_mode (int handle);
|
||
void __gnat_set_mode (int handle, int mode);
|
||
|
||
These functions have no effect in Unix (or similar systems where there is
|
||
no distinction between binary and text files), but in DOS (and similar
|
||
systems where text mode does CR/LF translation), these functions allow
|
||
the mode of the stream with the given handle (fileno can be used to get
|
||
the handle of a stream) to be changed dynamically. The returned result
|
||
is 0 if no error occurs and -1 if an error occurs.
|
||
|
||
Finally there is a boolean (character) variable
|
||
|
||
char __gnat_text_translation_required;
|
||
|
||
which is zero (false) in Unix mode, and one (true) in DOS mode, with a
|
||
true value indicating that text translation is required on text files
|
||
and that fopen supports the trailing t and b modifiers.
|
||
|
||
*/
|
||
|
||
#if defined (WINNT) || defined (__CYGWIN__) || defined (__DJGPP__)
|
||
|
||
const char __gnat_text_translation_required = 1;
|
||
|
||
#ifdef __CYGWIN__
|
||
#define WIN_SETMODE setmode
|
||
#include <io.h>
|
||
#else
|
||
#define WIN_SETMODE _setmode
|
||
#endif
|
||
|
||
#if defined (__DJGPP__)
|
||
#include <io.h>
|
||
#define _setmode setmode
|
||
#endif /* __DJGPP__ */
|
||
|
||
void
|
||
__gnat_set_binary_mode (int handle)
|
||
{
|
||
WIN_SETMODE (handle, O_BINARY);
|
||
}
|
||
|
||
void
|
||
__gnat_set_text_mode (int handle)
|
||
{
|
||
WIN_SETMODE (handle, O_TEXT);
|
||
}
|
||
|
||
#if defined (__CYGWIN__) || defined (__DJGPP__)
|
||
void
|
||
__gnat_set_mode (int handle, int mode)
|
||
{
|
||
/* the values here must be synchronized with
|
||
System.File_Control_Block.Content_Encodding:
|
||
|
||
None = 0
|
||
Default_Text = 1
|
||
Text = 2
|
||
U8text = 3
|
||
Wtext = 4
|
||
U16text = 5 */
|
||
|
||
switch (mode) {
|
||
case 0 : setmode(handle, O_BINARY); break;
|
||
case 1 : setmode(handle, O_TEXT); break;
|
||
case 2 : setmode(handle, O_TEXT); break;
|
||
case 3 : setmode(handle, O_TEXT); break;
|
||
case 4 : setmode(handle, O_BINARY); break;
|
||
case 5 : setmode(handle, O_BINARY); break;
|
||
}
|
||
}
|
||
#else
|
||
void
|
||
__gnat_set_mode (int handle, int mode)
|
||
{
|
||
/* the values here must be synchronized with
|
||
System.File_Control_Block.Content_Encodding:
|
||
|
||
None = 0
|
||
Default_Text = 1
|
||
Text = 2
|
||
U8text = 3
|
||
Wtext = 4
|
||
U16text = 5 */
|
||
|
||
switch (mode) {
|
||
case 0 : WIN_SETMODE (handle, _O_BINARY); break;
|
||
case 1 : WIN_SETMODE (handle, __gnat_current_ccs_encoding); break;
|
||
case 2 : WIN_SETMODE (handle, _O_TEXT); break;
|
||
case 3 : WIN_SETMODE (handle, _O_U8TEXT); break;
|
||
case 4 : WIN_SETMODE (handle, _O_WTEXT); break;
|
||
case 5 : WIN_SETMODE (handle, _O_U16TEXT); break;
|
||
}
|
||
}
|
||
#endif
|
||
|
||
#ifdef __CYGWIN__
|
||
|
||
char *
|
||
__gnat_ttyname (int filedes)
|
||
{
|
||
extern char *ttyname (int);
|
||
|
||
return ttyname (filedes);
|
||
}
|
||
|
||
#endif /* __CYGWIN__ */
|
||
|
||
#if defined (__CYGWIN__) || defined (__MINGW32__)
|
||
#include <windows.h>
|
||
|
||
int __gnat_is_windows_xp (void);
|
||
|
||
int
|
||
__gnat_is_windows_xp (void)
|
||
{
|
||
static int is_win_xp=0, is_win_xp_checked=0;
|
||
|
||
if (!is_win_xp_checked)
|
||
{
|
||
OSVERSIONINFO version;
|
||
|
||
is_win_xp_checked = 1;
|
||
|
||
memset (&version, 0, sizeof (version));
|
||
version.dwOSVersionInfoSize = sizeof (version);
|
||
|
||
is_win_xp = GetVersionEx (&version)
|
||
&& version.dwPlatformId == VER_PLATFORM_WIN32_NT
|
||
&& (version.dwMajorVersion > 5
|
||
|| (version.dwMajorVersion == 5 && version.dwMinorVersion >= 1));
|
||
}
|
||
return is_win_xp;
|
||
}
|
||
|
||
/* Get the bounds of the stack. The stack pointer is supposed to be
|
||
initialized to BASE when a thread is created and the stack can be extended
|
||
to LIMIT before reaching a guard page.
|
||
Note: for the main thread, the system automatically extend the stack, so
|
||
LIMIT is only the current limit. */
|
||
|
||
void
|
||
__gnat_get_stack_bounds (void **base, void **limit)
|
||
{
|
||
NT_TIB *tib;
|
||
|
||
/* We know that the first field of the TEB is the TIB. */
|
||
tib = (NT_TIB *)NtCurrentTeb ();
|
||
|
||
*base = tib->StackBase;
|
||
*limit = tib->StackLimit;
|
||
}
|
||
|
||
#endif /* __CYGWIN__ || __MINGW32__ */
|
||
|
||
#ifdef __MINGW32__
|
||
|
||
/* Return the name of the tty. Under windows there is no name for
|
||
the tty, so this function, if connected to a tty, returns the generic name
|
||
"console". */
|
||
|
||
char *
|
||
__gnat_ttyname (int filedes)
|
||
{
|
||
if (isatty (filedes))
|
||
return "console";
|
||
else
|
||
return NULL;
|
||
}
|
||
|
||
#endif /* __MINGW32__ */
|
||
|
||
#else
|
||
|
||
const char __gnat_text_translation_required = 0;
|
||
|
||
/* These functions do nothing in non-DOS systems. */
|
||
|
||
void
|
||
__gnat_set_binary_mode (int handle ATTRIBUTE_UNUSED)
|
||
{
|
||
}
|
||
|
||
void
|
||
__gnat_set_text_mode (int handle ATTRIBUTE_UNUSED)
|
||
{
|
||
}
|
||
|
||
void
|
||
__gnat_set_mode (int handle ATTRIBUTE_UNUSED, int mode ATTRIBUTE_UNUSED)
|
||
{
|
||
}
|
||
|
||
char *
|
||
__gnat_ttyname (int filedes ATTRIBUTE_UNUSED)
|
||
{
|
||
#if defined (__vxworks)
|
||
return "";
|
||
#else
|
||
extern char *ttyname (int);
|
||
|
||
return ttyname (filedes);
|
||
#endif /* defined (__vxworks) */
|
||
}
|
||
#endif
|
||
|
||
#if defined (__linux__) || defined (__sun__) \
|
||
|| defined (WINNT) \
|
||
|| defined (__MACHTEN__) || defined (__hpux__) || defined (_AIX) \
|
||
|| (defined (__svr4__) && defined (__i386__)) || defined (__Lynx__) \
|
||
|| defined (__CYGWIN__) || defined (__FreeBSD__) || defined (__OpenBSD__) \
|
||
|| defined (__GLIBC__) || defined (__APPLE__) || defined (__DragonFly__) \
|
||
|| defined (__QNX__)
|
||
|
||
# ifdef __MINGW32__
|
||
# if OLD_MINGW
|
||
# include <termios.h>
|
||
# else
|
||
# include <conio.h> /* for getch(), kbhit() */
|
||
# endif
|
||
# else
|
||
# include <termios.h>
|
||
# endif
|
||
|
||
#endif
|
||
|
||
/* Implements the common processing for getc_immediate and
|
||
getc_immediate_nowait. */
|
||
|
||
extern void getc_immediate (FILE *, int *, int *);
|
||
extern void getc_immediate_nowait (FILE *, int *, int *, int *);
|
||
extern void getc_immediate_common (FILE *, int *, int *, int *, int);
|
||
|
||
/* Called by Get_Immediate (Foo); */
|
||
|
||
void
|
||
getc_immediate (FILE *stream, int *ch, int *end_of_file)
|
||
{
|
||
int avail;
|
||
|
||
getc_immediate_common (stream, ch, end_of_file, &avail, 1);
|
||
}
|
||
|
||
/* Called by Get_Immediate (Foo, Available); */
|
||
|
||
void
|
||
getc_immediate_nowait (FILE *stream, int *ch, int *end_of_file, int *avail)
|
||
{
|
||
getc_immediate_common (stream, ch, end_of_file, avail, 0);
|
||
}
|
||
|
||
/* Called by getc_immediate () and getc_immediate_nowait () */
|
||
|
||
void
|
||
getc_immediate_common (FILE *stream,
|
||
int *ch,
|
||
int *end_of_file,
|
||
int *avail,
|
||
int waiting ATTRIBUTE_UNUSED)
|
||
{
|
||
#if defined (__linux__) || defined (__sun__) \
|
||
|| defined (__CYGWIN32__) || defined (__MACHTEN__) || defined (__hpux__) \
|
||
|| defined (_AIX) || (defined (__svr4__) && defined (__i386__)) \
|
||
|| defined (__Lynx__) || defined (__FreeBSD__) || defined (__OpenBSD__) \
|
||
|| defined (__GLIBC__) || defined (__APPLE__) || defined (__DragonFly__) \
|
||
|| defined (__QNX__)
|
||
char c;
|
||
int nread;
|
||
int good_one = 0;
|
||
int eof_ch = 4; /* Ctrl-D */
|
||
int fd = fileno (stream);
|
||
struct termios otermios_rec, termios_rec;
|
||
|
||
if (isatty (fd))
|
||
{
|
||
tcgetattr (fd, &termios_rec);
|
||
memcpy (&otermios_rec, &termios_rec, sizeof (struct termios));
|
||
|
||
/* Set RAW mode, with no echo */
|
||
termios_rec.c_lflag = termios_rec.c_lflag & ~ICANON & ~ECHO;
|
||
|
||
#if defined (__linux__) || defined (__sun__) \
|
||
|| defined (__MACHTEN__) || defined (__hpux__) \
|
||
|| defined (_AIX) || (defined (__svr4__) && defined (__i386__)) \
|
||
|| defined (__Lynx__) || defined (__FreeBSD__) || defined (__OpenBSD__) \
|
||
|| defined (__GLIBC__) || defined (__APPLE__) || defined (__DragonFly__) \
|
||
|| defined (__QNX__)
|
||
eof_ch = termios_rec.c_cc[VEOF];
|
||
|
||
/* If waiting (i.e. Get_Immediate (Char)), set MIN = 1 and wait for
|
||
a character forever. This doesn't seem to effect Ctrl-Z or
|
||
Ctrl-C processing.
|
||
If not waiting (i.e. Get_Immediate (Char, Available)),
|
||
don't wait for anything but timeout immediately. */
|
||
termios_rec.c_cc[VMIN] = waiting;
|
||
termios_rec.c_cc[VTIME] = 0;
|
||
#endif
|
||
tcsetattr (fd, TCSANOW, &termios_rec);
|
||
|
||
while (! good_one)
|
||
{
|
||
/* Read is used here instead of fread, because fread doesn't
|
||
work on Solaris5 and Sunos4 in this situation. Maybe because we
|
||
are mixing calls that use file descriptors and streams. */
|
||
nread = read (fd, &c, 1);
|
||
if (nread > 0)
|
||
{
|
||
/* On Unix terminals, Ctrl-D (EOT) is an End of File. */
|
||
if (c == eof_ch)
|
||
{
|
||
*avail = 0;
|
||
*end_of_file = 1;
|
||
good_one = 1;
|
||
}
|
||
|
||
/* Everything else is ok */
|
||
else if (c != eof_ch)
|
||
{
|
||
*avail = 1;
|
||
*end_of_file = 0;
|
||
good_one = 1;
|
||
}
|
||
}
|
||
|
||
else if (! waiting)
|
||
{
|
||
*avail = 0;
|
||
*end_of_file = 0;
|
||
good_one = 1;
|
||
}
|
||
else
|
||
good_one = 0;
|
||
}
|
||
|
||
tcsetattr (fd, TCSANOW, &otermios_rec);
|
||
*ch = c;
|
||
}
|
||
|
||
else
|
||
#elif defined (__MINGW32__)
|
||
int fd = fileno (stream);
|
||
int char_waiting;
|
||
int eot_ch = 4; /* Ctrl-D */
|
||
|
||
if (isatty (fd))
|
||
{
|
||
if (waiting)
|
||
{
|
||
*ch = getch ();
|
||
|
||
if (*ch == eot_ch)
|
||
*end_of_file = 1;
|
||
else
|
||
*end_of_file = 0;
|
||
|
||
*avail = 1;
|
||
}
|
||
else /* ! waiting */
|
||
{
|
||
char_waiting = kbhit();
|
||
|
||
if (char_waiting == 1)
|
||
{
|
||
*avail = 1;
|
||
*ch = getch ();
|
||
|
||
if (*ch == eot_ch)
|
||
*end_of_file = 1;
|
||
else
|
||
*end_of_file = 0;
|
||
}
|
||
else
|
||
{
|
||
*avail = 0;
|
||
*end_of_file = 0;
|
||
}
|
||
}
|
||
}
|
||
else
|
||
#elif defined (__vxworks)
|
||
/* Bit masks of file descriptors to read from. */
|
||
struct fd_set readFds;
|
||
/* Timeout before select returns if nothing can be read. */
|
||
struct timeval timeOut;
|
||
char c;
|
||
int fd = fileno (stream);
|
||
int nread;
|
||
int option;
|
||
int readable;
|
||
int status;
|
||
int width;
|
||
|
||
if (isatty (fd))
|
||
{
|
||
/* If we do not want to wait, we have to set up fd in RAW mode. This
|
||
should be done outside this function as setting fd in RAW mode under
|
||
vxWorks flushes the buffer of fd. If the RAW mode was set here, the
|
||
buffer would be empty and we would always return that no character
|
||
is available */
|
||
if (! waiting)
|
||
{
|
||
/* Initialization of timeOut for its use with select. */
|
||
timeOut.tv_sec = 0;
|
||
timeOut.tv_usec = 0;
|
||
|
||
/* Initialization of readFds for its use with select;
|
||
FD is the only file descriptor to be monitored */
|
||
FD_ZERO (&readFds);
|
||
FD_SET (fd, &readFds);
|
||
width = 2;
|
||
|
||
/* We do all this processing to emulate a non blocking read. */
|
||
readable = select (width, &readFds, NULL, NULL, &timeOut);
|
||
if (readable == ERROR)
|
||
*avail = -1, *end_of_file = -1;
|
||
/* No character available in input. */
|
||
else if (readable == 0)
|
||
*avail = 0, *end_of_file = 0;
|
||
else
|
||
{
|
||
nread = read (fd, &c, 1);
|
||
if (nread > 0)
|
||
*avail = 1, *end_of_file = 0;
|
||
/* End Of File. */
|
||
else if (nread == 0)
|
||
*avail = 0, *end_of_file = 1;
|
||
/* Error. */
|
||
else
|
||
*avail = -1, *end_of_file = -1;
|
||
}
|
||
}
|
||
|
||
/* We have to wait until we get a character */
|
||
else
|
||
{
|
||
*avail = -1;
|
||
*end_of_file = -1;
|
||
|
||
/* Save the current mode of FD. */
|
||
option = ioctl (fd, FIOGETOPTIONS, 0);
|
||
|
||
/* Set FD in RAW mode. */
|
||
status = ioctl (fd, FIOSETOPTIONS, OPT_RAW);
|
||
if (status != -1)
|
||
{
|
||
nread = read (fd, &c, 1);
|
||
if (nread > 0)
|
||
*avail = 1, *end_of_file = 0;
|
||
/* End of file. */
|
||
else if (nread == 0)
|
||
*avail = 0, *end_of_file = 1;
|
||
/* Else there is an ERROR. */
|
||
}
|
||
|
||
/* Revert FD to its previous mode. */
|
||
status = ioctl (fd, FIOSETOPTIONS, option);
|
||
}
|
||
|
||
*ch = c;
|
||
}
|
||
else
|
||
#endif
|
||
{
|
||
/* If we're not on a terminal, then we don't need any fancy processing.
|
||
Also this is the only thing that's left if we're not on one of the
|
||
supported systems; which means that for non supported systems,
|
||
get_immediate may wait for a carriage return on terminals. */
|
||
*ch = fgetc (stream);
|
||
if (feof (stream))
|
||
{
|
||
*end_of_file = 1;
|
||
*avail = 0;
|
||
}
|
||
else
|
||
{
|
||
*end_of_file = 0;
|
||
*avail = 1;
|
||
}
|
||
}
|
||
}
|
||
|
||
/* The following definitions are provided in NT to support Windows based
|
||
Ada programs. */
|
||
|
||
#ifdef WINNT
|
||
#include <windows.h>
|
||
|
||
/* Provide functions to echo the values passed to WinMain (windows bindings
|
||
will want to import these). We use the same names as the routines used
|
||
by AdaMagic for compatibility. */
|
||
|
||
char *rts_get_hInstance (void);
|
||
char *rts_get_hPrevInstance (void);
|
||
char *rts_get_lpCommandLine (void);
|
||
int rts_get_nShowCmd (void);
|
||
|
||
char *
|
||
rts_get_hInstance (void)
|
||
{
|
||
return (char *)GetModuleHandleA (0);
|
||
}
|
||
|
||
char *
|
||
rts_get_hPrevInstance (void)
|
||
{
|
||
return 0;
|
||
}
|
||
|
||
char *
|
||
rts_get_lpCommandLine (void)
|
||
{
|
||
return GetCommandLineA ();
|
||
}
|
||
|
||
int
|
||
rts_get_nShowCmd (void)
|
||
{
|
||
return 1;
|
||
}
|
||
|
||
#endif /* WINNT */
|
||
|
||
/* This value is returned as the time zone offset when a valid value
|
||
cannot be determined. It is simply a bizarre value that will never
|
||
occur. It is 3 days plus 73 seconds (offset is in seconds). */
|
||
|
||
long __gnat_invalid_tzoff = 259273;
|
||
|
||
/* Definition of __gnat_localtime_r used by a-calend.adb */
|
||
|
||
#if defined (__MINGW32__)
|
||
|
||
/* Reentrant localtime for Windows. */
|
||
|
||
extern void
|
||
__gnat_localtime_tzoff (const time_t *, const int *, long *);
|
||
|
||
static const unsigned long long w32_epoch_offset = 11644473600ULL;
|
||
void
|
||
__gnat_localtime_tzoff (const time_t *timer, const int *is_historic, long *off)
|
||
{
|
||
TIME_ZONE_INFORMATION tzi;
|
||
|
||
DWORD tzi_status;
|
||
|
||
tzi_status = GetTimeZoneInformation (&tzi);
|
||
|
||
/* Cases where we simply want to extract the offset of the current time
|
||
zone, regardless of the date. A value of "0" for flag "is_historic"
|
||
signifies that the date is NOT historic, see the
|
||
body of Ada.Calendar.UTC_Time_Offset. */
|
||
|
||
if (*is_historic == 0) {
|
||
*off = tzi.Bias;
|
||
|
||
/* The system is operating in the range covered by the StandardDate
|
||
member. */
|
||
if (tzi_status == TIME_ZONE_ID_STANDARD) {
|
||
*off = *off + tzi.StandardBias;
|
||
}
|
||
|
||
/* The system is operating in the range covered by the DaylightDate
|
||
member. */
|
||
else if (tzi_status == TIME_ZONE_ID_DAYLIGHT) {
|
||
*off = *off + tzi.DaylightBias;
|
||
}
|
||
|
||
*off = *off * -60;
|
||
}
|
||
|
||
/* Time zone offset calculations for a historic or future date */
|
||
|
||
else {
|
||
union
|
||
{
|
||
FILETIME ft_time;
|
||
unsigned long long ull_time;
|
||
} utc_time, local_time;
|
||
|
||
SYSTEMTIME utc_sys_time, local_sys_time;
|
||
BOOL status;
|
||
|
||
/* First convert unix time_t structure to windows FILETIME format. */
|
||
utc_time.ull_time = ((unsigned long long) *timer + w32_epoch_offset)
|
||
* 10000000ULL;
|
||
|
||
/* If GetTimeZoneInformation does not return a value between 0 and 2 then
|
||
it means that we were not able to retrieve timezone information. Note
|
||
that we cannot use here FileTimeToLocalFileTime as Windows will use in
|
||
always in this case the current timezone setting. As suggested on MSDN
|
||
we use the following three system calls to get the right information.
|
||
Note also that starting with Windows Vista new functions are provided
|
||
to get timezone settings that depend on the year. We cannot use them as
|
||
we still support Windows XP and Windows 2003. */
|
||
|
||
status = tzi_status <= 2
|
||
&& FileTimeToSystemTime (&utc_time.ft_time, &utc_sys_time)
|
||
&& SystemTimeToTzSpecificLocalTime (&tzi, &utc_sys_time, &local_sys_time)
|
||
&& SystemTimeToFileTime (&local_sys_time, &local_time.ft_time);
|
||
|
||
/* An error has occurred, return invalid_tzoff */
|
||
|
||
if (!status) {
|
||
*off = __gnat_invalid_tzoff;
|
||
}
|
||
else {
|
||
if (local_time.ull_time > utc_time.ull_time) {
|
||
*off = (long) ((local_time.ull_time - utc_time.ull_time)
|
||
/ 10000000ULL);
|
||
}
|
||
else {
|
||
*off = - (long) ((utc_time.ull_time - local_time.ull_time)
|
||
/ 10000000ULL);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
#elif defined (__Lynx__)
|
||
|
||
/* On Lynx, all time values are treated in GMT */
|
||
|
||
/* As of LynxOS 3.1.0a patch level 040, LynuxWorks changes the
|
||
prototype to the C library function localtime_r from the POSIX.4
|
||
Draft 9 to the POSIX 1.c version. Before this change the following
|
||
spec is required. Only use when ___THREADS_POSIX4ad4__ is defined,
|
||
the Lynx convention when building against the legacy API. */
|
||
|
||
extern void
|
||
__gnat_localtime_tzoff (const time_t *, const int *, long *);
|
||
|
||
void
|
||
__gnat_localtime_tzoff (const time_t *timer, const int *is_historic, long *off)
|
||
{
|
||
*off = 0;
|
||
}
|
||
|
||
#else
|
||
|
||
/* Other targets except Lynx and Windows provide a standard localtime_r */
|
||
|
||
#define Lock_Task system__soft_links__lock_task
|
||
extern void (*Lock_Task) (void);
|
||
|
||
#define Unlock_Task system__soft_links__unlock_task
|
||
extern void (*Unlock_Task) (void);
|
||
|
||
extern void
|
||
__gnat_localtime_tzoff (const time_t *, const int *, long *);
|
||
|
||
void
|
||
__gnat_localtime_tzoff (const time_t *timer ATTRIBUTE_UNUSED,
|
||
const int *is_historic ATTRIBUTE_UNUSED,
|
||
long *off ATTRIBUTE_UNUSED)
|
||
{
|
||
struct tm tp ATTRIBUTE_UNUSED;
|
||
|
||
/* AIX, HPUX, Sun Solaris */
|
||
#if defined (_AIX) || defined (__hpux__) || defined (__sun__)
|
||
{
|
||
(*Lock_Task) ();
|
||
|
||
localtime_r (timer, &tp);
|
||
*off = (long) -timezone;
|
||
|
||
(*Unlock_Task) ();
|
||
|
||
/* Correct the offset if Daylight Saving Time is in effect */
|
||
|
||
if (tp.tm_isdst > 0)
|
||
*off = *off + 3600;
|
||
}
|
||
|
||
/* VxWorks */
|
||
#elif defined (__vxworks)
|
||
#include <stdlib.h>
|
||
{
|
||
(*Lock_Task) ();
|
||
|
||
localtime_r (timer, &tp);
|
||
|
||
/* Try to read the environment variable TIMEZONE. The variable may not have
|
||
been initialize, in that case return an offset of zero (0) for UTC. */
|
||
|
||
char *tz_str = getenv ("TIMEZONE");
|
||
|
||
if ((tz_str == NULL) || (*tz_str == '\0'))
|
||
*off = 0;
|
||
else
|
||
{
|
||
char *tz_start, *tz_end;
|
||
|
||
/* The format of the data contained in TIMEZONE is N::U:S:E where N is the
|
||
name of the time zone, U are the minutes difference from UTC, S is the
|
||
start of DST in mmddhh and E is the end of DST in mmddhh. Extracting
|
||
the value of U involves setting two pointers, one at the beginning and
|
||
one at the end of the value. The end pointer is then set to null in
|
||
order to delimit a string slice for atol to process. */
|
||
|
||
tz_start = index (tz_str, ':') + 2;
|
||
tz_end = index (tz_start, ':');
|
||
*tz_end = '\0';
|
||
|
||
/* The Ada layer expects an offset in seconds. Note that we must reverse
|
||
the sign of the result since west is positive and east is negative on
|
||
VxWorks targets. */
|
||
|
||
*off = -atol (tz_start) * 60;
|
||
|
||
/* Correct the offset if Daylight Saving Time is in effect */
|
||
|
||
if (tp.tm_isdst > 0)
|
||
*off = *off + 3600;
|
||
}
|
||
|
||
(*Unlock_Task) ();
|
||
}
|
||
|
||
/* Darwin, Free BSD, Linux, where component tm_gmtoff is present in
|
||
struct tm */
|
||
|
||
#elif defined (__APPLE__) || defined (__FreeBSD__) || defined (__linux__) \
|
||
|| defined (__GLIBC__) || defined (__DragonFly__) || defined (__OpenBSD__) \
|
||
|| defined (__DJGPP__) || defined (__QNX__)
|
||
{
|
||
localtime_r (timer, &tp);
|
||
*off = tp.tm_gmtoff;
|
||
}
|
||
|
||
/* Default: treat all time values in GMT */
|
||
|
||
#else
|
||
*off = 0;
|
||
|
||
#endif /* defined(_AIX) ... */
|
||
}
|
||
|
||
#endif
|
||
|
||
#ifdef __vxworks
|
||
|
||
#include <taskLib.h>
|
||
|
||
/* __gnat_get_task_options is used by s-taprop.adb only for VxWorks. This
|
||
function returns the options to be set when creating a new task. It fetches
|
||
the options assigned to the current task (parent), so offering some user
|
||
level control over the options for a task hierarchy. It forces VX_FP_TASK
|
||
because it is almost always required. On processors with the SPE
|
||
category, VX_SPE_TASK should be used instead to enable the SPE. */
|
||
extern int __gnat_get_task_options (void);
|
||
|
||
int
|
||
__gnat_get_task_options (void)
|
||
{
|
||
int options;
|
||
|
||
/* Get the options for the task creator */
|
||
taskOptionsGet (taskIdSelf (), &options);
|
||
|
||
/* Force VX_FP_TASK or VX_SPE_TASK as needed */
|
||
#if defined (__SPE__)
|
||
options |= VX_SPE_TASK;
|
||
#else
|
||
options |= VX_FP_TASK;
|
||
#endif
|
||
|
||
/* Mask those bits that are not under user control */
|
||
#ifdef VX_USR_TASK_OPTIONS
|
||
/* O810-007, TSR 00043679:
|
||
Workaround a bug in Vx-7 where VX_DEALLOC_TCB == VX_PRIVATE_UMASK and:
|
||
- VX_DEALLOC_TCB is an internal option not to be used by users
|
||
- VX_PRIVATE_UMASK as a user-definable option
|
||
This leads to VX_USR_TASK_OPTIONS allowing 0x8000 as VX_PRIVATE_UMASK but
|
||
taskCreate refusing this option (VX_DEALLOC_TCB is not allowed)
|
||
|
||
Note that the same error occurs in both RTP and Kernel mode, but
|
||
VX_DEALLOC_TCB is not defined in the RTP headers, so we need to
|
||
explicitely check if VX_PRIVATE_UMASK has value 0x8000
|
||
*/
|
||
# if defined (VX_PRIVATE_UMASK) && (0x8000 == VX_PRIVATE_UMASK)
|
||
options &= ~VX_PRIVATE_UMASK;
|
||
# endif
|
||
options &= VX_USR_TASK_OPTIONS;
|
||
#endif
|
||
return options;
|
||
}
|
||
|
||
#endif
|
||
|
||
int
|
||
__gnat_is_file_not_found_error (int errno_val)
|
||
{
|
||
/* WARNING: Do not rewrite this as a switch/case statement.
|
||
* Some of the "cases" are duplicated in some versions of
|
||
* Vxworks, notably VxWorks7r2 SR0610. */
|
||
if (errno_val == ENOENT)
|
||
return 1;
|
||
#ifdef __vxworks
|
||
/* In the case of VxWorks, we also have to take into account various
|
||
* filesystem-specific variants of this error.
|
||
*/
|
||
#if ! defined (VTHREADS) && (_WRS_VXWORKS_MAJOR < 7)
|
||
else if (errno_val == S_dosFsLib_FILE_NOT_FOUND)
|
||
return 1;
|
||
#endif
|
||
#if ! defined (__RTP__) && (! defined (VTHREADS) || defined (__VXWORKSMILS__))
|
||
else if (errno_val == S_nfsLib_NFSERR_NOENT)
|
||
return 1;
|
||
#endif
|
||
#if defined (__RTP__)
|
||
/* An RTP can return an NFS file not found, and the NFS bits must
|
||
first be masked on to check the errno. */
|
||
else if (errno_val == (M_nfsStat | ENOENT))
|
||
return 1;
|
||
#endif
|
||
#endif
|
||
else
|
||
return 0;
|
||
}
|
||
|
||
#if defined (__linux__)
|
||
|
||
/* Note well: If this code is modified, it should be tested by hand,
|
||
because automated testing doesn't exercise it.
|
||
*/
|
||
|
||
/* HAVE_CAPABILITY is supposed to be defined if sys/capability.h exists on the
|
||
system where this is being compiled. If this macro is defined, we #include
|
||
the header. Otherwise we have the relevant declarations textually here.
|
||
*/
|
||
|
||
#if defined (HAVE_CAPABILITY)
|
||
#include <sys/capability.h>
|
||
#else
|
||
|
||
/* HAVE_CAPABILITY is not defined, so sys/capability.h does might not exist. */
|
||
|
||
typedef struct _cap_struct *cap_t;
|
||
typedef enum {
|
||
CAP_CLEAR=0,
|
||
CAP_SET=1
|
||
} cap_flag_value_t;
|
||
#define CAP_SYS_NICE 23
|
||
typedef enum {
|
||
CAP_EFFECTIVE=0, /* Specifies the effective flag */
|
||
CAP_PERMITTED=1, /* Specifies the permitted flag */
|
||
CAP_INHERITABLE=2 /* Specifies the inheritable flag */
|
||
} cap_flag_t;
|
||
|
||
typedef int cap_value_t;
|
||
|
||
extern cap_t cap_get_proc(void);
|
||
extern int cap_get_flag(cap_t, cap_value_t, cap_flag_t, cap_flag_value_t *);
|
||
extern int cap_free(void *);
|
||
|
||
#endif
|
||
|
||
/* __gnat_has_cap_sys_nice returns 1 if the current process has the
|
||
CAP_SYS_NICE capability. This capability is necessary to use the
|
||
Ceiling_Locking policy. Returns 0 otherwise. Note that this is
|
||
defined only for Linux.
|
||
*/
|
||
|
||
/* Define these as weak symbols, so if support for capabilities is not present,
|
||
programs can still link. On Ubuntu, support for capabilities can be
|
||
installed via "sudo apt-get --assume-yes install libcap-dev".
|
||
In addition, the user must link with "-lcap", or else these
|
||
symbols will be 0, and __gnat_has_cap_sys_nice will return 0.
|
||
*/
|
||
|
||
static cap_t cap_get_proc_weak(void)
|
||
__attribute__ ((weakref ("cap_get_proc")));
|
||
static int cap_get_flag_weak(cap_t, cap_value_t, cap_flag_t, cap_flag_value_t *)
|
||
__attribute__ ((weakref ("cap_get_flag")));
|
||
static int cap_free_weak(void *)
|
||
__attribute__ ((weakref ("cap_free")));
|
||
|
||
int
|
||
__gnat_has_cap_sys_nice () {
|
||
/* If the address of cap_get_proc_weak is 0, this means support for
|
||
capabilities is not present, so we return 0. */
|
||
if (&cap_get_proc_weak == 0)
|
||
return 0;
|
||
|
||
cap_t caps = cap_get_proc_weak();
|
||
if (caps == NULL)
|
||
return 0;
|
||
|
||
cap_flag_value_t value;
|
||
|
||
if (cap_get_flag_weak(caps, CAP_SYS_NICE, CAP_EFFECTIVE, &value) == -1)
|
||
return 0;
|
||
|
||
if (cap_free_weak(caps) == -1)
|
||
return 0;
|
||
|
||
if (value == CAP_SET)
|
||
return 1;
|
||
|
||
return 0;
|
||
}
|
||
#endif
|
||
|
||
#ifdef __ANDROID__
|
||
|
||
/* Provide extern symbols for sig* as needed by the tasking run-time, instead
|
||
of static inline functions. */
|
||
|
||
#include <signal.h>
|
||
|
||
int
|
||
_sigismember (sigset_t *set, int signum)
|
||
{
|
||
return sigismember (set, signum);
|
||
}
|
||
|
||
int
|
||
_sigaddset (sigset_t *set, int signum)
|
||
{
|
||
return sigaddset (set, signum);
|
||
}
|
||
|
||
int
|
||
_sigdelset (sigset_t *set, int signum)
|
||
{
|
||
return sigdelset (set, signum);
|
||
}
|
||
|
||
int
|
||
_sigemptyset (sigset_t *set)
|
||
{
|
||
return sigemptyset (set);
|
||
}
|
||
|
||
int
|
||
_sigfillset (sigset_t *set)
|
||
{
|
||
return sigfillset (set);
|
||
}
|
||
|
||
#include <unistd.h>
|
||
int
|
||
_getpagesize (void)
|
||
{
|
||
return getpagesize ();
|
||
}
|
||
#endif
|
||
|
||
int
|
||
__gnat_name_case_equivalence ()
|
||
{
|
||
/* the values here must be synchronized with Ada.Directories.Name_Case_Kind:
|
||
|
||
Unknown = 0
|
||
Case_Sensitive = 1
|
||
Case_Insensitive = 2
|
||
Case_Preserving = 3 */
|
||
|
||
#if defined (__APPLE__) || defined (WIN32)
|
||
return 3;
|
||
#else
|
||
return 1;
|
||
#endif
|
||
}
|