OSDN Git Service

2002-08-25 Andre Leis <a.leis@gmx.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  *                                                                          *
10  *          Copyright (C) 1992-2002 Free Software Foundation, Inc.          *
11  *                                                                          *
12  * GNAT is free software;  you can  redistribute it  and/or modify it under *
13  * terms of the  GNU General Public License as published  by the Free Soft- *
14  * ware  Foundation;  either version 2,  or (at your option) any later ver- *
15  * sion.  GNAT is distributed in the hope that it will be useful, but WITH- *
16  * OUT ANY WARRANTY;  without even the  implied warranty of MERCHANTABILITY *
17  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License *
18  * for  more details.  You should have  received  a copy of the GNU General *
19  * Public License  distributed with GNAT;  see file COPYING.  If not, write *
20  * to  the Free Software Foundation,  59 Temple Place - Suite 330,  Boston, *
21  * MA 02111-1307, USA.                                                      *
22  *                                                                          *
23  * As a  special  exception,  if you  link  this file  with other  files to *
24  * produce an executable,  this file does not by itself cause the resulting *
25  * executable to be covered by the GNU General Public License. This except- *
26  * ion does not  however invalidate  any other reasons  why the  executable *
27  * file might be covered by the  GNU Public License.                        *
28  *                                                                          *
29  * GNAT was originally developed  by the GNAT team at  New York University. *
30  * It is now maintained by Ada Core Technologies Inc (http://www.gnat.com). *
31  *                                                                          *
32  ****************************************************************************/
33
34 /* This file contains system dependent symbols that are referenced in the
35    GNAT Run Time Library */
36
37 #ifdef __vxworks
38 #include "ioLib.h"
39 #include "selectLib.h"
40 #include "vxWorks.h"
41 #endif
42 #ifdef IN_RTS
43 #define POSIX
44 #include "tconfig.h"
45 #include "tsystem.h"
46 #include <fcntl.h>
47 #include <sys/stat.h>
48 #include "time.h"
49 #else
50 #include "config.h"
51 #include "system.h"
52 #endif
53
54 #include "adaint.h"
55
56 /*
57    mode_read_text
58    open text file for reading
59    rt for DOS and Windows NT, r for Unix
60
61    mode_write_text
62    truncate to zero length or create text file for writing
63    wt for DOS and Windows NT, w for Unix
64
65    mode_append_text
66    append; open or create text file for writing at end-of-file
67    at for DOS and Windows NT, a for Unix
68
69    mode_read_binary
70    open binary file for reading
71    rb for DOS and Windows NT, r for Unix
72
73    mode_write_binary
74    truncate to zero length or create binary file for writing
75    wb for DOS and Windows NT, w for Unix
76
77    mode_append_binary
78    append; open or create binary file for writing at end-of-file
79    ab for DOS and Windows NT, a for Unix
80
81    mode_read_text_plus
82    open text file for update (reading and writing)
83    r+t for DOS and Windows NT, r+ for Unix
84
85    mode_write_text_plus
86    truncate to zero length or create text file for update
87    w+t for DOS and Windows NT, w+ for Unix
88
89    mode_append_text_plus
90    append; open or create text file for update, writing at end-of-file
91    a+t for DOS and Windows NT, a+ for Unix
92
93    mode_read_binary_plus
94    open binary file for update (reading and writing)
95    r+b for DOS and Windows NT, r+ for Unix
96
97    mode_write_binary_plus
98    truncate to zero length or create binary file for update
99    w+b for DOS and Windows NT, w+ for Unix
100
101    mode_append_binary_plus
102    append; open or create binary file for update, writing at end-of-file
103    a+b for DOS and Windows NT, a+ for Unix
104
105    Notes:
106
107    (1) Opening a file with read mode fails if the file does not exist or
108    cannot be read.
109
110    (2) Opening a file with append mode causes all subsequent writes to the
111    file to be forced to the then current end-of-file, regardless of
112    intervening calls to the fseek function.
113
114    (3) When a file is opened with update mode, both input and output may be
115    performed on the associated stream.  However, output may not be directly
116    followed by input without an intervening call to the fflush function or
117    to a file positioning function (fseek, fsetpos, or rewind), and input
118    may not be directly followed by output without an intervening call to a
119    file positioning function, unless the input operation encounters
120    end-of-file.
121
122    The other target dependent declarations here are for the two functions
123    __gnat_set_binary_mode and __gnat_set_text_mode:
124
125       void __gnat_set_binary_mode (int handle);
126       void __gnat_set_text_mode   (int handle);
127
128    These functions have no effect in Unix (or similar systems where there is
129    no distinction between binary and text files), but in DOS (and similar
130    systems where text mode does CR/LF translation), these functions allow
131    the mode of the stream with the given handle (fileno can be used to get
132    the handle of a stream) to be changed dynamically. The returned result
133    is 0 if no error occurs and -1 if an error occurs.
134
135    Finally there is a boolean (character) variable
136
137       char __gnat_text_translation_required;
138
139    which is zero (false) in Unix mode, and one (true) in DOS mode, with a
140    true value indicating that text translation is required on text files
141    and that fopen supports the trailing t and b modifiers.
142
143 */
144
145 #if defined(WINNT) || defined (MSDOS) || defined (__EMX__)
146 static const char *mode_read_text = "rt";
147 static const char *mode_write_text = "wt";
148 static const char *mode_append_text = "at";
149 static const char *mode_read_binary = "rb";
150 static const char *mode_write_binary = "wb";
151 static const char *mode_append_binary = "ab";
152 static const char *mode_read_text_plus = "r+t";
153 static const char *mode_write_text_plus = "w+t";
154 static const char *mode_append_text_plus = "a+t";
155 static const char *mode_read_binary_plus = "r+b";
156 static const char *mode_write_binary_plus = "w+b";
157 static const char *mode_append_binary_plus = "a+b";
158 const char __gnat_text_translation_required = 1;
159
160 void
161 __gnat_set_binary_mode (handle)
162      int handle;
163 {
164   _setmode (handle, O_BINARY);
165 }
166
167 void
168 __gnat_set_text_mode (handle)
169      int handle;
170 {
171   _setmode (handle, O_TEXT);
172 }
173
174 #ifdef __MINGW32__
175 #include <windows.h>
176
177 /* Return the name of the tty.   Under windows there is no name for
178    the tty, so this function, if connected to a tty, returns the generic name
179    "console".  */
180
181 char *
182 __gnat_ttyname (filedes)
183      int filedes;
184 {
185   if (isatty (filedes))
186     return "console";
187   else
188     return NULL;
189 }
190
191 /* This function is needed to fix a bug under Win95/98. Under these plateforms
192    doing :
193                 ch1 = getch();
194                 ch2 = fgetc (stdin);
195
196    will put the same character into ch1 and ch2. It seem that the character
197    read by getch() is not correctly removed from the buffer. Even a
198    fflush(stdin) does not fix the bug. This bug does not appear under Window
199    NT. So we have two version of this routine below one for 95/98 and one for
200    NT/2000 version of Windows. There is also a special routine (winflushinit)
201    that will be called only the first time to check which version of Windows
202    we are running running on to set the right routine to use.
203
204    This problem occurs when using Text_IO.Get_Line after Text_IO.Get_Immediate
205    for example.
206
207    Calling FlushConsoleInputBuffer just after getch() fix the bug under 
208    95/98. */
209
210 static void winflush_init PARAMS ((void));
211
212 static void winflush_95 PARAMS ((void));
213
214 static void winflush_nt PARAMS ((void));
215
216 /* winflusfunction is set first to the winflushinit function which will check
217    the OS version 95/98 or NT/2000 */
218
219 static void (*winflush_function) PARAMS ((void)) = winflush_init;
220
221 /* This function does the runtime check of the OS version and then sets
222    winflush_function to the appropriate function and then call it. */ 
223
224 static void
225 winflush_init ()
226
227   DWORD dwVersion = GetVersion();
228
229   if (dwVersion < 0x80000000)                /* Windows NT/2000 */
230     winflush_function = winflush_nt;
231   else                                       /* Windows 95/98   */
232     winflush_function = winflush_95;
233
234   (*winflush_function)();      /* Perform the 'flush' */
235
236 }
237
238 static void winflush_95 ()
239
240   FlushConsoleInputBuffer (GetStdHandle (STD_INPUT_HANDLE));
241 }
242
243 static void winflush_nt ()
244 {
245   /* Does nothing as there is no problem under NT.  */
246 }
247 #endif
248
249 #else
250
251 static const char *mode_read_text = "r";
252 static const char *mode_write_text = "w";
253 static const char *mode_append_text = "a";
254 static const char *mode_read_binary = "r";
255 static const char *mode_write_binary = "w";
256 static const char *mode_append_binary = "a";
257 static const char *mode_read_text_plus = "r+";
258 static const char *mode_write_text_plus = "w+";
259 static const char *mode_append_text_plus = "a+";
260 static const char *mode_read_binary_plus = "r+";
261 static const char *mode_write_binary_plus = "w+";
262 static const char *mode_append_binary_plus = "a+";
263 const char __gnat_text_translation_required = 0;
264
265 /* These functions do nothing in non-DOS systems. */
266
267 void
268 __gnat_set_binary_mode (handle)
269      int handle ATTRIBUTE_UNUSED;
270 {
271 }
272
273 void
274 __gnat_set_text_mode (handle)
275      int handle ATTRIBUTE_UNUSED;
276 {
277 }
278 char *
279 __gnat_ttyname (filedes)
280      int filedes;
281 {
282 #ifndef __vxworks
283   extern char *ttyname PARAMS ((int));
284
285   return ttyname (filedes);
286
287 #else
288   return "";
289
290 #endif
291 }
292 #endif
293 \f
294 #if defined (linux) || defined (sun) || defined (sgi) || defined (__EMX__) \
295   || (defined (__osf__) && ! defined (__alpha_vxworks)) || defined (WINNT) \
296   || defined (__MACHTEN__) || defined (hpux) || defined (_AIX) \
297   || (defined (__svr4__) && defined (i386)) || defined (__Lynx__) \
298   || defined (__CYGWIN__)
299 #include <termios.h>
300
301 #else
302 #if defined (VMS)
303 extern char *decc$ga_stdscr;
304 static int initted = 0;
305 #endif
306 #endif
307
308 /* Implements the common processing for getc_immediate and
309    getc_immediate_nowait. */
310
311 extern void getc_immediate              PARAMS ((FILE *, int *, int *));
312 extern void getc_immediate_nowait       PARAMS ((FILE *, int *, int *, int *));
313 extern void getc_immediate_common       PARAMS ((FILE *, int *, int *,
314                                                  int *, int));
315
316 /* Called by Get_Immediate (Foo); */
317
318 void
319 getc_immediate (stream, ch, end_of_file)
320      FILE *stream;
321      int *ch;
322      int *end_of_file;
323 {
324   int avail;
325
326   getc_immediate_common (stream, ch, end_of_file, &avail, 1);
327 }
328
329 /* Called by Get_Immediate (Foo, Available); */
330
331 void
332 getc_immediate_nowait (stream, ch, end_of_file, avail)
333      FILE *stream;
334      int *ch;
335      int *end_of_file;
336      int *avail;
337 {
338   getc_immediate_common (stream, ch, end_of_file, avail, 0);
339 }
340
341 /* Called by getc_immediate () and getc_immediate_nowait () */
342
343 void
344 getc_immediate_common (stream, ch, end_of_file, avail, waiting)
345      FILE *stream;
346      int *ch;
347      int *end_of_file;
348      int *avail;
349      int waiting;
350 {
351 #if defined (linux) || defined (sun) || defined (sgi) || defined (__EMX__) \
352     || (defined (__osf__) && ! defined (__alpha_vxworks)) \
353     || defined (__CYGWIN__) || defined (__MACHTEN__) || defined (hpux) \
354     || defined (_AIX) || (defined (__svr4__) && defined (i386)) \
355     || defined (__Lynx__)
356   char c;
357   int nread;
358   int good_one = 0;
359   int eof_ch = 4; /* Ctrl-D */
360   int fd = fileno (stream);
361   struct termios otermios_rec, termios_rec;
362
363   if (isatty (fd))
364     {
365       tcgetattr (fd, &termios_rec);
366       memcpy (&otermios_rec, &termios_rec, sizeof (struct termios));
367
368       /* Set RAW mode, with no echo */
369       termios_rec.c_lflag = termios_rec.c_lflag & ~ICANON & ~ECHO;
370
371 #if defined(linux) || defined (sun) || defined (sgi) || defined (__EMX__) \
372     || defined (__osf__) || defined (__MACHTEN__) || defined (hpux) \
373     || defined (_AIX) || (defined (__svr4__) && defined (i386)) \
374     || defined (__Lynx__)
375       eof_ch = termios_rec.c_cc[VEOF];
376
377       /* If waiting (i.e. Get_Immediate (Char)), set MIN = 1 and wait for
378          a character forever. This doesn't seem to effect Ctrl-Z or
379          Ctrl-C processing except on OS/2 where Ctrl-C won't work right
380          unless we do a read loop. Luckily we can delay a bit between
381          iterations. If not waiting (i.e. Get_Immediate (Char, Available)),
382          don't wait for anything but timeout immediately. */
383 #ifdef __EMX__
384       termios_rec.c_cc[VMIN] = 0;
385       termios_rec.c_cc[VTIME] = waiting;
386 #else
387       termios_rec.c_cc[VMIN] = waiting;
388       termios_rec.c_cc[VTIME] = 0;
389 #endif
390 #endif
391       tcsetattr (fd, TCSANOW, &termios_rec);
392
393       while (! good_one)
394         {
395           /* Read is used here instead of fread, because fread doesn't
396              work on Solaris5 and Sunos4 in this situation.  Maybe because we
397              are mixing calls that use file descriptors and streams. */
398           nread = read (fd, &c, 1);
399           if (nread > 0)
400             {
401               /* On Unix terminals, Ctrl-D (EOT) is an End of File. */
402               if (c == eof_ch)
403                 {
404                   *avail = 0;
405                   *end_of_file = 1;
406                   good_one = 1;
407                 }
408
409               /* Everything else is ok */
410               else if (c != eof_ch)
411                 {
412                   *avail = 1;
413                   *end_of_file = 0;
414                   good_one = 1;
415                 }
416             }
417
418           else if (! waiting)
419             {
420               *avail = 0;
421               *end_of_file = 0;
422               good_one = 1;
423             }
424           else
425             good_one = 0;
426         }
427
428       tcsetattr (fd, TCSANOW, &otermios_rec);
429       *ch = c;
430     }
431
432   else
433 #elif defined (VMS)
434   int fd = fileno (stream);
435
436   if (isatty (fd))
437     {
438       if (initted == 0)
439         {
440           decc$bsd_initscr ();
441           initted = 1;
442         }
443
444       decc$bsd_cbreak ();
445       *ch = decc$bsd_wgetch (decc$ga_stdscr);
446
447       if (*ch == 4)
448         *end_of_file = 1;
449       else
450         *end_of_file = 0;
451
452       *avail = 1;
453       decc$bsd_nocbreak ();
454     }
455   else
456 #elif defined (__MINGW32__)
457   int fd = fileno (stream);
458   int char_waiting;
459   int eot_ch = 4; /* Ctrl-D */
460
461   if (isatty (fd))
462     {
463       if (waiting)
464         {
465           *ch = getch ();
466           (*winflush_function) ();
467
468           if (*ch == eot_ch)
469             *end_of_file = 1;
470           else
471             *end_of_file = 0;
472
473           *avail = 1;
474         }
475       else /* ! waiting */
476         {
477           char_waiting = kbhit();
478
479           if (char_waiting == 1)
480             {
481               *avail = 1;
482               *ch = getch ();
483               (*winflush_function) ();
484
485               if (*ch == eot_ch)
486                 *end_of_file = 1;
487               else
488                 *end_of_file = 0;
489             }
490           else
491             {
492               *avail = 0;
493               *end_of_file = 0;
494             }
495         }
496     }
497   else
498 #elif defined (__vxworks)
499   /* Bit masks of file descriptors to read from.  */
500   struct fd_set readFds;
501   /* Timeout before select returns if nothing can be read.  */ 
502   struct timeval timeOut;
503   char c;
504   int fd = fileno (stream);
505   int nread;
506   int option;
507   int readable;
508   int status;
509   int width;
510
511   if (isatty (fd)) 
512     {
513       /* If we do not want to wait, we have to set up fd in RAW mode. This
514          should be done outside this function as setting fd in RAW mode under
515          vxWorks flushes the buffer of fd. If the RAW mode was set here, the
516          buffer would be empty and we would always return that no character
517          is available */
518       if (! waiting) 
519         {
520           /* Initialization of timeOut for its use with select.  */
521           timeOut.tv_sec  = 0;
522           timeOut.tv_usec = 0;
523
524           /* Initialization of readFds for its use with select;
525              FD is the only file descriptor to be monitored */
526           FD_ZERO (&readFds);
527           FD_SET (fd, &readFds);
528           width = 2;
529
530           /* We do all this processing to emulate a non blocking read.  */
531           readable = select (width, &readFds, NULL, NULL, &timeOut);
532           if (readable == ERROR)
533             *avail = -1, *end_of_file = -1;
534           /* No character available in input.  */
535           else if (readable == 0)
536             *avail = 0, *end_of_file = 0;
537           else
538             {
539               nread = read (fd, &c, 1);
540               if (nread > 0) 
541                 *avail = 1, *end_of_file = 0;
542               /* End Of File. */
543               else if (nread == 0) 
544                 *avail = 0, *end_of_file = 1;
545               /* Error.  */
546               else 
547                 *avail = -1, *end_of_file = -1;
548             }   
549         }
550
551       /* We have to wait until we get a character */
552       else 
553         {
554           *avail = -1;
555           *end_of_file = -1;
556
557           /* Save the current mode of FD.  */
558           option = ioctl (fd, FIOGETOPTIONS, 0);
559
560           /* Set FD in RAW mode.  */
561           status = ioctl (fd, FIOSETOPTIONS, OPT_RAW);
562           if (status != -1) 
563             {
564               nread = read (fd, &c, 1);
565               if (nread > 0) 
566                 *avail = 1, *end_of_file = 0;
567               /* End of file.  */
568               else if (nread == 0) 
569                 *avail = 0, *end_of_file = 1;
570               /* Else there is an ERROR.  */
571             }
572
573           /* Revert FD to its previous mode. */
574           status = ioctl (fd, FIOSETOPTIONS, option);
575         }
576
577       *ch = c;
578     }
579   else
580 #endif
581     {
582       /* If we're not on a terminal, then we don't need any fancy processing.
583          Also this is the only thing that's left if we're not on one of the
584          supported systems; which means that for non supported systems,
585          get_immediate may wait for a carriage return on terminals. */
586       *ch = fgetc (stream);
587       if (feof (stream))
588         {
589           *end_of_file = 1;
590           *avail = 0;
591         }
592       else
593         {
594           *end_of_file = 0;
595           *avail = 1;
596         }
597     }
598 }
599
600 /* The following definitions are provided in NT to support Windows based
601    Ada programs.  */
602
603 #ifdef WINNT
604 #include <windows.h>
605
606 /* Provide functions to echo the values passed to WinMain (windows bindings
607    will want to import these).  We use the same names as the routines used
608    by AdaMagic for compatibility.  */
609
610 char *rts_get_hInstance     PARAMS ((void));
611 char *rts_get_hPrevInstance PARAMS ((void));
612 char *rts_get_lpCommandLine PARAMS ((void));
613 int   rts_get_nShowCmd      PARAMS ((void));
614
615 char *
616 rts_get_hInstance () 
617
618   return GetModuleHandleA (0); 
619 }
620
621 char *
622 rts_get_hPrevInstance () 
623
624   return 0; 
625 }
626
627 char *
628 rts_get_lpCommandLine () 
629
630   return GetCommandLineA (); 
631 }
632
633 int   
634 rts_get_nShowCmd () 
635
636   return 1; 
637 }
638
639 #endif /* WINNT */
640 #ifdef VMS
641
642 /* This gets around a problem with using the old threads library on VMS 7.0. */
643
644 #include <time.h>
645
646 extern long get_gmtoff PARAMS ((void));
647
648 long
649 get_gmtoff ()
650 {
651   time_t t;
652   struct tm *ts;
653
654   t = time ((time_t) 0);
655   ts = localtime (&t);
656   return ts->tm_gmtoff;
657 }
658 #endif
659
660 /* Definition of __gnat_locatime_r used by a-calend.adb */
661
662 #if defined (_AIX) || defined (__EMX__)
663 #define Lock_Task system__soft_links__lock_task
664 extern void (*Lock_Task) PARAMS ((void));
665
666 #define Unlock_Task system__soft_links__unlock_task
667 extern void (*Unlock_Task) PARAMS ((void));
668
669 /* Provide reentrant version of localtime on Aix and OS/2. Note that AiX does
670    provide localtime_r, but in the library libc_r which doesn't get included
671    systematically, so we can't use it. */
672
673 extern void struct tm *__gnat_localtime_r PARAMS ((const time_t *,
674                                                    struct tm *));
675
676 struct tm *
677 __gnat_localtime_r (timer, tp)
678      const time_t *timer;
679      struct tm *tp;
680 {
681   struct tm *tmp;
682
683   (*Lock_Task) ();
684   tmp = localtime (timer);
685   memcpy (tp, tmp, sizeof (struct tm));
686   (*Unlock_Task) ();
687   return tp;
688 }
689
690 #else
691 #if defined (__Lynx__) && defined (___THREADS_POSIX4ad4__)
692
693 /* As of LynxOS 3.1.0a patch level 040, LynuxWorks changes the
694    prototype to the C library function localtime_r from the POSIX.4
695    Draft 9 to the POSIX 1.c version. Before this change the following
696    spec is required. Only use when ___THREADS_POSIX4ad4__ is defined,
697    the Lynx convention when building against the legacy API. */
698
699 extern struct tm *__gnat_localtime_r PARAMS ((const time_t *, struct tm *));
700
701 struct tm *
702 __gnat_localtime_r (timer, tp)
703      const time_t *timer;
704      struct tm *tp;
705 {
706   localtime_r (tp, timer);
707   return NULL;
708 }
709
710 #else
711 #if defined (VMS) || defined (__MINGW32__)
712
713 /* __gnat_localtime_r is not needed on NT and VMS */
714
715 #else
716
717 /* All other targets provide a standard localtime_r */
718
719 extern struct tm *__gnat_localtime_r PARAMS ((const time_t *, struct tm *));
720
721 struct tm *
722 __gnat_localtime_r (timer, tp)
723      const time_t *timer;
724      struct tm *tp;
725 {
726   return (struct tm *) localtime_r (timer, tp);
727 }
728 #endif
729 #endif
730 #endif