OSDN Git Service

2001-11-17 Laurent Guerby <guerby@acm.org>
[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: 1.3 $
10  *                                                                          *
11  *          Copyright (C) 1992-2001 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 "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 #include "time.h"
48 #else
49 #include "config.h"
50 #include "system.h"
51 #endif
52
53 #include "adaint.h"
54
55 /*
56    mode_read_text
57    open text file for reading
58    rt for DOS and Windows NT, r for Unix
59
60    mode_write_text
61    truncate to zero length or create text file for writing
62    wt for DOS and Windows NT, w for Unix
63
64    mode_append_text
65    append; open or create text file for writing at end-of-file
66    at for DOS and Windows NT, a for Unix
67
68    mode_read_binary
69    open binary file for reading
70    rb for DOS and Windows NT, r for Unix
71
72    mode_write_binary
73    truncate to zero length or create binary file for writing
74    wb for DOS and Windows NT, w for Unix
75
76    mode_append_binary
77    append; open or create binary file for writing at end-of-file
78    ab for DOS and Windows NT, a for Unix
79
80    mode_read_text_plus
81    open text file for update (reading and writing)
82    r+t for DOS and Windows NT, r+ for Unix
83
84    mode_write_text_plus
85    truncate to zero length or create text file for update
86    w+t for DOS and Windows NT, w+ for Unix
87
88    mode_append_text_plus
89    append; open or create text file for update, writing at end-of-file
90    a+t for DOS and Windows NT, a+ for Unix
91
92    mode_read_binary_plus
93    open binary file for update (reading and writing)
94    r+b for DOS and Windows NT, r+ for Unix
95
96    mode_write_binary_plus
97    truncate to zero length or create binary file for update
98    w+b for DOS and Windows NT, w+ for Unix
99
100    mode_append_binary_plus
101    append; open or create binary file for update, writing at end-of-file
102    a+b for DOS and Windows NT, a+ for Unix
103
104    Notes:
105
106    (1) Opening a file with read mode fails if the file does not exist or
107    cannot be read.
108
109    (2) Opening a file with append mode causes all subsequent writes to the
110    file to be forced to the then current end-of-file, regardless of
111    intervening calls to the fseek function.
112
113    (3) When a file is opened with update mode, both input and output may be
114    performed on the associated stream.  However, output may not be directly
115    followed by input without an intervening call to the fflush function or
116    to a file positioning function (fseek, fsetpos, or rewind), and input
117    may not be directly followed by output without an intervening call to a
118    file positioning function, unless the input operation encounters
119    end-of-file.
120
121    The other target dependent declarations here are for the two functions
122    __gnat_set_binary_mode and __gnat_set_text_mode:
123
124       void __gnat_set_binary_mode (int handle);
125       void __gnat_set_text_mode   (int handle);
126
127    These functions have no effect in Unix (or similar systems where there is
128    no distinction between binary and text files), but in DOS (and similar
129    systems where text mode does CR/LF translation), these functions allow
130    the mode of the stream with the given handle (fileno can be used to get
131    the handle of a stream) to be changed dynamically. The returned result
132    is 0 if no error occurs and -1 if an error occurs.
133
134    Finally there is a boolean (character) variable
135
136       char __gnat_text_translation_required;
137
138    which is zero (false) in Unix mode, and one (true) in DOS mode, with a
139    true value indicating that text translation is required on text files
140    and that fopen supports the trailing t and b modifiers.
141
142 */
143
144 #if defined(WINNT) || defined (MSDOS) || defined (__EMX__)
145 const char *mode_read_text = "rt";
146 const char *mode_write_text = "wt";
147 const char *mode_append_text = "at";
148 const char *mode_read_binary = "rb";
149 const char *mode_write_binary = "wb";
150 const char *mode_append_binary = "ab";
151 const char *mode_read_text_plus = "r+t";
152 const char *mode_write_text_plus = "w+t";
153 const char *mode_append_text_plus = "a+t";
154 const char *mode_read_binary_plus = "r+b";
155 const char *mode_write_binary_plus = "w+b";
156 const char *mode_append_binary_plus = "a+b";
157 const char __gnat_text_translation_required = 1;
158
159 void
160 __gnat_set_binary_mode (handle)
161      int handle;
162 {
163   _setmode (handle, O_BINARY);
164 }
165
166 void
167 __gnat_set_text_mode (handle)
168      int handle;
169 {
170   _setmode (handle, O_TEXT);
171 }
172
173 #ifdef __MINGW32__
174 #include <windows.h>
175
176 /* Return the name of the tty.   Under windows there is no name for
177    the tty, so this function, if connected to a tty, returns the generic name
178    "console".  */
179
180 char *
181 __gnat_ttyname (filedes)
182      int filedes;
183 {
184   if (isatty (filedes))
185     return "console";
186   else
187     return NULL;
188 }
189
190 /* This function is needed to fix a bug under Win95/98. Under these plateforms
191    doing :
192                 ch1 = getch();
193                 ch2 = fgetc (stdin);
194
195    will put the same character into ch1 and ch2. It seem that the character
196    read by getch() is not correctly removed from the buffer. Even a
197    fflush(stdin) does not fix the bug. This bug does not appear under Window
198    NT. So we have two version of this routine below one for 95/98 and one for
199    NT/2000 version of Windows. There is also a special routine (winflushinit)
200    that will be called only the first time to check which version of Windows
201    we are running running on to set the right routine to use.
202
203    This problem occurs when using Text_IO.Get_Line after Text_IO.Get_Immediate
204    for example.
205
206    Calling FlushConsoleInputBuffer just after getch() fix the bug under 
207    95/98. */
208
209 static void winflush_init PARAMS ((void));
210
211 static void winflush_95 PARAMS ((void));
212
213 static void winflush_nt PARAMS ((void));
214
215 /* winflusfunction is set first to the winflushinit function which will check
216    the OS version 95/98 or NT/2000 */
217
218 static void (*winflush_function) PARAMS ((void)) = winflush_init;
219
220 /* This function does the runtime check of the OS version and then sets
221    winflush_function to the appropriate function and then call it. */ 
222
223 static void
224 winflush_init ()
225
226   DWORD dwVersion = GetVersion();
227
228   if (dwVersion < 0x80000000)                /* Windows NT/2000 */
229     winflush_function = winflush_nt;
230   else                                       /* Windows 95/98   */
231     winflush_function = winflush_95;
232
233   (*winflush_function)();      /* Perform the 'flush' */
234
235 }
236
237 static void winflush_95 ()
238
239   FlushConsoleInputBuffer (GetStdHandle (STD_INPUT_HANDLE));
240 }
241
242 static void winflush_nt ()
243 {
244   /* Does nothing as there is no problem under NT.  */
245 }
246 #endif
247
248 #else
249
250 const char *mode_read_text = "r";
251 const char *mode_write_text = "w";
252 const char *mode_append_text = "a";
253 const char *mode_read_binary = "r";
254 const char *mode_write_binary = "w";
255 const char *mode_append_binary = "a";
256 const char *mode_read_text_plus = "r+";
257 const char *mode_write_text_plus = "w+";
258 const char *mode_append_text_plus = "a+";
259 const char *mode_read_binary_plus = "r+";
260 const char *mode_write_binary_plus = "w+";
261 const char *mode_append_binary_plus = "a+";
262 const char __gnat_text_translation_required = 0;
263
264 /* These functions do nothing in non-DOS systems. */
265
266 void
267 __gnat_set_binary_mode (handle)
268      int handle ATTRIBUTE_UNUSED;
269 {
270 }
271
272 void
273 __gnat_set_text_mode (handle)
274      int handle ATTRIBUTE_UNUSED;
275 {
276 }
277 char *
278 __gnat_ttyname (filedes)
279      int filedes;
280 {
281 #ifndef __vxworks
282   extern char *ttyname PARAMS ((int));
283
284   return ttyname (filedes);
285
286 #else
287   return "";
288
289 #endif
290 }
291 #endif
292 \f
293 #if defined (linux) || defined (sun) || defined (sgi) || defined (__EMX__) \
294   || (defined (__osf__) && ! defined (__alpha_vxworks)) || defined (WINNT) \
295   || defined (__MACHTEN__)
296 #include <termios.h>
297
298 #else
299 #if defined (VMS)
300 extern char *decc$ga_stdscr;
301 static int initted = 0;
302 #endif
303 #endif
304
305 /* Implements the common processing for getc_immediate and
306    getc_immediate_nowait. */
307
308 extern void getc_immediate              PARAMS ((FILE *, int *, int *));
309 extern void getc_immediate_nowait       PARAMS ((FILE *, int *, int *, int *));
310 extern void getc_immediate_common       PARAMS ((FILE *, int *, int *,
311                                                  int *, int));
312
313 /* Called by Get_Immediate (Foo); */
314
315 void
316 getc_immediate (stream, ch, end_of_file)
317      FILE *stream;
318      int *ch;
319      int *end_of_file;
320 {
321   int avail;
322
323   getc_immediate_common (stream, ch, end_of_file, &avail, 1);
324 }
325
326 /* Called by Get_Immediate (Foo, Available); */
327
328 void
329 getc_immediate_nowait (stream, ch, end_of_file, avail)
330      FILE *stream;
331      int *ch;
332      int *end_of_file;
333      int *avail;
334 {
335   getc_immediate_common (stream, ch, end_of_file, avail, 0);
336 }
337
338 /* Called by getc_immediate () and getc_immediate_nowait () */
339
340 void
341 getc_immediate_common (stream, ch, end_of_file, avail, waiting)
342      FILE *stream;
343      int *ch;
344      int *end_of_file;
345      int *avail;
346      int waiting;
347 {
348 #if defined (linux) || defined (sun) || defined (sgi) || defined (__EMX__) \
349     || (defined (__osf__) && ! defined (__alpha_vxworks)) \
350     || defined (__CYGWIN32__) || defined (__MACHTEN__)
351   char c;
352   int nread;
353   int good_one = 0;
354   int eof_ch = 4; /* Ctrl-D */
355   int fd = fileno (stream);
356   struct termios otermios_rec, termios_rec;
357
358   if (isatty (fd))
359     {
360       tcgetattr (fd, &termios_rec);
361       memcpy (&otermios_rec, &termios_rec, sizeof (struct termios));
362       while (! good_one)
363         {
364           /* Set RAW mode */
365           termios_rec.c_lflag = termios_rec.c_lflag & ~ICANON;
366 #if defined(sgi) || defined (sun) || defined (__EMX__) || defined (__osf__) \
367       || defined (linux) || defined (__MACHTEN__)
368           eof_ch = termios_rec.c_cc[VEOF];
369
370           /* If waiting (i.e. Get_Immediate (Char)), set MIN = 1 and wait for
371              a character forever. This doesn't seem to effect Ctrl-Z or
372              Ctrl-C processing except on OS/2 where Ctrl-C won't work right
373              unless we do a read loop. Luckily we can delay a bit between
374              iterations. If not waiting (i.e. Get_Immediate (Char, Available)),
375              don't wait for anything but timeout immediately. */
376 #ifdef __EMX__
377           termios_rec.c_cc[VMIN] = 0;
378           termios_rec.c_cc[VTIME] = waiting;
379 #else
380           termios_rec.c_cc[VMIN] = waiting;
381           termios_rec.c_cc[VTIME] = 0;
382 #endif
383 #endif
384           tcsetattr (fd, TCSANOW, &termios_rec);
385
386           /* Read() is used here instead of fread(), because fread() doesn't
387              work on Solaris5 and Sunos4 in this situation.  Maybe because we
388              are mixing calls that use file descriptors and streams. */
389
390           nread = read (fd, &c, 1);
391           if (nread > 0)
392             {
393               /* On Unix terminals, Ctrl-D (EOT) is an End of File. */
394               if (c == eof_ch)
395                 {
396                   *avail = 0;
397                   *end_of_file = 1;
398                   good_one = 1;
399                 }
400
401               /* Everything else is ok */
402               else if (c != eof_ch)
403                 {
404                   *avail = 1;
405                   *end_of_file = 0;
406                   good_one = 1;
407                 }
408             }
409
410           else if (! waiting)
411             {
412               *avail = 0;
413               *end_of_file = 0;
414               good_one = 1;
415             }
416           else
417             {
418               good_one = 0;
419             }
420         }
421
422       tcsetattr (fd, TCSANOW, &otermios_rec);
423       *ch = c;
424     }
425
426   else
427 #else
428 #if defined (VMS)
429   int fd = fileno (stream);
430
431   if (isatty (fd))
432     {
433       if (initted == 0)
434         {
435           decc$bsd_initscr ();
436           initted = 1;
437         }
438       decc$bsd_cbreak ();
439       *ch = decc$bsd_wgetch (decc$ga_stdscr);
440
441       if (*ch == 4)
442         *end_of_file = 1;
443       else
444         *end_of_file = 0;
445
446       *avail = 1;
447       decc$bsd_nocbreak ();
448     }
449   else
450 #else
451 #if defined (__MINGW32__)
452   int fd = fileno (stream);
453   int char_waiting;
454   int eot_ch = 4; /* Ctrl-D */
455
456   if (isatty (fd))
457     {
458       if (waiting)
459         {
460           *ch = getch();
461           (*winflush_function)();
462
463           if (*ch == eot_ch)
464             *end_of_file = 1;
465           else
466             *end_of_file = 0;
467
468           *avail = 1;
469         }
470       else /* ! waiting */
471         {
472           char_waiting = kbhit();
473
474           if (char_waiting == 1)
475             {
476               *avail = 1;
477               *ch = getch();
478               (*winflush_function)();
479
480               if (*ch == eot_ch)
481                 *end_of_file = 1;
482               else
483                 *end_of_file = 0;
484             }
485           else
486             {
487               *avail = 0;
488               *end_of_file = 0;
489             }
490         }
491     }
492   else
493 #endif
494 #endif
495 #endif
496     {
497       /* If we're not on a terminal, then we don't need any fancy processing.
498          Also this is the only thing that's left if we're not on one of the
499          supported systems. */
500       *ch = fgetc (stream);
501       if (feof (stream))
502         {
503           *end_of_file = 1;
504           *avail = 0;
505         }
506       else
507         {
508           *end_of_file = 0;
509           *avail = 1;
510         }
511     }
512 }
513
514 /* The following definitions are provided in NT to support Windows based
515    Ada programs.  */
516
517 #ifdef WINNT
518 #include <windows.h>
519
520 /* Provide functions to echo the values passed to WinMain (windows bindings
521    will want to import these).  We use the same names as the routines used
522    by AdaMagic for compatibility.  */
523
524 char *rts_get_hInstance     PARAMS ((void));
525 char *rts_get_hPrevInstance PARAMS ((void));
526 char *rts_get_lpCommandLine PARAMS ((void));
527 int   rts_get_nShowCmd      PARAMS ((void));
528
529 char *rts_get_hInstance     () { return (GetModuleHandleA (0)); }
530 char *rts_get_hPrevInstance () { return (0); }
531 char *rts_get_lpCommandLine () { return (GetCommandLineA ()); }
532 int   rts_get_nShowCmd      () { return (1); }
533
534 #endif /* WINNT */
535 #ifdef VMS
536
537 /* This gets around a problem with using the old threads library on VMS 7.0. */
538
539 #include <time.h>
540
541 extern long get_gmtoff PARAMS ((void));
542
543 long
544 get_gmtoff ()
545 {
546   time_t t;
547   struct tm *ts;
548
549   t = time ((time_t) 0);
550   ts = localtime (&t);
551   return ts->tm_gmtoff;
552 }
553 #endif
554
555 /* Definition of __gnat_locatime_r used by a-calend.adb */
556
557 #if defined (_AIX) || defined (__EMX__)
558 #define Lock_Task system__soft_links__lock_task
559 extern void (*Lock_Task) PARAMS ((void));
560
561 #define Unlock_Task system__soft_links__unlock_task
562 extern void (*Unlock_Task) PARAMS ((void));
563
564 /* Provide reentrant version of localtime on Aix and OS/2. Note that AiX does
565    provide localtime_r, but in the library libc_r which doesn't get included
566    systematically, so we can't use it. */
567
568 exrern void struct tm *__gnat_localtime_r PARAMS ((const time_t *,
569                                                    struct tm *));
570
571 struct tm *
572 __gnat_localtime_r (timer, tp)
573      const time_t *timer;
574      struct tm *tp;
575 {
576   struct tm *tmp;
577
578   (*Lock_Task) ();
579   tmp = localtime (timer);
580   memcpy (tp, tmp, sizeof (struct tm));
581   (*Unlock_Task) ();
582   return tp;
583 }
584
585 #else
586 #if defined (__Lynx__) && defined (___THREADS_POSIX4ad4__)
587
588 /* As of LynxOS 3.1.0a patch level 040, LynuxWorks changes the
589    prototype to the C library function localtime_r from the POSIX.4
590    Draft 9 to the POSIX 1.c version. Before this change the following
591    spec is required. Only use when ___THREADS_POSIX4ad4__ is defined,
592    the Lynx convention when building against the legacy API. */
593
594 extern struct tm *__gnat_localtime_r PARAMS ((const time_t *, struct tm *));
595
596 struct tm *
597 __gnat_localtime_r (timer, tp)
598      const time_t *timer;
599      struct tm *tp;
600 {
601   localtime_r (tp, timer);
602   return NULL;
603 }
604
605 #else
606 #if defined (VMS) || defined (__MINGW32__)
607
608 /* __gnat_localtime_r is not needed on NT and VMS */
609
610 #else
611
612 /* All other targets provide a standard localtime_r */
613
614 extern struct tm *__gnat_localtime_r PARAMS ((const time_t *, struct tm *));
615
616 struct tm *
617 __gnat_localtime_r (timer, tp)
618      const time_t *timer;
619      struct tm *tp;
620 {
621   return (struct tm *) localtime_r (timer, tp);
622 }
623 #endif
624 #endif
625 #endif