* *
* C Implementation File *
* *
- * Copyright (C) 1992-2003 Free Software Foundation, Inc. *
+ * Copyright (C) 1992-2012, 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 2, or (at your option) any later ver- *
+ * 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. See the GNU General Public License *
- * for more details. You should have received a copy of the GNU General *
- * Public License distributed with GNAT; see file COPYING. If not, write *
- * to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, *
- * MA 02111-1307, USA. *
+ * or FITNESS FOR A PARTICULAR PURPOSE. *
* *
- * As a special exception, if you link this file with other files to *
- * produce an executable, this file does not by itself cause the resulting *
- * executable to be covered by the GNU General Public License. This except- *
- * ion does not however invalidate any other reasons why the executable *
- * file might be covered by the GNU Public License. *
+ * 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. *
#ifdef __vxworks
#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 "vxWorks.h"
#endif
+
#ifdef IN_RTS
#define POSIX
#include "tconfig.h"
#include "tsystem.h"
#include <fcntl.h>
#include <sys/stat.h>
-#include "time.h"
+#ifdef VMS
+#include <unixio.h>
+#endif
#else
#include "config.h"
#include "system.h"
#endif
-#include "adaint.h"
-
-/*
- mode_read_text
- open text file for reading
- rt for DOS and Windows NT, r for Unix
-
- mode_write_text
- truncate to zero length or create text file for writing
- wt for DOS and Windows NT, w for Unix
-
- mode_append_text
- append; open or create text file for writing at end-of-file
- at for DOS and Windows NT, a for Unix
-
- mode_read_binary
- open binary file for reading
- rb for DOS and Windows NT, r for Unix
-
- mode_write_binary
- truncate to zero length or create binary file for writing
- wb for DOS and Windows NT, w for Unix
-
- mode_append_binary
- append; open or create binary file for writing at end-of-file
- ab for DOS and Windows NT, a for Unix
-
- mode_read_text_plus
- open text file for update (reading and writing)
- r+t for DOS and Windows NT, r+ for Unix
-
- mode_write_text_plus
- truncate to zero length or create text file for update
- w+t for DOS and Windows NT, w+ for Unix
-
- mode_append_text_plus
- append; open or create text file for update, writing at end-of-file
- a+t for DOS and Windows NT, a+ for Unix
+#include <time.h>
+#include <errno.h>
- mode_read_binary_plus
- open binary file for update (reading and writing)
- r+b for DOS and Windows NT, r+ for Unix
+#if defined (sun) && defined (__SVR4) && !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
- mode_write_binary_plus
- truncate to zero length or create binary file for update
- w+b for DOS and Windows NT, w+ for Unix
+#include "adaint.h"
- mode_append_binary_plus
- append; open or create binary file for update, writing at end-of-file
- a+b for DOS and Windows NT, a+ for Unix
+/* 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
*/
-#if defined(WINNT) || defined (MSDOS) || defined (__EMX__)
-static const char *mode_read_text = "rt";
-static const char *mode_write_text = "wt";
-static const char *mode_append_text = "at";
-static const char *mode_read_binary = "rb";
-static const char *mode_write_binary = "wb";
-static const char *mode_append_binary = "ab";
-static const char *mode_read_text_plus = "r+t";
-static const char *mode_write_text_plus = "w+t";
-static const char *mode_append_text_plus = "a+t";
-static const char *mode_read_binary_plus = "r+b";
-static const char *mode_write_binary_plus = "w+b";
-static const char *mode_append_binary_plus = "a+b";
+#if defined (WINNT) || defined (__CYGWIN__)
+
const char __gnat_text_translation_required = 1;
+#ifdef __CYGWIN__
+#define WIN_SETMODE setmode
+#include <io.h>
+#else
+#define WIN_SETMODE _setmode
+#endif
+
void
__gnat_set_binary_mode (int handle)
{
- _setmode (handle, O_BINARY);
+ WIN_SETMODE (handle, O_BINARY);
}
void
__gnat_set_text_mode (int handle)
{
- _setmode (handle, O_TEXT);
+ WIN_SETMODE (handle, O_TEXT);
}
-#ifdef __MINGW32__
-#include <windows.h>
-
-/* 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". */
+#ifdef __CYGWIN__
char *
__gnat_ttyname (int filedes)
{
- if (isatty (filedes))
- return "console";
- else
- return NULL;
+ extern char *ttyname (int);
+
+ return ttyname (filedes);
}
-/* This function is needed to fix a bug under Win95/98. Under these plateforms
- doing :
- ch1 = getch();
- ch2 = fgetc (stdin);
+#endif /* __CYGWIN__ */
- will put the same character into ch1 and ch2. It seem that the character
- read by getch() is not correctly removed from the buffer. Even a
- fflush(stdin) does not fix the bug. This bug does not appear under Window
- NT. So we have two version of this routine below one for 95/98 and one for
- NT/2000 version of Windows. There is also a special routine (winflushinit)
- that will be called only the first time to check which version of Windows
- we are running running on to set the right routine to use.
+#if defined (__CYGWIN__) || defined (__MINGW32__)
+#include <windows.h>
- This problem occurs when using Text_IO.Get_Line after Text_IO.Get_Immediate
- for example.
+#ifndef RTX
- Calling FlushConsoleInputBuffer just after getch() fix the bug under
- 95/98. */
+int __gnat_is_windows_xp (void);
-static void winflush_init (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;
-static void winflush_95 (void);
+ is_win_xp_checked = 1;
-static void winflush_nt (void);
+ memset (&version, 0, sizeof (version));
+ version.dwOSVersionInfoSize = sizeof (version);
-/* winflusfunction is set first to the winflushinit function which will check
- the OS version 95/98 or NT/2000 */
+ is_win_xp = GetVersionEx (&version)
+ && version.dwPlatformId == VER_PLATFORM_WIN32_NT
+ && (version.dwMajorVersion > 5
+ || (version.dwMajorVersion == 5 && version.dwMinorVersion >= 1));
+ }
+ return is_win_xp;
+}
-static void (*winflush_function) (void) = winflush_init;
+#endif /* !RTX */
-/* This function does the runtime check of the OS version and then sets
- winflush_function to the appropriate function and then call it. */
+/* 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. */
-static void
-winflush_init (void)
+void
+__gnat_get_stack_bounds (void **base, void **limit)
{
- DWORD dwVersion = GetVersion();
+ NT_TIB *tib;
- if (dwVersion < 0x80000000) /* Windows NT/2000 */
- winflush_function = winflush_nt;
- else /* Windows 95/98 */
- winflush_function = winflush_95;
-
- (*winflush_function)(); /* Perform the 'flush' */
+ /* We know that the first field of the TEB is the TIB. */
+ tib = (NT_TIB *)NtCurrentTeb ();
+ *base = tib->StackBase;
+ *limit = tib->StackLimit;
}
-static void winflush_95 (void)
-{
- FlushConsoleInputBuffer (GetStdHandle (STD_INPUT_HANDLE));
-}
+#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". */
-static void winflush_nt (void)
+char *
+__gnat_ttyname (int filedes)
{
- /* Does nothing as there is no problem under NT. */
+ if (isatty (filedes))
+ return "console";
+ else
+ return NULL;
}
-#endif
+
+#endif /* __MINGW32__ */
#else
-static const char *mode_read_text = "r";
-static const char *mode_write_text = "w";
-static const char *mode_append_text = "a";
-static const char *mode_read_binary = "r";
-static const char *mode_write_binary = "w";
-static const char *mode_append_binary = "a";
-static const char *mode_read_text_plus = "r+";
-static const char *mode_write_text_plus = "w+";
-static const char *mode_append_text_plus = "a+";
-static const char *mode_read_binary_plus = "r+";
-static const char *mode_write_binary_plus = "w+";
-static const char *mode_append_binary_plus = "a+";
const char __gnat_text_translation_required = 0;
/* These functions do nothing in non-DOS systems. */
char *
__gnat_ttyname (int filedes)
{
-#ifndef __vxworks
+#if defined (__vxworks) || defined (__nucleus)
+ return "";
+#else
extern char *ttyname (int);
return ttyname (filedes);
-
-#else
- return "";
-
-#endif
+#endif /* defined (__vxworks) || defined (__nucleus) */
}
#endif
\f
-#if defined (linux) || defined (sun) || defined (sgi) || defined (__EMX__) \
+#if defined (linux) || defined (sun) || defined (sgi) \
|| (defined (__osf__) && ! defined (__alpha_vxworks)) || defined (WINNT) \
- || defined (__MACHTEN__) || defined (hpux) || defined (_AIX) \
- || (defined (__svr4__) && defined (i386)) || defined (__Lynx__)
+ || defined (__MACHTEN__) || defined (__hpux__) || defined (_AIX) \
+ || (defined (__svr4__) && defined (i386)) || defined (__Lynx__) \
+ || defined (__CYGWIN__) || defined (__FreeBSD__) || defined (__OpenBSD__) \
+ || defined (__GLIBC__) || defined (__APPLE__)
#ifdef __MINGW32__
#if OLD_MINGW
int *avail,
int waiting)
{
-#if defined (linux) || defined (sun) || defined (sgi) || defined (__EMX__) \
+#if defined (linux) || defined (sun) || defined (sgi) \
|| (defined (__osf__) && ! defined (__alpha_vxworks)) \
- || defined (__CYGWIN32__) || defined (__MACHTEN__) || defined (hpux) \
+ || defined (__CYGWIN32__) || defined (__MACHTEN__) || defined (__hpux__) \
|| defined (_AIX) || (defined (__svr4__) && defined (i386)) \
- || defined (__Lynx__)
+ || defined (__Lynx__) || defined (__FreeBSD__) || defined (__OpenBSD__) \
+ || defined (__GLIBC__) || defined (__APPLE__)
char c;
int nread;
int good_one = 0;
/* Set RAW mode, with no echo */
termios_rec.c_lflag = termios_rec.c_lflag & ~ICANON & ~ECHO;
-#if defined(linux) || defined (sun) || defined (sgi) || defined (__EMX__) \
- || defined (__osf__) || defined (__MACHTEN__) || defined (hpux) \
+#if defined(linux) || defined (sun) || defined (sgi) \
+ || defined (__osf__) || defined (__MACHTEN__) || defined (__hpux__) \
|| defined (_AIX) || (defined (__svr4__) && defined (i386)) \
- || defined (__Lynx__)
+ || defined (__Lynx__) || defined (__FreeBSD__) || defined (__OpenBSD__) \
+ || defined (__GLIBC__) || defined (__APPLE__)
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 except on OS/2 where Ctrl-C won't work right
- unless we do a read loop. Luckily we can delay a bit between
- iterations. If not waiting (i.e. Get_Immediate (Char, Available)),
+ Ctrl-C processing.
+ If not waiting (i.e. Get_Immediate (Char, Available)),
don't wait for anything but timeout immediately. */
-#ifdef __EMX__
- termios_rec.c_cc[VMIN] = 0;
- termios_rec.c_cc[VTIME] = waiting;
-#else
termios_rec.c_cc[VMIN] = waiting;
termios_rec.c_cc[VTIME] = 0;
#endif
-#endif
tcsetattr (fd, TCSANOW, &termios_rec);
while (! good_one)
if (waiting)
{
*ch = getch ();
- (*winflush_function) ();
if (*ch == eot_ch)
*end_of_file = 1;
{
*avail = 1;
*ch = getch ();
- (*winflush_function) ();
if (*ch == eot_ch)
*end_of_file = 1;
/* This gets around a problem with using the old threads library on VMS 7.0. */
-#include <time.h>
-
extern long get_gmtoff (void);
long
}
#endif
-/* Definition of __gnat_locatime_r used by a-calend.adb */
+/* 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__)
+
+#ifdef CERT
+
+/* For the Cert run times on native Windows we use dummy functions
+ for locking and unlocking tasks since we do not support multiple
+ threads on this configuration (Cert run time on native Windows). */
+
+void dummy (void) {}
+
+void (*Lock_Task) () = &dummy;
+void (*Unlock_Task) () = &dummy;
+
+#else
-#if defined (_AIX) || defined (__EMX__)
#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);
-/* Provide reentrant version of localtime on Aix and OS/2. Note that AiX does
- provide localtime_r, but in the library libc_r which doesn't get included
- systematically, so we can't use it. */
+#endif
+
+/* Reentrant localtime for Windows. */
-extern struct tm *__gnat_localtime_r (const time_t *, struct tm *);
+extern void
+__gnat_localtime_tzoff (const time_t *, const int *, long *);
-struct tm *
-__gnat_localtime_r (const time_t *timer, struct tm *tp)
+static const unsigned long long w32_epoch_offset = 11644473600ULL;
+void
+__gnat_localtime_tzoff (const time_t *timer, const int *is_historic, long *off)
{
- struct tm *tmp;
+ TIME_ZONE_INFORMATION tzi;
+
+ BOOL rtx_active;
+ DWORD tzi_status;
+
+#ifdef RTX
+ rtx_active = 1;
+#else
+ rtx_active = 0;
+#endif
(*Lock_Task) ();
- tmp = localtime (timer);
- memcpy (tp, tmp, sizeof (struct tm));
+
+ tzi_status = GetTimeZoneInformation (&tzi);
+
+ /* Processing for RTX targets or cases where we simply want to extract the
+ offset of the current time zone, regardless of the date. */
+
+ if (rtx_active || !is_historic) {
+ *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 informations. 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 >= 0 && 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 occured, 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);
+ }
+ }
+ }
+
(*Unlock_Task) ();
- return tp;
}
#else
-#if defined (__Lynx__) && defined (___THREADS_POSIX4ad4__)
+
+/* On Lynx, all time values are treated in GMT */
+
+#if defined (__Lynx__)
/* As of LynxOS 3.1.0a patch level 040, LynuxWorks changes the
prototype to the C library function localtime_r from the POSIX.4
spec is required. Only use when ___THREADS_POSIX4ad4__ is defined,
the Lynx convention when building against the legacy API. */
-extern struct tm *__gnat_localtime_r (const time_t *, struct tm *);
+extern void
+__gnat_localtime_tzoff (const time_t *, const int *, long *);
-struct tm *
-__gnat_localtime_r (const time_t *timer, struct tm *tp)
+void
+__gnat_localtime_tzoff (const time_t *timer, const int *is_historic, long *off)
{
- localtime_r (tp, timer);
- return NULL;
+ *off = 0;
}
#else
-#if defined (VMS) || defined (__MINGW32__)
-/* __gnat_localtime_r is not needed on NT and VMS */
+/* VMS does not need __gnat_localtime_tzoff */
+
+#if defined (VMS)
+
+/* Other targets except Lynx, VMS and Windows provide a standard localtime_r */
+
+#else
+
+#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, const int *is_historic, long *off)
+{
+ struct tm tp;
+
+/* AIX, HPUX, SGI Irix, Sun Solaris */
+#if defined (_AIX) || defined (__hpux__) || defined (sgi) || 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, Tru64, where component tm_gmtoff is present in
+ struct tm */
+
+#elif defined (__APPLE__) || defined (__FreeBSD__) || defined (linux) ||\
+ (defined (__alpha__) && defined (__osf__)) || defined (__GLIBC__)
+{
+ localtime_r (timer, &tp);
+ *off = tp.tm_gmtoff;
+}
+
+/* Default: treat all time values in GMT */
#else
+ *off = 0;
-/* All other targets provide a standard localtime_r */
+#endif
+}
-extern struct tm *__gnat_localtime_r (const time_t *, struct tm *);
+#endif
+#endif
+#endif
+
+#ifdef __vxworks
+
+#include <taskLib.h>
-struct tm *
-__gnat_localtime_r (const time_t *timer, struct tm *tp)
+/* __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)
{
- return (struct tm *) localtime_r (timer, tp);
+ 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
+ return options & VX_USR_TASK_OPTIONS;
+#else
+ return options;
+#endif
}
+
#endif
+
+int
+__gnat_is_file_not_found_error (int errno_val) {
+ switch (errno_val) {
+ case ENOENT:
+#ifdef __vxworks
+ /* In the case of VxWorks, we also have to take into account various
+ * filesystem-specific variants of this error.
+ */
+#if ! defined (VTHREADS)
+ case S_dosFsLib_FILE_NOT_FOUND:
+#endif
+#if ! defined (__RTP__) && (! defined (VTHREADS) || defined (__VXWORKSMILS__))
+ case S_nfsLib_NFSERR_NOENT:
#endif
#endif
+ return 1;
+
+ default:
+ return 0;
+ }
+}