|
DataMuseum.dkPresents historical artifacts from the history of: Rational R1000/400 |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about Rational R1000/400 Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - download
Length: 28672 (0x7000) Types: Ada Source Notes: 03_class, FILE, R1k_Segment, e3_tag, package body File_Support, seg_04b932
└─⟦8527c1e9b⟧ Bits:30000544 8mm tape, Rational 1000, Arrival backup of disks in PAM's R1000 └─ ⟦cfc2e13cd⟧ »Space Info Vol 2« └─⟦this⟧
with System; use System; with Io_Exceptions; use Io_Exceptions; with Os_Files; use Os_Files; with A_Strings; use A_Strings; with Close_All; with Unchecked_Deallocation; with Unchecked_Conversion; with Safe_Support; with Ada_Krn_I; with Ada_Krn_Defs; pragma Elaborate (Io_Exceptions, Os_Files); package body File_Support is pragma Suppress (Access_Check); pragma Suppress (Discriminant_Check); pragma Suppress (Index_Check); pragma Suppress (Length_Check); pragma Suppress (Range_Check); pragma Suppress (Division_Check); pragma Suppress (Overflow_Check); -- NOTE: to inhibit mutex deadlock, when file_support is locked, -- no file can be locked. After doing a file_support_lock(), file_lock() -- is called in check_file_already_open(). Char_Size : constant := Character'Size / 8; -- Access to buffer_pool must be protected via -- safe_support.file_support_lock(). Buffer_Pool : array (0 .. 4) of Access_Bytes; Open_Modes : constant array (File_Mode) of Open_Flags := (Input => O_Rdonly, Output => O_Wronly, In_Out => O_Rdwr); procedure Free is new Unchecked_Deallocation (File_Record, File_Ptr); procedure Free is new Unchecked_Deallocation (String_Rec, A_String); function To_Long_Addr is new Unchecked_Conversion (Address, Long_Address); -- Upon entry/exit: file is unlocked procedure Free_File (F : in out File_Ptr) is Other_Fd : File_Ptr; begin if F = null or else F.Style = Special then return; end if; Safe_Support.File_Support_Lock; -- protect linked list of files Other_Fd := File_List; F.File_Id := Invalid; if F = Other_Fd then File_List := F.Next; else while Other_Fd /= null loop if Other_Fd.Next = F then Other_Fd.Next := F.Next; exit; end if; Other_Fd := Other_Fd.Next; end loop; end if; Safe_Support.File_Support_Unlock; Safe_Support.File_Mutex_Destroy (F); if F.Name /= null then Free (F.Name); end if; if F.Form /= null then Free (F.Form); end if; Free (F); end Free_File; procedure Put_Buffer (B : in out Access_Bytes) is procedure Free is new Unchecked_Deallocation (Buffer_Rec, Access_Bytes); begin Safe_Support.File_Support_Lock; -- protect buffer pool for I in Buffer_Pool'Range loop if Buffer_Pool (I) = null then Buffer_Pool (I) := B; Safe_Support.File_Support_Unlock; return; end if; end loop; Safe_Support.File_Support_Unlock; Free (B); end Put_Buffer; function Get_Buffer (Size : Integer) return Access_Bytes is B : Access_Bytes; begin Safe_Support.File_Support_Lock; -- protect buffer pool for I in Buffer_Pool'Range loop if Buffer_Pool (I) /= null then if Buffer_Pool (I).Size = Size then B := Buffer_Pool (I); Buffer_Pool (I) := null; Safe_Support.File_Support_Unlock; return B; end if; end if; end loop; Safe_Support.File_Support_Unlock; return new Buffer_Rec (Size); end Get_Buffer; procedure Write_Buffer (File : File_Ptr); -- Upon entry/exit: file_support is locked, the file is unlocked. -- Also upon entry, the file being opened hasn't been added to the -- file list. procedure Check_File_Already_Open (File : File_Ptr) is Other_Fd : File_Ptr; begin if File.File_Id = Invalid then return; end if; -- cross-io may try to reopen stdin & stdout-- if File.Style = Special then return; end if; Other_Fd := File_List; while (Other_Fd /= null) loop if Same_Id (File.File_Id, Other_Fd.File_Id) then begin Safe_Support.File_Lock (Other_Fd); if not Flushable (Other_Fd.Fd) or else not Flushable (File.Fd) then raise Use_Error; end if; if Other_Fd.Mode = Input then if Other_Fd.Pos /= Unknown and then File.Mode /= Input then raise Use_Error; end if; elsif Other_Fd.Out_Ptr /= -1 then Write_Buffer (Other_Fd); end if; Other_Fd.Always_Flush := True; File.Always_Flush := True; Safe_Support.File_Unlock (Other_Fd); exception when others => Safe_Support.File_Unlock (Other_Fd); raise; end; end if; Other_Fd := Other_Fd.Next; end loop; end Check_File_Already_Open; -- Upon exit: the file is unlocked procedure File_Open (Name : String := ""; File : in out File_Ptr; Mode : File_Mode := In_Out; Create : Boolean := False; Form : String := ""; Style : File_Styles := Text; Record_Size : Integer := 0) is Temp : Name_String; Len : Integer := 0; Open_Mode : Open_Flags; This_Name : A_String; This_Form : A_String; Is_Temp : Boolean := Name'Length = 0; begin if File /= null then raise Status_Error; end if; -- -- a null string is used to create a temporary file\x09 -- if Is_Temp and then not Create then raise Name_Error; end if; This_Name := Get_Full_Name (Name, Style); if Form = "" then This_Form := null; else This_Form := new String_Rec (Form'Length); This_Form.S := Form; end if; Open_Mode := Open_Modes (Mode); if Create then Open_Mode := Open_Mode + O_Creat + O_Trunc; elsif Style /= Direct and Mode /= Input then Open_Mode := Open_Mode + O_Trunc; end if; File := new File_Record; if not Safe_Support.File_Mutex_Init (File) then raise Storage_Error; end if; File.Fd := File_Descriptor (0); File.Name := This_Name; File.Mode := Mode; File.Form := This_Form; File.Style := Style; File.Resetable := True; File.Index := 1; File.Linelength := Record_Size; File.Pagelength := 0; File.Line := 1; File.Page := 1; File.Pos := Unknown; File.Delete := Is_Temp; File.File_Id := Invalid; File.Eof_Char := Ascii.Eot; File.Test_Eof := False; File.Buffer := null; File.Last := -1; File.Last_Lf := -1; File.In_Ptr := -1; File.Out_Ptr := -1; File.Always_Flush := Os_Files.Always_Flush_Files; File.Want_Ff := False; --\x09\x09file.next\x09\x09-- initialized below --\x09\x09file.mutex\x09\x09-- initialized above by safe_support.file_mutex_init() -- we now have an initialized file that can be free_file()'ed begin Safe_Support.File_Support_Lock; Open (File.all'Long_Address, Style, Open_Mode); Check_File_Already_Open (File); -- for acvc ce3208a: -- AS A RESULT OF AI-00048, OPENING A FILE WITH IN_FILE MODE WHICH -- IS THE DEFAULT OUTPUT FILE WILL RAISE MODE_ERROR, and vice-versa. if Mode /= Input and then Same_Id (File.File_Id, Cur_Input_Id) and then Name /= Os_Files.Std_Error_Name and then Name /= Os_Files.Std_Output_Name then raise Mode_Error; end if; if Mode /= Output and then Same_Id (File.File_Id, Cur_Output_Id) and then Name /= Os_Files.Std_Input_Name then raise Mode_Error; end if; -- Add just opened file to list of files File.Next := File_List; File_List := File; Safe_Support.File_Support_Unlock; exception when others => Safe_Support.File_Support_Unlock; if File.Fd /= File_Descriptor (0) then Close (File.Fd); end if; Free_File (File); raise; end; end File_Open; -- Upon entry: file is locked -- Upon exit: file is unlocked procedure File_Close (File : in out File_Ptr) is begin if File = null then raise Status_Error; -- we better not be locked end if; begin Free_File_Id (File.File_Id); if File.Mode /= Input then Flush (File); end if; Close (File.Fd); if File.Delete then Delete (File.Fd, File.Name); end if; File.File_Id := Invalid; Safe_Support.File_Unlock (File); exception when others => Safe_Support.File_Unlock (File); raise; end; -- put_buffer does a file_support_lock(). Therefore, file must -- be unlocked before it is called. Put_Buffer (File.Buffer); Free_File (File); end File_Close; -- Since we are called from a program exit callout, don't do any -- locks or frees. procedure File_Close_Upon_Exit (File : File_Ptr) is begin if File.Mode /= Input then Flush (File); end if; Close (File.Fd); if File.Delete then Delete (File.Fd, File.Name); end if; end File_Close_Upon_Exit; -- Upon entry/exit: --\x09when called from setup_buffer() => file is unlocked. --\x09when called from file_reset() => file is locked. procedure Setup_Buffer_Ptrs (File : File_Ptr) is begin if File.Style = Text or else File.Style = Special then File.Last := File.Buffer.Size; File.In_Ptr := File.Last; -- for use by lookaheads for tstfile_beyond_eol File.Buffer.Elem (0) := Ascii.Lf; if File.Mode = Output then File.Out_Ptr := 0; else File.Out_Ptr := File.In_Ptr; end if; File.Last_Lf := File.Out_Ptr; end if; end Setup_Buffer_Ptrs; -- Upon entry/exit: file is unlocked. procedure Setup_Buffer (File : File_Ptr; Size : Natural) is begin -- get_buffer does a file_support_lock() File.Buffer := Get_Buffer (Size); Setup_Buffer_Ptrs (File); end Setup_Buffer; -- Upon entry: file is locked -- Upon exit: file is unlocked procedure File_Delete (File : in out File_Ptr) is begin if File = null then raise Status_Error; -- better not be locked end if; begin Free_File_Id (File.File_Id); Close (File.Fd); if File.Name /= null then Delete (File.Fd, File.Name); end if; File.File_Id := Invalid; Safe_Support.File_Unlock (File); exception when others => Safe_Support.File_Unlock (File); raise; end; -- put_buffer does a file_support_lock(). Therefore, file must -- be unlocked before it is called. Put_Buffer (File.Buffer); Free_File (File); end File_Delete; -- Upon entry/exit: file is locked procedure File_Reset (File : in out File_Ptr; Mode : File_Mode) is Open_Mode : Open_Flags := Open_Modes (Mode); begin if File.Mode /= Input then Flush (File); end if; Close (File.Fd); File.Mode := Mode; File.Index := 1; File.Line := 1; File.Page := 1; File.Pos := Unknown; File.File_Id := Invalid; Open (File.all'Long_Address, File.Style, Open_Mode); if (File.Out_Ptr /= -1) then Setup_Buffer_Ptrs (File); end if; end File_Reset; -- Upon entry/exit: file is locked function Input_Col (File : File_Ptr) return Natural is begin return File.In_Ptr - File.Last_Lf + 1; end Input_Col; -- Upon entry/exit: file is locked function Output_Col (File : File_Ptr) return Natural is begin return File.Out_Ptr - File.Last_Lf + 1; end Output_Col; -- Upon entry/exit: file is locked function File_Eof (File : in File_Ptr) return Boolean is begin return At_End_Of_File (File.Fd); end File_Eof; -- Upon entry/exit: file is locked procedure Write_Buffer (File : File_Ptr) is Desired : Integer; Last_Out : Integer; begin if (Ok_To_Write (File.all'Long_Address)) then Last_Out := File.Out_Ptr; File.Out_Ptr := 0; Desired := Last_Out - File.Out_Ptr; File.Last_Lf := File.Last_Lf - Desired; Write (File.Fd, File.Buffer.Elem (File.Out_Ptr + 1)'Long_Address, Desired * Char_Size); elsif File.Out_Ptr >= File.Last then -- truncate buffer so file can be closed File.Out_Ptr := File.Last; File.Buffer.Elem (File.Out_Ptr) := Ascii.Lf; raise Device_Error; end if; end Write_Buffer; -- Upon entry/exit: file is locked procedure Putchar (File : File_Ptr; Char : Character) is begin if File.Out_Ptr >= File.Last then Write_Buffer (File); end if; File.Out_Ptr := File.Out_Ptr + 1; File.Buffer.Elem (File.Out_Ptr) := Char; if Char = Ascii.Ff then if Output_Col (File) = 2 then -- already incremented File.Line := 1; File.Page := File.Page + 1; File.Last_Lf := File.Out_Ptr; end if; elsif Char = Ascii.Lf then File.Last_Lf := File.Out_Ptr; Write_Buffer (File); File.Line := File.Line + 1; if File.Pagelength /= 0 and then File.Line > File.Pagelength then Putchar (File, Ascii.Ff); end if; else if File.Linelength /= 0 and then Output_Col (File) > File.Linelength + 1 then File.Out_Ptr := File.Out_Ptr - 1; Putchar (File, Ascii.Lf); Putchar (File, Char); end if; end if; end Putchar; -- Upon entry/exit: file is locked procedure Perform_Buffer_Read (File : File_Ptr) is Actual : Integer; Next : Integer := File.Last + 1; begin Actual := Read (File.Fd, File.Buffer.Elem (Next)'Long_Address, Char_Size * (File.Buffer.Size - File.Last)) / Char_Size; if File.Last = 0 then File.In_Ptr := 0; else File.In_Ptr := 1; end if; File.Last := File.Last + Actual; Fix_End_Of_Record (File.all'Long_Address, Actual); if Actual > 0 then if File.Test_Eof and then File.Buffer.Elem (Next) = File.Eof_Char then raise End_Error; end if; return; elsif Actual = 0 then if Is_Interactive (File.Fd) then File.Test_Eof := True; File.Buffer.Elem (Next) := File.Eof_Char; end if; raise End_Error; else raise Device_Error; end if; end Perform_Buffer_Read; -- -- refill_buffer exists so that if there are only a few characters left -- in a buffer more characters can be read in before doing a get of -- a real or integer. If there are less than 100 characters in the -- buffer and no end of line markers in the buffer the data at the -- end of the buffer is moved to the front and another read performed. -- This will only happen for disc files. -- -- Upon entry/exit: file is locked procedure Refill_Buffer (File : File_Ptr) is Size_In_Bytes : Natural; begin if File.In_Ptr + 100 < File.Last then return; end if; for I in File.In_Ptr + 1 .. File.Last loop if File.Buffer.Elem (I) = Ascii.Lf then return; end if; end loop; Size_In_Bytes := File.Last - File.In_Ptr + 1; File.Buffer.Elem (1 .. Size_In_Bytes) := File.Buffer.Elem (File.In_Ptr .. File.Last); File.Last_Lf := File.Last_Lf - File.Last + Size_In_Bytes; File.Last := Size_In_Bytes; Perform_Buffer_Read (File); end Refill_Buffer; -- Upon entry/exit: file is locked procedure Read_Buffer (File : File_Ptr) is Actual : Integer; begin if File.Test_Eof and then File.Buffer.Elem (1) = File.Eof_Char then raise End_Error; end if; File.Last_Lf := File.Last_Lf - File.Last; File.Last := 0; Perform_Buffer_Read (File); end Read_Buffer; -- Upon entry/exit: file is locked function Getchar (File : File_Ptr) return Character is C : Character; begin if File = null then raise Status_Error; end if; loop if File.In_Ptr >= File.Last then if File.Mode /= Input then raise Mode_Error; end if; if File.Pos = At_Eof then raise End_Error; end if; begin Read_Buffer (File); exception when End_Error => if File.Pos = Unknown then File.Pos := At_Delayed_Eol; end if; File.Pos := Tstfile (File); -- set page, etc. return ' '; end; end if; File.In_Ptr := File.In_Ptr + 1; C := File.Buffer.Elem (File.In_Ptr); if C = Ascii.Lf then File.Line := File.Line + 1; File.Pos := At_Delayed_Eol; File.Last_Lf := File.In_Ptr; return ' '; elsif C /= Ascii.Ff then File.Pos := At_Char; return C; elsif File.Pos = At_Delayed_Eol then -- this ff is considered to be "part" of the previous lf; -- together, they make up a page_terminator. File.Last_Lf := File.In_Ptr; -- considered part of lf File.Line := 1; File.Page := File.Page + 1; else File.Pos := At_Char; return C; end if; end loop; end Getchar; -- get the NEXT file_pos that we're going to see for "file" -- -- Upon entry/exit: file is locked function Tstfile (File : File_Ptr) return File_Pos is C : Character; begin if File.In_Ptr >= File.Last then if File.Mode /= Input then raise Mode_Error; end if; if File.Pos = At_Eof then return At_Eof; end if; begin Read_Buffer (File); exception when End_Error => if File.Pos /= Unknown then if File.Pos /= At_Eop then File.Line := 1; File.Page := File.Page + 1; end if; File.Last_Lf := File.In_Ptr; -- set col to 1 File.Pos := At_Eof; end if; return At_Eof; end; end if; C := File.Buffer.Elem (File.In_Ptr + 1); if C = Ascii.Ff and then File.Pos = At_Delayed_Eol then File.Line := 1; File.Page := File.Page + 1; File.Pos := At_Eop; File.In_Ptr := File.In_Ptr + 1; -- consume the ff File.Last_Lf := File.In_Ptr; -- considered part of lf -- want form feed in the string, if want_ff flag is set in the file. if File.Want_Ff then File.In_Ptr := File.In_Ptr - 1; return At_Char; end if; return Tstfile (File); end if; if C = Ascii.Lf then return At_Delayed_Eol; else return At_Char; end if; end Tstfile; -- if we will next read an ascii.lf, then if the character that follows -- is an ascii.ff then the two behave as one character, called a -- page_terminator. This routine looks at the next two characters (maybe -- forcing a read of the next input line) and returns at_eol, at_eop, -- or at_eof as appropriate. It puts everything back as it -- was, except, of course, that the next line is now in the buffer. Note -- that elem(0), which contains an ascii.lf, may be used to simulate the -- last character from the previous buffer. -- -- Upon entry/exit: file is locked function Tstfile_Beyond_Eol (File : File_Ptr) return File_Pos is C : Character; Pos : File_Pos := Tstfile (File); begin if Pos = At_Eof then return At_Eof; end if; if Pos = At_Delayed_Eol then if File.In_Ptr + 1 >= File.Last then begin Read_Buffer (File); exception when End_Error => File.In_Ptr := File.In_Ptr - 1; -- push back the elem(0) lf --file.last := file.last - 1; return At_Eof; end; File.In_Ptr := File.In_Ptr - 1; -- push back the elem(0) lf end if; -- look past the ascii.lf for an ascii.ff if File.Buffer.Elem (File.In_Ptr + 2) /= Ascii.Ff then return At_Eol; end if; -- at end-of-file? if File.In_Ptr + 2 >= File.Last then if At_End_Of_File (File.Fd) then return At_Eof; end if; end if; return At_Eop; end if; return Pos; end Tstfile_Beyond_Eol; -- Upon entry/exit: file is locked procedure Skip_Past_Eol (File : File_Ptr) is Void : Character; Void_Pos : File_Pos := Tstfile (File); begin loop if File.In_Ptr >= File.Last then begin Read_Buffer (File); exception when End_Error => if File.Pos = Unknown then File.Pos := At_Eof; return; end if; Void := Getchar (File); -- set line, etc. reraise end; end if; File.In_Ptr := File.In_Ptr + 1; exit when File.Buffer.Elem (File.In_Ptr) = Ascii.Lf; end loop; File.In_Ptr := File.In_Ptr - 1; Void := Getchar (File); end Skip_Past_Eol; -- Upon entry/exit: file is locked procedure Always_Flush (File : File_Ptr) is begin File.Always_Flush := True; Flush (File); end Always_Flush; -- Want text_io.get_line to return any ff's in the returned string. -- Upon entry/exit: file is locked procedure Want_Ff (File : File_Ptr) is begin if File = null then raise Status_Error; end if; File.Want_Ff := True; end Want_Ff; -- Upon entry/exit: file is locked procedure Flush (File : File_Ptr) is begin if File = null then raise Status_Error; end if; if File.Out_Ptr = -1 then return; end if; if File.Mode /= Output then raise Mode_Error; end if; Write_Buffer (File_Ptr (File)); end Flush; -- Upon entry/exit: file is locked procedure Set_Buffer_Size (File : File_Ptr; Size : Natural) is begin if File = null then raise Status_Error; end if; null; end Set_Buffer_Size; -- Upon entry/exit: file is locked procedure Set_Eof_Char (File : File_Ptr; Eof_Char : Character := Ascii.Eot) is begin if File = null then raise Status_Error; end if; if File.Mode /= Input then raise Mode_Error; end if; File.Eof_Char := Eof_Char; File.Test_Eof := True; end Set_Eof_Char; procedure Write_To_Stderr (Message : String) is begin Write (Stderr_Fd, Message'Long_Address, Message'Length * Char_Size); end Write_To_Stderr; function Read (Fd : File_Descriptor; Addr : System.Address; Cnt : Integer) return Integer is begin return Read (Fd, To_Long_Addr (Addr), Cnt); end Read; procedure Write (Fd : File_Descriptor; Addr : System.Address; Cnt : Integer) is begin Write (Fd, To_Long_Addr (Addr), Cnt); end Write; begin declare Result : Boolean; begin Result := Ada_Krn_I.Callout_Install (Ada_Krn_Defs.Exit_Event, Close_All'Address); end; end File_Support;
nblk1=1b nid=0 hdr6=36 [0x00] rec0=25 rec1=00 rec2=01 rec3=02c [0x01] rec0=1a rec1=00 rec2=02 rec3=032 [0x02] rec0=20 rec1=00 rec2=03 rec3=06a [0x03] rec0=1c rec1=00 rec2=04 rec3=01e [0x04] rec0=19 rec1=00 rec2=05 rec3=040 [0x05] rec0=1b rec1=00 rec2=06 rec3=00e [0x06] rec0=22 rec1=00 rec2=07 rec3=00c [0x07] rec0=1c rec1=00 rec2=08 rec3=000 [0x08] rec0=16 rec1=00 rec2=09 rec3=060 [0x09] rec0=22 rec1=00 rec2=0a rec3=02c [0x0a] rec0=1c rec1=00 rec2=0b rec3=008 [0x0b] rec0=1e rec1=00 rec2=0c rec3=012 [0x0c] rec0=1e rec1=00 rec2=0d rec3=048 [0x0d] rec0=20 rec1=00 rec2=0e rec3=044 [0x0e] rec0=1a rec1=00 rec2=0f rec3=03e [0x0f] rec0=1c rec1=00 rec2=10 rec3=018 [0x10] rec0=1b rec1=00 rec2=11 rec3=018 [0x11] rec0=1b rec1=00 rec2=12 rec3=036 [0x12] rec0=1d rec1=00 rec2=13 rec3=036 [0x13] rec0=18 rec1=00 rec2=14 rec3=026 [0x14] rec0=1d rec1=00 rec2=15 rec3=024 [0x15] rec0=1a rec1=00 rec2=16 rec3=030 [0x16] rec0=16 rec1=00 rec2=17 rec3=066 [0x17] rec0=1d rec1=00 rec2=18 rec3=008 [0x18] rec0=1c rec1=00 rec2=19 rec3=01c [0x19] rec0=24 rec1=00 rec2=1a rec3=00a [0x1a] rec0=22 rec1=00 rec2=1b rec3=000 tail 0x21750b81c868434ddbb61 0x42a00088462060003