DataMuseum.dk

Presents historical artifacts from the history of:

Rational R1000/400

This is an automatic "excavation" of a thematic subset of
artifacts from Datamuseum.dk's BitArchive.

See our Wiki for more about Rational R1000/400

Excavated with: AutoArchaeologist - Free & Open Source Software.


top - download

⟦9c023e49c⟧ Ada Source

    Length: 28672 (0x7000)
    Types: Ada Source
    Notes: 03_class, FILE, R1k_Segment, e3_tag, package body File_Support, seg_04b932

Derivation

└─⟦8527c1e9b⟧ Bits:30000544 8mm tape, Rational 1000, Arrival backup of disks in PAM's R1000
    └─ ⟦cfc2e13cd⟧ »Space Info Vol 2« 
        └─⟦this⟧ 

E3 Source Code



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;

E3 Meta Data

    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