]> gcc.gnu.org Git - gcc.git/blame - gcc/ada/s-os_lib.adb
sem_prag.adb (Analyze_Global_Item): Move the check concerning the use of volatile...
[gcc.git] / gcc / ada / s-os_lib.adb
CommitLineData
30681738
RD
1------------------------------------------------------------------------------
2-- --
3-- GNAT COMPILER COMPONENTS --
4-- --
5-- S Y S T E M . O S _ L I B --
6-- --
7-- B o d y --
8-- --
2ae395d6 9-- Copyright (C) 1995-2013, AdaCore --
30681738
RD
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- --
607d0635 13-- ware Foundation; either version 3, or (at your option) any later ver- --
30681738
RD
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 --
607d0635
AC
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/>. --
30681738
RD
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
2d9ea47f 32pragma Compiler_Unit;
2d9ea47f 33
30681738
RD
34with Ada.Unchecked_Conversion;
35with Ada.Unchecked_Deallocation;
36with System; use System;
75685ef7
PO
37with System.Case_Util;
38with System.CRTL;
39with System.Soft_Links;
30681738
RD
40
41package body System.OS_Lib is
42
43 -- Imported procedures Dup and Dup2 are used in procedures Spawn and
44 -- Non_Blocking_Spawn.
45
46 function Dup (Fd : File_Descriptor) return File_Descriptor;
47 pragma Import (C, Dup, "__gnat_dup");
48
49 procedure Dup2 (Old_Fd, New_Fd : File_Descriptor);
50 pragma Import (C, Dup2, "__gnat_dup2");
51
52 On_Windows : constant Boolean := Directory_Separator = '\';
53 -- An indication that we are on Windows. Used in Normalize_Pathname, to
54 -- deal with drive letters in the beginning of absolute paths.
55
56 package SSL renames System.Soft_Links;
57
58 -- The following are used by Create_Temp_File
59
60 First_Temp_File_Name : constant String := "GNAT-TEMP-000000.TMP";
61 -- Used to initialize Current_Temp_File_Name and Temp_File_Name_Last_Digit
62
63 Current_Temp_File_Name : String := First_Temp_File_Name;
64 -- Name of the temp file last created
65
66 Temp_File_Name_Last_Digit : constant Positive :=
67 First_Temp_File_Name'Last - 4;
68 -- Position of the last digit in Current_Temp_File_Name
69
70 Max_Attempts : constant := 100;
71 -- The maximum number of attempts to create a new temp file
72
73 -----------------------
74 -- Local Subprograms --
75 -----------------------
76
77 function Args_Length (Args : Argument_List) return Natural;
76b84bf0
AC
78 -- Returns total number of characters needed to create a string of all Args
79 -- terminated by ASCII.NUL characters.
30681738 80
477b99b6 81 procedure Create_Temp_File_Internal
76b84bf0
AC
82 (FD : out File_Descriptor;
83 Name : out String_Access;
84 Stdout : Boolean);
477b99b6
AC
85 -- Internal routine to implement two Create_Temp_File routines. If Stdout
86 -- is set to True the created descriptor is stdout-compatible, otherwise
87 -- it might not be depending on the OS (VMS is one example). The first two
88 -- parameters are as in Create_Temp_File.
89
30681738
RD
90 function C_String_Length (S : Address) return Integer;
91 -- Returns the length of a C string. Does check for null address
92 -- (returns 0).
93
94 procedure Spawn_Internal
95 (Program_Name : String;
96 Args : Argument_List;
97 Result : out Integer;
98 Pid : out Process_Id;
99 Blocking : Boolean);
100 -- Internal routine to implement the two Spawn (blocking/non blocking)
101 -- routines. If Blocking is set to True then the spawn is blocking
102 -- otherwise it is non blocking. In this latter case the Pid contains the
103 -- process id number. The first three parameters are as in Spawn. Note that
104 -- Spawn_Internal normalizes the argument list before calling the low level
105 -- system spawn routines (see Normalize_Arguments).
106 --
107 -- Note: Normalize_Arguments is designed to do nothing if it is called more
108 -- than once, so calling Normalize_Arguments before calling one of the
109 -- spawn routines is fine.
110
111 function To_Path_String_Access
112 (Path_Addr : Address;
113 Path_Len : Integer) return String_Access;
114 -- Converts a C String to an Ada String. We could do this making use of
115 -- Interfaces.C.Strings but we prefer not to import that entire package
116
117 ---------
118 -- "<" --
119 ---------
120
121 function "<" (X, Y : OS_Time) return Boolean is
122 begin
123 return Long_Integer (X) < Long_Integer (Y);
124 end "<";
125
126 ----------
127 -- "<=" --
128 ----------
129
130 function "<=" (X, Y : OS_Time) return Boolean is
131 begin
132 return Long_Integer (X) <= Long_Integer (Y);
133 end "<=";
134
135 ---------
136 -- ">" --
137 ---------
138
139 function ">" (X, Y : OS_Time) return Boolean is
140 begin
141 return Long_Integer (X) > Long_Integer (Y);
142 end ">";
143
144 ----------
145 -- ">=" --
146 ----------
147
148 function ">=" (X, Y : OS_Time) return Boolean is
149 begin
150 return Long_Integer (X) >= Long_Integer (Y);
151 end ">=";
152
153 -----------------
154 -- Args_Length --
155 -----------------
156
157 function Args_Length (Args : Argument_List) return Natural is
158 Len : Natural := 0;
159
160 begin
161 for J in Args'Range loop
162 Len := Len + Args (J)'Length + 1; -- One extra for ASCII.NUL
163 end loop;
164
165 return Len;
166 end Args_Length;
167
168 -----------------------------
169 -- Argument_String_To_List --
170 -----------------------------
171
172 function Argument_String_To_List
173 (Arg_String : String) return Argument_List_Access
174 is
175 Max_Args : constant Integer := Arg_String'Length;
176 New_Argv : Argument_List (1 .. Max_Args);
177 New_Argc : Natural := 0;
178 Idx : Integer;
179
180 begin
181 Idx := Arg_String'First;
182
183 loop
184 exit when Idx > Arg_String'Last;
185
186 declare
187 Quoted : Boolean := False;
188 Backqd : Boolean := False;
189 Old_Idx : Integer;
190
191 begin
192 Old_Idx := Idx;
193
194 loop
195 -- An unquoted space is the end of an argument
196
197 if not (Backqd or Quoted)
198 and then Arg_String (Idx) = ' '
199 then
200 exit;
201
202 -- Start of a quoted string
203
204 elsif not (Backqd or Quoted)
205 and then Arg_String (Idx) = '"'
206 then
207 Quoted := True;
208
209 -- End of a quoted string and end of an argument
210
211 elsif (Quoted and not Backqd)
212 and then Arg_String (Idx) = '"'
213 then
214 Idx := Idx + 1;
215 exit;
216
217 -- Following character is backquoted
218
219 elsif Arg_String (Idx) = '\' then
220 Backqd := True;
221
222 -- Turn off backquoting after advancing one character
223
224 elsif Backqd then
225 Backqd := False;
226
227 end if;
228
229 Idx := Idx + 1;
230 exit when Idx > Arg_String'Last;
231 end loop;
232
233 -- Found an argument
234
235 New_Argc := New_Argc + 1;
236 New_Argv (New_Argc) :=
237 new String'(Arg_String (Old_Idx .. Idx - 1));
238
239 -- Skip extraneous spaces
240
241 while Idx <= Arg_String'Last and then Arg_String (Idx) = ' ' loop
242 Idx := Idx + 1;
243 end loop;
244 end;
245 end loop;
246
247 return new Argument_List'(New_Argv (1 .. New_Argc));
248 end Argument_String_To_List;
249
250 ---------------------
251 -- C_String_Length --
252 ---------------------
253
254 function C_String_Length (S : Address) return Integer is
255 function Strlen (S : Address) return Integer;
256 pragma Import (C, Strlen, "strlen");
257 begin
258 if S = Null_Address then
259 return 0;
260 else
261 return Strlen (S);
262 end if;
263 end C_String_Length;
264
265 -----------
266 -- Close --
267 -----------
268
269 procedure Close (FD : File_Descriptor) is
270 procedure C_Close (FD : File_Descriptor);
271 pragma Import (C, C_Close, "close");
272 begin
273 C_Close (FD);
274 end Close;
275
276 procedure Close (FD : File_Descriptor; Status : out Boolean) is
277 function C_Close (FD : File_Descriptor) return Integer;
278 pragma Import (C, C_Close, "close");
279 begin
280 Status := (C_Close (FD) = 0);
281 end Close;
282
283 ---------------
284 -- Copy_File --
285 ---------------
286
287 procedure Copy_File
288 (Name : String;
289 Pathname : String;
290 Success : out Boolean;
291 Mode : Copy_Mode := Copy;
292 Preserve : Attribute := Time_Stamps)
293 is
294 From : File_Descriptor;
295 To : File_Descriptor;
296
297 Copy_Error : exception;
298 -- Internal exception raised to signal error in copy
299
300 function Build_Path (Dir : String; File : String) return String;
276e95ca 301 -- Returns pathname Dir concatenated with File adding the directory
30681738
RD
302 -- separator only if needed.
303
304 procedure Copy (From, To : File_Descriptor);
305 -- Read data from From and place them into To. In both cases the
306 -- operations uses the current file position. Raises Constraint_Error
307 -- if a problem occurs during the copy.
308
309 procedure Copy_To (To_Name : String);
310 -- Does a straight copy from source to designated destination file
311
312 ----------------
313 -- Build_Path --
314 ----------------
315
316 function Build_Path (Dir : String; File : String) return String is
317 Res : String (1 .. Dir'Length + File'Length + 1);
318
319 Base_File_Ptr : Integer;
320 -- The base file name is File (Base_File_Ptr + 1 .. File'Last)
321
322 function Is_Dirsep (C : Character) return Boolean;
323 pragma Inline (Is_Dirsep);
324 -- Returns True if C is a directory separator. On Windows we
325 -- handle both styles of directory separator.
326
327 ---------------
328 -- Is_Dirsep --
329 ---------------
330
331 function Is_Dirsep (C : Character) return Boolean is
332 begin
333 return C = Directory_Separator or else C = '/';
334 end Is_Dirsep;
335
336 -- Start of processing for Build_Path
337
338 begin
339 -- Find base file name
340
341 Base_File_Ptr := File'Last;
342 while Base_File_Ptr >= File'First loop
343 exit when Is_Dirsep (File (Base_File_Ptr));
344 Base_File_Ptr := Base_File_Ptr - 1;
345 end loop;
346
347 declare
348 Base_File : String renames
349 File (Base_File_Ptr + 1 .. File'Last);
350
351 begin
352 Res (1 .. Dir'Length) := Dir;
353
354 if Is_Dirsep (Dir (Dir'Last)) then
355 Res (Dir'Length + 1 .. Dir'Length + Base_File'Length) :=
356 Base_File;
357 return Res (1 .. Dir'Length + Base_File'Length);
358
359 else
360 Res (Dir'Length + 1) := Directory_Separator;
361 Res (Dir'Length + 2 .. Dir'Length + 1 + Base_File'Length) :=
362 Base_File;
363 return Res (1 .. Dir'Length + 1 + Base_File'Length);
364 end if;
365 end;
366 end Build_Path;
367
368 ----------
369 -- Copy --
370 ----------
371
372 procedure Copy (From, To : File_Descriptor) is
373 Buf_Size : constant := 200_000;
374 type Buf is array (1 .. Buf_Size) of Character;
375 type Buf_Ptr is access Buf;
376
377 Buffer : Buf_Ptr;
378 R : Integer;
379 W : Integer;
380
381 Status_From : Boolean;
382 Status_To : Boolean;
383 -- Statuses for the calls to Close
384
385 procedure Free is new Ada.Unchecked_Deallocation (Buf, Buf_Ptr);
386
387 begin
388 -- Check for invalid descriptors, making sure that we do not
389 -- accidentally leave an open file descriptor around.
390
391 if From = Invalid_FD then
392 if To /= Invalid_FD then
393 Close (To, Status_To);
394 end if;
395
396 raise Copy_Error;
397
398 elsif To = Invalid_FD then
399 Close (From, Status_From);
400 raise Copy_Error;
401 end if;
402
403 -- Allocate the buffer on the heap
404
405 Buffer := new Buf;
406
407 loop
408 R := Read (From, Buffer (1)'Address, Buf_Size);
409
410 -- For VMS, the buffer may not be full. So, we need to try again
411 -- until there is nothing to read.
412
413 exit when R = 0;
414
415 W := Write (To, Buffer (1)'Address, R);
416
417 if W < R then
418
419 -- Problem writing data, could be a disk full. Close files
420 -- without worrying about status, since we are raising a
421 -- Copy_Error exception in any case.
422
423 Close (From, Status_From);
424 Close (To, Status_To);
425
426 Free (Buffer);
427
428 raise Copy_Error;
429 end if;
430 end loop;
431
432 Close (From, Status_From);
433 Close (To, Status_To);
434
435 Free (Buffer);
436
437 if not (Status_From and Status_To) then
438 raise Copy_Error;
439 end if;
440 end Copy;
441
442 -------------
443 -- Copy_To --
444 -------------
445
446 procedure Copy_To (To_Name : String) is
447
448 function Copy_Attributes
449 (From, To : System.Address;
450 Mode : Integer) return Integer;
451 pragma Import (C, Copy_Attributes, "__gnat_copy_attribs");
452 -- Mode = 0 - copy only time stamps.
453 -- Mode = 1 - copy time stamps and read/write/execute attributes
454
455 C_From : String (1 .. Name'Length + 1);
456 C_To : String (1 .. To_Name'Length + 1);
457
458 begin
459 From := Open_Read (Name, Binary);
e401e17b
TQ
460
461 -- Do not clobber destination file if source file could not be opened
462
463 if From /= Invalid_FD then
464 To := Create_File (To_Name, Binary);
465 end if;
466
30681738
RD
467 Copy (From, To);
468
469 -- Copy attributes
470
471 C_From (1 .. Name'Length) := Name;
43c6e0cb 472 C_From (C_From'Last) := ASCII.NUL;
30681738
RD
473
474 C_To (1 .. To_Name'Length) := To_Name;
43c6e0cb 475 C_To (C_To'Last) := ASCII.NUL;
30681738
RD
476
477 case Preserve is
478
479 when Time_Stamps =>
480 if Copy_Attributes (C_From'Address, C_To'Address, 0) = -1 then
481 raise Copy_Error;
482 end if;
483
484 when Full =>
485 if Copy_Attributes (C_From'Address, C_To'Address, 1) = -1 then
486 raise Copy_Error;
487 end if;
488
489 when None =>
490 null;
491 end case;
492
493 end Copy_To;
494
495 -- Start of processing for Copy_File
496
497 begin
498 Success := True;
499
500 -- The source file must exist
501
502 if not Is_Regular_File (Name) then
503 raise Copy_Error;
504 end if;
505
506 -- The source file exists
507
508 case Mode is
509
510 -- Copy case, target file must not exist
511
512 when Copy =>
513
514 -- If the target file exists, we have an error
515
516 if Is_Regular_File (Pathname) then
517 raise Copy_Error;
518
519 -- Case of target is a directory
520
521 elsif Is_Directory (Pathname) then
522 declare
523 Dest : constant String := Build_Path (Pathname, Name);
524
525 begin
526 -- If target file exists, we have an error, else do copy
527
528 if Is_Regular_File (Dest) then
529 raise Copy_Error;
530 else
531 Copy_To (Dest);
532 end if;
533 end;
534
535 -- Case of normal copy to file (destination does not exist)
536
537 else
538 Copy_To (Pathname);
539 end if;
540
541 -- Overwrite case (destination file may or may not exist)
542
543 when Overwrite =>
544 if Is_Directory (Pathname) then
545 Copy_To (Build_Path (Pathname, Name));
546 else
547 Copy_To (Pathname);
548 end if;
549
550 -- Append case (destination file may or may not exist)
551
552 when Append =>
553
554 -- Appending to existing file
555
556 if Is_Regular_File (Pathname) then
557
558 -- Append mode and destination file exists, append data at the
e401e17b
TQ
559 -- end of Pathname. But if we fail to open source file, do not
560 -- touch destination file at all.
30681738
RD
561
562 From := Open_Read (Name, Binary);
e401e17b
TQ
563 if From /= Invalid_FD then
564 To := Open_Read_Write (Pathname, Binary);
565 end if;
566
30681738
RD
567 Lseek (To, 0, Seek_End);
568
569 Copy (From, To);
570
571 -- Appending to directory, not allowed
572
573 elsif Is_Directory (Pathname) then
574 raise Copy_Error;
575
576 -- Appending when target file does not exist
577
578 else
579 Copy_To (Pathname);
580 end if;
581 end case;
582
583 -- All error cases are caught here
584
585 exception
586 when Copy_Error =>
587 Success := False;
588 end Copy_File;
589
590 procedure Copy_File
591 (Name : C_File_Name;
592 Pathname : C_File_Name;
593 Success : out Boolean;
594 Mode : Copy_Mode := Copy;
595 Preserve : Attribute := Time_Stamps)
596 is
8b79ad42
AC
597 Ada_Name : String_Access :=
598 To_Path_String_Access
599 (Name, C_String_Length (Name));
30681738
RD
600 Ada_Pathname : String_Access :=
601 To_Path_String_Access
602 (Pathname, C_String_Length (Pathname));
30681738
RD
603 begin
604 Copy_File (Ada_Name.all, Ada_Pathname.all, Success, Mode, Preserve);
605 Free (Ada_Name);
606 Free (Ada_Pathname);
607 end Copy_File;
608
609 ----------------------
610 -- Copy_Time_Stamps --
611 ----------------------
612
613 procedure Copy_Time_Stamps (Source, Dest : String; Success : out Boolean) is
30681738
RD
614 function Copy_Attributes
615 (From, To : System.Address;
616 Mode : Integer) return Integer;
617 pragma Import (C, Copy_Attributes, "__gnat_copy_attribs");
618 -- Mode = 0 - copy only time stamps.
619 -- Mode = 1 - copy time stamps and read/write/execute attributes
620
621 begin
622 if Is_Regular_File (Source) and then Is_Writable_File (Dest) then
623 declare
624 C_Source : String (1 .. Source'Length + 1);
625 C_Dest : String (1 .. Dest'Length + 1);
d61f428e 626
30681738
RD
627 begin
628 C_Source (1 .. Source'Length) := Source;
629 C_Source (C_Source'Last) := ASCII.NUL;
630
631 C_Dest (1 .. Dest'Length) := Dest;
632 C_Dest (C_Dest'Last) := ASCII.NUL;
633
634 if Copy_Attributes (C_Source'Address, C_Dest'Address, 0) = -1 then
635 Success := False;
636 else
637 Success := True;
638 end if;
639 end;
640
641 else
642 Success := False;
643 end if;
644 end Copy_Time_Stamps;
645
646 procedure Copy_Time_Stamps
647 (Source, Dest : C_File_Name;
648 Success : out Boolean)
649 is
650 Ada_Source : String_Access :=
651 To_Path_String_Access
652 (Source, C_String_Length (Source));
8b79ad42
AC
653 Ada_Dest : String_Access :=
654 To_Path_String_Access
655 (Dest, C_String_Length (Dest));
30681738
RD
656 begin
657 Copy_Time_Stamps (Ada_Source.all, Ada_Dest.all, Success);
658 Free (Ada_Source);
659 Free (Ada_Dest);
660 end Copy_Time_Stamps;
661
662 -----------------
663 -- Create_File --
664 -----------------
665
666 function Create_File
667 (Name : C_File_Name;
668 Fmode : Mode) return File_Descriptor
669 is
670 function C_Create_File
671 (Name : C_File_Name;
672 Fmode : Mode) return File_Descriptor;
673 pragma Import (C, C_Create_File, "__gnat_open_create");
30681738
RD
674 begin
675 return C_Create_File (Name, Fmode);
676 end Create_File;
677
678 function Create_File
679 (Name : String;
680 Fmode : Mode) return File_Descriptor
681 is
682 C_Name : String (1 .. Name'Length + 1);
30681738
RD
683 begin
684 C_Name (1 .. Name'Length) := Name;
685 C_Name (C_Name'Last) := ASCII.NUL;
686 return Create_File (C_Name (C_Name'First)'Address, Fmode);
687 end Create_File;
688
689 ---------------------
690 -- Create_New_File --
691 ---------------------
692
693 function Create_New_File
694 (Name : C_File_Name;
695 Fmode : Mode) return File_Descriptor
696 is
697 function C_Create_New_File
698 (Name : C_File_Name;
699 Fmode : Mode) return File_Descriptor;
700 pragma Import (C, C_Create_New_File, "__gnat_open_new");
30681738
RD
701 begin
702 return C_Create_New_File (Name, Fmode);
703 end Create_New_File;
704
705 function Create_New_File
706 (Name : String;
707 Fmode : Mode) return File_Descriptor
708 is
709 C_Name : String (1 .. Name'Length + 1);
30681738
RD
710 begin
711 C_Name (1 .. Name'Length) := Name;
712 C_Name (C_Name'Last) := ASCII.NUL;
713 return Create_New_File (C_Name (C_Name'First)'Address, Fmode);
714 end Create_New_File;
715
716 -----------------------------
717 -- Create_Output_Text_File --
718 -----------------------------
719
720 function Create_Output_Text_File (Name : String) return File_Descriptor is
721 function C_Create_File
722 (Name : C_File_Name) return File_Descriptor;
723 pragma Import (C, C_Create_File, "__gnat_create_output_file");
30681738 724 C_Name : String (1 .. Name'Length + 1);
30681738
RD
725 begin
726 C_Name (1 .. Name'Length) := Name;
727 C_Name (C_Name'Last) := ASCII.NUL;
728 return C_Create_File (C_Name (C_Name'First)'Address);
729 end Create_Output_Text_File;
730
731 ----------------------
732 -- Create_Temp_File --
733 ----------------------
734
735 procedure Create_Temp_File
736 (FD : out File_Descriptor;
737 Name : out Temp_File_Name)
738 is
739 function Open_New_Temp
740 (Name : System.Address;
741 Fmode : Mode) return File_Descriptor;
742 pragma Import (C, Open_New_Temp, "__gnat_open_new_temp");
743
744 begin
745 FD := Open_New_Temp (Name'Address, Binary);
746 end Create_Temp_File;
747
748 procedure Create_Temp_File
749 (FD : out File_Descriptor;
750 Name : out String_Access)
477b99b6
AC
751 is
752 begin
753 Create_Temp_File_Internal (FD, Name, Stdout => False);
754 end Create_Temp_File;
755
13f39091
AC
756 -----------------------------
757 -- Create_Temp_Output_File --
758 -----------------------------
759
477b99b6
AC
760 procedure Create_Temp_Output_File
761 (FD : out File_Descriptor;
762 Name : out String_Access)
763 is
764 begin
765 Create_Temp_File_Internal (FD, Name, Stdout => True);
766 end Create_Temp_Output_File;
767
768 -------------------------------
769 -- Create_Temp_File_Internal --
770 -------------------------------
771
772 procedure Create_Temp_File_Internal
13f39091
AC
773 (FD : out File_Descriptor;
774 Name : out String_Access;
775 Stdout : Boolean)
30681738
RD
776 is
777 Pos : Positive;
778 Attempts : Natural := 0;
779 Current : String (Current_Temp_File_Name'Range);
780
fdfcc663
AC
781 function Create_New_Output_Text_File
782 (Name : String) return File_Descriptor;
783 -- Similar to Create_Output_Text_File, except it fails if the file
784 -- already exists. We need this behavior to ensure we don't accidentally
785 -- open a temp file that has just been created by a concurrently running
786 -- process. There is no point exposing this function, as it's generally
787 -- not particularly useful.
788
13f39091
AC
789 ---------------------------------
790 -- Create_New_Output_Text_File --
791 ---------------------------------
792
fdfcc663 793 function Create_New_Output_Text_File
13f39091
AC
794 (Name : String) return File_Descriptor
795 is
fdfcc663
AC
796 function C_Create_File
797 (Name : C_File_Name) return File_Descriptor;
798 pragma Import (C, C_Create_File, "__gnat_create_output_file_new");
fdfcc663 799 C_Name : String (1 .. Name'Length + 1);
fdfcc663
AC
800 begin
801 C_Name (1 .. Name'Length) := Name;
802 C_Name (C_Name'Last) := ASCII.NUL;
803 return C_Create_File (C_Name (C_Name'First)'Address);
804 end Create_New_Output_Text_File;
805
30681738
RD
806 begin
807 -- Loop until a new temp file can be created
808
809 File_Loop : loop
810 Locked : begin
13f39091 811
30681738
RD
812 -- We need to protect global variable Current_Temp_File_Name
813 -- against concurrent access by different tasks.
814
815 SSL.Lock_Task.all;
816
817 -- Start at the last digit
818
819 Pos := Temp_File_Name_Last_Digit;
820
821 Digit_Loop :
822 loop
823 -- Increment the digit by one
824
825 case Current_Temp_File_Name (Pos) is
826 when '0' .. '8' =>
827 Current_Temp_File_Name (Pos) :=
828 Character'Succ (Current_Temp_File_Name (Pos));
829 exit Digit_Loop;
830
831 when '9' =>
832
833 -- For 9, set the digit to 0 and go to the previous digit
834
835 Current_Temp_File_Name (Pos) := '0';
836 Pos := Pos - 1;
837
838 when others =>
839
840 -- If it is not a digit, then there are no available
13f39091
AC
841 -- temp file names. Return Invalid_FD. There is almost no
842 -- chance that this code will be ever be executed, since
843 -- it would mean that there are one million temp files in
844 -- the same directory.
30681738
RD
845
846 SSL.Unlock_Task.all;
847 FD := Invalid_FD;
848 Name := null;
849 exit File_Loop;
850 end case;
851 end loop Digit_Loop;
852
853 Current := Current_Temp_File_Name;
854
13f39091
AC
855 -- We can now release the lock, because we are no longer accessing
856 -- Current_Temp_File_Name.
30681738
RD
857
858 SSL.Unlock_Task.all;
859
860 exception
861 when others =>
862 SSL.Unlock_Task.all;
863 raise;
864 end Locked;
865
866 -- Attempt to create the file
867
477b99b6 868 if Stdout then
fdfcc663 869 FD := Create_New_Output_Text_File (Current);
477b99b6 870 else
fdfcc663 871 FD := Create_New_File (Current, Binary);
477b99b6 872 end if;
30681738
RD
873
874 if FD /= Invalid_FD then
875 Name := new String'(Current);
876 exit File_Loop;
877 end if;
878
879 if not Is_Regular_File (Current) then
880
881 -- If the file does not already exist and we are unable to create
882 -- it, we give up after Max_Attempts. Otherwise, we try again with
883 -- the next available file name.
884
885 Attempts := Attempts + 1;
886
887 if Attempts >= Max_Attempts then
888 FD := Invalid_FD;
889 Name := null;
890 exit File_Loop;
891 end if;
892 end if;
893 end loop File_Loop;
477b99b6 894 end Create_Temp_File_Internal;
30681738
RD
895
896 -----------------
897 -- Delete_File --
898 -----------------
899
900 procedure Delete_File (Name : Address; Success : out Boolean) is
901 R : Integer;
30681738 902 begin
bca17d51 903 R := System.CRTL.unlink (Name);
30681738
RD
904 Success := (R = 0);
905 end Delete_File;
906
907 procedure Delete_File (Name : String; Success : out Boolean) is
908 C_Name : String (1 .. Name'Length + 1);
30681738
RD
909 begin
910 C_Name (1 .. Name'Length) := Name;
911 C_Name (C_Name'Last) := ASCII.NUL;
30681738
RD
912 Delete_File (C_Name'Address, Success);
913 end Delete_File;
914
915 ---------------------
916 -- File_Time_Stamp --
917 ---------------------
918
919 function File_Time_Stamp (FD : File_Descriptor) return OS_Time is
8b79ad42 920 function File_Time (FD : File_Descriptor) return OS_Time;
30681738
RD
921 pragma Import (C, File_Time, "__gnat_file_time_fd");
922 begin
923 return File_Time (FD);
924 end File_Time_Stamp;
925
926 function File_Time_Stamp (Name : C_File_Name) return OS_Time is
927 function File_Time (Name : Address) return OS_Time;
928 pragma Import (C, File_Time, "__gnat_file_time_name");
929 begin
930 return File_Time (Name);
931 end File_Time_Stamp;
932
933 function File_Time_Stamp (Name : String) return OS_Time is
934 F_Name : String (1 .. Name'Length + 1);
935 begin
936 F_Name (1 .. Name'Length) := Name;
937 F_Name (F_Name'Last) := ASCII.NUL;
938 return File_Time_Stamp (F_Name'Address);
939 end File_Time_Stamp;
940
941 ---------------------------
942 -- Get_Debuggable_Suffix --
943 ---------------------------
944
945 function Get_Debuggable_Suffix return String_Access is
946 procedure Get_Suffix_Ptr (Length, Ptr : Address);
947 pragma Import (C, Get_Suffix_Ptr, "__gnat_get_debuggable_suffix_ptr");
948
949 procedure Strncpy (Astring_Addr, Cstring : Address; N : Integer);
950 pragma Import (C, Strncpy, "strncpy");
951
952 Suffix_Ptr : Address;
953 Suffix_Length : Integer;
954 Result : String_Access;
955
956 begin
957 Get_Suffix_Ptr (Suffix_Length'Address, Suffix_Ptr'Address);
30681738
RD
958 Result := new String (1 .. Suffix_Length);
959
960 if Suffix_Length > 0 then
961 Strncpy (Result.all'Address, Suffix_Ptr, Suffix_Length);
962 end if;
963
964 return Result;
965 end Get_Debuggable_Suffix;
966
967 ---------------------------
968 -- Get_Executable_Suffix --
969 ---------------------------
970
971 function Get_Executable_Suffix return String_Access is
972 procedure Get_Suffix_Ptr (Length, Ptr : Address);
973 pragma Import (C, Get_Suffix_Ptr, "__gnat_get_executable_suffix_ptr");
974
975 procedure Strncpy (Astring_Addr, Cstring : Address; N : Integer);
976 pragma Import (C, Strncpy, "strncpy");
977
978 Suffix_Ptr : Address;
979 Suffix_Length : Integer;
980 Result : String_Access;
981
982 begin
983 Get_Suffix_Ptr (Suffix_Length'Address, Suffix_Ptr'Address);
30681738
RD
984 Result := new String (1 .. Suffix_Length);
985
986 if Suffix_Length > 0 then
987 Strncpy (Result.all'Address, Suffix_Ptr, Suffix_Length);
988 end if;
989
990 return Result;
991 end Get_Executable_Suffix;
992
993 -----------------------
994 -- Get_Object_Suffix --
995 -----------------------
996
997 function Get_Object_Suffix return String_Access is
998 procedure Get_Suffix_Ptr (Length, Ptr : Address);
999 pragma Import (C, Get_Suffix_Ptr, "__gnat_get_object_suffix_ptr");
1000
1001 procedure Strncpy (Astring_Addr, Cstring : Address; N : Integer);
1002 pragma Import (C, Strncpy, "strncpy");
1003
1004 Suffix_Ptr : Address;
1005 Suffix_Length : Integer;
1006 Result : String_Access;
1007
1008 begin
1009 Get_Suffix_Ptr (Suffix_Length'Address, Suffix_Ptr'Address);
30681738
RD
1010 Result := new String (1 .. Suffix_Length);
1011
1012 if Suffix_Length > 0 then
1013 Strncpy (Result.all'Address, Suffix_Ptr, Suffix_Length);
1014 end if;
1015
1016 return Result;
1017 end Get_Object_Suffix;
1018
1019 ----------------------------------
1020 -- Get_Target_Debuggable_Suffix --
1021 ----------------------------------
1022
1023 function Get_Target_Debuggable_Suffix return String_Access is
1024 Target_Exec_Ext_Ptr : Address;
1025 pragma Import
1026 (C, Target_Exec_Ext_Ptr, "__gnat_target_debuggable_extension");
1027
1028 procedure Strncpy (Astring_Addr, Cstring : Address; N : Integer);
1029 pragma Import (C, Strncpy, "strncpy");
1030
1031 function Strlen (Cstring : Address) return Integer;
1032 pragma Import (C, Strlen, "strlen");
1033
1034 Suffix_Length : Integer;
1035 Result : String_Access;
1036
1037 begin
1038 Suffix_Length := Strlen (Target_Exec_Ext_Ptr);
30681738
RD
1039 Result := new String (1 .. Suffix_Length);
1040
1041 if Suffix_Length > 0 then
1042 Strncpy (Result.all'Address, Target_Exec_Ext_Ptr, Suffix_Length);
1043 end if;
1044
1045 return Result;
1046 end Get_Target_Debuggable_Suffix;
1047
1048 ----------------------------------
1049 -- Get_Target_Executable_Suffix --
1050 ----------------------------------
1051
1052 function Get_Target_Executable_Suffix return String_Access is
1053 Target_Exec_Ext_Ptr : Address;
1054 pragma Import
1055 (C, Target_Exec_Ext_Ptr, "__gnat_target_executable_extension");
1056
1057 procedure Strncpy (Astring_Addr, Cstring : Address; N : Integer);
1058 pragma Import (C, Strncpy, "strncpy");
1059
1060 function Strlen (Cstring : Address) return Integer;
1061 pragma Import (C, Strlen, "strlen");
1062
1063 Suffix_Length : Integer;
1064 Result : String_Access;
1065
1066 begin
1067 Suffix_Length := Strlen (Target_Exec_Ext_Ptr);
30681738
RD
1068 Result := new String (1 .. Suffix_Length);
1069
1070 if Suffix_Length > 0 then
1071 Strncpy (Result.all'Address, Target_Exec_Ext_Ptr, Suffix_Length);
1072 end if;
1073
1074 return Result;
1075 end Get_Target_Executable_Suffix;
1076
1077 ------------------------------
1078 -- Get_Target_Object_Suffix --
1079 ------------------------------
1080
1081 function Get_Target_Object_Suffix return String_Access is
1082 Target_Object_Ext_Ptr : Address;
1083 pragma Import
1084 (C, Target_Object_Ext_Ptr, "__gnat_target_object_extension");
1085
1086 procedure Strncpy (Astring_Addr, Cstring : Address; N : Integer);
1087 pragma Import (C, Strncpy, "strncpy");
1088
1089 function Strlen (Cstring : Address) return Integer;
1090 pragma Import (C, Strlen, "strlen");
1091
1092 Suffix_Length : Integer;
1093 Result : String_Access;
1094
1095 begin
1096 Suffix_Length := Strlen (Target_Object_Ext_Ptr);
30681738
RD
1097 Result := new String (1 .. Suffix_Length);
1098
1099 if Suffix_Length > 0 then
1100 Strncpy (Result.all'Address, Target_Object_Ext_Ptr, Suffix_Length);
1101 end if;
1102
1103 return Result;
1104 end Get_Target_Object_Suffix;
1105
1106 ------------
1107 -- Getenv --
1108 ------------
1109
1110 function Getenv (Name : String) return String_Access is
1111 procedure Get_Env_Value_Ptr (Name, Length, Ptr : Address);
1112 pragma Import (C, Get_Env_Value_Ptr, "__gnat_getenv");
1113
1114 procedure Strncpy (Astring_Addr, Cstring : Address; N : Integer);
1115 pragma Import (C, Strncpy, "strncpy");
1116
1117 Env_Value_Ptr : aliased Address;
1118 Env_Value_Length : aliased Integer;
1119 F_Name : aliased String (1 .. Name'Length + 1);
1120 Result : String_Access;
1121
1122 begin
1123 F_Name (1 .. Name'Length) := Name;
1124 F_Name (F_Name'Last) := ASCII.NUL;
1125
1126 Get_Env_Value_Ptr
1127 (F_Name'Address, Env_Value_Length'Address, Env_Value_Ptr'Address);
1128
1129 Result := new String (1 .. Env_Value_Length);
1130
1131 if Env_Value_Length > 0 then
1132 Strncpy (Result.all'Address, Env_Value_Ptr, Env_Value_Length);
1133 end if;
1134
1135 return Result;
1136 end Getenv;
1137
1138 ------------
1139 -- GM_Day --
1140 ------------
1141
1142 function GM_Day (Date : OS_Time) return Day_Type is
67ce0d7e
RD
1143 D : Day_Type;
1144
30681738
RD
1145 Y : Year_Type;
1146 Mo : Month_Type;
30681738
RD
1147 H : Hour_Type;
1148 Mn : Minute_Type;
1149 S : Second_Type;
13f39091 1150 pragma Unreferenced (Y, Mo, H, Mn, S);
30681738
RD
1151
1152 begin
1153 GM_Split (Date, Y, Mo, D, H, Mn, S);
1154 return D;
1155 end GM_Day;
1156
1157 -------------
1158 -- GM_Hour --
1159 -------------
1160
1161 function GM_Hour (Date : OS_Time) return Hour_Type is
67ce0d7e
RD
1162 H : Hour_Type;
1163
30681738
RD
1164 Y : Year_Type;
1165 Mo : Month_Type;
1166 D : Day_Type;
30681738
RD
1167 Mn : Minute_Type;
1168 S : Second_Type;
13f39091 1169 pragma Unreferenced (Y, Mo, D, Mn, S);
30681738
RD
1170
1171 begin
1172 GM_Split (Date, Y, Mo, D, H, Mn, S);
1173 return H;
1174 end GM_Hour;
1175
1176 ---------------
1177 -- GM_Minute --
1178 ---------------
1179
1180 function GM_Minute (Date : OS_Time) return Minute_Type is
67ce0d7e
RD
1181 Mn : Minute_Type;
1182
30681738
RD
1183 Y : Year_Type;
1184 Mo : Month_Type;
1185 D : Day_Type;
1186 H : Hour_Type;
30681738 1187 S : Second_Type;
13f39091 1188 pragma Unreferenced (Y, Mo, D, H, S);
30681738
RD
1189
1190 begin
1191 GM_Split (Date, Y, Mo, D, H, Mn, S);
1192 return Mn;
1193 end GM_Minute;
1194
1195 --------------
1196 -- GM_Month --
1197 --------------
1198
1199 function GM_Month (Date : OS_Time) return Month_Type is
30681738 1200 Mo : Month_Type;
67ce0d7e 1201
67ce0d7e 1202 Y : Year_Type;
30681738
RD
1203 D : Day_Type;
1204 H : Hour_Type;
1205 Mn : Minute_Type;
1206 S : Second_Type;
13f39091 1207 pragma Unreferenced (Y, D, H, Mn, S);
30681738
RD
1208
1209 begin
1210 GM_Split (Date, Y, Mo, D, H, Mn, S);
1211 return Mo;
1212 end GM_Month;
1213
1214 ---------------
1215 -- GM_Second --
1216 ---------------
1217
1218 function GM_Second (Date : OS_Time) return Second_Type is
67ce0d7e
RD
1219 S : Second_Type;
1220
30681738
RD
1221 Y : Year_Type;
1222 Mo : Month_Type;
1223 D : Day_Type;
1224 H : Hour_Type;
1225 Mn : Minute_Type;
13f39091 1226 pragma Unreferenced (Y, Mo, D, H, Mn);
30681738
RD
1227
1228 begin
1229 GM_Split (Date, Y, Mo, D, H, Mn, S);
1230 return S;
1231 end GM_Second;
1232
1233 --------------
1234 -- GM_Split --
1235 --------------
1236
1237 procedure GM_Split
1238 (Date : OS_Time;
1239 Year : out Year_Type;
1240 Month : out Month_Type;
1241 Day : out Day_Type;
1242 Hour : out Hour_Type;
1243 Minute : out Minute_Type;
1244 Second : out Second_Type)
1245 is
1246 procedure To_GM_Time
1247 (P_Time_T, P_Year, P_Month, P_Day, P_Hours, P_Mins, P_Secs : Address);
1248 pragma Import (C, To_GM_Time, "__gnat_to_gm_time");
1249
1250 T : OS_Time := Date;
1251 Y : Integer;
1252 Mo : Integer;
1253 D : Integer;
1254 H : Integer;
1255 Mn : Integer;
1256 S : Integer;
1257
1258 begin
1259 -- Use the global lock because To_GM_Time is not thread safe
1260
1261 Locked_Processing : begin
1262 SSL.Lock_Task.all;
1263 To_GM_Time
1264 (T'Address, Y'Address, Mo'Address, D'Address,
1265 H'Address, Mn'Address, S'Address);
1266 SSL.Unlock_Task.all;
1267
1268 exception
1269 when others =>
1270 SSL.Unlock_Task.all;
1271 raise;
1272 end Locked_Processing;
1273
1274 Year := Y + 1900;
1275 Month := Mo + 1;
1276 Day := D;
1277 Hour := H;
1278 Minute := Mn;
1279 Second := S;
1280 end GM_Split;
1281
1282 -------------
1283 -- GM_Year --
1284 -------------
1285
1286 function GM_Year (Date : OS_Time) return Year_Type is
1287 Y : Year_Type;
67ce0d7e 1288
30681738
RD
1289 Mo : Month_Type;
1290 D : Day_Type;
1291 H : Hour_Type;
1292 Mn : Minute_Type;
1293 S : Second_Type;
13f39091 1294 pragma Unreferenced (Mo, D, H, Mn, S);
30681738
RD
1295
1296 begin
1297 GM_Split (Date, Y, Mo, D, H, Mn, S);
1298 return Y;
1299 end GM_Year;
1300
1301 ----------------------
1302 -- Is_Absolute_Path --
1303 ----------------------
1304
1305 function Is_Absolute_Path (Name : String) return Boolean is
1306 function Is_Absolute_Path
1307 (Name : Address;
1308 Length : Integer) return Integer;
1309 pragma Import (C, Is_Absolute_Path, "__gnat_is_absolute_path");
1310 begin
1311 return Is_Absolute_Path (Name'Address, Name'Length) /= 0;
1312 end Is_Absolute_Path;
1313
1314 ------------------
1315 -- Is_Directory --
1316 ------------------
1317
1318 function Is_Directory (Name : C_File_Name) return Boolean is
1319 function Is_Directory (Name : Address) return Integer;
1320 pragma Import (C, Is_Directory, "__gnat_is_directory");
1321 begin
1322 return Is_Directory (Name) /= 0;
1323 end Is_Directory;
1324
1325 function Is_Directory (Name : String) return Boolean is
1326 F_Name : String (1 .. Name'Length + 1);
1327 begin
1328 F_Name (1 .. Name'Length) := Name;
1329 F_Name (F_Name'Last) := ASCII.NUL;
1330 return Is_Directory (F_Name'Address);
1331 end Is_Directory;
1332
1333 ----------------------
1334 -- Is_Readable_File --
1335 ----------------------
1336
1337 function Is_Readable_File (Name : C_File_Name) return Boolean is
1338 function Is_Readable_File (Name : Address) return Integer;
1339 pragma Import (C, Is_Readable_File, "__gnat_is_readable_file");
1340 begin
1341 return Is_Readable_File (Name) /= 0;
1342 end Is_Readable_File;
1343
1344 function Is_Readable_File (Name : String) return Boolean is
1345 F_Name : String (1 .. Name'Length + 1);
1346 begin
1347 F_Name (1 .. Name'Length) := Name;
1348 F_Name (F_Name'Last) := ASCII.NUL;
1349 return Is_Readable_File (F_Name'Address);
1350 end Is_Readable_File;
1351
d559d5c6
AC
1352 ------------------------
1353 -- Is_Executable_File --
1354 ------------------------
1355
1356 function Is_Executable_File (Name : C_File_Name) return Boolean is
1357 function Is_Executable_File (Name : Address) return Integer;
1358 pragma Import (C, Is_Executable_File, "__gnat_is_executable_file");
1359 begin
1360 return Is_Executable_File (Name) /= 0;
1361 end Is_Executable_File;
1362
1363 function Is_Executable_File (Name : String) return Boolean is
1364 F_Name : String (1 .. Name'Length + 1);
1365 begin
1366 F_Name (1 .. Name'Length) := Name;
1367 F_Name (F_Name'Last) := ASCII.NUL;
1368 return Is_Executable_File (F_Name'Address);
1369 end Is_Executable_File;
1370
30681738
RD
1371 ---------------------
1372 -- Is_Regular_File --
1373 ---------------------
1374
1375 function Is_Regular_File (Name : C_File_Name) return Boolean is
1376 function Is_Regular_File (Name : Address) return Integer;
1377 pragma Import (C, Is_Regular_File, "__gnat_is_regular_file");
1378 begin
1379 return Is_Regular_File (Name) /= 0;
1380 end Is_Regular_File;
1381
1382 function Is_Regular_File (Name : String) return Boolean is
1383 F_Name : String (1 .. Name'Length + 1);
1384 begin
1385 F_Name (1 .. Name'Length) := Name;
1386 F_Name (F_Name'Last) := ASCII.NUL;
1387 return Is_Regular_File (F_Name'Address);
1388 end Is_Regular_File;
1389
1390 ----------------------
1391 -- Is_Symbolic_Link --
1392 ----------------------
1393
1394 function Is_Symbolic_Link (Name : C_File_Name) return Boolean is
1395 function Is_Symbolic_Link (Name : Address) return Integer;
1396 pragma Import (C, Is_Symbolic_Link, "__gnat_is_symbolic_link");
1397 begin
1398 return Is_Symbolic_Link (Name) /= 0;
1399 end Is_Symbolic_Link;
1400
1401 function Is_Symbolic_Link (Name : String) return Boolean is
1402 F_Name : String (1 .. Name'Length + 1);
1403 begin
1404 F_Name (1 .. Name'Length) := Name;
1405 F_Name (F_Name'Last) := ASCII.NUL;
1406 return Is_Symbolic_Link (F_Name'Address);
1407 end Is_Symbolic_Link;
1408
1409 ----------------------
1410 -- Is_Writable_File --
1411 ----------------------
1412
1413 function Is_Writable_File (Name : C_File_Name) return Boolean is
1414 function Is_Writable_File (Name : Address) return Integer;
1415 pragma Import (C, Is_Writable_File, "__gnat_is_writable_file");
1416 begin
1417 return Is_Writable_File (Name) /= 0;
1418 end Is_Writable_File;
1419
1420 function Is_Writable_File (Name : String) return Boolean is
1421 F_Name : String (1 .. Name'Length + 1);
1422 begin
1423 F_Name (1 .. Name'Length) := Name;
1424 F_Name (F_Name'Last) := ASCII.NUL;
1425 return Is_Writable_File (F_Name'Address);
1426 end Is_Writable_File;
1427
1428 -------------------------
1429 -- Locate_Exec_On_Path --
1430 -------------------------
1431
1432 function Locate_Exec_On_Path
1433 (Exec_Name : String) return String_Access
1434 is
1435 function Locate_Exec_On_Path (C_Exec_Name : Address) return Address;
1436 pragma Import (C, Locate_Exec_On_Path, "__gnat_locate_exec_on_path");
1437
1438 procedure Free (Ptr : System.Address);
1439 pragma Import (C, Free, "free");
1440
1441 C_Exec_Name : String (1 .. Exec_Name'Length + 1);
1442 Path_Addr : Address;
1443 Path_Len : Integer;
1444 Result : String_Access;
1445
1446 begin
1447 C_Exec_Name (1 .. Exec_Name'Length) := Exec_Name;
1448 C_Exec_Name (C_Exec_Name'Last) := ASCII.NUL;
1449
1450 Path_Addr := Locate_Exec_On_Path (C_Exec_Name'Address);
1451 Path_Len := C_String_Length (Path_Addr);
1452
1453 if Path_Len = 0 then
1454 return null;
1455
1456 else
1457 Result := To_Path_String_Access (Path_Addr, Path_Len);
1458 Free (Path_Addr);
1459
1460 -- Always return an absolute path name
1461
1462 if not Is_Absolute_Path (Result.all) then
1463 declare
1464 Absolute_Path : constant String :=
2ae395d6 1465 Normalize_Pathname (Result.all, Resolve_Links => False);
30681738
RD
1466 begin
1467 Free (Result);
1468 Result := new String'(Absolute_Path);
1469 end;
1470 end if;
1471
1472 return Result;
1473 end if;
1474 end Locate_Exec_On_Path;
1475
1476 -------------------------
1477 -- Locate_Regular_File --
1478 -------------------------
1479
1480 function Locate_Regular_File
1481 (File_Name : C_File_Name;
1482 Path : C_File_Name) return String_Access
1483 is
1484 function Locate_Regular_File
1485 (C_File_Name, Path_Val : Address) return Address;
1486 pragma Import (C, Locate_Regular_File, "__gnat_locate_regular_file");
1487
1488 procedure Free (Ptr : System.Address);
1489 pragma Import (C, Free, "free");
1490
1491 Path_Addr : Address;
1492 Path_Len : Integer;
1493 Result : String_Access;
1494
1495 begin
1496 Path_Addr := Locate_Regular_File (File_Name, Path);
1497 Path_Len := C_String_Length (Path_Addr);
1498
1499 if Path_Len = 0 then
1500 return null;
8b79ad42 1501
30681738
RD
1502 else
1503 Result := To_Path_String_Access (Path_Addr, Path_Len);
1504 Free (Path_Addr);
1505 return Result;
1506 end if;
1507 end Locate_Regular_File;
1508
1509 function Locate_Regular_File
1510 (File_Name : String;
1511 Path : String) return String_Access
1512 is
1513 C_File_Name : String (1 .. File_Name'Length + 1);
1514 C_Path : String (1 .. Path'Length + 1);
1515 Result : String_Access;
1516
1517 begin
1518 C_File_Name (1 .. File_Name'Length) := File_Name;
1519 C_File_Name (C_File_Name'Last) := ASCII.NUL;
1520
1521 C_Path (1 .. Path'Length) := Path;
1522 C_Path (C_Path'Last) := ASCII.NUL;
1523
1524 Result := Locate_Regular_File (C_File_Name'Address, C_Path'Address);
1525
1526 -- Always return an absolute path name
1527
1528 if Result /= null and then not Is_Absolute_Path (Result.all) then
1529 declare
1530 Absolute_Path : constant String := Normalize_Pathname (Result.all);
1531 begin
1532 Free (Result);
1533 Result := new String'(Absolute_Path);
1534 end;
1535 end if;
1536
1537 return Result;
1538 end Locate_Regular_File;
1539
1540 ------------------------
1541 -- Non_Blocking_Spawn --
1542 ------------------------
1543
1544 function Non_Blocking_Spawn
1545 (Program_Name : String;
1546 Args : Argument_List) return Process_Id
1547 is
30681738 1548 Pid : Process_Id;
67ce0d7e
RD
1549 Junk : Integer;
1550 pragma Warnings (Off, Junk);
30681738
RD
1551 begin
1552 Spawn_Internal (Program_Name, Args, Junk, Pid, Blocking => False);
1553 return Pid;
1554 end Non_Blocking_Spawn;
1555
1556 function Non_Blocking_Spawn
1557 (Program_Name : String;
1558 Args : Argument_List;
1559 Output_File_Descriptor : File_Descriptor;
1560 Err_To_Out : Boolean := True) return Process_Id
1561 is
1562 Saved_Output : File_Descriptor;
1563 Saved_Error : File_Descriptor := Invalid_FD; -- prevent warning
1564 Pid : Process_Id;
1565
1566 begin
1567 if Output_File_Descriptor = Invalid_FD then
1568 return Invalid_Pid;
1569 end if;
1570
1571 -- Set standard output and, if specified, error to the temporary file
1572
1573 Saved_Output := Dup (Standout);
1574 Dup2 (Output_File_Descriptor, Standout);
1575
1576 if Err_To_Out then
1577 Saved_Error := Dup (Standerr);
1578 Dup2 (Output_File_Descriptor, Standerr);
1579 end if;
1580
1581 -- Spawn the program
1582
1583 Pid := Non_Blocking_Spawn (Program_Name, Args);
1584
1585 -- Restore the standard output and error
1586
1587 Dup2 (Saved_Output, Standout);
1588
1589 if Err_To_Out then
1590 Dup2 (Saved_Error, Standerr);
1591 end if;
1592
1593 -- And close the saved standard output and error file descriptors
1594
1595 Close (Saved_Output);
1596
1597 if Err_To_Out then
1598 Close (Saved_Error);
1599 end if;
1600
1601 return Pid;
1602 end Non_Blocking_Spawn;
1603
1604 function Non_Blocking_Spawn
1605 (Program_Name : String;
1606 Args : Argument_List;
1607 Output_File : String;
1608 Err_To_Out : Boolean := True) return Process_Id
1609 is
1610 Output_File_Descriptor : constant File_Descriptor :=
1611 Create_Output_Text_File (Output_File);
1612 Result : Process_Id;
1613
1614 begin
1615 -- Do not attempt to spawn if the output file could not be created
1616
1617 if Output_File_Descriptor = Invalid_FD then
1618 return Invalid_Pid;
1619
1620 else
1621 Result := Non_Blocking_Spawn
1622 (Program_Name, Args, Output_File_Descriptor, Err_To_Out);
1623
1624 -- Close the file just created for the output, as the file descriptor
1625 -- cannot be used anywhere, being a local value. It is safe to do
1626 -- that, as the file descriptor has been duplicated to form
1627 -- standard output and error of the spawned process.
1628
1629 Close (Output_File_Descriptor);
1630
1631 return Result;
1632 end if;
1633 end Non_Blocking_Spawn;
1634
1635 -------------------------
1636 -- Normalize_Arguments --
1637 -------------------------
1638
1639 procedure Normalize_Arguments (Args : in out Argument_List) is
1640
1641 procedure Quote_Argument (Arg : in out String_Access);
c91dbd18 1642 -- Add quote around argument if it contains spaces (or HT characters)
30681738
RD
1643
1644 C_Argument_Needs_Quote : Integer;
1645 pragma Import (C, C_Argument_Needs_Quote, "__gnat_argument_needs_quote");
1646 Argument_Needs_Quote : constant Boolean := C_Argument_Needs_Quote /= 0;
1647
1648 --------------------
1649 -- Quote_Argument --
1650 --------------------
1651
1652 procedure Quote_Argument (Arg : in out String_Access) is
1653 Res : String (1 .. Arg'Length * 2);
1654 J : Positive := 1;
1655 Quote_Needed : Boolean := False;
1656
1657 begin
1658 if Arg (Arg'First) /= '"' or else Arg (Arg'Last) /= '"' then
1659
1660 -- Starting quote
1661
1662 Res (J) := '"';
1663
1664 for K in Arg'Range loop
1665
1666 J := J + 1;
1667
1668 if Arg (K) = '"' then
1669 Res (J) := '\';
1670 J := J + 1;
1671 Res (J) := '"';
1672 Quote_Needed := True;
1673
ba08ba84 1674 elsif Arg (K) = ' ' or else Arg (K) = ASCII.HT then
30681738
RD
1675 Res (J) := Arg (K);
1676 Quote_Needed := True;
1677
1678 else
1679 Res (J) := Arg (K);
1680 end if;
30681738
RD
1681 end loop;
1682
1683 if Quote_Needed then
1684
260359e3 1685 -- Case of null terminated string
30681738 1686
43c6e0cb 1687 if Res (J) = ASCII.NUL then
75685ef7
PO
1688
1689 -- If the string ends with \, double it
1690
1691 if Res (J - 1) = '\' then
1692 Res (J) := '\';
1693 J := J + 1;
1694 end if;
1695
260359e3 1696 -- Put a quote just before the null at the end
75685ef7 1697
30681738
RD
1698 Res (J) := '"';
1699 J := J + 1;
43c6e0cb 1700 Res (J) := ASCII.NUL;
30681738
RD
1701
1702 -- If argument is terminated by '\', then double it. Otherwise
1703 -- the ending quote will be taken as-is. This is quite strange
a90bd866 1704 -- spawn behavior from Windows, but this is what we see.
30681738
RD
1705
1706 else
1707 if Res (J) = '\' then
1708 J := J + 1;
1709 Res (J) := '\';
1710 end if;
1711
1712 -- Ending quote
1713
1714 J := J + 1;
1715 Res (J) := '"';
1716 end if;
1717
1718 declare
1719 Old : String_Access := Arg;
1720
1721 begin
1722 Arg := new String'(Res (1 .. J));
1723 Free (Old);
1724 end;
1725 end if;
1726
1727 end if;
1728 end Quote_Argument;
1729
1730 -- Start of processing for Normalize_Arguments
1731
1732 begin
1733 if Argument_Needs_Quote then
1734 for K in Args'Range loop
1735 if Args (K) /= null and then Args (K)'Length /= 0 then
1736 Quote_Argument (Args (K));
1737 end if;
1738 end loop;
1739 end if;
1740 end Normalize_Arguments;
1741
1742 ------------------------
1743 -- Normalize_Pathname --
1744 ------------------------
1745
1746 function Normalize_Pathname
1747 (Name : String;
1748 Directory : String := "";
1749 Resolve_Links : Boolean := True;
1750 Case_Sensitive : Boolean := True) return String
1751 is
1752 Max_Path : Integer;
1753 pragma Import (C, Max_Path, "__gnat_max_path_len");
1754 -- Maximum length of a path name
1755
1756 procedure Get_Current_Dir
1757 (Dir : System.Address;
1758 Length : System.Address);
1759 pragma Import (C, Get_Current_Dir, "__gnat_get_current_dir");
1760
1761 Path_Buffer : String (1 .. Max_Path + Max_Path + 2);
1762 End_Path : Natural := 0;
1763 Link_Buffer : String (1 .. Max_Path + 2);
1764 Status : Integer;
1765 Last : Positive;
1766 Start : Natural;
1767 Finish : Positive;
1768
1769 Max_Iterations : constant := 500;
1770
1771 function Get_File_Names_Case_Sensitive return Integer;
1772 pragma Import
1773 (C, Get_File_Names_Case_Sensitive,
1774 "__gnat_get_file_names_case_sensitive");
1775
1776 Fold_To_Lower_Case : constant Boolean :=
1777 not Case_Sensitive
1778 and then Get_File_Names_Case_Sensitive = 0;
1779
1780 function Readlink
1781 (Path : System.Address;
1782 Buf : System.Address;
1783 Bufsiz : Integer) return Integer;
1784 pragma Import (C, Readlink, "__gnat_readlink");
1785
1786 function To_Canonical_File_Spec
1787 (Host_File : System.Address) return System.Address;
1788 pragma Import
1789 (C, To_Canonical_File_Spec, "__gnat_to_canonical_file_spec");
1790
1791 The_Name : String (1 .. Name'Length + 1);
1792 Canonical_File_Addr : System.Address;
1793 Canonical_File_Len : Integer;
1794
30681738
RD
1795 function Strlen (S : System.Address) return Integer;
1796 pragma Import (C, Strlen, "strlen");
1797
1798 function Final_Value (S : String) return String;
33c423c8
AC
1799 -- Make final adjustment to the returned string. This function strips
1800 -- trailing directory separators, and folds returned string to lower
1801 -- case if required.
30681738
RD
1802
1803 function Get_Directory (Dir : String) return String;
1804 -- If Dir is not empty, return it, adding a directory separator
1805 -- if not already present, otherwise return current working directory
1806 -- with terminating directory separator.
1807
1808 -----------------
1809 -- Final_Value --
1810 -----------------
1811
1812 function Final_Value (S : String) return String is
1813 S1 : String := S;
1814 -- We may need to fold S to lower case, so we need a variable
1815
1816 Last : Natural;
1817
1818 begin
33c423c8
AC
1819 if Fold_To_Lower_Case then
1820 System.Case_Util.To_Lower (S1);
1821 end if;
30681738 1822
33c423c8 1823 -- Remove trailing directory separator, if any
30681738 1824
33c423c8 1825 Last := S1'Last;
30681738 1826
33c423c8
AC
1827 if Last > 1
1828 and then (S1 (Last) = '/'
1829 or else
1830 S1 (Last) = Directory_Separator)
1831 then
1832 -- Special case for Windows: C:\
30681738 1833
33c423c8
AC
1834 if Last = 3
1835 and then S1 (1) /= Directory_Separator
1836 and then S1 (2) = ':'
30681738 1837 then
33c423c8 1838 null;
30681738 1839
33c423c8
AC
1840 else
1841 Last := Last - 1;
30681738 1842 end if;
30681738 1843 end if;
33c423c8
AC
1844
1845 return S1 (1 .. Last);
30681738
RD
1846 end Final_Value;
1847
1848 -------------------
1849 -- Get_Directory --
1850 -------------------
1851
1852 function Get_Directory (Dir : String) return String is
5b900a45
AC
1853 Result : String (1 .. Dir'Length + 1);
1854 Length : constant Natural := Dir'Length;
1855
30681738
RD
1856 begin
1857 -- Directory given, add directory separator if needed
1858
5b900a45
AC
1859 if Length > 0 then
1860 Result (1 .. Length) := Dir;
1861
1862 -- On Windows, change all '/' to '\'
1863
1864 if On_Windows then
1865 for J in 1 .. Length loop
1866 if Result (J) = '/' then
1867 Result (J) := Directory_Separator;
1868 end if;
1869 end loop;
1870 end if;
1871
1872 -- Add directory separator, if needed
1873
1874 if Result (Length) = Directory_Separator then
1875 return Result (1 .. Length);
30681738 1876 else
5b900a45
AC
1877 Result (Result'Length) := Directory_Separator;
1878 return Result;
30681738
RD
1879 end if;
1880
1881 -- Directory name not given, get current directory
1882
1883 else
1884 declare
1885 Buffer : String (1 .. Max_Path + 2);
1886 Path_Len : Natural := Max_Path;
1887
1888 begin
1889 Get_Current_Dir (Buffer'Address, Path_Len'Address);
1890
1891 if Buffer (Path_Len) /= Directory_Separator then
1892 Path_Len := Path_Len + 1;
1893 Buffer (Path_Len) := Directory_Separator;
1894 end if;
1895
1896 -- By default, the drive letter on Windows is in upper case
1897
e34ca162
AC
1898 if On_Windows
1899 and then Path_Len >= 2
ee9aa7b6 1900 and then Buffer (2) = ':'
30681738
RD
1901 then
1902 System.Case_Util.To_Upper (Buffer (1 .. 1));
1903 end if;
1904
1905 return Buffer (1 .. Path_Len);
1906 end;
1907 end if;
1908 end Get_Directory;
1909
30681738
RD
1910 -- Start of processing for Normalize_Pathname
1911
1912 begin
cca7f107
AC
1913 -- Special case, return null if name is null, or if it is bigger than
1914 -- the biggest name allowed.
30681738 1915
cca7f107 1916 if Name'Length = 0 or else Name'Length > Max_Path then
30681738
RD
1917 return "";
1918 end if;
1919
1920 -- First, convert VMS file spec to Unix file spec.
1921 -- If Name is not in VMS syntax, then this is equivalent
276e95ca 1922 -- to put Name at the beginning of Path_Buffer.
30681738
RD
1923
1924 VMS_Conversion : begin
1925 The_Name (1 .. Name'Length) := Name;
1926 The_Name (The_Name'Last) := ASCII.NUL;
1927
1928 Canonical_File_Addr := To_Canonical_File_Spec (The_Name'Address);
1929 Canonical_File_Len := Strlen (Canonical_File_Addr);
1930
1931 -- If VMS syntax conversion has failed, return an empty string
1932 -- to indicate the failure.
1933
1934 if Canonical_File_Len = 0 then
1935 return "";
1936 end if;
1937
1938 declare
1939 subtype Path_String is String (1 .. Canonical_File_Len);
1940 type Path_String_Access is access Path_String;
1941
1942 function Address_To_Access is new
1943 Ada.Unchecked_Conversion (Source => Address,
1944 Target => Path_String_Access);
1945
1946 Path_Access : constant Path_String_Access :=
1947 Address_To_Access (Canonical_File_Addr);
1948
1949 begin
1950 Path_Buffer (1 .. Canonical_File_Len) := Path_Access.all;
1951 End_Path := Canonical_File_Len;
1952 Last := 1;
1953 end;
1954 end VMS_Conversion;
1955
1956 -- Replace all '/' by Directory Separators (this is for Windows)
1957
1958 if Directory_Separator /= '/' then
1959 for Index in 1 .. End_Path loop
1960 if Path_Buffer (Index) = '/' then
1961 Path_Buffer (Index) := Directory_Separator;
1962 end if;
1963 end loop;
1964 end if;
1965
1966 -- Resolve directory names for Windows (formerly also VMS)
1967
1968 -- On VMS, if we have a Unix path such as /temp/..., and TEMP is a
1969 -- logical name, we must not try to resolve this logical name, because
1970 -- it may have multiple equivalences and if resolved we will only
1971 -- get the first one.
1972
ee9aa7b6 1973 if On_Windows then
30681738 1974
ee9aa7b6
AC
1975 -- On Windows, if we have an absolute path starting with a directory
1976 -- separator, we need to have the drive letter appended in front.
30681738 1977
ee9aa7b6
AC
1978 -- On Windows, Get_Current_Dir will return a suitable directory name
1979 -- (path starting with a drive letter on Windows). So we take this
1980 -- drive letter and prepend it to the current path.
30681738 1981
ee9aa7b6
AC
1982 if Path_Buffer (1) = Directory_Separator
1983 and then Path_Buffer (2) /= Directory_Separator
1984 then
1985 declare
1986 Cur_Dir : constant String := Get_Directory ("");
1987 -- Get the current directory to get the drive letter
1988
1989 begin
1990 if Cur_Dir'Length > 2
1991 and then Cur_Dir (Cur_Dir'First + 1) = ':'
1992 then
1993 Path_Buffer (3 .. End_Path + 2) :=
1994 Path_Buffer (1 .. End_Path);
1995 Path_Buffer (1 .. 2) :=
1996 Cur_Dir (Cur_Dir'First .. Cur_Dir'First + 1);
1997 End_Path := End_Path + 2;
1998 end if;
1999 end;
2000
2001 -- We have a drive letter, ensure it is upper-case
2002
2003 elsif Path_Buffer (1) in 'a' .. 'z'
2004 and then Path_Buffer (2) = ':'
2005 then
2006 System.Case_Util.To_Upper (Path_Buffer (1 .. 1));
2007 end if;
30681738
RD
2008 end if;
2009
d1b4f87d
AC
2010 -- On Windows, remove all double-quotes that are possibly part of the
2011 -- path but can cause problems with other methods.
2012
2013 if On_Windows then
2014 declare
f7fd2ec3
RD
2015 Index : Natural;
2016
d1b4f87d 2017 begin
f7fd2ec3 2018 Index := Path_Buffer'First;
d1b4f87d
AC
2019 for Current in Path_Buffer'First .. End_Path loop
2020 if Path_Buffer (Current) /= '"' then
2021 Path_Buffer (Index) := Path_Buffer (Current);
2022 Index := Index + 1;
2023 end if;
2024 end loop;
2025
2026 End_Path := Index - 1;
2027 end;
2028 end if;
2029
30681738
RD
2030 -- Start the conversions
2031
2032 -- If this is not finished after Max_Iterations, give up and return an
2033 -- empty string.
2034
2035 for J in 1 .. Max_Iterations loop
2036
2037 -- If we don't have an absolute pathname, prepend the directory
2038 -- Reference_Dir.
2039
2040 if Last = 1
2041 and then not Is_Absolute_Path (Path_Buffer (1 .. End_Path))
2042 then
aee21c6f
EB
2043 declare
2044 Reference_Dir : constant String := Get_Directory (Directory);
2045 Ref_Dir_Len : constant Natural := Reference_Dir'Length;
2046 -- Current directory name specified and its length
2047
2048 begin
2049 Path_Buffer (Ref_Dir_Len + 1 .. Ref_Dir_Len + End_Path) :=
30681738 2050 Path_Buffer (1 .. End_Path);
aee21c6f
EB
2051 End_Path := Ref_Dir_Len + End_Path;
2052 Path_Buffer (1 .. Ref_Dir_Len) := Reference_Dir;
2053 Last := Ref_Dir_Len;
2054 end;
30681738
RD
2055 end if;
2056
30681738
RD
2057 Start := Last + 1;
2058 Finish := Last;
2059
2060 -- Ensure that Windows network drives are kept, e.g: \\server\drive-c
2061
2062 if Start = 2
2063 and then Directory_Separator = '\'
2064 and then Path_Buffer (1 .. 2) = "\\"
2065 then
2066 Start := 3;
2067 end if;
2068
2069 -- If we have traversed the full pathname, return it
2070
2071 if Start > End_Path then
2072 return Final_Value (Path_Buffer (1 .. End_Path));
2073 end if;
2074
2075 -- Remove duplicate directory separators
2076
2077 while Path_Buffer (Start) = Directory_Separator loop
2078 if Start = End_Path then
2079 return Final_Value (Path_Buffer (1 .. End_Path - 1));
2080
2081 else
2082 Path_Buffer (Start .. End_Path - 1) :=
2083 Path_Buffer (Start + 1 .. End_Path);
2084 End_Path := End_Path - 1;
2085 end if;
2086 end loop;
2087
2088 -- Find the end of the current field: last character or the one
2089 -- preceding the next directory separator.
2090
2091 while Finish < End_Path
2092 and then Path_Buffer (Finish + 1) /= Directory_Separator
2093 loop
2094 Finish := Finish + 1;
2095 end loop;
2096
2097 -- Remove "." field
2098
2099 if Start = Finish and then Path_Buffer (Start) = '.' then
2100 if Start = End_Path then
2101 if Last = 1 then
2102 return (1 => Directory_Separator);
2103 else
2104
2105 if Fold_To_Lower_Case then
2106 System.Case_Util.To_Lower (Path_Buffer (1 .. Last - 1));
2107 end if;
2108
2109 return Path_Buffer (1 .. Last - 1);
2110
2111 end if;
2112
2113 else
2114 Path_Buffer (Last + 1 .. End_Path - 2) :=
2115 Path_Buffer (Last + 3 .. End_Path);
2116 End_Path := End_Path - 2;
2117 end if;
2118
2119 -- Remove ".." fields
2120
2121 elsif Finish = Start + 1
2122 and then Path_Buffer (Start .. Finish) = ".."
2123 then
2124 Start := Last;
2125 loop
2126 Start := Start - 1;
75685ef7
PO
2127 exit when Start < 1
2128 or else Path_Buffer (Start) = Directory_Separator;
30681738
RD
2129 end loop;
2130
2131 if Start <= 1 then
2132 if Finish = End_Path then
2133 return (1 => Directory_Separator);
2134
2135 else
2136 Path_Buffer (1 .. End_Path - Finish) :=
2137 Path_Buffer (Finish + 1 .. End_Path);
2138 End_Path := End_Path - Finish;
2139 Last := 1;
2140 end if;
2141
2142 else
2143 if Finish = End_Path then
2144 return Final_Value (Path_Buffer (1 .. Start - 1));
2145
2146 else
2147 Path_Buffer (Start + 1 .. Start + End_Path - Finish - 1) :=
2148 Path_Buffer (Finish + 2 .. End_Path);
2149 End_Path := Start + End_Path - Finish - 1;
2150 Last := Start;
2151 end if;
2152 end if;
2153
2154 -- Check if current field is a symbolic link
2155
2156 elsif Resolve_Links then
2157 declare
2158 Saved : constant Character := Path_Buffer (Finish + 1);
2159
2160 begin
2161 Path_Buffer (Finish + 1) := ASCII.NUL;
2162 Status := Readlink (Path_Buffer'Address,
2163 Link_Buffer'Address,
2164 Link_Buffer'Length);
2165 Path_Buffer (Finish + 1) := Saved;
2166 end;
2167
2168 -- Not a symbolic link, move to the next field, if any
2169
2170 if Status <= 0 then
2171 Last := Finish + 1;
2172
2173 -- Replace symbolic link with its value
2174
2175 else
2176 if Is_Absolute_Path (Link_Buffer (1 .. Status)) then
2177 Path_Buffer (Status + 1 .. End_Path - (Finish - Status)) :=
2178 Path_Buffer (Finish + 1 .. End_Path);
2179 End_Path := End_Path - (Finish - Status);
2180 Path_Buffer (1 .. Status) := Link_Buffer (1 .. Status);
2181 Last := 1;
2182
2183 else
2184 Path_Buffer
2185 (Last + Status + 1 .. End_Path - Finish + Last + Status) :=
2186 Path_Buffer (Finish + 1 .. End_Path);
2187 End_Path := End_Path - Finish + Last + Status;
2188 Path_Buffer (Last + 1 .. Last + Status) :=
2189 Link_Buffer (1 .. Status);
2190 end if;
2191 end if;
2192
2193 else
2194 Last := Finish + 1;
2195 end if;
2196 end loop;
2197
2198 -- Too many iterations: give up
2199
2200 -- This can happen when there is a circularity in the symbolic links: A
2201 -- is a symbolic link for B, which itself is a symbolic link, and the
2202 -- target of B or of another symbolic link target of B is A. In this
2203 -- case, we return an empty string to indicate failure to resolve.
2204
2205 return "";
2206 end Normalize_Pathname;
2207
2208 ---------------
2209 -- Open_Read --
2210 ---------------
2211
2212 function Open_Read
2213 (Name : C_File_Name;
2214 Fmode : Mode) return File_Descriptor
2215 is
2216 function C_Open_Read
2217 (Name : C_File_Name;
2218 Fmode : Mode) return File_Descriptor;
2219 pragma Import (C, C_Open_Read, "__gnat_open_read");
2220 begin
2221 return C_Open_Read (Name, Fmode);
2222 end Open_Read;
2223
2224 function Open_Read
2225 (Name : String;
2226 Fmode : Mode) return File_Descriptor
2227 is
2228 C_Name : String (1 .. Name'Length + 1);
2229 begin
2230 C_Name (1 .. Name'Length) := Name;
2231 C_Name (C_Name'Last) := ASCII.NUL;
2232 return Open_Read (C_Name (C_Name'First)'Address, Fmode);
2233 end Open_Read;
2234
2235 ---------------------
2236 -- Open_Read_Write --
2237 ---------------------
2238
2239 function Open_Read_Write
2240 (Name : C_File_Name;
2241 Fmode : Mode) return File_Descriptor
2242 is
2243 function C_Open_Read_Write
2244 (Name : C_File_Name;
2245 Fmode : Mode) return File_Descriptor;
2246 pragma Import (C, C_Open_Read_Write, "__gnat_open_rw");
2247 begin
2248 return C_Open_Read_Write (Name, Fmode);
2249 end Open_Read_Write;
2250
2251 function Open_Read_Write
2252 (Name : String;
2253 Fmode : Mode) return File_Descriptor
2254 is
2255 C_Name : String (1 .. Name'Length + 1);
2256 begin
2257 C_Name (1 .. Name'Length) := Name;
2258 C_Name (C_Name'Last) := ASCII.NUL;
2259 return Open_Read_Write (C_Name (C_Name'First)'Address, Fmode);
2260 end Open_Read_Write;
2261
33c423c8
AC
2262 -------------
2263 -- OS_Exit --
2264 -------------
2265
2266 procedure OS_Exit (Status : Integer) is
2267 begin
2268 OS_Exit_Ptr (Status);
2269 raise Program_Error;
2270 end OS_Exit;
2271
2272 ---------------------
2273 -- OS_Exit_Default --
2274 ---------------------
2275
2276 procedure OS_Exit_Default (Status : Integer) is
2277 procedure GNAT_OS_Exit (Status : Integer);
2278 pragma Import (C, GNAT_OS_Exit, "__gnat_os_exit");
2279 pragma No_Return (GNAT_OS_Exit);
2280 begin
2281 GNAT_OS_Exit (Status);
2282 end OS_Exit_Default;
2283
30681738
RD
2284 --------------------
2285 -- Pid_To_Integer --
2286 --------------------
2287
2288 function Pid_To_Integer (Pid : Process_Id) return Integer is
2289 begin
2290 return Integer (Pid);
2291 end Pid_To_Integer;
2292
2293 ----------
2294 -- Read --
2295 ----------
2296
2297 function Read
2298 (FD : File_Descriptor;
2299 A : System.Address;
2300 N : Integer) return Integer
2301 is
2302 begin
b29def53
AC
2303 return
2304 Integer (System.CRTL.read
2305 (System.CRTL.int (FD),
2306 System.CRTL.chars (A),
2307 System.CRTL.size_t (N)));
30681738
RD
2308 end Read;
2309
2310 -----------------
2311 -- Rename_File --
2312 -----------------
2313
2314 procedure Rename_File
2315 (Old_Name : C_File_Name;
2316 New_Name : C_File_Name;
2317 Success : out Boolean)
2318 is
2319 function rename (From, To : Address) return Integer;
55cc1a05 2320 pragma Import (C, rename, "__gnat_rename");
30681738
RD
2321 R : Integer;
2322 begin
2323 R := rename (Old_Name, New_Name);
2324 Success := (R = 0);
2325 end Rename_File;
2326
2327 procedure Rename_File
2328 (Old_Name : String;
2329 New_Name : String;
2330 Success : out Boolean)
2331 is
2332 C_Old_Name : String (1 .. Old_Name'Length + 1);
2333 C_New_Name : String (1 .. New_Name'Length + 1);
2334 begin
2335 C_Old_Name (1 .. Old_Name'Length) := Old_Name;
2336 C_Old_Name (C_Old_Name'Last) := ASCII.NUL;
2337 C_New_Name (1 .. New_Name'Length) := New_Name;
2338 C_New_Name (C_New_Name'Last) := ASCII.NUL;
2339 Rename_File (C_Old_Name'Address, C_New_Name'Address, Success);
2340 end Rename_File;
2341
2342 -----------------------
2343 -- Set_Close_On_Exec --
2344 -----------------------
2345
2346 procedure Set_Close_On_Exec
2347 (FD : File_Descriptor;
2348 Close_On_Exec : Boolean;
2349 Status : out Boolean)
2350 is
2351 function C_Set_Close_On_Exec
2352 (FD : File_Descriptor; Close_On_Exec : System.CRTL.int)
2353 return System.CRTL.int;
2354 pragma Import (C, C_Set_Close_On_Exec, "__gnat_set_close_on_exec");
2355 begin
2356 Status := C_Set_Close_On_Exec (FD, Boolean'Pos (Close_On_Exec)) = 0;
2357 end Set_Close_On_Exec;
2358
2359 --------------------
2360 -- Set_Executable --
2361 --------------------
2362
2363 procedure Set_Executable (Name : String) is
2364 procedure C_Set_Executable (Name : C_File_Name);
2365 pragma Import (C, C_Set_Executable, "__gnat_set_executable");
2366 C_Name : aliased String (Name'First .. Name'Last + 1);
2367 begin
2368 C_Name (Name'Range) := Name;
2369 C_Name (C_Name'Last) := ASCII.NUL;
2370 C_Set_Executable (C_Name (C_Name'First)'Address);
2371 end Set_Executable;
2372
43540ec6
AC
2373 ----------------------
2374 -- Set_Non_Readable --
2375 ----------------------
2376
2377 procedure Set_Non_Readable (Name : String) is
2378 procedure C_Set_Non_Readable (Name : C_File_Name);
2379 pragma Import (C, C_Set_Non_Readable, "__gnat_set_non_readable");
2380 C_Name : aliased String (Name'First .. Name'Last + 1);
2381 begin
2382 C_Name (Name'Range) := Name;
2383 C_Name (C_Name'Last) := ASCII.NUL;
2384 C_Set_Non_Readable (C_Name (C_Name'First)'Address);
2385 end Set_Non_Readable;
2386
2387 ----------------------
2388 -- Set_Non_Writable --
2389 ----------------------
2390
2391 procedure Set_Non_Writable (Name : String) is
2392 procedure C_Set_Non_Writable (Name : C_File_Name);
2393 pragma Import (C, C_Set_Non_Writable, "__gnat_set_non_writable");
2394 C_Name : aliased String (Name'First .. Name'Last + 1);
2395 begin
2396 C_Name (Name'Range) := Name;
2397 C_Name (C_Name'Last) := ASCII.NUL;
2398 C_Set_Non_Writable (C_Name (C_Name'First)'Address);
2399 end Set_Non_Writable;
2400
2401 ------------------
2402 -- Set_Readable --
2403 ------------------
2404
2405 procedure Set_Readable (Name : String) is
2406 procedure C_Set_Readable (Name : C_File_Name);
2407 pragma Import (C, C_Set_Readable, "__gnat_set_readable");
2408 C_Name : aliased String (Name'First .. Name'Last + 1);
2409 begin
2410 C_Name (Name'Range) := Name;
2411 C_Name (C_Name'Last) := ASCII.NUL;
2412 C_Set_Readable (C_Name (C_Name'First)'Address);
2413 end Set_Readable;
2414
30681738
RD
2415 --------------------
2416 -- Set_Writable --
2417 --------------------
2418
2419 procedure Set_Writable (Name : String) is
2420 procedure C_Set_Writable (Name : C_File_Name);
2421 pragma Import (C, C_Set_Writable, "__gnat_set_writable");
2422 C_Name : aliased String (Name'First .. Name'Last + 1);
2423 begin
2424 C_Name (Name'Range) := Name;
2425 C_Name (C_Name'Last) := ASCII.NUL;
2426 C_Set_Writable (C_Name (C_Name'First)'Address);
2427 end Set_Writable;
2428
2429 ------------
2430 -- Setenv --
2431 ------------
2432
2433 procedure Setenv (Name : String; Value : String) is
2434 F_Name : String (1 .. Name'Length + 1);
2435 F_Value : String (1 .. Value'Length + 1);
2436
2437 procedure Set_Env_Value (Name, Value : System.Address);
2438 pragma Import (C, Set_Env_Value, "__gnat_setenv");
2439
2440 begin
2441 F_Name (1 .. Name'Length) := Name;
2442 F_Name (F_Name'Last) := ASCII.NUL;
2443
2444 F_Value (1 .. Value'Length) := Value;
2445 F_Value (F_Value'Last) := ASCII.NUL;
2446
2447 Set_Env_Value (F_Name'Address, F_Value'Address);
2448 end Setenv;
2449
2450 -----------
2451 -- Spawn --
2452 -----------
2453
2454 function Spawn
2455 (Program_Name : String;
2456 Args : Argument_List) return Integer
2457 is
30681738 2458 Result : Integer;
67ce0d7e
RD
2459 Junk : Process_Id;
2460 pragma Warnings (Off, Junk);
30681738
RD
2461 begin
2462 Spawn_Internal (Program_Name, Args, Result, Junk, Blocking => True);
2463 return Result;
2464 end Spawn;
2465
2466 procedure Spawn
2467 (Program_Name : String;
2468 Args : Argument_List;
2469 Success : out Boolean)
2470 is
2471 begin
2472 Success := (Spawn (Program_Name, Args) = 0);
2473 end Spawn;
2474
2475 procedure Spawn
2476 (Program_Name : String;
2477 Args : Argument_List;
2478 Output_File_Descriptor : File_Descriptor;
2479 Return_Code : out Integer;
2480 Err_To_Out : Boolean := True)
2481 is
2482 Saved_Output : File_Descriptor;
2483 Saved_Error : File_Descriptor := Invalid_FD; -- prevent compiler warning
2484
2485 begin
2486 -- Set standard output and error to the temporary file
2487
2488 Saved_Output := Dup (Standout);
2489 Dup2 (Output_File_Descriptor, Standout);
2490
2491 if Err_To_Out then
2492 Saved_Error := Dup (Standerr);
2493 Dup2 (Output_File_Descriptor, Standerr);
2494 end if;
2495
2496 -- Spawn the program
2497
2498 Return_Code := Spawn (Program_Name, Args);
2499
2500 -- Restore the standard output and error
2501
2502 Dup2 (Saved_Output, Standout);
2503
2504 if Err_To_Out then
2505 Dup2 (Saved_Error, Standerr);
2506 end if;
2507
2508 -- And close the saved standard output and error file descriptors
2509
2510 Close (Saved_Output);
2511
2512 if Err_To_Out then
2513 Close (Saved_Error);
2514 end if;
2515 end Spawn;
2516
2517 procedure Spawn
8b79ad42
AC
2518 (Program_Name : String;
2519 Args : Argument_List;
2520 Output_File : String;
2521 Success : out Boolean;
2522 Return_Code : out Integer;
2523 Err_To_Out : Boolean := True)
30681738
RD
2524 is
2525 FD : File_Descriptor;
2526
2527 begin
2528 Success := True;
2529 Return_Code := 0;
2530
2531 FD := Create_Output_Text_File (Output_File);
2532
2533 if FD = Invalid_FD then
2534 Success := False;
2535 return;
2536 end if;
2537
2538 Spawn (Program_Name, Args, FD, Return_Code, Err_To_Out);
2539
2540 Close (FD, Success);
2541 end Spawn;
2542
2543 --------------------
2544 -- Spawn_Internal --
2545 --------------------
2546
2547 procedure Spawn_Internal
2548 (Program_Name : String;
2549 Args : Argument_List;
2550 Result : out Integer;
2551 Pid : out Process_Id;
2552 Blocking : Boolean)
2553 is
2554
2555 procedure Spawn (Args : Argument_List);
2556 -- Call Spawn with given argument list
2557
2558 N_Args : Argument_List (Args'Range);
2559 -- Normalized arguments
2560
2561 -----------
2562 -- Spawn --
2563 -----------
2564
2565 procedure Spawn (Args : Argument_List) is
2566 type Chars is array (Positive range <>) of aliased Character;
2567 type Char_Ptr is access constant Character;
2568
8b79ad42
AC
2569 Command_Len : constant Positive := Program_Name'Length + 1
2570 + Args_Length (Args);
30681738 2571 Command_Last : Natural := 0;
8b79ad42 2572 Command : aliased Chars (1 .. Command_Len);
30681738 2573 -- Command contains all characters of the Program_Name and Args, all
d61f428e 2574 -- terminated by ASCII.NUL characters.
30681738 2575
8b79ad42 2576 Arg_List_Len : constant Positive := Args'Length + 2;
30681738 2577 Arg_List_Last : Natural := 0;
8b79ad42 2578 Arg_List : aliased array (1 .. Arg_List_Len) of Char_Ptr;
30681738
RD
2579 -- List with pointers to NUL-terminated strings of the Program_Name
2580 -- and the Args and terminated with a null pointer. We rely on the
2581 -- default initialization for the last null pointer.
2582
2583 procedure Add_To_Command (S : String);
2584 -- Add S and a NUL character to Command, updating Last
2585
2586 function Portable_Spawn (Args : Address) return Integer;
2587 pragma Import (C, Portable_Spawn, "__gnat_portable_spawn");
2588
2589 function Portable_No_Block_Spawn (Args : Address) return Process_Id;
2590 pragma Import
2591 (C, Portable_No_Block_Spawn, "__gnat_portable_no_block_spawn");
2592
2593 --------------------
2594 -- Add_To_Command --
2595 --------------------
2596
2597 procedure Add_To_Command (S : String) is
2598 First : constant Natural := Command_Last + 1;
2599
2600 begin
2601 Command_Last := Command_Last + S'Length;
2602
2603 -- Move characters one at a time, because Command has aliased
2604 -- components.
2605
2606 -- But not volatile, so why is this necessary ???
2607
2608 for J in S'Range loop
2609 Command (First + J - S'First) := S (J);
2610 end loop;
2611
2612 Command_Last := Command_Last + 1;
2613 Command (Command_Last) := ASCII.NUL;
2614
2615 Arg_List_Last := Arg_List_Last + 1;
2616 Arg_List (Arg_List_Last) := Command (First)'Access;
2617 end Add_To_Command;
2618
2619 -- Start of processing for Spawn
2620
2621 begin
2622 Add_To_Command (Program_Name);
2623
2624 for J in Args'Range loop
2625 Add_To_Command (Args (J).all);
2626 end loop;
2627
2628 if Blocking then
ffdeb702
AC
2629 Pid := Invalid_Pid;
2630 Result := Portable_Spawn (Arg_List'Address);
30681738 2631 else
ffdeb702
AC
2632 Pid := Portable_No_Block_Spawn (Arg_List'Address);
2633 Result := Boolean'Pos (Pid /= Invalid_Pid);
30681738
RD
2634 end if;
2635 end Spawn;
2636
2637 -- Start of processing for Spawn_Internal
2638
2639 begin
2640 -- Copy arguments into a local structure
2641
2642 for K in N_Args'Range loop
2643 N_Args (K) := new String'(Args (K).all);
2644 end loop;
2645
2646 -- Normalize those arguments
2647
2648 Normalize_Arguments (N_Args);
2649
2650 -- Call spawn using the normalized arguments
2651
2652 Spawn (N_Args);
2653
2654 -- Free arguments list
2655
2656 for K in N_Args'Range loop
2657 Free (N_Args (K));
2658 end loop;
2659 end Spawn_Internal;
2660
2661 ---------------------------
2662 -- To_Path_String_Access --
2663 ---------------------------
2664
2665 function To_Path_String_Access
2666 (Path_Addr : Address;
2667 Path_Len : Integer) return String_Access
2668 is
2669 subtype Path_String is String (1 .. Path_Len);
2670 type Path_String_Access is access Path_String;
2671
8b79ad42
AC
2672 function Address_To_Access is new Ada.Unchecked_Conversion
2673 (Source => Address, Target => Path_String_Access);
30681738
RD
2674
2675 Path_Access : constant Path_String_Access :=
2676 Address_To_Access (Path_Addr);
2677
2678 Return_Val : String_Access;
2679
2680 begin
2681 Return_Val := new String (1 .. Path_Len);
2682
2683 for J in 1 .. Path_Len loop
2684 Return_Val (J) := Path_Access (J);
2685 end loop;
2686
2687 return Return_Val;
2688 end To_Path_String_Access;
2689
2690 ------------------
2691 -- Wait_Process --
2692 ------------------
2693
2694 procedure Wait_Process (Pid : out Process_Id; Success : out Boolean) is
2695 Status : Integer;
2696
2697 function Portable_Wait (S : Address) return Process_Id;
2698 pragma Import (C, Portable_Wait, "__gnat_portable_wait");
2699
2700 begin
2701 Pid := Portable_Wait (Status'Address);
2702 Success := (Status = 0);
2703 end Wait_Process;
2704
2705 -----------
2706 -- Write --
2707 -----------
2708
2709 function Write
2710 (FD : File_Descriptor;
2711 A : System.Address;
2712 N : Integer) return Integer
2713 is
2714 begin
b29def53
AC
2715 return
2716 Integer (System.CRTL.write
2717 (System.CRTL.int (FD),
2718 System.CRTL.chars (A),
2719 System.CRTL.size_t (N)));
30681738
RD
2720 end Write;
2721
2722end System.OS_Lib;
This page took 5.254999 seconds and 5 git commands to generate.