annotate gcc/ada/libgnat/s-fileio.adb @ 145:1830386684a0

gcc-9.2.0
author anatofuz
date Thu, 13 Feb 2020 11:34:05 +0900
parents 84e7813d76e9
children
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
111
kono
parents:
diff changeset
1 ------------------------------------------------------------------------------
kono
parents:
diff changeset
2 -- --
kono
parents:
diff changeset
3 -- GNAT RUN-TIME COMPONENTS --
kono
parents:
diff changeset
4 -- --
kono
parents:
diff changeset
5 -- S Y S T E M . F I L E _ I O --
kono
parents:
diff changeset
6 -- --
kono
parents:
diff changeset
7 -- B o d y --
kono
parents:
diff changeset
8 -- --
145
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
9 -- Copyright (C) 1992-2019, Free Software Foundation, Inc. --
111
kono
parents:
diff changeset
10 -- --
kono
parents:
diff changeset
11 -- GNAT is free software; you can redistribute it and/or modify it under --
kono
parents:
diff changeset
12 -- terms of the GNU General Public License as published by the Free Soft- --
kono
parents:
diff changeset
13 -- ware Foundation; either version 3, or (at your option) any later ver- --
kono
parents:
diff changeset
14 -- sion. GNAT is distributed in the hope that it will be useful, but WITH- --
kono
parents:
diff changeset
15 -- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY --
kono
parents:
diff changeset
16 -- or FITNESS FOR A PARTICULAR PURPOSE. --
kono
parents:
diff changeset
17 -- --
kono
parents:
diff changeset
18 -- As a special exception under Section 7 of GPL version 3, you are granted --
kono
parents:
diff changeset
19 -- additional permissions described in the GCC Runtime Library Exception, --
kono
parents:
diff changeset
20 -- version 3.1, as published by the Free Software Foundation. --
kono
parents:
diff changeset
21 -- --
kono
parents:
diff changeset
22 -- You should have received a copy of the GNU General Public License and --
kono
parents:
diff changeset
23 -- a copy of the GCC Runtime Library Exception along with this program; --
kono
parents:
diff changeset
24 -- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see --
kono
parents:
diff changeset
25 -- <http://www.gnu.org/licenses/>. --
kono
parents:
diff changeset
26 -- --
kono
parents:
diff changeset
27 -- GNAT was originally developed by the GNAT team at New York University. --
kono
parents:
diff changeset
28 -- Extensive contributions were provided by Ada Core Technologies Inc. --
kono
parents:
diff changeset
29 -- --
kono
parents:
diff changeset
30 ------------------------------------------------------------------------------
kono
parents:
diff changeset
31
kono
parents:
diff changeset
32 with Ada.Finalization; use Ada.Finalization;
kono
parents:
diff changeset
33 with Ada.IO_Exceptions; use Ada.IO_Exceptions;
kono
parents:
diff changeset
34 with Ada.Unchecked_Deallocation;
kono
parents:
diff changeset
35
kono
parents:
diff changeset
36 with Interfaces.C_Streams; use Interfaces.C_Streams;
kono
parents:
diff changeset
37
kono
parents:
diff changeset
38 with System.Case_Util; use System.Case_Util;
kono
parents:
diff changeset
39 with System.CRTL;
kono
parents:
diff changeset
40 with System.OS_Lib;
kono
parents:
diff changeset
41 with System.Soft_Links;
kono
parents:
diff changeset
42
kono
parents:
diff changeset
43 package body System.File_IO is
kono
parents:
diff changeset
44
kono
parents:
diff changeset
45 use System.File_Control_Block;
kono
parents:
diff changeset
46
kono
parents:
diff changeset
47 package SSL renames System.Soft_Links;
kono
parents:
diff changeset
48
kono
parents:
diff changeset
49 use type CRTL.size_t;
kono
parents:
diff changeset
50
kono
parents:
diff changeset
51 ----------------------
kono
parents:
diff changeset
52 -- Global Variables --
kono
parents:
diff changeset
53 ----------------------
kono
parents:
diff changeset
54
kono
parents:
diff changeset
55 Open_Files : AFCB_Ptr;
kono
parents:
diff changeset
56 -- This points to a list of AFCB's for all open files. This is a doubly
kono
parents:
diff changeset
57 -- linked list, with the Prev pointer of the first entry, and the Next
kono
parents:
diff changeset
58 -- pointer of the last entry containing null. Note that this global
kono
parents:
diff changeset
59 -- variable must be properly protected to provide thread safety.
kono
parents:
diff changeset
60
kono
parents:
diff changeset
61 type Temp_File_Record;
kono
parents:
diff changeset
62 type Temp_File_Record_Ptr is access all Temp_File_Record;
kono
parents:
diff changeset
63
kono
parents:
diff changeset
64 type Temp_File_Record is record
kono
parents:
diff changeset
65 File : AFCB_Ptr;
kono
parents:
diff changeset
66 Next : aliased Temp_File_Record_Ptr;
kono
parents:
diff changeset
67 Name : String (1 .. max_path_len + 1);
kono
parents:
diff changeset
68 end record;
kono
parents:
diff changeset
69 -- One of these is allocated for each temporary file created
kono
parents:
diff changeset
70
kono
parents:
diff changeset
71 Temp_Files : aliased Temp_File_Record_Ptr;
kono
parents:
diff changeset
72 -- Points to list of names of temporary files. Note that this global
kono
parents:
diff changeset
73 -- variable must be properly protected to provide thread safety.
kono
parents:
diff changeset
74
kono
parents:
diff changeset
75 procedure Free is new Ada.Unchecked_Deallocation
kono
parents:
diff changeset
76 (Temp_File_Record, Temp_File_Record_Ptr);
kono
parents:
diff changeset
77
kono
parents:
diff changeset
78 type File_IO_Clean_Up_Type is new Limited_Controlled with null record;
kono
parents:
diff changeset
79 -- The closing of all open files and deletion of temporary files is an
kono
parents:
diff changeset
80 -- action that takes place at the end of execution of the main program.
kono
parents:
diff changeset
81 -- This action is implemented using a library level object that gets
kono
parents:
diff changeset
82 -- finalized at the end of program execution. Note that the type is
kono
parents:
diff changeset
83 -- limited, in order to stop the compiler optimizing away the declaration
kono
parents:
diff changeset
84 -- which would be allowed in the non-limited case.
kono
parents:
diff changeset
85
kono
parents:
diff changeset
86 procedure Finalize (V : in out File_IO_Clean_Up_Type);
kono
parents:
diff changeset
87 -- This is the finalize operation that is used to do the cleanup
kono
parents:
diff changeset
88
kono
parents:
diff changeset
89 File_IO_Clean_Up_Object : File_IO_Clean_Up_Type;
kono
parents:
diff changeset
90 pragma Warnings (Off, File_IO_Clean_Up_Object);
kono
parents:
diff changeset
91 -- This is the single object of the type that triggers the finalization
kono
parents:
diff changeset
92 -- call. Since it is at the library level, this happens just before the
kono
parents:
diff changeset
93 -- environment task is finalized.
kono
parents:
diff changeset
94
kono
parents:
diff changeset
95 text_translation_required : Boolean;
kono
parents:
diff changeset
96 for text_translation_required'Size use Character'Size;
kono
parents:
diff changeset
97 pragma Import
kono
parents:
diff changeset
98 (C, text_translation_required, "__gnat_text_translation_required");
kono
parents:
diff changeset
99 -- If true, add appropriate suffix to control string for Open
kono
parents:
diff changeset
100
kono
parents:
diff changeset
101 -----------------------
kono
parents:
diff changeset
102 -- Local Subprograms --
kono
parents:
diff changeset
103 -----------------------
kono
parents:
diff changeset
104
kono
parents:
diff changeset
105 procedure Free_String is new Ada.Unchecked_Deallocation (String, Pstring);
kono
parents:
diff changeset
106
kono
parents:
diff changeset
107 subtype Fopen_String is String (1 .. 4);
kono
parents:
diff changeset
108 -- Holds open string (longest is "w+b" & nul)
kono
parents:
diff changeset
109
kono
parents:
diff changeset
110 procedure Fopen_Mode
kono
parents:
diff changeset
111 (Namestr : String;
kono
parents:
diff changeset
112 Mode : File_Mode;
kono
parents:
diff changeset
113 Text : Boolean;
kono
parents:
diff changeset
114 Creat : Boolean;
kono
parents:
diff changeset
115 Amethod : Character;
kono
parents:
diff changeset
116 Fopstr : out Fopen_String);
kono
parents:
diff changeset
117 -- Determines proper open mode for a file to be opened in the given Ada
kono
parents:
diff changeset
118 -- mode. Namestr is the NUL-terminated file name. Text is true for a text
kono
parents:
diff changeset
119 -- file and false otherwise, and Creat is true for a create call, and False
kono
parents:
diff changeset
120 -- for an open call. The value stored in Fopstr is a nul-terminated string
kono
parents:
diff changeset
121 -- suitable for a call to fopen or freopen. Amethod is the character
kono
parents:
diff changeset
122 -- designating the access method from the Access_Method field of the FCB.
kono
parents:
diff changeset
123
kono
parents:
diff changeset
124 function Errno_Message
kono
parents:
diff changeset
125 (Name : String;
kono
parents:
diff changeset
126 Errno : Integer := OS_Lib.Errno) return String;
kono
parents:
diff changeset
127 -- Return Errno_Message for Errno, with file name prepended
kono
parents:
diff changeset
128
kono
parents:
diff changeset
129 procedure Raise_Device_Error
kono
parents:
diff changeset
130 (File : AFCB_Ptr;
kono
parents:
diff changeset
131 Errno : Integer := OS_Lib.Errno);
kono
parents:
diff changeset
132 pragma No_Return (Raise_Device_Error);
kono
parents:
diff changeset
133 -- Clear error indication on File and raise Device_Error with an exception
kono
parents:
diff changeset
134 -- message providing errno information.
kono
parents:
diff changeset
135
kono
parents:
diff changeset
136 ----------------
kono
parents:
diff changeset
137 -- Append_Set --
kono
parents:
diff changeset
138 ----------------
kono
parents:
diff changeset
139
kono
parents:
diff changeset
140 procedure Append_Set (File : AFCB_Ptr) is
kono
parents:
diff changeset
141 begin
kono
parents:
diff changeset
142 if File.Mode = Append_File then
kono
parents:
diff changeset
143 if fseek (File.Stream, 0, SEEK_END) /= 0 then
kono
parents:
diff changeset
144 Raise_Device_Error (File);
kono
parents:
diff changeset
145 end if;
kono
parents:
diff changeset
146 end if;
kono
parents:
diff changeset
147 end Append_Set;
kono
parents:
diff changeset
148
kono
parents:
diff changeset
149 ----------------
kono
parents:
diff changeset
150 -- Chain_File --
kono
parents:
diff changeset
151 ----------------
kono
parents:
diff changeset
152
kono
parents:
diff changeset
153 procedure Chain_File (File : AFCB_Ptr) is
kono
parents:
diff changeset
154 begin
kono
parents:
diff changeset
155 -- Take a task lock, to protect the global data value Open_Files
kono
parents:
diff changeset
156
kono
parents:
diff changeset
157 SSL.Lock_Task.all;
kono
parents:
diff changeset
158
kono
parents:
diff changeset
159 -- Do the chaining operation locked
kono
parents:
diff changeset
160
kono
parents:
diff changeset
161 File.Next := Open_Files;
kono
parents:
diff changeset
162 File.Prev := null;
kono
parents:
diff changeset
163 Open_Files := File;
kono
parents:
diff changeset
164
kono
parents:
diff changeset
165 if File.Next /= null then
kono
parents:
diff changeset
166 File.Next.Prev := File;
kono
parents:
diff changeset
167 end if;
kono
parents:
diff changeset
168
kono
parents:
diff changeset
169 SSL.Unlock_Task.all;
kono
parents:
diff changeset
170
kono
parents:
diff changeset
171 exception
kono
parents:
diff changeset
172 when others =>
kono
parents:
diff changeset
173 SSL.Unlock_Task.all;
kono
parents:
diff changeset
174 raise;
kono
parents:
diff changeset
175 end Chain_File;
kono
parents:
diff changeset
176
kono
parents:
diff changeset
177 ---------------------
kono
parents:
diff changeset
178 -- Check_File_Open --
kono
parents:
diff changeset
179 ---------------------
kono
parents:
diff changeset
180
kono
parents:
diff changeset
181 procedure Check_File_Open (File : AFCB_Ptr) is
kono
parents:
diff changeset
182 begin
kono
parents:
diff changeset
183 if File = null then
kono
parents:
diff changeset
184 raise Status_Error with "file not open";
kono
parents:
diff changeset
185 end if;
kono
parents:
diff changeset
186 end Check_File_Open;
kono
parents:
diff changeset
187
kono
parents:
diff changeset
188 -----------------------
kono
parents:
diff changeset
189 -- Check_Read_Status --
kono
parents:
diff changeset
190 -----------------------
kono
parents:
diff changeset
191
kono
parents:
diff changeset
192 procedure Check_Read_Status (File : AFCB_Ptr) is
kono
parents:
diff changeset
193 begin
kono
parents:
diff changeset
194 if File = null then
kono
parents:
diff changeset
195 raise Status_Error with "file not open";
kono
parents:
diff changeset
196 elsif File.Mode not in Read_File_Mode then
kono
parents:
diff changeset
197 raise Mode_Error with "file not readable";
kono
parents:
diff changeset
198 end if;
kono
parents:
diff changeset
199 end Check_Read_Status;
kono
parents:
diff changeset
200
kono
parents:
diff changeset
201 ------------------------
kono
parents:
diff changeset
202 -- Check_Write_Status --
kono
parents:
diff changeset
203 ------------------------
kono
parents:
diff changeset
204
kono
parents:
diff changeset
205 procedure Check_Write_Status (File : AFCB_Ptr) is
kono
parents:
diff changeset
206 begin
kono
parents:
diff changeset
207 if File = null then
kono
parents:
diff changeset
208 raise Status_Error with "file not open";
kono
parents:
diff changeset
209 elsif File.Mode = In_File then
kono
parents:
diff changeset
210 raise Mode_Error with "file not writable";
kono
parents:
diff changeset
211 end if;
kono
parents:
diff changeset
212 end Check_Write_Status;
kono
parents:
diff changeset
213
kono
parents:
diff changeset
214 -----------
kono
parents:
diff changeset
215 -- Close --
kono
parents:
diff changeset
216 -----------
kono
parents:
diff changeset
217
kono
parents:
diff changeset
218 procedure Close (File_Ptr : access AFCB_Ptr) is
kono
parents:
diff changeset
219 Close_Status : int := 0;
kono
parents:
diff changeset
220 Dup_Strm : Boolean := False;
kono
parents:
diff changeset
221 Errno : Integer := 0;
kono
parents:
diff changeset
222
kono
parents:
diff changeset
223 File : AFCB_Ptr renames File_Ptr.all;
kono
parents:
diff changeset
224
kono
parents:
diff changeset
225 begin
kono
parents:
diff changeset
226 -- Take a task lock, to protect the global variables Open_Files and
kono
parents:
diff changeset
227 -- Temp_Files, and the chains they point to.
kono
parents:
diff changeset
228
kono
parents:
diff changeset
229 SSL.Lock_Task.all;
kono
parents:
diff changeset
230
kono
parents:
diff changeset
231 Check_File_Open (File);
kono
parents:
diff changeset
232 AFCB_Close (File);
kono
parents:
diff changeset
233
kono
parents:
diff changeset
234 -- Sever the association between the given file and its associated
kono
parents:
diff changeset
235 -- external file. The given file is left closed. Do not perform system
kono
parents:
diff changeset
236 -- closes on the standard input, output and error files and also do not
kono
parents:
diff changeset
237 -- attempt to close a stream that does not exist (signalled by a null
kono
parents:
diff changeset
238 -- stream value -- happens in some error situations).
kono
parents:
diff changeset
239
kono
parents:
diff changeset
240 if not File.Is_System_File and then File.Stream /= NULL_Stream then
kono
parents:
diff changeset
241
kono
parents:
diff changeset
242 -- Do not do an fclose if this is a shared file and there is at least
kono
parents:
diff changeset
243 -- one other instance of the stream that is open.
kono
parents:
diff changeset
244
kono
parents:
diff changeset
245 if File.Shared_Status = Yes then
kono
parents:
diff changeset
246 declare
kono
parents:
diff changeset
247 P : AFCB_Ptr;
kono
parents:
diff changeset
248
kono
parents:
diff changeset
249 begin
kono
parents:
diff changeset
250 P := Open_Files;
kono
parents:
diff changeset
251 while P /= null loop
kono
parents:
diff changeset
252 if P /= File and then File.Stream = P.Stream then
kono
parents:
diff changeset
253 Dup_Strm := True;
kono
parents:
diff changeset
254 exit;
kono
parents:
diff changeset
255 end if;
kono
parents:
diff changeset
256
kono
parents:
diff changeset
257 P := P.Next;
kono
parents:
diff changeset
258 end loop;
kono
parents:
diff changeset
259 end;
kono
parents:
diff changeset
260 end if;
kono
parents:
diff changeset
261
kono
parents:
diff changeset
262 -- Do the fclose unless this was a duplicate in the shared case
kono
parents:
diff changeset
263
kono
parents:
diff changeset
264 if not Dup_Strm then
kono
parents:
diff changeset
265 Close_Status := fclose (File.Stream);
kono
parents:
diff changeset
266
kono
parents:
diff changeset
267 if Close_Status /= 0 then
kono
parents:
diff changeset
268 Errno := OS_Lib.Errno;
kono
parents:
diff changeset
269 end if;
kono
parents:
diff changeset
270 end if;
kono
parents:
diff changeset
271 end if;
kono
parents:
diff changeset
272
kono
parents:
diff changeset
273 -- Dechain file from list of open files and then free the storage
kono
parents:
diff changeset
274
kono
parents:
diff changeset
275 if File.Prev = null then
kono
parents:
diff changeset
276 Open_Files := File.Next;
kono
parents:
diff changeset
277 else
kono
parents:
diff changeset
278 File.Prev.Next := File.Next;
kono
parents:
diff changeset
279 end if;
kono
parents:
diff changeset
280
kono
parents:
diff changeset
281 if File.Next /= null then
kono
parents:
diff changeset
282 File.Next.Prev := File.Prev;
kono
parents:
diff changeset
283 end if;
kono
parents:
diff changeset
284
kono
parents:
diff changeset
285 -- If it's a temp file, remove the corresponding record from Temp_Files,
kono
parents:
diff changeset
286 -- and delete the file. There are unlikely to be large numbers of temp
kono
parents:
diff changeset
287 -- files open, so a linear search is sufficiently efficient. Note that
kono
parents:
diff changeset
288 -- we don't need to check for end of list, because the file must be
kono
parents:
diff changeset
289 -- somewhere on the list. Note that as for Finalize, we ignore any
kono
parents:
diff changeset
290 -- errors while attempting the unlink operation.
kono
parents:
diff changeset
291
kono
parents:
diff changeset
292 if File.Is_Temporary_File then
kono
parents:
diff changeset
293 declare
kono
parents:
diff changeset
294 Temp : access Temp_File_Record_Ptr := Temp_Files'Access;
kono
parents:
diff changeset
295 -- Note the double indirection here
kono
parents:
diff changeset
296
kono
parents:
diff changeset
297 Discard : int;
kono
parents:
diff changeset
298 New_Temp : Temp_File_Record_Ptr;
kono
parents:
diff changeset
299
kono
parents:
diff changeset
300 begin
kono
parents:
diff changeset
301 while Temp.all.all.File /= File loop
kono
parents:
diff changeset
302 Temp := Temp.all.all.Next'Access;
kono
parents:
diff changeset
303 end loop;
kono
parents:
diff changeset
304
kono
parents:
diff changeset
305 Discard := unlink (Temp.all.all.Name'Address);
kono
parents:
diff changeset
306 New_Temp := Temp.all.all.Next;
kono
parents:
diff changeset
307 Free (Temp.all);
kono
parents:
diff changeset
308 Temp.all := New_Temp;
kono
parents:
diff changeset
309 end;
kono
parents:
diff changeset
310 end if;
kono
parents:
diff changeset
311
kono
parents:
diff changeset
312 -- Deallocate some parts of the file structure that were kept in heap
kono
parents:
diff changeset
313 -- storage with the exception of system files (standard input, output
kono
parents:
diff changeset
314 -- and error) since they had some information allocated in the stack.
kono
parents:
diff changeset
315
kono
parents:
diff changeset
316 if not File.Is_System_File then
kono
parents:
diff changeset
317 Free_String (File.Name);
kono
parents:
diff changeset
318 Free_String (File.Form);
kono
parents:
diff changeset
319 AFCB_Free (File);
kono
parents:
diff changeset
320 end if;
kono
parents:
diff changeset
321
kono
parents:
diff changeset
322 File := null;
kono
parents:
diff changeset
323
kono
parents:
diff changeset
324 if Close_Status /= 0 then
kono
parents:
diff changeset
325 Raise_Device_Error (null, Errno);
kono
parents:
diff changeset
326 end if;
kono
parents:
diff changeset
327
kono
parents:
diff changeset
328 SSL.Unlock_Task.all;
kono
parents:
diff changeset
329
kono
parents:
diff changeset
330 exception
kono
parents:
diff changeset
331 when others =>
kono
parents:
diff changeset
332 SSL.Unlock_Task.all;
kono
parents:
diff changeset
333 raise;
kono
parents:
diff changeset
334 end Close;
kono
parents:
diff changeset
335
kono
parents:
diff changeset
336 ------------
kono
parents:
diff changeset
337 -- Delete --
kono
parents:
diff changeset
338 ------------
kono
parents:
diff changeset
339
kono
parents:
diff changeset
340 procedure Delete (File_Ptr : access AFCB_Ptr) is
kono
parents:
diff changeset
341 File : AFCB_Ptr renames File_Ptr.all;
kono
parents:
diff changeset
342
kono
parents:
diff changeset
343 begin
kono
parents:
diff changeset
344 Check_File_Open (File);
kono
parents:
diff changeset
345
kono
parents:
diff changeset
346 if not File.Is_Regular_File then
kono
parents:
diff changeset
347 raise Use_Error with "cannot delete non-regular file";
kono
parents:
diff changeset
348 end if;
kono
parents:
diff changeset
349
kono
parents:
diff changeset
350 declare
kono
parents:
diff changeset
351 Filename : aliased constant String := File.Name.all;
kono
parents:
diff changeset
352 Is_Temporary_File : constant Boolean := File.Is_Temporary_File;
kono
parents:
diff changeset
353
kono
parents:
diff changeset
354 begin
kono
parents:
diff changeset
355 Close (File_Ptr);
kono
parents:
diff changeset
356
kono
parents:
diff changeset
357 -- Now unlink the external file. Note that we use the full name in
kono
parents:
diff changeset
358 -- this unlink, because the working directory may have changed since
kono
parents:
diff changeset
359 -- we did the open, and we want to unlink the right file. However, if
kono
parents:
diff changeset
360 -- it's a temporary file, then closing it already unlinked it.
kono
parents:
diff changeset
361
kono
parents:
diff changeset
362 if not Is_Temporary_File then
kono
parents:
diff changeset
363 if unlink (Filename'Address) = -1 then
kono
parents:
diff changeset
364 raise Use_Error with OS_Lib.Errno_Message;
kono
parents:
diff changeset
365 end if;
kono
parents:
diff changeset
366 end if;
kono
parents:
diff changeset
367 end;
kono
parents:
diff changeset
368 end Delete;
kono
parents:
diff changeset
369
kono
parents:
diff changeset
370 -----------------
kono
parents:
diff changeset
371 -- End_Of_File --
kono
parents:
diff changeset
372 -----------------
kono
parents:
diff changeset
373
kono
parents:
diff changeset
374 function End_Of_File (File : AFCB_Ptr) return Boolean is
kono
parents:
diff changeset
375 begin
kono
parents:
diff changeset
376 Check_File_Open (File);
kono
parents:
diff changeset
377
kono
parents:
diff changeset
378 if feof (File.Stream) /= 0 then
kono
parents:
diff changeset
379 return True;
kono
parents:
diff changeset
380
kono
parents:
diff changeset
381 else
kono
parents:
diff changeset
382 Check_Read_Status (File);
kono
parents:
diff changeset
383
kono
parents:
diff changeset
384 if ungetc (fgetc (File.Stream), File.Stream) = EOF then
kono
parents:
diff changeset
385 clearerr (File.Stream);
kono
parents:
diff changeset
386 return True;
kono
parents:
diff changeset
387 else
kono
parents:
diff changeset
388 return False;
kono
parents:
diff changeset
389 end if;
kono
parents:
diff changeset
390 end if;
kono
parents:
diff changeset
391 end End_Of_File;
kono
parents:
diff changeset
392
kono
parents:
diff changeset
393 -------------------
kono
parents:
diff changeset
394 -- Errno_Message --
kono
parents:
diff changeset
395 -------------------
kono
parents:
diff changeset
396
kono
parents:
diff changeset
397 function Errno_Message
kono
parents:
diff changeset
398 (Name : String;
kono
parents:
diff changeset
399 Errno : Integer := OS_Lib.Errno) return String
kono
parents:
diff changeset
400 is
kono
parents:
diff changeset
401 begin
kono
parents:
diff changeset
402 return Name & ": " & OS_Lib.Errno_Message (Err => Errno);
kono
parents:
diff changeset
403 end Errno_Message;
kono
parents:
diff changeset
404
kono
parents:
diff changeset
405 --------------
kono
parents:
diff changeset
406 -- Finalize --
kono
parents:
diff changeset
407 --------------
kono
parents:
diff changeset
408
kono
parents:
diff changeset
409 procedure Finalize (V : in out File_IO_Clean_Up_Type) is
kono
parents:
diff changeset
410 pragma Warnings (Off, V);
kono
parents:
diff changeset
411
kono
parents:
diff changeset
412 Fptr1 : aliased AFCB_Ptr;
kono
parents:
diff changeset
413 Fptr2 : AFCB_Ptr;
kono
parents:
diff changeset
414
kono
parents:
diff changeset
415 Discard : int;
kono
parents:
diff changeset
416
kono
parents:
diff changeset
417 begin
kono
parents:
diff changeset
418 -- Take a lock to protect global Open_Files data structure
kono
parents:
diff changeset
419
kono
parents:
diff changeset
420 SSL.Lock_Task.all;
kono
parents:
diff changeset
421
kono
parents:
diff changeset
422 -- First close all open files (the slightly complex form of this loop is
kono
parents:
diff changeset
423 -- required because Close nulls out its argument).
kono
parents:
diff changeset
424
kono
parents:
diff changeset
425 Fptr1 := Open_Files;
kono
parents:
diff changeset
426 while Fptr1 /= null loop
kono
parents:
diff changeset
427 Fptr2 := Fptr1.Next;
kono
parents:
diff changeset
428 Close (Fptr1'Access);
kono
parents:
diff changeset
429 Fptr1 := Fptr2;
kono
parents:
diff changeset
430 end loop;
kono
parents:
diff changeset
431
kono
parents:
diff changeset
432 -- Now unlink all temporary files. We do not bother to free the blocks
kono
parents:
diff changeset
433 -- because we are just about to terminate the program. We also ignore
kono
parents:
diff changeset
434 -- any errors while attempting these unlink operations.
kono
parents:
diff changeset
435
kono
parents:
diff changeset
436 while Temp_Files /= null loop
kono
parents:
diff changeset
437 Discard := unlink (Temp_Files.Name'Address);
kono
parents:
diff changeset
438 Temp_Files := Temp_Files.Next;
kono
parents:
diff changeset
439 end loop;
kono
parents:
diff changeset
440
kono
parents:
diff changeset
441 SSL.Unlock_Task.all;
kono
parents:
diff changeset
442
kono
parents:
diff changeset
443 exception
kono
parents:
diff changeset
444 when others =>
kono
parents:
diff changeset
445 SSL.Unlock_Task.all;
kono
parents:
diff changeset
446 raise;
kono
parents:
diff changeset
447 end Finalize;
kono
parents:
diff changeset
448
kono
parents:
diff changeset
449 -----------
kono
parents:
diff changeset
450 -- Flush --
kono
parents:
diff changeset
451 -----------
kono
parents:
diff changeset
452
kono
parents:
diff changeset
453 procedure Flush (File : AFCB_Ptr) is
kono
parents:
diff changeset
454 begin
kono
parents:
diff changeset
455 Check_Write_Status (File);
kono
parents:
diff changeset
456
kono
parents:
diff changeset
457 if fflush (File.Stream) /= 0 then
kono
parents:
diff changeset
458 Raise_Device_Error (File);
kono
parents:
diff changeset
459 end if;
kono
parents:
diff changeset
460 end Flush;
kono
parents:
diff changeset
461
kono
parents:
diff changeset
462 ----------------
kono
parents:
diff changeset
463 -- Fopen_Mode --
kono
parents:
diff changeset
464 ----------------
kono
parents:
diff changeset
465
kono
parents:
diff changeset
466 -- The fopen mode to be used is shown by the following table:
kono
parents:
diff changeset
467
kono
parents:
diff changeset
468 -- OPEN CREATE
kono
parents:
diff changeset
469 -- Append_File "r+" "w+"
kono
parents:
diff changeset
470 -- In_File "r" "w+"
kono
parents:
diff changeset
471 -- Out_File (Direct_IO, Stream_IO) "r+" [*] "w"
kono
parents:
diff changeset
472 -- Out_File (others) "w" "w"
kono
parents:
diff changeset
473 -- Inout_File "r+" "w+"
kono
parents:
diff changeset
474
kono
parents:
diff changeset
475 -- [*] Except that for Out_File, if the file exists and is a fifo (i.e. a
kono
parents:
diff changeset
476 -- named pipe), we use "w" instead of "r+". This is necessary to make a
kono
parents:
diff changeset
477 -- write to the fifo block until a reader is ready.
kono
parents:
diff changeset
478
kono
parents:
diff changeset
479 -- Note: we do not use "a" or "a+" for Append_File, since this would not
kono
parents:
diff changeset
480 -- work in the case of stream files, where even if in append file mode,
kono
parents:
diff changeset
481 -- you can reset to earlier points in the file. The caller must use the
kono
parents:
diff changeset
482 -- Append_Set routine to deal with the necessary positioning.
kono
parents:
diff changeset
483
kono
parents:
diff changeset
484 -- Note: in several cases, the fopen mode used allows reading and writing,
kono
parents:
diff changeset
485 -- but the setting of the Ada mode is more restrictive. For instance,
kono
parents:
diff changeset
486 -- Create in In_File mode uses "w+" which allows writing, but the Ada mode
kono
parents:
diff changeset
487 -- In_File will cause any write operations to be rejected with Mode_Error
kono
parents:
diff changeset
488 -- in any case.
kono
parents:
diff changeset
489
kono
parents:
diff changeset
490 -- Note: for the Out_File/Open cases for other than the Direct_IO case, an
kono
parents:
diff changeset
491 -- initial call will be made by the caller to first open the file in "r"
kono
parents:
diff changeset
492 -- mode to be sure that it exists. The real open, in "w" mode, will then
kono
parents:
diff changeset
493 -- destroy this file. This is peculiar, but that's what Ada semantics
kono
parents:
diff changeset
494 -- require and the ACATS tests insist on.
kono
parents:
diff changeset
495
kono
parents:
diff changeset
496 -- If text file translation is required, then either "b" or "t" is appended
kono
parents:
diff changeset
497 -- to the mode, depending on the setting of Text.
kono
parents:
diff changeset
498
kono
parents:
diff changeset
499 procedure Fopen_Mode
kono
parents:
diff changeset
500 (Namestr : String;
kono
parents:
diff changeset
501 Mode : File_Mode;
kono
parents:
diff changeset
502 Text : Boolean;
kono
parents:
diff changeset
503 Creat : Boolean;
kono
parents:
diff changeset
504 Amethod : Character;
kono
parents:
diff changeset
505 Fopstr : out Fopen_String)
kono
parents:
diff changeset
506 is
kono
parents:
diff changeset
507 Fptr : Positive;
kono
parents:
diff changeset
508
kono
parents:
diff changeset
509 function is_fifo (Path : Address) return Integer;
kono
parents:
diff changeset
510 pragma Import (C, is_fifo, "__gnat_is_fifo");
kono
parents:
diff changeset
511
kono
parents:
diff changeset
512 begin
kono
parents:
diff changeset
513 case Mode is
kono
parents:
diff changeset
514 when In_File =>
kono
parents:
diff changeset
515 if Creat then
kono
parents:
diff changeset
516 Fopstr (1) := 'w';
kono
parents:
diff changeset
517 Fopstr (2) := '+';
kono
parents:
diff changeset
518 Fptr := 3;
kono
parents:
diff changeset
519 else
kono
parents:
diff changeset
520 Fopstr (1) := 'r';
kono
parents:
diff changeset
521 Fptr := 2;
kono
parents:
diff changeset
522 end if;
kono
parents:
diff changeset
523
kono
parents:
diff changeset
524 when Out_File =>
kono
parents:
diff changeset
525 if Amethod in 'D' | 'S'
kono
parents:
diff changeset
526 and then not Creat
kono
parents:
diff changeset
527 and then is_fifo (Namestr'Address) = 0
kono
parents:
diff changeset
528 then
kono
parents:
diff changeset
529 Fopstr (1) := 'r';
kono
parents:
diff changeset
530 Fopstr (2) := '+';
kono
parents:
diff changeset
531 Fptr := 3;
kono
parents:
diff changeset
532 else
kono
parents:
diff changeset
533 Fopstr (1) := 'w';
kono
parents:
diff changeset
534 Fptr := 2;
kono
parents:
diff changeset
535 end if;
kono
parents:
diff changeset
536
kono
parents:
diff changeset
537 when Append_File
kono
parents:
diff changeset
538 | Inout_File
kono
parents:
diff changeset
539 =>
kono
parents:
diff changeset
540 Fopstr (1) := (if Creat then 'w' else 'r');
kono
parents:
diff changeset
541 Fopstr (2) := '+';
kono
parents:
diff changeset
542 Fptr := 3;
kono
parents:
diff changeset
543 end case;
kono
parents:
diff changeset
544
kono
parents:
diff changeset
545 -- If text_translation_required is true then we need to append either a
kono
parents:
diff changeset
546 -- "t" or "b" to the string to get the right mode.
kono
parents:
diff changeset
547
kono
parents:
diff changeset
548 if text_translation_required then
kono
parents:
diff changeset
549 Fopstr (Fptr) := (if Text then 't' else 'b');
kono
parents:
diff changeset
550 Fptr := Fptr + 1;
kono
parents:
diff changeset
551 end if;
kono
parents:
diff changeset
552
kono
parents:
diff changeset
553 Fopstr (Fptr) := ASCII.NUL;
kono
parents:
diff changeset
554 end Fopen_Mode;
kono
parents:
diff changeset
555
kono
parents:
diff changeset
556 ----------
kono
parents:
diff changeset
557 -- Form --
kono
parents:
diff changeset
558 ----------
kono
parents:
diff changeset
559
kono
parents:
diff changeset
560 function Form (File : AFCB_Ptr) return String is
kono
parents:
diff changeset
561 begin
kono
parents:
diff changeset
562 if File = null then
kono
parents:
diff changeset
563 raise Status_Error with "Form: file not open";
kono
parents:
diff changeset
564 else
kono
parents:
diff changeset
565 return File.Form.all (1 .. File.Form'Length - 1);
kono
parents:
diff changeset
566 end if;
kono
parents:
diff changeset
567 end Form;
kono
parents:
diff changeset
568
kono
parents:
diff changeset
569 ------------------
kono
parents:
diff changeset
570 -- Form_Boolean --
kono
parents:
diff changeset
571 ------------------
kono
parents:
diff changeset
572
kono
parents:
diff changeset
573 function Form_Boolean
kono
parents:
diff changeset
574 (Form : String;
kono
parents:
diff changeset
575 Keyword : String;
kono
parents:
diff changeset
576 Default : Boolean) return Boolean
kono
parents:
diff changeset
577 is
kono
parents:
diff changeset
578 V1, V2 : Natural;
kono
parents:
diff changeset
579 pragma Unreferenced (V2);
kono
parents:
diff changeset
580
kono
parents:
diff changeset
581 begin
kono
parents:
diff changeset
582 Form_Parameter (Form, Keyword, V1, V2);
kono
parents:
diff changeset
583
kono
parents:
diff changeset
584 if V1 = 0 then
kono
parents:
diff changeset
585 return Default;
kono
parents:
diff changeset
586 elsif Form (V1) = 'y' then
kono
parents:
diff changeset
587 return True;
kono
parents:
diff changeset
588 elsif Form (V1) = 'n' then
kono
parents:
diff changeset
589 return False;
kono
parents:
diff changeset
590 else
kono
parents:
diff changeset
591 raise Use_Error with "invalid Form";
kono
parents:
diff changeset
592 end if;
kono
parents:
diff changeset
593 end Form_Boolean;
kono
parents:
diff changeset
594
kono
parents:
diff changeset
595 ------------------
kono
parents:
diff changeset
596 -- Form_Integer --
kono
parents:
diff changeset
597 ------------------
kono
parents:
diff changeset
598
kono
parents:
diff changeset
599 function Form_Integer
kono
parents:
diff changeset
600 (Form : String;
kono
parents:
diff changeset
601 Keyword : String;
kono
parents:
diff changeset
602 Default : Integer) return Integer
kono
parents:
diff changeset
603 is
kono
parents:
diff changeset
604 V1, V2 : Natural;
kono
parents:
diff changeset
605 V : Integer;
kono
parents:
diff changeset
606
kono
parents:
diff changeset
607 begin
kono
parents:
diff changeset
608 Form_Parameter (Form, Keyword, V1, V2);
kono
parents:
diff changeset
609
kono
parents:
diff changeset
610 if V1 = 0 then
kono
parents:
diff changeset
611 return Default;
kono
parents:
diff changeset
612
kono
parents:
diff changeset
613 else
kono
parents:
diff changeset
614 V := 0;
kono
parents:
diff changeset
615
kono
parents:
diff changeset
616 for J in V1 .. V2 loop
kono
parents:
diff changeset
617 if Form (J) not in '0' .. '9' then
kono
parents:
diff changeset
618 raise Use_Error with "invalid Form";
kono
parents:
diff changeset
619 else
kono
parents:
diff changeset
620 V := V * 10 + Character'Pos (Form (J)) - Character'Pos ('0');
kono
parents:
diff changeset
621 end if;
kono
parents:
diff changeset
622
kono
parents:
diff changeset
623 if V > 999_999 then
kono
parents:
diff changeset
624 raise Use_Error with "invalid Form";
kono
parents:
diff changeset
625 end if;
kono
parents:
diff changeset
626 end loop;
kono
parents:
diff changeset
627
kono
parents:
diff changeset
628 return V;
kono
parents:
diff changeset
629 end if;
kono
parents:
diff changeset
630 end Form_Integer;
kono
parents:
diff changeset
631
kono
parents:
diff changeset
632 --------------------
kono
parents:
diff changeset
633 -- Form_Parameter --
kono
parents:
diff changeset
634 --------------------
kono
parents:
diff changeset
635
kono
parents:
diff changeset
636 procedure Form_Parameter
kono
parents:
diff changeset
637 (Form : String;
kono
parents:
diff changeset
638 Keyword : String;
kono
parents:
diff changeset
639 Start : out Natural;
kono
parents:
diff changeset
640 Stop : out Natural)
kono
parents:
diff changeset
641 is
kono
parents:
diff changeset
642 Klen : constant Integer := Keyword'Length;
kono
parents:
diff changeset
643
kono
parents:
diff changeset
644 begin
kono
parents:
diff changeset
645 for J in Form'First + Klen .. Form'Last - 1 loop
kono
parents:
diff changeset
646 if Form (J) = '='
kono
parents:
diff changeset
647 and then Form (J - Klen .. J - 1) = Keyword
kono
parents:
diff changeset
648 then
kono
parents:
diff changeset
649 Start := J + 1;
kono
parents:
diff changeset
650 Stop := Start - 1;
kono
parents:
diff changeset
651 while Form (Stop + 1) /= ASCII.NUL
kono
parents:
diff changeset
652 and then Form (Stop + 1) /= ','
kono
parents:
diff changeset
653 loop
kono
parents:
diff changeset
654 Stop := Stop + 1;
kono
parents:
diff changeset
655 end loop;
kono
parents:
diff changeset
656
kono
parents:
diff changeset
657 return;
kono
parents:
diff changeset
658 end if;
kono
parents:
diff changeset
659 end loop;
kono
parents:
diff changeset
660
kono
parents:
diff changeset
661 Start := 0;
kono
parents:
diff changeset
662 Stop := 0;
kono
parents:
diff changeset
663 end Form_Parameter;
kono
parents:
diff changeset
664
kono
parents:
diff changeset
665 -------------
kono
parents:
diff changeset
666 -- Is_Open --
kono
parents:
diff changeset
667 -------------
kono
parents:
diff changeset
668
kono
parents:
diff changeset
669 function Is_Open (File : AFCB_Ptr) return Boolean is
kono
parents:
diff changeset
670 begin
kono
parents:
diff changeset
671 -- We return True if the file is open, and the underlying file stream is
kono
parents:
diff changeset
672 -- usable. In particular on Windows an application linked with -mwindows
kono
parents:
diff changeset
673 -- option set does not have a console attached. In this case standard
kono
parents:
diff changeset
674 -- files (Current_Output, Current_Error, Current_Input) are not created.
kono
parents:
diff changeset
675 -- We want Is_Open (Current_Output) to return False in this case.
kono
parents:
diff changeset
676
kono
parents:
diff changeset
677 return File /= null and then fileno (File.Stream) /= -1;
kono
parents:
diff changeset
678 end Is_Open;
kono
parents:
diff changeset
679
kono
parents:
diff changeset
680 -------------------
kono
parents:
diff changeset
681 -- Make_Buffered --
kono
parents:
diff changeset
682 -------------------
kono
parents:
diff changeset
683
kono
parents:
diff changeset
684 procedure Make_Buffered
kono
parents:
diff changeset
685 (File : AFCB_Ptr;
kono
parents:
diff changeset
686 Buf_Siz : Interfaces.C_Streams.size_t)
kono
parents:
diff changeset
687 is
kono
parents:
diff changeset
688 status : Integer;
kono
parents:
diff changeset
689 pragma Unreferenced (status);
kono
parents:
diff changeset
690
kono
parents:
diff changeset
691 begin
kono
parents:
diff changeset
692 status := setvbuf (File.Stream, Null_Address, IOFBF, Buf_Siz);
kono
parents:
diff changeset
693 end Make_Buffered;
kono
parents:
diff changeset
694
kono
parents:
diff changeset
695 ------------------------
kono
parents:
diff changeset
696 -- Make_Line_Buffered --
kono
parents:
diff changeset
697 ------------------------
kono
parents:
diff changeset
698
kono
parents:
diff changeset
699 procedure Make_Line_Buffered
kono
parents:
diff changeset
700 (File : AFCB_Ptr;
kono
parents:
diff changeset
701 Line_Siz : Interfaces.C_Streams.size_t)
kono
parents:
diff changeset
702 is
kono
parents:
diff changeset
703 status : Integer;
kono
parents:
diff changeset
704 pragma Unreferenced (status);
kono
parents:
diff changeset
705
kono
parents:
diff changeset
706 begin
kono
parents:
diff changeset
707 status := setvbuf (File.Stream, Null_Address, IOLBF, Line_Siz);
kono
parents:
diff changeset
708 -- No error checking???
kono
parents:
diff changeset
709 end Make_Line_Buffered;
kono
parents:
diff changeset
710
kono
parents:
diff changeset
711 ---------------------
kono
parents:
diff changeset
712 -- Make_Unbuffered --
kono
parents:
diff changeset
713 ---------------------
kono
parents:
diff changeset
714
kono
parents:
diff changeset
715 procedure Make_Unbuffered (File : AFCB_Ptr) is
kono
parents:
diff changeset
716 status : Integer;
kono
parents:
diff changeset
717 pragma Unreferenced (status);
kono
parents:
diff changeset
718
kono
parents:
diff changeset
719 begin
kono
parents:
diff changeset
720 status := setvbuf (File.Stream, Null_Address, IONBF, 0);
kono
parents:
diff changeset
721 -- No error checking???
kono
parents:
diff changeset
722 end Make_Unbuffered;
kono
parents:
diff changeset
723
kono
parents:
diff changeset
724 ----------
kono
parents:
diff changeset
725 -- Mode --
kono
parents:
diff changeset
726 ----------
kono
parents:
diff changeset
727
kono
parents:
diff changeset
728 function Mode (File : AFCB_Ptr) return File_Mode is
kono
parents:
diff changeset
729 begin
kono
parents:
diff changeset
730 if File = null then
kono
parents:
diff changeset
731 raise Status_Error with "Mode: file not open";
kono
parents:
diff changeset
732 else
kono
parents:
diff changeset
733 return File.Mode;
kono
parents:
diff changeset
734 end if;
kono
parents:
diff changeset
735 end Mode;
kono
parents:
diff changeset
736
kono
parents:
diff changeset
737 ----------
kono
parents:
diff changeset
738 -- Name --
kono
parents:
diff changeset
739 ----------
kono
parents:
diff changeset
740
kono
parents:
diff changeset
741 function Name (File : AFCB_Ptr) return String is
kono
parents:
diff changeset
742 begin
kono
parents:
diff changeset
743 if File = null then
kono
parents:
diff changeset
744 raise Status_Error with "Name: file not open";
kono
parents:
diff changeset
745 else
kono
parents:
diff changeset
746 return File.Name.all (1 .. File.Name'Length - 1);
kono
parents:
diff changeset
747 end if;
kono
parents:
diff changeset
748 end Name;
kono
parents:
diff changeset
749
kono
parents:
diff changeset
750 ----------
kono
parents:
diff changeset
751 -- Open --
kono
parents:
diff changeset
752 ----------
kono
parents:
diff changeset
753
kono
parents:
diff changeset
754 procedure Open
kono
parents:
diff changeset
755 (File_Ptr : in out AFCB_Ptr;
kono
parents:
diff changeset
756 Dummy_FCB : AFCB'Class;
kono
parents:
diff changeset
757 Mode : File_Mode;
kono
parents:
diff changeset
758 Name : String;
kono
parents:
diff changeset
759 Form : String;
kono
parents:
diff changeset
760 Amethod : Character;
kono
parents:
diff changeset
761 Creat : Boolean;
kono
parents:
diff changeset
762 Text : Boolean;
kono
parents:
diff changeset
763 C_Stream : FILEs := NULL_Stream)
kono
parents:
diff changeset
764 is
kono
parents:
diff changeset
765 pragma Warnings (Off, Dummy_FCB);
kono
parents:
diff changeset
766 -- Yes we know this is never assigned a value. That's intended, since
kono
parents:
diff changeset
767 -- all we ever use of this value is the tag for dispatching purposes.
kono
parents:
diff changeset
768
kono
parents:
diff changeset
769 procedure Tmp_Name (Buffer : Address);
kono
parents:
diff changeset
770 pragma Import (C, Tmp_Name, "__gnat_tmp_name");
kono
parents:
diff changeset
771 -- Set buffer (a String address) with a temporary filename
kono
parents:
diff changeset
772
kono
parents:
diff changeset
773 function Get_Case_Sensitive return Integer;
kono
parents:
diff changeset
774 pragma Import (C, Get_Case_Sensitive,
kono
parents:
diff changeset
775 "__gnat_get_file_names_case_sensitive");
kono
parents:
diff changeset
776
kono
parents:
diff changeset
777 procedure Record_AFCB;
kono
parents:
diff changeset
778 -- Create and record new AFCB into the runtime, note that the
kono
parents:
diff changeset
779 -- implementation uses the variables below which corresponds to the
kono
parents:
diff changeset
780 -- status of the opened file.
kono
parents:
diff changeset
781
kono
parents:
diff changeset
782 File_Names_Case_Sensitive : constant Boolean := Get_Case_Sensitive /= 0;
kono
parents:
diff changeset
783 -- Set to indicate whether the operating system convention is for file
kono
parents:
diff changeset
784 -- names to be case sensitive (e.g., in Unix, set True), or not case
kono
parents:
diff changeset
785 -- sensitive (e.g., in Windows, set False). Declared locally to avoid
kono
parents:
diff changeset
786 -- breaking the Preelaborate rule that disallows function calls at the
kono
parents:
diff changeset
787 -- library level.
kono
parents:
diff changeset
788
kono
parents:
diff changeset
789 Stream : FILEs := C_Stream;
kono
parents:
diff changeset
790 -- Stream which we open in response to this request
kono
parents:
diff changeset
791
kono
parents:
diff changeset
792 Shared : Shared_Status_Type;
kono
parents:
diff changeset
793 -- Setting of Shared_Status field for file
kono
parents:
diff changeset
794
kono
parents:
diff changeset
795 Fopstr : aliased Fopen_String;
kono
parents:
diff changeset
796 -- Mode string used in fopen call
kono
parents:
diff changeset
797
kono
parents:
diff changeset
798 Formstr : aliased String (1 .. Form'Length + 1);
kono
parents:
diff changeset
799 -- Form string with ASCII.NUL appended, folded to lower case
kono
parents:
diff changeset
800
kono
parents:
diff changeset
801 Text_Encoding : Content_Encoding;
kono
parents:
diff changeset
802
kono
parents:
diff changeset
803 Tempfile : constant Boolean := Name = "";
kono
parents:
diff changeset
804 -- Indicates temporary file case, which is indicated by an empty file
kono
parents:
diff changeset
805 -- name.
kono
parents:
diff changeset
806
kono
parents:
diff changeset
807 Namelen : constant Integer := max_path_len;
kono
parents:
diff changeset
808 -- Length required for file name, not including final ASCII.NUL.
kono
parents:
diff changeset
809 -- Note that we used to reference L_tmpnam here, which is not reliable
kono
parents:
diff changeset
810 -- since __gnat_tmp_name does not always use tmpnam.
kono
parents:
diff changeset
811
kono
parents:
diff changeset
812 Namestr : aliased String (1 .. Namelen + 1);
kono
parents:
diff changeset
813 -- Name as given or temporary file name with ASCII.NUL appended
kono
parents:
diff changeset
814
kono
parents:
diff changeset
815 Fullname : aliased String (1 .. max_path_len + 1);
kono
parents:
diff changeset
816 -- Full name (as required for Name function, and as stored in the
kono
parents:
diff changeset
817 -- control block in the Name field) with ASCII.NUL appended.
kono
parents:
diff changeset
818
kono
parents:
diff changeset
819 Full_Name_Len : Integer;
kono
parents:
diff changeset
820 -- Length of name actually stored in Fullname
kono
parents:
diff changeset
821
kono
parents:
diff changeset
822 Encoding : CRTL.Filename_Encoding;
kono
parents:
diff changeset
823 -- Filename encoding specified into the form parameter
kono
parents:
diff changeset
824
kono
parents:
diff changeset
825 -----------------
kono
parents:
diff changeset
826 -- Record_AFCB --
kono
parents:
diff changeset
827 -----------------
kono
parents:
diff changeset
828
kono
parents:
diff changeset
829 procedure Record_AFCB is
kono
parents:
diff changeset
830 begin
kono
parents:
diff changeset
831 File_Ptr := AFCB_Allocate (Dummy_FCB);
kono
parents:
diff changeset
832
kono
parents:
diff changeset
833 -- Note that we cannot use an aggregate here as File_Ptr is a
kono
parents:
diff changeset
834 -- class-wide access to a limited type (Root_Stream_Type).
kono
parents:
diff changeset
835
kono
parents:
diff changeset
836 File_Ptr.Is_Regular_File := is_regular_file (fileno (Stream)) /= 0;
kono
parents:
diff changeset
837 File_Ptr.Is_System_File := False;
kono
parents:
diff changeset
838 File_Ptr.Text_Encoding := Text_Encoding;
kono
parents:
diff changeset
839 File_Ptr.Shared_Status := Shared;
kono
parents:
diff changeset
840 File_Ptr.Access_Method := Amethod;
kono
parents:
diff changeset
841 File_Ptr.Stream := Stream;
kono
parents:
diff changeset
842 File_Ptr.Form := new String'(Formstr);
kono
parents:
diff changeset
843 File_Ptr.Name := new String'(Fullname
kono
parents:
diff changeset
844 (1 .. Full_Name_Len));
kono
parents:
diff changeset
845 File_Ptr.Mode := Mode;
kono
parents:
diff changeset
846 File_Ptr.Is_Temporary_File := Tempfile;
kono
parents:
diff changeset
847 File_Ptr.Encoding := Encoding;
kono
parents:
diff changeset
848
kono
parents:
diff changeset
849 Chain_File (File_Ptr);
kono
parents:
diff changeset
850 Append_Set (File_Ptr);
kono
parents:
diff changeset
851 end Record_AFCB;
kono
parents:
diff changeset
852
kono
parents:
diff changeset
853 -- Start of processing for Open
kono
parents:
diff changeset
854
kono
parents:
diff changeset
855 begin
kono
parents:
diff changeset
856 if File_Ptr /= null then
kono
parents:
diff changeset
857 raise Status_Error with "file already open";
kono
parents:
diff changeset
858 end if;
kono
parents:
diff changeset
859
kono
parents:
diff changeset
860 -- Acquire form string, setting required NUL terminator
kono
parents:
diff changeset
861
kono
parents:
diff changeset
862 Formstr (1 .. Form'Length) := Form;
kono
parents:
diff changeset
863 Formstr (Formstr'Last) := ASCII.NUL;
kono
parents:
diff changeset
864
kono
parents:
diff changeset
865 -- Convert form string to lower case
kono
parents:
diff changeset
866
kono
parents:
diff changeset
867 for J in Formstr'Range loop
kono
parents:
diff changeset
868 if Formstr (J) in 'A' .. 'Z' then
kono
parents:
diff changeset
869 Formstr (J) := Character'Val (Character'Pos (Formstr (J)) + 32);
kono
parents:
diff changeset
870 end if;
kono
parents:
diff changeset
871 end loop;
kono
parents:
diff changeset
872
kono
parents:
diff changeset
873 -- Acquire setting of shared parameter
kono
parents:
diff changeset
874
kono
parents:
diff changeset
875 declare
kono
parents:
diff changeset
876 V1, V2 : Natural;
kono
parents:
diff changeset
877
kono
parents:
diff changeset
878 begin
kono
parents:
diff changeset
879 Form_Parameter (Formstr, "shared", V1, V2);
kono
parents:
diff changeset
880
kono
parents:
diff changeset
881 if V1 = 0 then
kono
parents:
diff changeset
882 Shared := None;
kono
parents:
diff changeset
883 elsif Formstr (V1 .. V2) = "yes" then
kono
parents:
diff changeset
884 Shared := Yes;
kono
parents:
diff changeset
885 elsif Formstr (V1 .. V2) = "no" then
kono
parents:
diff changeset
886 Shared := No;
kono
parents:
diff changeset
887 else
kono
parents:
diff changeset
888 raise Use_Error with "invalid Form";
kono
parents:
diff changeset
889 end if;
kono
parents:
diff changeset
890 end;
kono
parents:
diff changeset
891
kono
parents:
diff changeset
892 -- Acquire setting of encoding parameter
kono
parents:
diff changeset
893
kono
parents:
diff changeset
894 declare
kono
parents:
diff changeset
895 V1, V2 : Natural;
kono
parents:
diff changeset
896
kono
parents:
diff changeset
897 begin
kono
parents:
diff changeset
898 Form_Parameter (Formstr, "encoding", V1, V2);
kono
parents:
diff changeset
899
kono
parents:
diff changeset
900 if V1 = 0 then
kono
parents:
diff changeset
901 Encoding := CRTL.Unspecified;
kono
parents:
diff changeset
902 elsif Formstr (V1 .. V2) = "utf8" then
kono
parents:
diff changeset
903 Encoding := CRTL.UTF8;
kono
parents:
diff changeset
904 elsif Formstr (V1 .. V2) = "8bits" then
kono
parents:
diff changeset
905 Encoding := CRTL.ASCII_8bits;
kono
parents:
diff changeset
906 else
kono
parents:
diff changeset
907 raise Use_Error with "invalid Form";
kono
parents:
diff changeset
908 end if;
kono
parents:
diff changeset
909 end;
kono
parents:
diff changeset
910
kono
parents:
diff changeset
911 -- Acquire setting of text_translation parameter. Only needed if this is
kono
parents:
diff changeset
912 -- a [Wide_[Wide_]]Text_IO file, in which case we default to True, but
kono
parents:
diff changeset
913 -- if the Form says Text_Translation=No, we use binary mode, so new-line
kono
parents:
diff changeset
914 -- will be just LF, even on Windows.
kono
parents:
diff changeset
915
kono
parents:
diff changeset
916 if Text then
kono
parents:
diff changeset
917 Text_Encoding := Default_Text;
kono
parents:
diff changeset
918 else
kono
parents:
diff changeset
919 Text_Encoding := None;
kono
parents:
diff changeset
920 end if;
kono
parents:
diff changeset
921
kono
parents:
diff changeset
922 if Text_Encoding in Text_Content_Encoding then
kono
parents:
diff changeset
923 declare
kono
parents:
diff changeset
924 V1, V2 : Natural;
kono
parents:
diff changeset
925
kono
parents:
diff changeset
926 begin
kono
parents:
diff changeset
927 Form_Parameter (Formstr, "text_translation", V1, V2);
kono
parents:
diff changeset
928
kono
parents:
diff changeset
929 if V1 = 0 then
kono
parents:
diff changeset
930 null;
kono
parents:
diff changeset
931 elsif Formstr (V1 .. V2) = "no" then
kono
parents:
diff changeset
932 Text_Encoding := None;
kono
parents:
diff changeset
933 elsif Formstr (V1 .. V2) = "text"
kono
parents:
diff changeset
934 or else Formstr (V1 .. V2) = "yes"
kono
parents:
diff changeset
935 then
kono
parents:
diff changeset
936 Text_Encoding := Interfaces.C_Streams.Text;
kono
parents:
diff changeset
937 elsif Formstr (V1 .. V2) = "wtext" then
kono
parents:
diff changeset
938 Text_Encoding := Wtext;
kono
parents:
diff changeset
939 elsif Formstr (V1 .. V2) = "u8text" then
kono
parents:
diff changeset
940 Text_Encoding := U8text;
kono
parents:
diff changeset
941 elsif Formstr (V1 .. V2) = "u16text" then
kono
parents:
diff changeset
942 Text_Encoding := U16text;
kono
parents:
diff changeset
943 else
kono
parents:
diff changeset
944 raise Use_Error with "invalid Form";
kono
parents:
diff changeset
945 end if;
kono
parents:
diff changeset
946 end;
kono
parents:
diff changeset
947 end if;
kono
parents:
diff changeset
948
kono
parents:
diff changeset
949 -- If we were given a stream (call from xxx.C_Streams.Open), then set
kono
parents:
diff changeset
950 -- the full name to the given one, and skip to end of processing.
kono
parents:
diff changeset
951
kono
parents:
diff changeset
952 if Stream /= NULL_Stream then
kono
parents:
diff changeset
953 Full_Name_Len := Name'Length + 1;
kono
parents:
diff changeset
954 Fullname (1 .. Full_Name_Len - 1) := Name;
kono
parents:
diff changeset
955 Fullname (Full_Name_Len) := ASCII.NUL;
kono
parents:
diff changeset
956
kono
parents:
diff changeset
957 -- Normal case of Open or Create
kono
parents:
diff changeset
958
kono
parents:
diff changeset
959 else
kono
parents:
diff changeset
960 -- If temporary file case, get temporary file name and add to the
kono
parents:
diff changeset
961 -- list of temporary files to be deleted on exit.
kono
parents:
diff changeset
962
kono
parents:
diff changeset
963 if Tempfile then
kono
parents:
diff changeset
964 if not Creat then
kono
parents:
diff changeset
965 raise Name_Error with "opening temp file without creating it";
kono
parents:
diff changeset
966 end if;
kono
parents:
diff changeset
967
kono
parents:
diff changeset
968 Tmp_Name (Namestr'Address);
kono
parents:
diff changeset
969
kono
parents:
diff changeset
970 if Namestr (1) = ASCII.NUL then
kono
parents:
diff changeset
971 raise Use_Error with "invalid temp file name";
kono
parents:
diff changeset
972 end if;
kono
parents:
diff changeset
973
kono
parents:
diff changeset
974 -- Normal case of non-empty name given (i.e. not a temp file)
kono
parents:
diff changeset
975
kono
parents:
diff changeset
976 else
kono
parents:
diff changeset
977 if Name'Length > Namelen then
kono
parents:
diff changeset
978 raise Name_Error with "file name too long";
kono
parents:
diff changeset
979 end if;
kono
parents:
diff changeset
980
kono
parents:
diff changeset
981 Namestr (1 .. Name'Length) := Name;
kono
parents:
diff changeset
982 Namestr (Name'Length + 1) := ASCII.NUL;
kono
parents:
diff changeset
983 end if;
kono
parents:
diff changeset
984
kono
parents:
diff changeset
985 -- Get full name in accordance with the advice of RM A.8.2(22)
kono
parents:
diff changeset
986
kono
parents:
diff changeset
987 full_name (Namestr'Address, Fullname'Address);
kono
parents:
diff changeset
988
kono
parents:
diff changeset
989 if Fullname (1) = ASCII.NUL then
kono
parents:
diff changeset
990 raise Use_Error with Errno_Message (Name);
kono
parents:
diff changeset
991 end if;
kono
parents:
diff changeset
992
kono
parents:
diff changeset
993 Full_Name_Len := 1;
kono
parents:
diff changeset
994 while Full_Name_Len < Fullname'Last
kono
parents:
diff changeset
995 and then Fullname (Full_Name_Len) /= ASCII.NUL
kono
parents:
diff changeset
996 loop
kono
parents:
diff changeset
997 Full_Name_Len := Full_Name_Len + 1;
kono
parents:
diff changeset
998 end loop;
kono
parents:
diff changeset
999
kono
parents:
diff changeset
1000 -- Fullname is generated by calling system's full_name. The problem
kono
parents:
diff changeset
1001 -- is, full_name does nothing about the casing, so a file name
kono
parents:
diff changeset
1002 -- comparison may generally speaking not be valid on non-case-
kono
parents:
diff changeset
1003 -- sensitive systems, and in particular we get unexpected failures
kono
parents:
diff changeset
1004 -- on Windows/Vista because of this. So we use s-casuti to force
kono
parents:
diff changeset
1005 -- the name to lower case.
kono
parents:
diff changeset
1006
kono
parents:
diff changeset
1007 if not File_Names_Case_Sensitive then
kono
parents:
diff changeset
1008 To_Lower (Fullname (1 .. Full_Name_Len));
kono
parents:
diff changeset
1009 end if;
kono
parents:
diff changeset
1010
kono
parents:
diff changeset
1011 -- If Shared=None or Shared=Yes, then check for the existence of
kono
parents:
diff changeset
1012 -- another file with exactly the same full name.
kono
parents:
diff changeset
1013
kono
parents:
diff changeset
1014 if Shared /= No then
kono
parents:
diff changeset
1015 declare
kono
parents:
diff changeset
1016 P : AFCB_Ptr;
kono
parents:
diff changeset
1017
kono
parents:
diff changeset
1018 begin
kono
parents:
diff changeset
1019 -- Take a task lock to protect Open_Files
kono
parents:
diff changeset
1020
kono
parents:
diff changeset
1021 SSL.Lock_Task.all;
kono
parents:
diff changeset
1022
kono
parents:
diff changeset
1023 -- Search list of open files
kono
parents:
diff changeset
1024
kono
parents:
diff changeset
1025 P := Open_Files;
kono
parents:
diff changeset
1026 while P /= null loop
kono
parents:
diff changeset
1027 if Fullname (1 .. Full_Name_Len) = P.Name.all then
kono
parents:
diff changeset
1028
kono
parents:
diff changeset
1029 -- If we get a match, and either file has Shared=None,
kono
parents:
diff changeset
1030 -- then raise Use_Error, since we don't allow two files
kono
parents:
diff changeset
1031 -- of the same name to be opened unless they specify the
kono
parents:
diff changeset
1032 -- required sharing mode.
kono
parents:
diff changeset
1033
kono
parents:
diff changeset
1034 if Shared = None
kono
parents:
diff changeset
1035 or else P.Shared_Status = None
kono
parents:
diff changeset
1036 then
kono
parents:
diff changeset
1037 raise Use_Error with "reopening shared file";
kono
parents:
diff changeset
1038
kono
parents:
diff changeset
1039 -- If both files have Shared=Yes, then we acquire the
kono
parents:
diff changeset
1040 -- stream from the located file to use as our stream.
kono
parents:
diff changeset
1041
kono
parents:
diff changeset
1042 elsif Shared = Yes
kono
parents:
diff changeset
1043 and then P.Shared_Status = Yes
kono
parents:
diff changeset
1044 then
kono
parents:
diff changeset
1045 Stream := P.Stream;
kono
parents:
diff changeset
1046
kono
parents:
diff changeset
1047 Record_AFCB;
kono
parents:
diff changeset
1048 pragma Assert (not Tempfile);
kono
parents:
diff changeset
1049
kono
parents:
diff changeset
1050 exit;
kono
parents:
diff changeset
1051
kono
parents:
diff changeset
1052 -- Otherwise one of the files has Shared=Yes and one has
kono
parents:
diff changeset
1053 -- Shared=No. If the current file has Shared=No then all
kono
parents:
diff changeset
1054 -- is well but we don't want to share any other file's
kono
parents:
diff changeset
1055 -- stream. If the current file has Shared=Yes, we would
kono
parents:
diff changeset
1056 -- like to share a stream, but not from a file that has
kono
parents:
diff changeset
1057 -- Shared=No, so either way, we just continue the search.
kono
parents:
diff changeset
1058
kono
parents:
diff changeset
1059 else
kono
parents:
diff changeset
1060 null;
kono
parents:
diff changeset
1061 end if;
kono
parents:
diff changeset
1062 end if;
kono
parents:
diff changeset
1063
kono
parents:
diff changeset
1064 P := P.Next;
kono
parents:
diff changeset
1065 end loop;
kono
parents:
diff changeset
1066
kono
parents:
diff changeset
1067 SSL.Unlock_Task.all;
kono
parents:
diff changeset
1068
kono
parents:
diff changeset
1069 exception
kono
parents:
diff changeset
1070 when others =>
kono
parents:
diff changeset
1071 SSL.Unlock_Task.all;
kono
parents:
diff changeset
1072 raise;
kono
parents:
diff changeset
1073 end;
kono
parents:
diff changeset
1074 end if;
kono
parents:
diff changeset
1075
kono
parents:
diff changeset
1076 -- Open specified file if we did not find an existing stream,
kono
parents:
diff changeset
1077 -- otherwise we just return as there is nothing more to be done.
kono
parents:
diff changeset
1078
kono
parents:
diff changeset
1079 if Stream /= NULL_Stream then
kono
parents:
diff changeset
1080 return;
kono
parents:
diff changeset
1081
kono
parents:
diff changeset
1082 else
kono
parents:
diff changeset
1083 Fopen_Mode
kono
parents:
diff changeset
1084 (Namestr => Namestr,
kono
parents:
diff changeset
1085 Mode => Mode,
kono
parents:
diff changeset
1086 Text => Text_Encoding in Text_Content_Encoding,
kono
parents:
diff changeset
1087 Creat => Creat,
kono
parents:
diff changeset
1088 Amethod => Amethod,
kono
parents:
diff changeset
1089 Fopstr => Fopstr);
kono
parents:
diff changeset
1090
kono
parents:
diff changeset
1091 -- A special case, if we are opening (OPEN case) a file and the
kono
parents:
diff changeset
1092 -- mode returned by Fopen_Mode is not "r" or "r+", then we first
kono
parents:
diff changeset
1093 -- make sure that the file exists as required by Ada semantics.
kono
parents:
diff changeset
1094
kono
parents:
diff changeset
1095 if not Creat and then Fopstr (1) /= 'r' then
kono
parents:
diff changeset
1096 if file_exists (Namestr'Address) = 0 then
kono
parents:
diff changeset
1097 raise Name_Error with Errno_Message (Name);
kono
parents:
diff changeset
1098 end if;
kono
parents:
diff changeset
1099 end if;
kono
parents:
diff changeset
1100
kono
parents:
diff changeset
1101 -- Now open the file. Note that we use the name as given in the
kono
parents:
diff changeset
1102 -- original Open call for this purpose, since that seems the
kono
parents:
diff changeset
1103 -- clearest implementation of the intent. It would presumably
kono
parents:
diff changeset
1104 -- work to use the full name here, but if there is any difference,
kono
parents:
diff changeset
1105 -- then we should use the name used in the call.
kono
parents:
diff changeset
1106
kono
parents:
diff changeset
1107 -- Note: for a corresponding delete, we will use the full name,
kono
parents:
diff changeset
1108 -- since by the time of the delete, the current working directory
kono
parents:
diff changeset
1109 -- may have changed and we do not want to delete a different file.
kono
parents:
diff changeset
1110
kono
parents:
diff changeset
1111 Stream :=
kono
parents:
diff changeset
1112 fopen (Namestr'Address, Fopstr'Address, Encoding);
kono
parents:
diff changeset
1113
kono
parents:
diff changeset
1114 if Stream = NULL_Stream then
kono
parents:
diff changeset
1115
kono
parents:
diff changeset
1116 -- Raise Name_Error if trying to open a non-existent file.
kono
parents:
diff changeset
1117 -- Otherwise raise Use_Error.
kono
parents:
diff changeset
1118
kono
parents:
diff changeset
1119 -- Should we raise Device_Error for ENOSPC???
kono
parents:
diff changeset
1120
kono
parents:
diff changeset
1121 declare
kono
parents:
diff changeset
1122 function Is_File_Not_Found_Error
kono
parents:
diff changeset
1123 (Errno_Value : Integer) return Integer;
kono
parents:
diff changeset
1124 pragma Import
kono
parents:
diff changeset
1125 (C, Is_File_Not_Found_Error,
kono
parents:
diff changeset
1126 "__gnat_is_file_not_found_error");
kono
parents:
diff changeset
1127 -- Non-zero when the given errno value indicates a non-
kono
parents:
diff changeset
1128 -- existing file.
kono
parents:
diff changeset
1129
kono
parents:
diff changeset
1130 Errno : constant Integer := OS_Lib.Errno;
kono
parents:
diff changeset
1131 Message : constant String := Errno_Message (Name, Errno);
kono
parents:
diff changeset
1132
kono
parents:
diff changeset
1133 begin
kono
parents:
diff changeset
1134 if Is_File_Not_Found_Error (Errno) /= 0 then
kono
parents:
diff changeset
1135 raise Name_Error with Message;
kono
parents:
diff changeset
1136 else
kono
parents:
diff changeset
1137 raise Use_Error with Message;
kono
parents:
diff changeset
1138 end if;
kono
parents:
diff changeset
1139 end;
kono
parents:
diff changeset
1140 end if;
kono
parents:
diff changeset
1141 end if;
kono
parents:
diff changeset
1142 end if;
kono
parents:
diff changeset
1143
kono
parents:
diff changeset
1144 -- Stream has been successfully located or opened, so now we are
kono
parents:
diff changeset
1145 -- committed to completing the opening of the file. Allocate block on
kono
parents:
diff changeset
1146 -- heap and fill in its fields.
kono
parents:
diff changeset
1147
kono
parents:
diff changeset
1148 Record_AFCB;
kono
parents:
diff changeset
1149
kono
parents:
diff changeset
1150 if Tempfile then
kono
parents:
diff changeset
1151 -- Chain to temp file list, ensuring thread safety with a lock
kono
parents:
diff changeset
1152
kono
parents:
diff changeset
1153 begin
kono
parents:
diff changeset
1154 SSL.Lock_Task.all;
kono
parents:
diff changeset
1155 Temp_Files :=
kono
parents:
diff changeset
1156 new Temp_File_Record'
kono
parents:
diff changeset
1157 (File => File_Ptr, Name => Namestr, Next => Temp_Files);
kono
parents:
diff changeset
1158 SSL.Unlock_Task.all;
kono
parents:
diff changeset
1159
kono
parents:
diff changeset
1160 exception
kono
parents:
diff changeset
1161 when others =>
kono
parents:
diff changeset
1162 SSL.Unlock_Task.all;
kono
parents:
diff changeset
1163 raise;
kono
parents:
diff changeset
1164 end;
kono
parents:
diff changeset
1165 end if;
kono
parents:
diff changeset
1166 end Open;
kono
parents:
diff changeset
1167
kono
parents:
diff changeset
1168 ------------------------
kono
parents:
diff changeset
1169 -- Raise_Device_Error --
kono
parents:
diff changeset
1170 ------------------------
kono
parents:
diff changeset
1171
kono
parents:
diff changeset
1172 procedure Raise_Device_Error
kono
parents:
diff changeset
1173 (File : AFCB_Ptr;
kono
parents:
diff changeset
1174 Errno : Integer := OS_Lib.Errno)
kono
parents:
diff changeset
1175 is
kono
parents:
diff changeset
1176 begin
kono
parents:
diff changeset
1177 -- Clear error status so that the same error is not reported twice
kono
parents:
diff changeset
1178
kono
parents:
diff changeset
1179 if File /= null then
kono
parents:
diff changeset
1180 clearerr (File.Stream);
kono
parents:
diff changeset
1181 end if;
kono
parents:
diff changeset
1182
kono
parents:
diff changeset
1183 raise Device_Error with OS_Lib.Errno_Message (Err => Errno);
kono
parents:
diff changeset
1184 end Raise_Device_Error;
kono
parents:
diff changeset
1185
kono
parents:
diff changeset
1186 --------------
kono
parents:
diff changeset
1187 -- Read_Buf --
kono
parents:
diff changeset
1188 --------------
kono
parents:
diff changeset
1189
kono
parents:
diff changeset
1190 procedure Read_Buf (File : AFCB_Ptr; Buf : Address; Siz : size_t) is
kono
parents:
diff changeset
1191 Nread : size_t;
kono
parents:
diff changeset
1192
kono
parents:
diff changeset
1193 begin
kono
parents:
diff changeset
1194 Nread := fread (Buf, 1, Siz, File.Stream);
kono
parents:
diff changeset
1195
kono
parents:
diff changeset
1196 if Nread = Siz then
kono
parents:
diff changeset
1197 return;
kono
parents:
diff changeset
1198
kono
parents:
diff changeset
1199 elsif ferror (File.Stream) /= 0 then
kono
parents:
diff changeset
1200 Raise_Device_Error (File);
kono
parents:
diff changeset
1201
kono
parents:
diff changeset
1202 elsif Nread = 0 then
kono
parents:
diff changeset
1203 raise End_Error;
kono
parents:
diff changeset
1204
kono
parents:
diff changeset
1205 else -- 0 < Nread < Siz
kono
parents:
diff changeset
1206 raise Data_Error with "not enough data read";
kono
parents:
diff changeset
1207 end if;
kono
parents:
diff changeset
1208 end Read_Buf;
kono
parents:
diff changeset
1209
kono
parents:
diff changeset
1210 procedure Read_Buf
kono
parents:
diff changeset
1211 (File : AFCB_Ptr;
kono
parents:
diff changeset
1212 Buf : Address;
kono
parents:
diff changeset
1213 Siz : Interfaces.C_Streams.size_t;
kono
parents:
diff changeset
1214 Count : out Interfaces.C_Streams.size_t)
kono
parents:
diff changeset
1215 is
kono
parents:
diff changeset
1216 begin
kono
parents:
diff changeset
1217 Count := fread (Buf, 1, Siz, File.Stream);
kono
parents:
diff changeset
1218
kono
parents:
diff changeset
1219 if Count = 0 and then ferror (File.Stream) /= 0 then
kono
parents:
diff changeset
1220 Raise_Device_Error (File);
kono
parents:
diff changeset
1221 end if;
kono
parents:
diff changeset
1222 end Read_Buf;
kono
parents:
diff changeset
1223
kono
parents:
diff changeset
1224 -----------
kono
parents:
diff changeset
1225 -- Reset --
kono
parents:
diff changeset
1226 -----------
kono
parents:
diff changeset
1227
kono
parents:
diff changeset
1228 -- The reset which does not change the mode simply does a rewind
kono
parents:
diff changeset
1229
kono
parents:
diff changeset
1230 procedure Reset (File_Ptr : access AFCB_Ptr) is
kono
parents:
diff changeset
1231 File : AFCB_Ptr renames File_Ptr.all;
kono
parents:
diff changeset
1232 begin
kono
parents:
diff changeset
1233 Check_File_Open (File);
kono
parents:
diff changeset
1234 Reset (File_Ptr, File.Mode);
kono
parents:
diff changeset
1235 end Reset;
kono
parents:
diff changeset
1236
kono
parents:
diff changeset
1237 -- The reset with a change in mode is done using freopen, and is not
kono
parents:
diff changeset
1238 -- permitted except for regular files (since otherwise there is no name for
kono
parents:
diff changeset
1239 -- the freopen, and in any case it seems meaningless).
kono
parents:
diff changeset
1240
kono
parents:
diff changeset
1241 procedure Reset (File_Ptr : access AFCB_Ptr; Mode : File_Mode) is
kono
parents:
diff changeset
1242 File : AFCB_Ptr renames File_Ptr.all;
kono
parents:
diff changeset
1243 Fopstr : aliased Fopen_String;
kono
parents:
diff changeset
1244
kono
parents:
diff changeset
1245 begin
kono
parents:
diff changeset
1246 Check_File_Open (File);
kono
parents:
diff changeset
1247
kono
parents:
diff changeset
1248 -- Change of mode not allowed for shared file or file with no name or
kono
parents:
diff changeset
1249 -- file that is not a regular file, or for a system file. Note that we
kono
parents:
diff changeset
1250 -- allow the "change" of mode if it is not in fact doing a change.
kono
parents:
diff changeset
1251
kono
parents:
diff changeset
1252 if Mode /= File.Mode then
kono
parents:
diff changeset
1253 if File.Shared_Status = Yes then
kono
parents:
diff changeset
1254 raise Use_Error with "cannot change mode of shared file";
kono
parents:
diff changeset
1255 elsif File.Name'Length <= 1 then
kono
parents:
diff changeset
1256 raise Use_Error with "cannot change mode of temp file";
kono
parents:
diff changeset
1257 elsif File.Is_System_File then
kono
parents:
diff changeset
1258 raise Use_Error with "cannot change mode of system file";
kono
parents:
diff changeset
1259 elsif not File.Is_Regular_File then
kono
parents:
diff changeset
1260 raise Use_Error with "cannot change mode of non-regular file";
kono
parents:
diff changeset
1261 end if;
kono
parents:
diff changeset
1262 end if;
kono
parents:
diff changeset
1263
kono
parents:
diff changeset
1264 -- For In_File or Inout_File for a regular file, we can just do a rewind
kono
parents:
diff changeset
1265 -- if the mode is unchanged, which is more efficient than doing a full
kono
parents:
diff changeset
1266 -- reopen.
kono
parents:
diff changeset
1267
kono
parents:
diff changeset
1268 if Mode = File.Mode
kono
parents:
diff changeset
1269 and then Mode in Read_File_Mode
kono
parents:
diff changeset
1270 then
kono
parents:
diff changeset
1271 rewind (File.Stream);
kono
parents:
diff changeset
1272
kono
parents:
diff changeset
1273 -- Here the change of mode is permitted, we do it by reopening the file
kono
parents:
diff changeset
1274 -- in the new mode and replacing the stream with a new stream.
kono
parents:
diff changeset
1275
kono
parents:
diff changeset
1276 else
kono
parents:
diff changeset
1277 Fopen_Mode
kono
parents:
diff changeset
1278 (Namestr => File.Name.all,
kono
parents:
diff changeset
1279 Mode => Mode,
kono
parents:
diff changeset
1280 Text => File.Text_Encoding in Text_Content_Encoding,
kono
parents:
diff changeset
1281 Creat => False,
kono
parents:
diff changeset
1282 Amethod => File.Access_Method,
kono
parents:
diff changeset
1283 Fopstr => Fopstr);
kono
parents:
diff changeset
1284
kono
parents:
diff changeset
1285 File.Stream := freopen
kono
parents:
diff changeset
1286 (File.Name.all'Address, Fopstr'Address, File.Stream,
kono
parents:
diff changeset
1287 File.Encoding);
kono
parents:
diff changeset
1288
kono
parents:
diff changeset
1289 if File.Stream = NULL_Stream then
kono
parents:
diff changeset
1290 Close (File_Ptr);
kono
parents:
diff changeset
1291 raise Use_Error;
kono
parents:
diff changeset
1292 else
kono
parents:
diff changeset
1293 File.Mode := Mode;
kono
parents:
diff changeset
1294 Append_Set (File);
kono
parents:
diff changeset
1295 end if;
kono
parents:
diff changeset
1296 end if;
kono
parents:
diff changeset
1297 end Reset;
kono
parents:
diff changeset
1298
kono
parents:
diff changeset
1299 ---------------
kono
parents:
diff changeset
1300 -- Write_Buf --
kono
parents:
diff changeset
1301 ---------------
kono
parents:
diff changeset
1302
kono
parents:
diff changeset
1303 procedure Write_Buf (File : AFCB_Ptr; Buf : Address; Siz : size_t) is
kono
parents:
diff changeset
1304 begin
kono
parents:
diff changeset
1305 -- Note: for most purposes, the Siz and 1 parameters in the fwrite call
kono
parents:
diff changeset
1306 -- could be reversed, but we have encountered systems where this is a
kono
parents:
diff changeset
1307 -- better choice, since for some file formats, reversing the parameters
kono
parents:
diff changeset
1308 -- results in records of one byte each.
kono
parents:
diff changeset
1309
kono
parents:
diff changeset
1310 SSL.Abort_Defer.all;
kono
parents:
diff changeset
1311
kono
parents:
diff changeset
1312 if fwrite (Buf, Siz, 1, File.Stream) /= 1 then
kono
parents:
diff changeset
1313 if Siz /= 0 then
kono
parents:
diff changeset
1314 SSL.Abort_Undefer.all;
kono
parents:
diff changeset
1315 Raise_Device_Error (File);
kono
parents:
diff changeset
1316 end if;
kono
parents:
diff changeset
1317 end if;
kono
parents:
diff changeset
1318
kono
parents:
diff changeset
1319 SSL.Abort_Undefer.all;
kono
parents:
diff changeset
1320 end Write_Buf;
kono
parents:
diff changeset
1321
kono
parents:
diff changeset
1322 end System.File_IO;