OSDN Git Service

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