111
|
1 /****************************************************************************
|
|
2 * *
|
|
3 * GNAT COMPILER COMPONENTS *
|
|
4 * *
|
|
5 * S Y S D E P *
|
|
6 * *
|
|
7 * C Implementation File *
|
|
8 * *
|
131
|
9 * Copyright (C) 1992-2018, Free Software Foundation, Inc. *
|
111
|
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 3, 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. *
|
|
17 * *
|
|
18 * As a special exception under Section 7 of GPL version 3, you are granted *
|
|
19 * additional permissions described in the GCC Runtime Library Exception, *
|
|
20 * version 3.1, as published by the Free Software Foundation. *
|
|
21 * *
|
|
22 * You should have received a copy of the GNU General Public License and *
|
|
23 * a copy of the GCC Runtime Library Exception along with this program; *
|
|
24 * see the files COPYING3 and COPYING.RUNTIME respectively. If not, see *
|
|
25 * <http://www.gnu.org/licenses/>. *
|
|
26 * *
|
|
27 * GNAT was originally developed by the GNAT team at New York University. *
|
|
28 * Extensive contributions were provided by Ada Core Technologies Inc. *
|
|
29 * *
|
|
30 ****************************************************************************/
|
|
31
|
|
32 /* This file contains system dependent symbols that are referenced in the
|
|
33 GNAT Run Time Library */
|
|
34
|
|
35 #ifdef __vxworks
|
|
36 #include "ioLib.h"
|
|
37 #if ! defined (VTHREADS)
|
|
38 #include "dosFsLib.h"
|
|
39 #endif
|
|
40 #if ! defined (__RTP__) && (! defined (VTHREADS) || defined (__VXWORKSMILS__))
|
|
41 # include "nfsLib.h"
|
|
42 #endif
|
|
43 #include "selectLib.h"
|
|
44 #include "vxWorks.h"
|
|
45 #include "version.h"
|
|
46 #if defined (__RTP__)
|
|
47 # include "vwModNum.h"
|
|
48 #endif /* __RTP__ */
|
|
49 #endif
|
|
50
|
|
51 #ifdef __ANDROID__
|
|
52 #undef __linux__
|
|
53 #endif
|
|
54
|
|
55 #ifdef IN_RTS
|
|
56 #define POSIX
|
|
57 #include "tconfig.h"
|
|
58 #include "tsystem.h"
|
|
59 #include <fcntl.h>
|
|
60 #include <sys/stat.h>
|
|
61 #else
|
|
62 #include "config.h"
|
|
63 #include "system.h"
|
|
64 #endif
|
|
65
|
|
66 #include <time.h>
|
|
67 #include <errno.h>
|
|
68
|
|
69 #if defined (__sun__) && !defined (__vxworks)
|
|
70 /* The declaration is present in <time.h> but conditionalized
|
|
71 on a couple of macros we don't define. */
|
|
72 extern struct tm *localtime_r(const time_t *, struct tm *);
|
|
73 #endif
|
|
74
|
|
75 #include "adaint.h"
|
|
76
|
|
77 /* Don't use macros versions of this functions on VxWorks since they cause
|
|
78 imcompatible changes in some VxWorks versions */
|
|
79 #ifdef __vxworks
|
|
80 #undef getchar
|
|
81 #undef putchar
|
|
82 #undef feof
|
|
83 #undef ferror
|
|
84 #undef fileno
|
|
85 #endif
|
|
86
|
|
87 /*
|
|
88 Notes:
|
|
89
|
|
90 (1) Opening a file with read mode fails if the file does not exist or
|
|
91 cannot be read.
|
|
92
|
|
93 (2) Opening a file with append mode causes all subsequent writes to the
|
|
94 file to be forced to the then current end-of-file, regardless of
|
|
95 intervening calls to the fseek function.
|
|
96
|
|
97 (3) When a file is opened with update mode, both input and output may be
|
|
98 performed on the associated stream. However, output may not be directly
|
|
99 followed by input without an intervening call to the fflush function or
|
|
100 to a file positioning function (fseek, fsetpos, or rewind), and input
|
|
101 may not be directly followed by output without an intervening call to a
|
|
102 file positioning function, unless the input operation encounters
|
|
103 end-of-file.
|
|
104
|
|
105 The other target dependent declarations here are for the three functions
|
|
106 __gnat_set_binary_mode, __gnat_set_text_mode and __gnat_set_mode:
|
|
107
|
|
108 void __gnat_set_binary_mode (int handle);
|
|
109 void __gnat_set_text_mode (int handle);
|
|
110 void __gnat_set_mode (int handle, int mode);
|
|
111
|
|
112 These functions have no effect in Unix (or similar systems where there is
|
|
113 no distinction between binary and text files), but in DOS (and similar
|
|
114 systems where text mode does CR/LF translation), these functions allow
|
|
115 the mode of the stream with the given handle (fileno can be used to get
|
|
116 the handle of a stream) to be changed dynamically. The returned result
|
|
117 is 0 if no error occurs and -1 if an error occurs.
|
|
118
|
|
119 Finally there is a boolean (character) variable
|
|
120
|
|
121 char __gnat_text_translation_required;
|
|
122
|
|
123 which is zero (false) in Unix mode, and one (true) in DOS mode, with a
|
|
124 true value indicating that text translation is required on text files
|
|
125 and that fopen supports the trailing t and b modifiers.
|
|
126
|
|
127 */
|
|
128
|
|
129 #if defined (WINNT) || defined (__CYGWIN__) || defined (__DJGPP__)
|
|
130
|
|
131 const char __gnat_text_translation_required = 1;
|
|
132
|
|
133 #ifdef __CYGWIN__
|
|
134 #define WIN_SETMODE setmode
|
|
135 #include <io.h>
|
|
136 #else
|
|
137 #define WIN_SETMODE _setmode
|
|
138 #endif
|
|
139
|
|
140 #if defined (__DJGPP__)
|
|
141 #include <io.h>
|
|
142 #define _setmode setmode
|
|
143 #endif /* __DJGPP__ */
|
|
144
|
|
145 void
|
|
146 __gnat_set_binary_mode (int handle)
|
|
147 {
|
|
148 WIN_SETMODE (handle, O_BINARY);
|
|
149 }
|
|
150
|
|
151 void
|
|
152 __gnat_set_text_mode (int handle)
|
|
153 {
|
|
154 WIN_SETMODE (handle, O_TEXT);
|
|
155 }
|
|
156
|
|
157 #if defined (__CYGWIN__) || defined (__DJGPP__)
|
|
158 void
|
|
159 __gnat_set_mode (int handle, int mode)
|
|
160 {
|
|
161 /* the values here must be synchronized with
|
|
162 System.File_Control_Block.Content_Encodding:
|
|
163
|
|
164 None = 0
|
|
165 Default_Text = 1
|
|
166 Text = 2
|
|
167 U8text = 3
|
|
168 Wtext = 4
|
|
169 U16text = 5 */
|
|
170
|
|
171 switch (mode) {
|
|
172 case 0 : setmode(handle, O_BINARY); break;
|
|
173 case 1 : setmode(handle, O_TEXT); break;
|
|
174 case 2 : setmode(handle, O_TEXT); break;
|
|
175 case 3 : setmode(handle, O_TEXT); break;
|
|
176 case 4 : setmode(handle, O_BINARY); break;
|
|
177 case 5 : setmode(handle, O_BINARY); break;
|
|
178 }
|
|
179 }
|
|
180 #else
|
|
181 void
|
|
182 __gnat_set_mode (int handle, int mode)
|
|
183 {
|
|
184 /* the values here must be synchronized with
|
|
185 System.File_Control_Block.Content_Encodding:
|
|
186
|
|
187 None = 0
|
|
188 Default_Text = 1
|
|
189 Text = 2
|
|
190 U8text = 3
|
|
191 Wtext = 4
|
|
192 U16text = 5 */
|
|
193
|
|
194 switch (mode) {
|
|
195 case 0 : WIN_SETMODE (handle, _O_BINARY); break;
|
|
196 case 1 : WIN_SETMODE (handle, __gnat_current_ccs_encoding); break;
|
|
197 case 2 : WIN_SETMODE (handle, _O_TEXT); break;
|
|
198 case 3 : WIN_SETMODE (handle, _O_U8TEXT); break;
|
|
199 case 4 : WIN_SETMODE (handle, _O_WTEXT); break;
|
|
200 case 5 : WIN_SETMODE (handle, _O_U16TEXT); break;
|
|
201 }
|
|
202 }
|
|
203 #endif
|
|
204
|
|
205 #ifdef __CYGWIN__
|
|
206
|
|
207 char *
|
|
208 __gnat_ttyname (int filedes)
|
|
209 {
|
|
210 extern char *ttyname (int);
|
|
211
|
|
212 return ttyname (filedes);
|
|
213 }
|
|
214
|
|
215 #endif /* __CYGWIN__ */
|
|
216
|
|
217 #if defined (__CYGWIN__) || defined (__MINGW32__)
|
|
218 #include <windows.h>
|
|
219
|
|
220 int __gnat_is_windows_xp (void);
|
|
221
|
|
222 int
|
|
223 __gnat_is_windows_xp (void)
|
|
224 {
|
|
225 static int is_win_xp=0, is_win_xp_checked=0;
|
|
226
|
|
227 if (!is_win_xp_checked)
|
|
228 {
|
|
229 OSVERSIONINFO version;
|
|
230
|
|
231 is_win_xp_checked = 1;
|
|
232
|
|
233 memset (&version, 0, sizeof (version));
|
|
234 version.dwOSVersionInfoSize = sizeof (version);
|
|
235
|
|
236 is_win_xp = GetVersionEx (&version)
|
|
237 && version.dwPlatformId == VER_PLATFORM_WIN32_NT
|
|
238 && (version.dwMajorVersion > 5
|
|
239 || (version.dwMajorVersion == 5 && version.dwMinorVersion >= 1));
|
|
240 }
|
|
241 return is_win_xp;
|
|
242 }
|
|
243
|
|
244 /* Get the bounds of the stack. The stack pointer is supposed to be
|
|
245 initialized to BASE when a thread is created and the stack can be extended
|
|
246 to LIMIT before reaching a guard page.
|
|
247 Note: for the main thread, the system automatically extend the stack, so
|
|
248 LIMIT is only the current limit. */
|
|
249
|
|
250 void
|
|
251 __gnat_get_stack_bounds (void **base, void **limit)
|
|
252 {
|
|
253 NT_TIB *tib;
|
|
254
|
|
255 /* We know that the first field of the TEB is the TIB. */
|
|
256 tib = (NT_TIB *)NtCurrentTeb ();
|
|
257
|
|
258 *base = tib->StackBase;
|
|
259 *limit = tib->StackLimit;
|
|
260 }
|
|
261
|
|
262 #endif /* __CYGWIN__ || __MINGW32__ */
|
|
263
|
|
264 #ifdef __MINGW32__
|
|
265
|
|
266 /* Return the name of the tty. Under windows there is no name for
|
|
267 the tty, so this function, if connected to a tty, returns the generic name
|
|
268 "console". */
|
|
269
|
|
270 char *
|
|
271 __gnat_ttyname (int filedes)
|
|
272 {
|
|
273 if (isatty (filedes))
|
|
274 return "console";
|
|
275 else
|
|
276 return NULL;
|
|
277 }
|
|
278
|
|
279 #endif /* __MINGW32__ */
|
|
280
|
|
281 #else
|
|
282
|
|
283 const char __gnat_text_translation_required = 0;
|
|
284
|
|
285 /* These functions do nothing in non-DOS systems. */
|
|
286
|
|
287 void
|
|
288 __gnat_set_binary_mode (int handle ATTRIBUTE_UNUSED)
|
|
289 {
|
|
290 }
|
|
291
|
|
292 void
|
|
293 __gnat_set_text_mode (int handle ATTRIBUTE_UNUSED)
|
|
294 {
|
|
295 }
|
|
296
|
|
297 void
|
|
298 __gnat_set_mode (int handle ATTRIBUTE_UNUSED, int mode ATTRIBUTE_UNUSED)
|
|
299 {
|
|
300 }
|
|
301
|
|
302 char *
|
|
303 __gnat_ttyname (int filedes)
|
|
304 {
|
|
305 #if defined (__vxworks)
|
|
306 return "";
|
|
307 #else
|
|
308 extern char *ttyname (int);
|
|
309
|
|
310 return ttyname (filedes);
|
|
311 #endif /* defined (__vxworks) */
|
|
312 }
|
|
313 #endif
|
|
314
|
|
315 #if defined (__linux__) || defined (__sun__) \
|
|
316 || defined (WINNT) \
|
|
317 || defined (__MACHTEN__) || defined (__hpux__) || defined (_AIX) \
|
|
318 || (defined (__svr4__) && defined (__i386__)) || defined (__Lynx__) \
|
|
319 || defined (__CYGWIN__) || defined (__FreeBSD__) || defined (__OpenBSD__) \
|
131
|
320 || defined (__GLIBC__) || defined (__APPLE__) || defined (__DragonFly__) \
|
|
321 || defined (__QNX__)
|
111
|
322
|
|
323 # ifdef __MINGW32__
|
|
324 # if OLD_MINGW
|
|
325 # include <termios.h>
|
|
326 # else
|
|
327 # include <conio.h> /* for getch(), kbhit() */
|
|
328 # endif
|
|
329 # else
|
|
330 # include <termios.h>
|
|
331 # endif
|
|
332
|
|
333 #endif
|
|
334
|
|
335 /* Implements the common processing for getc_immediate and
|
|
336 getc_immediate_nowait. */
|
|
337
|
|
338 extern void getc_immediate (FILE *, int *, int *);
|
|
339 extern void getc_immediate_nowait (FILE *, int *, int *, int *);
|
|
340 extern void getc_immediate_common (FILE *, int *, int *, int *, int);
|
|
341
|
|
342 /* Called by Get_Immediate (Foo); */
|
|
343
|
|
344 void
|
|
345 getc_immediate (FILE *stream, int *ch, int *end_of_file)
|
|
346 {
|
|
347 int avail;
|
|
348
|
|
349 getc_immediate_common (stream, ch, end_of_file, &avail, 1);
|
|
350 }
|
|
351
|
|
352 /* Called by Get_Immediate (Foo, Available); */
|
|
353
|
|
354 void
|
|
355 getc_immediate_nowait (FILE *stream, int *ch, int *end_of_file, int *avail)
|
|
356 {
|
|
357 getc_immediate_common (stream, ch, end_of_file, avail, 0);
|
|
358 }
|
|
359
|
|
360 /* Called by getc_immediate () and getc_immediate_nowait () */
|
|
361
|
|
362 void
|
|
363 getc_immediate_common (FILE *stream,
|
|
364 int *ch,
|
|
365 int *end_of_file,
|
|
366 int *avail,
|
|
367 int waiting ATTRIBUTE_UNUSED)
|
|
368 {
|
|
369 #if defined (__linux__) || defined (__sun__) \
|
|
370 || defined (__CYGWIN32__) || defined (__MACHTEN__) || defined (__hpux__) \
|
|
371 || defined (_AIX) || (defined (__svr4__) && defined (__i386__)) \
|
|
372 || defined (__Lynx__) || defined (__FreeBSD__) || defined (__OpenBSD__) \
|
131
|
373 || defined (__GLIBC__) || defined (__APPLE__) || defined (__DragonFly__) \
|
|
374 || defined (__QNX__)
|
111
|
375 char c;
|
|
376 int nread;
|
|
377 int good_one = 0;
|
|
378 int eof_ch = 4; /* Ctrl-D */
|
|
379 int fd = fileno (stream);
|
|
380 struct termios otermios_rec, termios_rec;
|
|
381
|
|
382 if (isatty (fd))
|
|
383 {
|
|
384 tcgetattr (fd, &termios_rec);
|
|
385 memcpy (&otermios_rec, &termios_rec, sizeof (struct termios));
|
|
386
|
|
387 /* Set RAW mode, with no echo */
|
|
388 termios_rec.c_lflag = termios_rec.c_lflag & ~ICANON & ~ECHO;
|
|
389
|
|
390 #if defined (__linux__) || defined (__sun__) \
|
|
391 || defined (__MACHTEN__) || defined (__hpux__) \
|
|
392 || defined (_AIX) || (defined (__svr4__) && defined (__i386__)) \
|
|
393 || defined (__Lynx__) || defined (__FreeBSD__) || defined (__OpenBSD__) \
|
131
|
394 || defined (__GLIBC__) || defined (__APPLE__) || defined (__DragonFly__) \
|
|
395 || defined (__QNX__)
|
111
|
396 eof_ch = termios_rec.c_cc[VEOF];
|
|
397
|
|
398 /* If waiting (i.e. Get_Immediate (Char)), set MIN = 1 and wait for
|
|
399 a character forever. This doesn't seem to effect Ctrl-Z or
|
|
400 Ctrl-C processing.
|
|
401 If not waiting (i.e. Get_Immediate (Char, Available)),
|
|
402 don't wait for anything but timeout immediately. */
|
|
403 termios_rec.c_cc[VMIN] = waiting;
|
|
404 termios_rec.c_cc[VTIME] = 0;
|
|
405 #endif
|
|
406 tcsetattr (fd, TCSANOW, &termios_rec);
|
|
407
|
|
408 while (! good_one)
|
|
409 {
|
|
410 /* Read is used here instead of fread, because fread doesn't
|
|
411 work on Solaris5 and Sunos4 in this situation. Maybe because we
|
|
412 are mixing calls that use file descriptors and streams. */
|
|
413 nread = read (fd, &c, 1);
|
|
414 if (nread > 0)
|
|
415 {
|
|
416 /* On Unix terminals, Ctrl-D (EOT) is an End of File. */
|
|
417 if (c == eof_ch)
|
|
418 {
|
|
419 *avail = 0;
|
|
420 *end_of_file = 1;
|
|
421 good_one = 1;
|
|
422 }
|
|
423
|
|
424 /* Everything else is ok */
|
|
425 else if (c != eof_ch)
|
|
426 {
|
|
427 *avail = 1;
|
|
428 *end_of_file = 0;
|
|
429 good_one = 1;
|
|
430 }
|
|
431 }
|
|
432
|
|
433 else if (! waiting)
|
|
434 {
|
|
435 *avail = 0;
|
|
436 *end_of_file = 0;
|
|
437 good_one = 1;
|
|
438 }
|
|
439 else
|
|
440 good_one = 0;
|
|
441 }
|
|
442
|
|
443 tcsetattr (fd, TCSANOW, &otermios_rec);
|
|
444 *ch = c;
|
|
445 }
|
|
446
|
|
447 else
|
|
448 #elif defined (__MINGW32__)
|
|
449 int fd = fileno (stream);
|
|
450 int char_waiting;
|
|
451 int eot_ch = 4; /* Ctrl-D */
|
|
452
|
|
453 if (isatty (fd))
|
|
454 {
|
|
455 if (waiting)
|
|
456 {
|
|
457 *ch = getch ();
|
|
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
|
|
475 if (*ch == eot_ch)
|
|
476 *end_of_file = 1;
|
|
477 else
|
|
478 *end_of_file = 0;
|
|
479 }
|
|
480 else
|
|
481 {
|
|
482 *avail = 0;
|
|
483 *end_of_file = 0;
|
|
484 }
|
|
485 }
|
|
486 }
|
|
487 else
|
|
488 #elif defined (__vxworks)
|
|
489 /* Bit masks of file descriptors to read from. */
|
|
490 struct fd_set readFds;
|
|
491 /* Timeout before select returns if nothing can be read. */
|
|
492 struct timeval timeOut;
|
|
493 char c;
|
|
494 int fd = fileno (stream);
|
|
495 int nread;
|
|
496 int option;
|
|
497 int readable;
|
|
498 int status;
|
|
499 int width;
|
|
500
|
|
501 if (isatty (fd))
|
|
502 {
|
|
503 /* If we do not want to wait, we have to set up fd in RAW mode. This
|
|
504 should be done outside this function as setting fd in RAW mode under
|
|
505 vxWorks flushes the buffer of fd. If the RAW mode was set here, the
|
|
506 buffer would be empty and we would always return that no character
|
|
507 is available */
|
|
508 if (! waiting)
|
|
509 {
|
|
510 /* Initialization of timeOut for its use with select. */
|
|
511 timeOut.tv_sec = 0;
|
|
512 timeOut.tv_usec = 0;
|
|
513
|
|
514 /* Initialization of readFds for its use with select;
|
|
515 FD is the only file descriptor to be monitored */
|
|
516 FD_ZERO (&readFds);
|
|
517 FD_SET (fd, &readFds);
|
|
518 width = 2;
|
|
519
|
|
520 /* We do all this processing to emulate a non blocking read. */
|
|
521 readable = select (width, &readFds, NULL, NULL, &timeOut);
|
|
522 if (readable == ERROR)
|
|
523 *avail = -1, *end_of_file = -1;
|
|
524 /* No character available in input. */
|
|
525 else if (readable == 0)
|
|
526 *avail = 0, *end_of_file = 0;
|
|
527 else
|
|
528 {
|
|
529 nread = read (fd, &c, 1);
|
|
530 if (nread > 0)
|
|
531 *avail = 1, *end_of_file = 0;
|
|
532 /* End Of File. */
|
|
533 else if (nread == 0)
|
|
534 *avail = 0, *end_of_file = 1;
|
|
535 /* Error. */
|
|
536 else
|
|
537 *avail = -1, *end_of_file = -1;
|
|
538 }
|
|
539 }
|
|
540
|
|
541 /* We have to wait until we get a character */
|
|
542 else
|
|
543 {
|
|
544 *avail = -1;
|
|
545 *end_of_file = -1;
|
|
546
|
|
547 /* Save the current mode of FD. */
|
|
548 option = ioctl (fd, FIOGETOPTIONS, 0);
|
|
549
|
|
550 /* Set FD in RAW mode. */
|
|
551 status = ioctl (fd, FIOSETOPTIONS, OPT_RAW);
|
|
552 if (status != -1)
|
|
553 {
|
|
554 nread = read (fd, &c, 1);
|
|
555 if (nread > 0)
|
|
556 *avail = 1, *end_of_file = 0;
|
|
557 /* End of file. */
|
|
558 else if (nread == 0)
|
|
559 *avail = 0, *end_of_file = 1;
|
|
560 /* Else there is an ERROR. */
|
|
561 }
|
|
562
|
|
563 /* Revert FD to its previous mode. */
|
|
564 status = ioctl (fd, FIOSETOPTIONS, option);
|
|
565 }
|
|
566
|
|
567 *ch = c;
|
|
568 }
|
|
569 else
|
|
570 #endif
|
|
571 {
|
|
572 /* If we're not on a terminal, then we don't need any fancy processing.
|
|
573 Also this is the only thing that's left if we're not on one of the
|
|
574 supported systems; which means that for non supported systems,
|
|
575 get_immediate may wait for a carriage return on terminals. */
|
|
576 *ch = fgetc (stream);
|
|
577 if (feof (stream))
|
|
578 {
|
|
579 *end_of_file = 1;
|
|
580 *avail = 0;
|
|
581 }
|
|
582 else
|
|
583 {
|
|
584 *end_of_file = 0;
|
|
585 *avail = 1;
|
|
586 }
|
|
587 }
|
|
588 }
|
|
589
|
|
590 /* The following definitions are provided in NT to support Windows based
|
|
591 Ada programs. */
|
|
592
|
|
593 #ifdef WINNT
|
|
594 #include <windows.h>
|
|
595
|
|
596 /* Provide functions to echo the values passed to WinMain (windows bindings
|
|
597 will want to import these). We use the same names as the routines used
|
|
598 by AdaMagic for compatibility. */
|
|
599
|
|
600 char *rts_get_hInstance (void);
|
|
601 char *rts_get_hPrevInstance (void);
|
|
602 char *rts_get_lpCommandLine (void);
|
|
603 int rts_get_nShowCmd (void);
|
|
604
|
|
605 char *
|
|
606 rts_get_hInstance (void)
|
|
607 {
|
|
608 return (char *)GetModuleHandleA (0);
|
|
609 }
|
|
610
|
|
611 char *
|
|
612 rts_get_hPrevInstance (void)
|
|
613 {
|
|
614 return 0;
|
|
615 }
|
|
616
|
|
617 char *
|
|
618 rts_get_lpCommandLine (void)
|
|
619 {
|
|
620 return GetCommandLineA ();
|
|
621 }
|
|
622
|
|
623 int
|
|
624 rts_get_nShowCmd (void)
|
|
625 {
|
|
626 return 1;
|
|
627 }
|
|
628
|
|
629 #endif /* WINNT */
|
|
630
|
|
631 /* This value is returned as the time zone offset when a valid value
|
|
632 cannot be determined. It is simply a bizarre value that will never
|
|
633 occur. It is 3 days plus 73 seconds (offset is in seconds). */
|
|
634
|
|
635 long __gnat_invalid_tzoff = 259273;
|
|
636
|
|
637 /* Definition of __gnat_localtime_r used by a-calend.adb */
|
|
638
|
|
639 #if defined (__MINGW32__)
|
|
640
|
|
641 /* Reentrant localtime for Windows. */
|
|
642
|
|
643 extern void
|
|
644 __gnat_localtime_tzoff (const time_t *, const int *, long *);
|
|
645
|
|
646 static const unsigned long long w32_epoch_offset = 11644473600ULL;
|
|
647 void
|
|
648 __gnat_localtime_tzoff (const time_t *timer, const int *is_historic, long *off)
|
|
649 {
|
|
650 TIME_ZONE_INFORMATION tzi;
|
|
651
|
|
652 DWORD tzi_status;
|
|
653
|
|
654 tzi_status = GetTimeZoneInformation (&tzi);
|
|
655
|
|
656 /* Cases where we simply want to extract the offset of the current time
|
|
657 zone, regardless of the date. A value of "0" for flag "is_historic"
|
|
658 signifies that the date is NOT historic, see the
|
|
659 body of Ada.Calendar.UTC_Time_Offset. */
|
|
660
|
|
661 if (*is_historic == 0) {
|
|
662 *off = tzi.Bias;
|
|
663
|
|
664 /* The system is operating in the range covered by the StandardDate
|
|
665 member. */
|
|
666 if (tzi_status == TIME_ZONE_ID_STANDARD) {
|
|
667 *off = *off + tzi.StandardBias;
|
|
668 }
|
|
669
|
|
670 /* The system is operating in the range covered by the DaylightDate
|
|
671 member. */
|
|
672 else if (tzi_status == TIME_ZONE_ID_DAYLIGHT) {
|
|
673 *off = *off + tzi.DaylightBias;
|
|
674 }
|
|
675
|
|
676 *off = *off * -60;
|
|
677 }
|
|
678
|
|
679 /* Time zone offset calculations for a historic or future date */
|
|
680
|
|
681 else {
|
|
682 union
|
|
683 {
|
|
684 FILETIME ft_time;
|
|
685 unsigned long long ull_time;
|
|
686 } utc_time, local_time;
|
|
687
|
|
688 SYSTEMTIME utc_sys_time, local_sys_time;
|
|
689 BOOL status;
|
|
690
|
|
691 /* First convert unix time_t structure to windows FILETIME format. */
|
|
692 utc_time.ull_time = ((unsigned long long) *timer + w32_epoch_offset)
|
|
693 * 10000000ULL;
|
|
694
|
|
695 /* If GetTimeZoneInformation does not return a value between 0 and 2 then
|
|
696 it means that we were not able to retrieve timezone information. Note
|
|
697 that we cannot use here FileTimeToLocalFileTime as Windows will use in
|
|
698 always in this case the current timezone setting. As suggested on MSDN
|
|
699 we use the following three system calls to get the right information.
|
|
700 Note also that starting with Windows Vista new functions are provided
|
|
701 to get timezone settings that depend on the year. We cannot use them as
|
|
702 we still support Windows XP and Windows 2003. */
|
|
703
|
|
704 status = (tzi_status >= 0 && tzi_status <= 2)
|
|
705 && FileTimeToSystemTime (&utc_time.ft_time, &utc_sys_time)
|
|
706 && SystemTimeToTzSpecificLocalTime (&tzi, &utc_sys_time, &local_sys_time)
|
|
707 && SystemTimeToFileTime (&local_sys_time, &local_time.ft_time);
|
|
708
|
|
709 /* An error has occurred, return invalid_tzoff */
|
|
710
|
|
711 if (!status) {
|
|
712 *off = __gnat_invalid_tzoff;
|
|
713 }
|
|
714 else {
|
|
715 if (local_time.ull_time > utc_time.ull_time) {
|
|
716 *off = (long) ((local_time.ull_time - utc_time.ull_time)
|
|
717 / 10000000ULL);
|
|
718 }
|
|
719 else {
|
|
720 *off = - (long) ((utc_time.ull_time - local_time.ull_time)
|
|
721 / 10000000ULL);
|
|
722 }
|
|
723 }
|
|
724 }
|
|
725 }
|
|
726
|
|
727 #elif defined (__Lynx__)
|
|
728
|
|
729 /* On Lynx, all time values are treated in GMT */
|
|
730
|
|
731 /* As of LynxOS 3.1.0a patch level 040, LynuxWorks changes the
|
|
732 prototype to the C library function localtime_r from the POSIX.4
|
|
733 Draft 9 to the POSIX 1.c version. Before this change the following
|
|
734 spec is required. Only use when ___THREADS_POSIX4ad4__ is defined,
|
|
735 the Lynx convention when building against the legacy API. */
|
|
736
|
|
737 extern void
|
|
738 __gnat_localtime_tzoff (const time_t *, const int *, long *);
|
|
739
|
|
740 void
|
|
741 __gnat_localtime_tzoff (const time_t *timer, const int *is_historic, long *off)
|
|
742 {
|
|
743 *off = 0;
|
|
744 }
|
|
745
|
|
746 #else
|
|
747
|
|
748 /* Other targets except Lynx and Windows provide a standard localtime_r */
|
|
749
|
|
750 #define Lock_Task system__soft_links__lock_task
|
|
751 extern void (*Lock_Task) (void);
|
|
752
|
|
753 #define Unlock_Task system__soft_links__unlock_task
|
|
754 extern void (*Unlock_Task) (void);
|
|
755
|
|
756 extern void
|
|
757 __gnat_localtime_tzoff (const time_t *, const int *, long *);
|
|
758
|
|
759 void
|
|
760 __gnat_localtime_tzoff (const time_t *timer ATTRIBUTE_UNUSED,
|
|
761 const int *is_historic ATTRIBUTE_UNUSED,
|
|
762 long *off ATTRIBUTE_UNUSED)
|
|
763 {
|
|
764 struct tm tp ATTRIBUTE_UNUSED;
|
|
765
|
|
766 /* AIX, HPUX, Sun Solaris */
|
|
767 #if defined (_AIX) || defined (__hpux__) || defined (__sun__)
|
|
768 {
|
|
769 (*Lock_Task) ();
|
|
770
|
|
771 localtime_r (timer, &tp);
|
|
772 *off = (long) -timezone;
|
|
773
|
|
774 (*Unlock_Task) ();
|
|
775
|
|
776 /* Correct the offset if Daylight Saving Time is in effect */
|
|
777
|
|
778 if (tp.tm_isdst > 0)
|
|
779 *off = *off + 3600;
|
|
780 }
|
|
781
|
|
782 /* VxWorks */
|
|
783 #elif defined (__vxworks)
|
|
784 #include <stdlib.h>
|
|
785 {
|
|
786 (*Lock_Task) ();
|
|
787
|
|
788 localtime_r (timer, &tp);
|
|
789
|
|
790 /* Try to read the environment variable TIMEZONE. The variable may not have
|
|
791 been initialize, in that case return an offset of zero (0) for UTC. */
|
|
792
|
|
793 char *tz_str = getenv ("TIMEZONE");
|
|
794
|
|
795 if ((tz_str == NULL) || (*tz_str == '\0'))
|
|
796 *off = 0;
|
|
797 else
|
|
798 {
|
|
799 char *tz_start, *tz_end;
|
|
800
|
|
801 /* The format of the data contained in TIMEZONE is N::U:S:E where N is the
|
|
802 name of the time zone, U are the minutes difference from UTC, S is the
|
|
803 start of DST in mmddhh and E is the end of DST in mmddhh. Extracting
|
|
804 the value of U involves setting two pointers, one at the beginning and
|
|
805 one at the end of the value. The end pointer is then set to null in
|
|
806 order to delimit a string slice for atol to process. */
|
|
807
|
|
808 tz_start = index (tz_str, ':') + 2;
|
|
809 tz_end = index (tz_start, ':');
|
|
810 *tz_end = '\0';
|
|
811
|
|
812 /* The Ada layer expects an offset in seconds. Note that we must reverse
|
|
813 the sign of the result since west is positive and east is negative on
|
|
814 VxWorks targets. */
|
|
815
|
|
816 *off = -atol (tz_start) * 60;
|
|
817
|
|
818 /* Correct the offset if Daylight Saving Time is in effect */
|
|
819
|
|
820 if (tp.tm_isdst > 0)
|
|
821 *off = *off + 3600;
|
|
822 }
|
|
823
|
|
824 (*Unlock_Task) ();
|
|
825 }
|
|
826
|
|
827 /* Darwin, Free BSD, Linux, where component tm_gmtoff is present in
|
|
828 struct tm */
|
|
829
|
|
830 #elif defined (__APPLE__) || defined (__FreeBSD__) || defined (__linux__) \
|
|
831 || defined (__GLIBC__) || defined (__DragonFly__) || defined (__OpenBSD__) \
|
131
|
832 || defined (__DJGPP__) || defined (__QNX__)
|
111
|
833 {
|
|
834 localtime_r (timer, &tp);
|
|
835 *off = tp.tm_gmtoff;
|
|
836 }
|
|
837
|
|
838 /* Default: treat all time values in GMT */
|
|
839
|
|
840 #else
|
|
841 *off = 0;
|
|
842
|
|
843 #endif /* defined(_AIX) ... */
|
|
844 }
|
|
845
|
|
846 #endif
|
|
847
|
|
848 #ifdef __vxworks
|
|
849
|
|
850 #include <taskLib.h>
|
|
851
|
|
852 /* __gnat_get_task_options is used by s-taprop.adb only for VxWorks. This
|
|
853 function returns the options to be set when creating a new task. It fetches
|
|
854 the options assigned to the current task (parent), so offering some user
|
|
855 level control over the options for a task hierarchy. It forces VX_FP_TASK
|
|
856 because it is almost always required. On processors with the SPE
|
|
857 category, VX_SPE_TASK should be used instead to enable the SPE. */
|
|
858 extern int __gnat_get_task_options (void);
|
|
859
|
|
860 int
|
|
861 __gnat_get_task_options (void)
|
|
862 {
|
|
863 int options;
|
|
864
|
|
865 /* Get the options for the task creator */
|
|
866 taskOptionsGet (taskIdSelf (), &options);
|
|
867
|
|
868 /* Force VX_FP_TASK or VX_SPE_TASK as needed */
|
|
869 #if defined (__SPE__)
|
|
870 options |= VX_SPE_TASK;
|
|
871 #else
|
|
872 options |= VX_FP_TASK;
|
|
873 #endif
|
|
874
|
|
875 /* Mask those bits that are not under user control */
|
|
876 #ifdef VX_USR_TASK_OPTIONS
|
|
877 /* O810-007, TSR 00043679:
|
|
878 Workaround a bug in Vx-7 where VX_DEALLOC_TCB == VX_PRIVATE_UMASK and:
|
|
879 - VX_DEALLOC_TCB is an internal option not to be used by users
|
|
880 - VX_PRIVATE_UMASK as a user-definable option
|
|
881 This leads to VX_USR_TASK_OPTIONS allowing 0x8000 as VX_PRIVATE_UMASK but
|
|
882 taskCreate refusing this option (VX_DEALLOC_TCB is not allowed)
|
|
883
|
|
884 Note that the same error occurs in both RTP and Kernel mode, but
|
|
885 VX_DEALLOC_TCB is not defined in the RTP headers, so we need to
|
|
886 explicitely check if VX_PRIVATE_UMASK has value 0x8000
|
|
887 */
|
|
888 # if defined (VX_PRIVATE_UMASK) && (0x8000 == VX_PRIVATE_UMASK)
|
|
889 options &= ~VX_PRIVATE_UMASK;
|
|
890 # endif
|
|
891 options &= VX_USR_TASK_OPTIONS;
|
|
892 #endif
|
|
893 return options;
|
|
894 }
|
|
895
|
|
896 #endif
|
|
897
|
|
898 int
|
|
899 __gnat_is_file_not_found_error (int errno_val) {
|
|
900 switch (errno_val) {
|
|
901 case ENOENT:
|
|
902 #ifdef __vxworks
|
|
903 /* In the case of VxWorks, we also have to take into account various
|
|
904 * filesystem-specific variants of this error.
|
|
905 */
|
|
906 #if ! defined (VTHREADS) && (_WRS_VXWORKS_MAJOR < 7)
|
|
907 case S_dosFsLib_FILE_NOT_FOUND:
|
|
908 #endif
|
|
909 #if ! defined (__RTP__) && (! defined (VTHREADS) || defined (__VXWORKSMILS__))
|
|
910 case S_nfsLib_NFSERR_NOENT:
|
|
911 #endif
|
|
912 #if defined (__RTP__)
|
|
913 /* An RTP can return an NFS file not found, and the NFS bits must
|
|
914 first be masked on to check the errno. */
|
|
915 case M_nfsStat | ENOENT:
|
|
916 #endif
|
|
917 #endif
|
|
918 return 1;
|
|
919
|
|
920 default:
|
|
921 return 0;
|
|
922 }
|
|
923 }
|
|
924
|
|
925 #if defined (__linux__)
|
|
926
|
|
927 /* Note well: If this code is modified, it should be tested by hand,
|
|
928 because automated testing doesn't exercise it.
|
|
929 */
|
|
930
|
|
931 /* HAVE_CAPABILITY is supposed to be defined if sys/capability.h exists on the
|
|
932 system where this is being compiled. If this macro is defined, we #include
|
|
933 the header. Otherwise we have the relevant declarations textually here.
|
|
934 */
|
|
935
|
|
936 #if defined (HAVE_CAPABILITY)
|
|
937 #include <sys/capability.h>
|
|
938 #else
|
|
939
|
|
940 /* HAVE_CAPABILITY is not defined, so sys/capability.h does might not exist. */
|
|
941
|
|
942 typedef struct _cap_struct *cap_t;
|
|
943 typedef enum {
|
|
944 CAP_CLEAR=0,
|
|
945 CAP_SET=1
|
|
946 } cap_flag_value_t;
|
|
947 #define CAP_SYS_NICE 23
|
|
948 typedef enum {
|
|
949 CAP_EFFECTIVE=0, /* Specifies the effective flag */
|
|
950 CAP_PERMITTED=1, /* Specifies the permitted flag */
|
|
951 CAP_INHERITABLE=2 /* Specifies the inheritable flag */
|
|
952 } cap_flag_t;
|
|
953
|
|
954 typedef int cap_value_t;
|
|
955
|
|
956 extern cap_t cap_get_proc(void);
|
|
957 extern int cap_get_flag(cap_t, cap_value_t, cap_flag_t, cap_flag_value_t *);
|
|
958 extern int cap_free(void *);
|
|
959
|
|
960 #endif
|
|
961
|
|
962 /* __gnat_has_cap_sys_nice returns 1 if the current process has the
|
|
963 CAP_SYS_NICE capability. This capability is necessary to use the
|
|
964 Ceiling_Locking policy. Returns 0 otherwise. Note that this is
|
|
965 defined only for Linux.
|
|
966 */
|
|
967
|
|
968 /* Define these as weak symbols, so if support for capabilities is not present,
|
|
969 programs can still link. On Ubuntu, support for capabilities can be
|
|
970 installed via "sudo apt-get --assume-yes install libcap-dev".
|
|
971 In addition, the user must link with "-lcap", or else these
|
|
972 symbols will be 0, and __gnat_has_cap_sys_nice will return 0.
|
|
973 */
|
|
974
|
|
975 static cap_t cap_get_proc_weak(void)
|
|
976 __attribute__ ((weakref ("cap_get_proc")));
|
|
977 static int cap_get_flag_weak(cap_t, cap_value_t, cap_flag_t, cap_flag_value_t *)
|
|
978 __attribute__ ((weakref ("cap_get_flag")));
|
|
979 static int cap_free_weak(void *)
|
|
980 __attribute__ ((weakref ("cap_free")));
|
|
981
|
|
982 int
|
|
983 __gnat_has_cap_sys_nice () {
|
|
984 /* If the address of cap_get_proc_weak is 0, this means support for
|
|
985 capabilities is not present, so we return 0. */
|
|
986 if (&cap_get_proc_weak == 0)
|
|
987 return 0;
|
|
988
|
|
989 cap_t caps = cap_get_proc_weak();
|
|
990 if (caps == NULL)
|
|
991 return 0;
|
|
992
|
|
993 cap_flag_value_t value;
|
|
994
|
|
995 if (cap_get_flag_weak(caps, CAP_SYS_NICE, CAP_EFFECTIVE, &value) == -1)
|
|
996 return 0;
|
|
997
|
|
998 if (cap_free_weak(caps) == -1)
|
|
999 return 0;
|
|
1000
|
|
1001 if (value == CAP_SET)
|
|
1002 return 1;
|
|
1003
|
|
1004 return 0;
|
|
1005 }
|
|
1006 #endif
|
|
1007
|
|
1008 #ifdef __ANDROID__
|
|
1009
|
|
1010 /* Provide extern symbols for sig* as needed by the tasking run-time, instead
|
|
1011 of static inline functions. */
|
|
1012
|
|
1013 #include <signal.h>
|
|
1014
|
|
1015 int
|
|
1016 _sigismember (sigset_t *set, int signum)
|
|
1017 {
|
|
1018 return sigismember (set, signum);
|
|
1019 }
|
|
1020
|
|
1021 int
|
|
1022 _sigaddset (sigset_t *set, int signum)
|
|
1023 {
|
|
1024 return sigaddset (set, signum);
|
|
1025 }
|
|
1026
|
|
1027 int
|
|
1028 _sigdelset (sigset_t *set, int signum)
|
|
1029 {
|
|
1030 return sigdelset (set, signum);
|
|
1031 }
|
|
1032
|
|
1033 int
|
|
1034 _sigemptyset (sigset_t *set)
|
|
1035 {
|
|
1036 return sigemptyset (set);
|
|
1037 }
|
|
1038
|
|
1039 int
|
|
1040 _sigfillset (sigset_t *set)
|
|
1041 {
|
|
1042 return sigfillset (set);
|
|
1043 }
|
|
1044
|
|
1045 #include <unistd.h>
|
|
1046 int
|
|
1047 _getpagesize (void)
|
|
1048 {
|
|
1049 return getpagesize ();
|
|
1050 }
|
|
1051 #endif
|
131
|
1052
|
|
1053 int
|
|
1054 __gnat_name_case_equivalence ()
|
|
1055 {
|
|
1056 /* the values here must be synchronized with Ada.Directories.Name_Case_Kind:
|
|
1057
|
|
1058 Unknown = 0
|
|
1059 Case_Sensitive = 1
|
|
1060 Case_Insensitive = 2
|
|
1061 Case_Preserving = 3 */
|
|
1062
|
|
1063 #if defined (__APPLE__) || defined (WIN32)
|
|
1064 return 3;
|
|
1065 #else
|
|
1066 return 1;
|
|
1067 #endif
|
|
1068 }
|
|
1069
|