OSDN Git Service

* 41intnam.ads, 42intnam.ads, 4aintnam.ads, 4cintnam.ads,
[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  *                            $Revision$
10  *                                                                          *
11  *          Copyright (C) 1992-2002 Free Software Foundation, Inc.          *
12  *                                                                          *
13  * GNAT is free software;  you can  redistribute it  and/or modify it under *
14  * terms of the  GNU General Public License as published  by the Free Soft- *
15  * ware  Foundation;  either version 2,  or (at your option) any later ver- *
16  * sion.  GNAT is distributed in the hope that it will be useful, but WITH- *
17  * OUT ANY WARRANTY;  without even the  implied warranty of MERCHANTABILITY *
18  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License *
19  * for  more details.  You should have  received  a copy of the GNU General *
20  * Public License  distributed with GNAT;  see file COPYING.  If not, write *
21  * to  the Free Software Foundation,  59 Temple Place - Suite 330,  Boston, *
22  * MA 02111-1307, USA.                                                      *
23  *                                                                          *
24  * As a  special  exception,  if you  link  this file  with other  files to *
25  * produce an executable,  this file does not by itself cause the resulting *
26  * executable to be covered by the GNU General Public License. This except- *
27  * ion does not  however invalidate  any other reasons  why the  executable *
28  * file might be covered by the  GNU Public License.                        *
29  *                                                                          *
30  * GNAT was originally developed  by the GNAT team at  New York University. *
31  * It is now maintained by Ada Core Technologies Inc (http://www.gnat.com). *
32  *                                                                          *
33  ****************************************************************************/
34
35 /* This file contains system dependent symbols that are referenced in the
36    GNAT Run Time Library */
37
38 #ifdef __vxworks
39 #include "ioLib.h"
40 #include "selectLib.h"
41 #include "vxWorks.h"
42 #endif
43 #ifdef IN_RTS
44 #define POSIX
45 #include "tconfig.h"
46 #include "tsystem.h"
47 #include <fcntl.h>
48 #include <sys/stat.h>
49 #include "time.h"
50 #else
51 #include "config.h"
52 #include "system.h"
53 #endif
54
55 #include "adaint.h"
56
57 /*
58    mode_read_text
59    open text file for reading
60    rt for DOS and Windows NT, r for Unix
61
62    mode_write_text
63    truncate to zero length or create text file for writing
64    wt for DOS and Windows NT, w for Unix
65
66    mode_append_text
67    append; open or create text file for writing at end-of-file
68    at for DOS and Windows NT, a for Unix
69
70    mode_read_binary
71    open binary file for reading
72    rb for DOS and Windows NT, r for Unix
73
74    mode_write_binary
75    truncate to zero length or create binary file for writing
76    wb for DOS and Windows NT, w for Unix
77
78    mode_append_binary
79    append; open or create binary file for writing at end-of-file
80    ab for DOS and Windows NT, a for Unix
81
82    mode_read_text_plus
83    open text file for update (reading and writing)
84    r+t for DOS and Windows NT, r+ for Unix
85
86    mode_write_text_plus
87    truncate to zero length or create text file for update
88    w+t for DOS and Windows NT, w+ for Unix
89
90    mode_append_text_plus
91    append; open or create text file for update, writing at end-of-file
92    a+t for DOS and Windows NT, a+ for Unix
93
94    mode_read_binary_plus
95    open binary file for update (reading and writing)
96    r+b for DOS and Windows NT, r+ for Unix
97
98    mode_write_binary_plus
99    truncate to zero length or create binary file for update
100    w+b for DOS and Windows NT, w+ for Unix
101
102    mode_append_binary_plus
103    append; open or create binary file for update, writing at end-of-file
104    a+b for DOS and Windows NT, a+ for Unix
105
106    Notes:
107
108    (1) Opening a file with read mode fails if the file does not exist or
109    cannot be read.
110
111    (2) Opening a file with append mode causes all subsequent writes to the
112    file to be forced to the then current end-of-file, regardless of
113    intervening calls to the fseek function.
114
115    (3) When a file is opened with update mode, both input and output may be
116    performed on the associated stream.  However, output may not be directly
117    followed by input without an intervening call to the fflush function or
118    to a file positioning function (fseek, fsetpos, or rewind), and input
119    may not be directly followed by output without an intervening call to a
120    file positioning function, unless the input operation encounters
121    end-of-file.
122
123    The other target dependent declarations here are for the two functions
124    __gnat_set_binary_mode and __gnat_set_text_mode:
125
126       void __gnat_set_binary_mode (int handle);
127       void __gnat_set_text_mode   (int handle);
128
129    These functions have no effect in Unix (or similar systems where there is
130    no distinction between binary and text files), but in DOS (and similar
131    systems where text mode does CR/LF translation), these functions allow
132    the mode of the stream with the given handle (fileno can be used to get
133    the handle of a stream) to be changed dynamically. The returned result
134    is 0 if no error occurs and -1 if an error occurs.
135
136    Finally there is a boolean (character) variable
137
138       char __gnat_text_translation_required;
139
140    which is zero (false) in Unix mode, and one (true) in DOS mode, with a
141    true value indicating that text translation is required on text files
142    and that fopen supports the trailing t and b modifiers.
143
144 */
145
146 #if defined(WINNT) || defined (MSDOS) || defined (__EMX__)
147 static const char *mode_read_text = "rt";
148 static const char *mode_write_text = "wt";
149 static const char *mode_append_text = "at";
150 static const char *mode_read_binary = "rb";
151 static const char *mode_write_binary = "wb";
152 static const char *mode_append_binary = "ab";
153 static const char *mode_read_text_plus = "r+t";
154 static const char *mode_write_text_plus = "w+t";
155 static const char *mode_append_text_plus = "a+t";
156 static const char *mode_read_binary_plus = "r+b";
157 static const char *mode_write_binary_plus = "w+b";
158 static const char *mode_append_binary_plus = "a+b";
159 const char __gnat_text_translation_required = 1;
160
161 void
162 __gnat_set_binary_mode (handle)
163      int handle;
164 {
165   _setmode (handle, O_BINARY);
166 }
167
168 void
169 __gnat_set_text_mode (handle)
170      int handle;
171 {
172   _setmode (handle, O_TEXT);
173 }
174
175 #ifdef __MINGW32__
176 #include <windows.h>
177
178 /* Return the name of the tty.   Under windows there is no name for
179    the tty, so this function, if connected to a tty, returns the generic name
180    "console".  */
181
182 char *
183 __gnat_ttyname (filedes)
184      int filedes;
185 {
186   if (isatty (filedes))
187     return "console";
188   else
189     return NULL;
190 }
191
192 /* This function is needed to fix a bug under Win95/98. Under these plateforms
193    doing :
194                 ch1 = getch();
195                 ch2 = fgetc (stdin);
196
197    will put the same character into ch1 and ch2. It seem that the character
198    read by getch() is not correctly removed from the buffer. Even a
199    fflush(stdin) does not fix the bug. This bug does not appear under Window
200    NT. So we have two version of this routine below one for 95/98 and one for
201    NT/2000 version of Windows. There is also a special routine (winflushinit)
202    that will be called only the first time to check which version of Windows
203    we are running running on to set the right routine to use.
204
205    This problem occurs when using Text_IO.Get_Line after Text_IO.Get_Immediate
206    for example.
207
208    Calling FlushConsoleInputBuffer just after getch() fix the bug under 
209    95/98. */
210
211 static void winflush_init PARAMS ((void));
212
213 static void winflush_95 PARAMS ((void));
214
215 static void winflush_nt PARAMS ((void));
216
217 /* winflusfunction is set first to the winflushinit function which will check
218    the OS version 95/98 or NT/2000 */
219
220 static void (*winflush_function) PARAMS ((void)) = winflush_init;
221
222 /* This function does the runtime check of the OS version and then sets
223    winflush_function to the appropriate function and then call it. */ 
224
225 static void
226 winflush_init ()
227
228   DWORD dwVersion = GetVersion();
229
230   if (dwVersion < 0x80000000)                /* Windows NT/2000 */
231     winflush_function = winflush_nt;
232   else                                       /* Windows 95/98   */
233     winflush_function = winflush_95;
234
235   (*winflush_function)();      /* Perform the 'flush' */
236
237 }
238
239 static void winflush_95 ()
240
241   FlushConsoleInputBuffer (GetStdHandle (STD_INPUT_HANDLE));
242 }
243
244 static void winflush_nt ()
245 {
246   /* Does nothing as there is no problem under NT.  */
247 }
248 #endif
249
250 #else
251
252 static const char *mode_read_text = "r";
253 static const char *mode_write_text = "w";
254 static const char *mode_append_text = "a";
255 static const char *mode_read_binary = "r";
256 static const char *mode_write_binary = "w";
257 static const char *mode_append_binary = "a";
258 static const char *mode_read_text_plus = "r+";
259 static const char *mode_write_text_plus = "w+";
260 static const char *mode_append_text_plus = "a+";
261 static const char *mode_read_binary_plus = "r+";
262 static const char *mode_write_binary_plus = "w+";
263 static const char *mode_append_binary_plus = "a+";
264 const char __gnat_text_translation_required = 0;
265
266 /* These functions do nothing in non-DOS systems. */
267
268 void
269 __gnat_set_binary_mode (handle)
270      int handle ATTRIBUTE_UNUSED;
271 {
272 }
273
274 void
275 __gnat_set_text_mode (handle)
276      int handle ATTRIBUTE_UNUSED;
277 {
278 }
279 char *
280 __gnat_ttyname (filedes)
281      int filedes;
282 {
283 #ifndef __vxworks
284   extern char *ttyname PARAMS ((int));
285
286   return ttyname (filedes);
287
288 #else
289   return "";
290
291 #endif
292 }
293 #endif
294 \f
295 #if defined (linux) || defined (sun) || defined (sgi) || defined (__EMX__) \
296   || (defined (__osf__) && ! defined (__alpha_vxworks)) || defined (WINNT) \
297   || defined (__MACHTEN__) || defined (hpux) || defined (_AIX) \
298   || (defined (__svr4__) && defined (i386)) || defined (__Lynx__)
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 (__CYGWIN32__) || 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