]>
Commit | Line | Data |
---|---|---|
d23b8f57 RK |
1 | ------------------------------------------------------------------------------ |
2 | -- -- | |
3 | -- GNAT RUNTIME COMPONENTS -- | |
4 | -- -- | |
5 | -- A D A . S T R E A M S . S T R E A M _ I O -- | |
6 | -- -- | |
7 | -- B o d y -- | |
8 | -- -- | |
fbf5a39b | 9 | -- Copyright (C) 1992-2003, Free Software Foundation, Inc. -- |
d23b8f57 RK |
10 | -- -- |
11 | -- GNAT is free software; you can redistribute it and/or modify it under -- | |
12 | -- terms of the GNU General Public License as published by the Free Soft- -- | |
13 | -- ware Foundation; either version 2, or (at your option) any later ver- -- | |
14 | -- sion. GNAT is distributed in the hope that it will be useful, but WITH- -- | |
15 | -- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY -- | |
16 | -- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -- | |
17 | -- for more details. You should have received a copy of the GNU General -- | |
18 | -- Public License distributed with GNAT; see file COPYING. If not, write -- | |
19 | -- to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, -- | |
20 | -- MA 02111-1307, USA. -- | |
21 | -- -- | |
22 | -- As a special exception, if other files instantiate generics from this -- | |
23 | -- unit, or you link this unit with other files to produce an executable, -- | |
24 | -- this unit does not by itself cause the resulting executable to be -- | |
25 | -- covered by the GNU General Public License. This exception does not -- | |
26 | -- however invalidate any other reasons why the executable file might be -- | |
27 | -- covered by the GNU Public License. -- | |
28 | -- -- | |
29 | -- GNAT was originally developed by the GNAT team at New York University. -- | |
71ff80dc | 30 | -- Extensive contributions were provided by Ada Core Technologies Inc. -- |
d23b8f57 RK |
31 | -- -- |
32 | ------------------------------------------------------------------------------ | |
33 | ||
34 | with Interfaces.C_Streams; use Interfaces.C_Streams; | |
35 | with System; use System; | |
36 | with System.File_IO; | |
37 | with System.Soft_Links; | |
38 | with Unchecked_Conversion; | |
39 | with Unchecked_Deallocation; | |
40 | ||
41 | package body Ada.Streams.Stream_IO is | |
42 | ||
43 | package FIO renames System.File_IO; | |
44 | package SSL renames System.Soft_Links; | |
45 | ||
46 | subtype AP is FCB.AFCB_Ptr; | |
47 | ||
48 | function To_FCB is new Unchecked_Conversion (File_Mode, FCB.File_Mode); | |
49 | function To_SIO is new Unchecked_Conversion (FCB.File_Mode, File_Mode); | |
50 | use type FCB.File_Mode; | |
51 | use type FCB.Shared_Status_Type; | |
52 | ||
53 | ----------------------- | |
54 | -- Local Subprograms -- | |
55 | ----------------------- | |
56 | ||
57 | procedure Set_Position (File : in File_Type); | |
58 | -- Sets file position pointer according to value of current index | |
59 | ||
60 | ------------------- | |
61 | -- AFCB_Allocate -- | |
62 | ------------------- | |
63 | ||
64 | function AFCB_Allocate (Control_Block : Stream_AFCB) return FCB.AFCB_Ptr is | |
07fc65c4 GB |
65 | pragma Warnings (Off, Control_Block); |
66 | ||
d23b8f57 RK |
67 | begin |
68 | return new Stream_AFCB; | |
69 | end AFCB_Allocate; | |
70 | ||
71 | ---------------- | |
72 | -- AFCB_Close -- | |
73 | ---------------- | |
74 | ||
75 | -- No special processing required for closing Stream_IO file | |
76 | ||
77 | procedure AFCB_Close (File : access Stream_AFCB) is | |
07fc65c4 GB |
78 | pragma Warnings (Off, File); |
79 | ||
d23b8f57 RK |
80 | begin |
81 | null; | |
82 | end AFCB_Close; | |
83 | ||
84 | --------------- | |
85 | -- AFCB_Free -- | |
86 | --------------- | |
87 | ||
88 | procedure AFCB_Free (File : access Stream_AFCB) is | |
89 | type FCB_Ptr is access all Stream_AFCB; | |
90 | FT : FCB_Ptr := FCB_Ptr (File); | |
91 | ||
92 | procedure Free is new Unchecked_Deallocation (Stream_AFCB, FCB_Ptr); | |
93 | ||
94 | begin | |
95 | Free (FT); | |
96 | end AFCB_Free; | |
97 | ||
98 | ----------- | |
99 | -- Close -- | |
100 | ----------- | |
101 | ||
102 | procedure Close (File : in out File_Type) is | |
103 | begin | |
104 | FIO.Close (AP (File)); | |
105 | end Close; | |
106 | ||
107 | ------------ | |
108 | -- Create -- | |
109 | ------------ | |
110 | ||
111 | procedure Create | |
112 | (File : in out File_Type; | |
113 | Mode : in File_Mode := Out_File; | |
114 | Name : in String := ""; | |
115 | Form : in String := "") | |
116 | is | |
fbf5a39b AC |
117 | Dummy_File_Control_Block : Stream_AFCB; |
118 | pragma Warnings (Off, Dummy_File_Control_Block); | |
119 | -- Yes, we know this is never assigned a value, only the tag | |
120 | -- is used for dispatching purposes, so that's expected. | |
d23b8f57 RK |
121 | |
122 | begin | |
123 | FIO.Open (File_Ptr => AP (File), | |
fbf5a39b | 124 | Dummy_FCB => Dummy_File_Control_Block, |
d23b8f57 RK |
125 | Mode => To_FCB (Mode), |
126 | Name => Name, | |
127 | Form => Form, | |
128 | Amethod => 'S', | |
129 | Creat => True, | |
130 | Text => False); | |
131 | File.Last_Op := Op_Write; | |
132 | end Create; | |
133 | ||
134 | ------------ | |
135 | -- Delete -- | |
136 | ------------ | |
137 | ||
138 | procedure Delete (File : in out File_Type) is | |
139 | begin | |
140 | FIO.Delete (AP (File)); | |
141 | end Delete; | |
142 | ||
143 | ----------------- | |
144 | -- End_Of_File -- | |
145 | ----------------- | |
146 | ||
147 | function End_Of_File (File : in File_Type) return Boolean is | |
148 | begin | |
149 | FIO.Check_Read_Status (AP (File)); | |
150 | return Count (File.Index) > Size (File); | |
151 | end End_Of_File; | |
152 | ||
153 | ----------- | |
154 | -- Flush -- | |
155 | ----------- | |
156 | ||
07fc65c4 | 157 | procedure Flush (File : File_Type) is |
d23b8f57 RK |
158 | begin |
159 | FIO.Flush (AP (File)); | |
160 | end Flush; | |
161 | ||
162 | ---------- | |
163 | -- Form -- | |
164 | ---------- | |
165 | ||
166 | function Form (File : in File_Type) return String is | |
167 | begin | |
168 | return FIO.Form (AP (File)); | |
169 | end Form; | |
170 | ||
171 | ----------- | |
172 | -- Index -- | |
173 | ----------- | |
174 | ||
175 | function Index (File : in File_Type) return Positive_Count is | |
176 | begin | |
177 | FIO.Check_File_Open (AP (File)); | |
178 | return Count (File.Index); | |
179 | end Index; | |
180 | ||
181 | ------------- | |
182 | -- Is_Open -- | |
183 | ------------- | |
184 | ||
185 | function Is_Open (File : in File_Type) return Boolean is | |
186 | begin | |
187 | return FIO.Is_Open (AP (File)); | |
188 | end Is_Open; | |
189 | ||
190 | ---------- | |
191 | -- Mode -- | |
192 | ---------- | |
193 | ||
194 | function Mode (File : in File_Type) return File_Mode is | |
195 | begin | |
196 | return To_SIO (FIO.Mode (AP (File))); | |
197 | end Mode; | |
198 | ||
199 | ---------- | |
200 | -- Name -- | |
201 | ---------- | |
202 | ||
203 | function Name (File : in File_Type) return String is | |
204 | begin | |
205 | return FIO.Name (AP (File)); | |
206 | end Name; | |
207 | ||
208 | ---------- | |
209 | -- Open -- | |
210 | ---------- | |
211 | ||
212 | procedure Open | |
213 | (File : in out File_Type; | |
214 | Mode : in File_Mode; | |
215 | Name : in String; | |
216 | Form : in String := "") | |
217 | is | |
fbf5a39b AC |
218 | Dummy_File_Control_Block : Stream_AFCB; |
219 | pragma Warnings (Off, Dummy_File_Control_Block); | |
220 | -- Yes, we know this is never assigned a value, only the tag | |
221 | -- is used for dispatching purposes, so that's expected. | |
d23b8f57 RK |
222 | |
223 | begin | |
224 | FIO.Open (File_Ptr => AP (File), | |
fbf5a39b | 225 | Dummy_FCB => Dummy_File_Control_Block, |
d23b8f57 RK |
226 | Mode => To_FCB (Mode), |
227 | Name => Name, | |
228 | Form => Form, | |
229 | Amethod => 'S', | |
230 | Creat => False, | |
231 | Text => False); | |
232 | ||
233 | -- Ensure that the stream index is set properly (e.g., for Append_File) | |
234 | ||
235 | Reset (File, Mode); | |
236 | ||
fbf5a39b AC |
237 | -- Set last operation. The purpose here is to ensure proper handling |
238 | -- of the initial operation. In general, a write after a read requires | |
239 | -- resetting and doing a seek, so we set the last operation as Read | |
240 | -- for an In_Out file, but for an Out file we set the last operation | |
241 | -- to Op_Write, since in this case it is not necessary to do a seek | |
242 | -- (and furthermore there are situations (such as the case of writing | |
243 | -- a sequential Posix FIFO file) where the lseek would cause problems. | |
244 | ||
245 | if Mode = Out_File then | |
246 | File.Last_Op := Op_Write; | |
247 | else | |
248 | File.Last_Op := Op_Read; | |
249 | end if; | |
d23b8f57 RK |
250 | end Open; |
251 | ||
252 | ---------- | |
253 | -- Read -- | |
254 | ---------- | |
255 | ||
256 | procedure Read | |
257 | (File : in File_Type; | |
258 | Item : out Stream_Element_Array; | |
259 | Last : out Stream_Element_Offset; | |
260 | From : in Positive_Count) | |
261 | is | |
262 | begin | |
263 | Set_Index (File, From); | |
264 | Read (File, Item, Last); | |
265 | end Read; | |
266 | ||
267 | procedure Read | |
268 | (File : in File_Type; | |
269 | Item : out Stream_Element_Array; | |
270 | Last : out Stream_Element_Offset) | |
271 | is | |
272 | Nread : size_t; | |
273 | ||
274 | begin | |
275 | FIO.Check_Read_Status (AP (File)); | |
276 | ||
277 | -- If last operation was not a read, or if in file sharing mode, | |
278 | -- then reset the physical pointer of the file to match the index | |
279 | -- We lock out task access over the two operations in this case. | |
280 | ||
281 | if File.Last_Op /= Op_Read | |
282 | or else File.Shared_Status = FCB.Yes | |
283 | then | |
d23b8f57 RK |
284 | Locked_Processing : begin |
285 | SSL.Lock_Task.all; | |
286 | Set_Position (File); | |
287 | FIO.Read_Buf (AP (File), Item'Address, Item'Length, Nread); | |
288 | SSL.Unlock_Task.all; | |
289 | ||
290 | exception | |
291 | when others => | |
292 | SSL.Unlock_Task.all; | |
293 | raise; | |
294 | end Locked_Processing; | |
295 | ||
296 | else | |
297 | FIO.Read_Buf (AP (File), Item'Address, Item'Length, Nread); | |
298 | end if; | |
299 | ||
300 | File.Index := File.Index + Count (Nread); | |
301 | Last := Item'First + Stream_Element_Offset (Nread) - 1; | |
302 | File.Last_Op := Op_Read; | |
303 | end Read; | |
304 | ||
305 | -- This version of Read is the primitive operation on the underlying | |
306 | -- Stream type, used when a Stream_IO file is treated as a Stream | |
307 | ||
308 | procedure Read | |
309 | (File : in out Stream_AFCB; | |
310 | Item : out Ada.Streams.Stream_Element_Array; | |
311 | Last : out Ada.Streams.Stream_Element_Offset) | |
312 | is | |
313 | begin | |
314 | Read (File'Unchecked_Access, Item, Last); | |
315 | end Read; | |
316 | ||
317 | ----------- | |
318 | -- Reset -- | |
319 | ----------- | |
320 | ||
321 | procedure Reset (File : in out File_Type; Mode : in File_Mode) is | |
322 | begin | |
323 | FIO.Check_File_Open (AP (File)); | |
324 | ||
325 | -- Reset file index to start of file for read/write cases. For | |
326 | -- the append case, the Set_Mode call repositions the index. | |
327 | ||
328 | File.Index := 1; | |
329 | Set_Mode (File, Mode); | |
330 | end Reset; | |
331 | ||
332 | procedure Reset (File : in out File_Type) is | |
333 | begin | |
334 | Reset (File, To_SIO (File.Mode)); | |
335 | end Reset; | |
336 | ||
337 | --------------- | |
338 | -- Set_Index -- | |
339 | --------------- | |
340 | ||
341 | procedure Set_Index (File : in File_Type; To : in Positive_Count) is | |
342 | begin | |
343 | FIO.Check_File_Open (AP (File)); | |
344 | File.Index := Count (To); | |
345 | File.Last_Op := Op_Other; | |
346 | end Set_Index; | |
347 | ||
348 | -------------- | |
349 | -- Set_Mode -- | |
350 | -------------- | |
351 | ||
352 | procedure Set_Mode (File : in out File_Type; Mode : in File_Mode) is | |
353 | begin | |
354 | FIO.Check_File_Open (AP (File)); | |
355 | ||
356 | -- If we are switching from read to write, or vice versa, and | |
357 | -- we are not already open in update mode, then reopen in update | |
358 | -- mode now. Note that we can use Inout_File as the mode for the | |
359 | -- call since File_IO handles all modes for all file types. | |
360 | ||
361 | if ((File.Mode = FCB.In_File) /= (Mode = In_File)) | |
362 | and then not File.Update_Mode | |
363 | then | |
364 | FIO.Reset (AP (File), FCB.Inout_File); | |
365 | File.Update_Mode := True; | |
366 | end if; | |
367 | ||
368 | -- Set required mode and position to end of file if append mode | |
369 | ||
370 | File.Mode := To_FCB (Mode); | |
371 | FIO.Append_Set (AP (File)); | |
372 | ||
373 | if File.Mode = FCB.Append_File then | |
374 | File.Index := Count (ftell (File.Stream)) + 1; | |
375 | end if; | |
376 | ||
377 | File.Last_Op := Op_Other; | |
378 | end Set_Mode; | |
379 | ||
380 | ------------------ | |
381 | -- Set_Position -- | |
382 | ------------------ | |
383 | ||
384 | procedure Set_Position (File : in File_Type) is | |
385 | begin | |
386 | if fseek (File.Stream, long (File.Index) - 1, SEEK_SET) /= 0 then | |
387 | raise Use_Error; | |
388 | end if; | |
389 | end Set_Position; | |
390 | ||
391 | ---------- | |
392 | -- Size -- | |
393 | ---------- | |
394 | ||
395 | function Size (File : in File_Type) return Count is | |
396 | begin | |
397 | FIO.Check_File_Open (AP (File)); | |
398 | ||
399 | if File.File_Size = -1 then | |
400 | File.Last_Op := Op_Other; | |
401 | ||
402 | if fseek (File.Stream, 0, SEEK_END) /= 0 then | |
403 | raise Device_Error; | |
404 | end if; | |
405 | ||
406 | File.File_Size := Stream_Element_Offset (ftell (File.Stream)); | |
407 | end if; | |
408 | ||
409 | return Count (File.File_Size); | |
410 | end Size; | |
411 | ||
412 | ------------ | |
413 | -- Stream -- | |
414 | ------------ | |
415 | ||
416 | function Stream (File : in File_Type) return Stream_Access is | |
417 | begin | |
418 | FIO.Check_File_Open (AP (File)); | |
419 | return Stream_Access (File); | |
420 | end Stream; | |
421 | ||
422 | ----------- | |
423 | -- Write -- | |
424 | ----------- | |
425 | ||
426 | procedure Write | |
427 | (File : in File_Type; | |
428 | Item : in Stream_Element_Array; | |
429 | To : in Positive_Count) | |
430 | is | |
431 | begin | |
432 | Set_Index (File, To); | |
433 | Write (File, Item); | |
434 | end Write; | |
435 | ||
436 | procedure Write (File : in File_Type; Item : in Stream_Element_Array) is | |
437 | begin | |
438 | FIO.Check_Write_Status (AP (File)); | |
439 | ||
440 | -- If last operation was not a write, or if in file sharing mode, | |
441 | -- then reset the physical pointer of the file to match the index | |
442 | -- We lock out task access over the two operations in this case. | |
443 | ||
444 | if File.Last_Op /= Op_Write | |
445 | or else File.Shared_Status = FCB.Yes | |
446 | then | |
447 | Locked_Processing : begin | |
448 | SSL.Lock_Task.all; | |
449 | Set_Position (File); | |
450 | FIO.Write_Buf (AP (File), Item'Address, Item'Length); | |
451 | SSL.Unlock_Task.all; | |
452 | ||
453 | exception | |
454 | when others => | |
455 | SSL.Unlock_Task.all; | |
456 | raise; | |
457 | end Locked_Processing; | |
458 | ||
459 | else | |
460 | FIO.Write_Buf (AP (File), Item'Address, Item'Length); | |
461 | end if; | |
462 | ||
463 | File.Index := File.Index + Item'Length; | |
464 | File.Last_Op := Op_Write; | |
465 | File.File_Size := -1; | |
466 | end Write; | |
467 | ||
468 | -- This version of Write is the primitive operation on the underlying | |
469 | -- Stream type, used when a Stream_IO file is treated as a Stream | |
470 | ||
471 | procedure Write | |
472 | (File : in out Stream_AFCB; | |
473 | Item : in Ada.Streams.Stream_Element_Array) | |
474 | is | |
475 | begin | |
476 | Write (File'Unchecked_Access, Item); | |
477 | end Write; | |
478 | ||
479 | end Ada.Streams.Stream_IO; |