5473ebee42ec5fa97494390f1140263628029981
[gcc.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.2 $
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 (stream)
268 FILE *stream ATTRIBUTE_UNUSED;
269 {
270 }
271
272 void
273 __gnat_set_text_mode (stream)
274 FILE *stream 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 #elif defined (VMS)
299 extern char *decc$ga_stdscr;
300 static int initted = 0;
301 #endif
302
303 /* Implements the common processing for getc_immediate and
304 getc_immediate_nowait. */
305
306 extern void getc_immediate PARAMS ((FILE *, int *, int *));
307 extern void getc_immediate_nowait PARAMS ((FILE *, int *, int *, int *));
308 extern void getc_immediate_common PARAMS ((FILE *, int *, int *,
309 int *, int));
310
311 /* Called by Get_Immediate (Foo); */
312
313 void
314 getc_immediate (stream, ch, end_of_file)
315 FILE *stream;
316 int *ch;
317 int *end_of_file;
318 {
319 int avail;
320
321 getc_immediate_common (stream, ch, end_of_file, &avail, 1);
322 }
323
324 /* Called by Get_Immediate (Foo, Available); */
325
326 void
327 getc_immediate_nowait (stream, ch, end_of_file, avail)
328 FILE *stream;
329 int *ch;
330 int *end_of_file;
331 int *avail;
332 {
333 getc_immediate_common (stream, ch, end_of_file, avail, 0);
334 }
335
336 /* Called by getc_immediate () and getc_immediate_nowait () */
337
338 void
339 getc_immediate_common (stream, ch, end_of_file, avail, waiting)
340 FILE *stream;
341 int *ch;
342 int *end_of_file;
343 int *avail;
344 int waiting;
345 {
346 #if defined (linux) || defined (sun) || defined (sgi) || defined (__EMX__) \
347 || (defined (__osf__) && ! defined (__alpha_vxworks)) \
348 || defined (__CYGWIN32__) || defined (__MACHTEN__)
349 char c;
350 int nread;
351 int good_one = 0;
352 int eof_ch = 4; /* Ctrl-D */
353 int fd = fileno (stream);
354 struct termios otermios_rec, termios_rec;
355
356 if (isatty (fd))
357 {
358 tcgetattr (fd, &termios_rec);
359 memcpy (&otermios_rec, &termios_rec, sizeof (struct termios));
360 while (! good_one)
361 {
362 /* Set RAW mode */
363 termios_rec.c_lflag = termios_rec.c_lflag & ~ICANON;
364 #if defined(sgi) || defined (sun) || defined (__EMX__) || defined (__osf__) \
365 || defined (linux) || defined (__MACHTEN__)
366 eof_ch = termios_rec.c_cc[VEOF];
367
368 /* If waiting (i.e. Get_Immediate (Char)), set MIN = 1 and wait for
369 a character forever. This doesn't seem to effect Ctrl-Z or
370 Ctrl-C processing except on OS/2 where Ctrl-C won't work right
371 unless we do a read loop. Luckily we can delay a bit between
372 iterations. If not waiting (i.e. Get_Immediate (Char, Available)),
373 don't wait for anything but timeout immediately. */
374 #ifdef __EMX__
375 termios_rec.c_cc[VMIN] = 0;
376 termios_rec.c_cc[VTIME] = waiting;
377 #else
378 termios_rec.c_cc[VMIN] = waiting;
379 termios_rec.c_cc[VTIME] = 0;
380 #endif
381 #endif
382 tcsetattr (fd, TCSANOW, &termios_rec);
383
384 /* Read() is used here instead of fread(), because fread() doesn't
385 work on Solaris5 and Sunos4 in this situation. Maybe because we
386 are mixing calls that use file descriptors and streams. */
387
388 nread = read (fd, &c, 1);
389 if (nread > 0)
390 {
391 /* On Unix terminals, Ctrl-D (EOT) is an End of File. */
392 if (c == eof_ch)
393 {
394 *avail = 0;
395 *end_of_file = 1;
396 good_one = 1;
397 }
398
399 /* Everything else is ok */
400 else if (c != eof_ch)
401 {
402 *avail = 1;
403 *end_of_file = 0;
404 good_one = 1;
405 }
406 }
407
408 else if (! waiting)
409 {
410 *avail = 0;
411 *end_of_file = 0;
412 good_one = 1;
413 }
414 else
415 {
416 good_one = 0;
417 }
418 }
419
420 tcsetattr (fd, TCSANOW, &otermios_rec);
421 *ch = c;
422 }
423
424 else
425 #elif defined (VMS)
426 int fd = fileno (stream);
427
428 if (isatty (fd))
429 {
430 if (initted == 0)
431 {
432 decc$bsd_initscr ();
433 initted = 1;
434 }
435 decc$bsd_cbreak ();
436 *ch = decc$bsd_wgetch (decc$ga_stdscr);
437
438 if (*ch == 4)
439 *end_of_file = 1;
440 else
441 *end_of_file = 0;
442
443 *avail = 1;
444 decc$bsd_nocbreak ();
445 }
446 else
447 #elif defined (__MINGW32__)
448 int fd = fileno (stream);
449 int char_waiting;
450 int eot_ch = 4; /* Ctrl-D */
451
452 if (isatty (fd))
453 {
454 if (waiting)
455 {
456 *ch = getch();
457 (*winflush_function)();
458
459 if (*ch == eot_ch)
460 *end_of_file = 1;
461 else
462 *end_of_file = 0;
463
464 *avail = 1;
465 }
466 else /* ! waiting */
467 {
468 char_waiting = kbhit();
469
470 if (char_waiting == 1)
471 {
472 *avail = 1;
473 *ch = getch();
474 (*winflush_function)();
475
476 if (*ch == eot_ch)
477 *end_of_file = 1;
478 else
479 *end_of_file = 0;
480 }
481 else
482 {
483 *avail = 0;
484 *end_of_file = 0;
485 }
486 }
487 }
488 else
489 #endif
490 {
491 /* If we're not on a terminal, then we don't need any fancy processing.
492 Also this is the only thing that's left if we're not on one of the
493 supported systems. */
494 *ch = fgetc (stream);
495 if (feof (stream))
496 {
497 *end_of_file = 1;
498 *avail = 0;
499 }
500 else
501 {
502 *end_of_file = 0;
503 *avail = 1;
504 }
505 }
506 }
507
508 /* The following definitions are provided in NT to support Windows based
509 Ada programs. */
510
511 #ifdef WINNT
512 #include <windows.h>
513
514 /* Provide functions to echo the values passed to WinMain (windows bindings
515 will want to import these). We use the same names as the routines used
516 by AdaMagic for compatibility. */
517
518 char *rts_get_hInstance (void) { return (GetModuleHandleA (0)); }
519 char *rts_get_hPrevInstance (void) { return (0); }
520 char *rts_get_lpCommandLine (void) { return (GetCommandLineA ()); }
521 int rts_get_nShowCmd (void) { return (1); }
522
523 #endif /* WINNT */
524 #ifdef VMS
525
526 /* This gets around a problem with using the old threads library on VMS 7.0. */
527
528 #include <time.h>
529
530 extern long get_gmtoff PARAMS ((void));
531
532 long
533 get_gmtoff ()
534 {
535 time_t t;
536 struct tm *ts;
537
538 t = time ((time_t) 0);
539 ts = localtime (&t);
540 return ts->tm_gmtoff;
541 }
542 #endif
543
544 /* Definition of __gnat_locatime_r used by a-calend.adb */
545
546 #if defined (_AIX) || defined (__EMX__)
547 #define Lock_Task system__soft_links__lock_task
548 extern void (*Lock_Task) (void);
549
550 #define Unlock_Task system__soft_links__unlock_task
551 extern void (*Unlock_Task) (void);
552
553 /* Provide reentrant version of localtime on Aix and OS/2. Note that AiX does
554 provide localtime_r, but in the library libc_r which doesn't get included
555 systematically, so we can't use it. */
556
557 exrern void struct tm *__gnat_localtime_r PARAMS ((const time_t *,
558 struct tm *));
559
560 struct tm *
561 __gnat_localtime_r (timer, tp)
562 const time_t *timer;
563 struct tm *tp;
564 {
565 struct tm *tmp;
566
567 (*Lock_Task) ();
568 tmp = localtime (timer);
569 memcpy (tp, tmp, sizeof (struct tm));
570 (*Unlock_Task) ();
571 return tp;
572 }
573
574 #elif defined (__Lynx__)
575
576 /* LynxOS provides a non standard localtime_r */
577
578 extern struct tm *__gnat_localtime_r PARAMS ((const time_t *, struct tm *));
579
580 struct tm *
581 __gnat_localtime_r (timer, tp)
582 const time_t *timer;
583 struct tm *tp;
584 {
585 return localtime_r (tp, timer);
586 }
587
588 #elif defined (VMS) || defined (__MINGW32__)
589
590 /* __gnat_localtime_r is not needed on NT and VMS */
591
592 #else
593
594 /* All other targets provide a standard localtime_r */
595
596 extern struct tm *__gnat_localtime_r PARAMS ((const time_t *, struct tm *));
597
598 struct tm *
599 __gnat_localtime_r (timer, tp)
600 const time_t *timer;
601 struct tm *tp;
602 {
603 return (struct tm *) localtime_r (timer, tp);
604 }
605 #endif