DataMuseum.dk

Presents historical artifacts from the history of:

Rational R1000/400 Tapes

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 Tapes

Excavated with: AutoArchaeologist - Free & Open Source Software.


top - download
Index: ┃ B T

⟦80c36058d⟧ TextFile

    Length: 36973 (0x906d)
    Types: TextFile
    Names: »B«

Derivation

└─⟦afbc8121e⟧ Bits:30000532 8mm tape, Rational 1000, MC68020_OS2000 7_2_2
    └─ ⟦77aa8350c⟧ »DATA« 
        └─⟦f794ecd1d⟧ 
            └─⟦4c85d69e2⟧ 
                └─⟦this⟧ 

TextFile

--    The use of this system is subject to the software license terms and
--    conditions agreed upon between Rational and the Customer.
--
--                Copyright 1988 by Rational.
--
--                          RESTRICTED RIGHTS LEGEND
--
--    Use, duplication, or disclosure by the Government is subject to
--    restrictions as set forth in subdivision (b)(3)(ii) of the Rights in
--    Technical Data and Computer Software clause at 52.227-7013.
--
--
--                Rational
--                3320 Scott Boulevard
--                Santa Clara, California 95054-3197
--
--   PROPRIETARY AND CONFIDENTIAL INFORMATION OF RATIONAL;
--   USE OR COPYING WITHOUT EXPRESS WRITTEN AUTHORIZATION
--   IS STRICTLY PROHIBITED.  THIS MATERIAL IS PROTECTED AS
--   AN UNPUBLISHED WORK UNDER THE U.S. COPYRIGHT ACT OF
--   1976.  CREATED 1988.  ALL RIGHTS RESERVED.
--
--

with Os2000_Io;
with Buffering;
with Primitive_Io;
with Io_Exceptions;
with Io_Exception_Flavors;
with Unchecked_Deallocation;
with Unchecked_Conversion;

package body Os_Dependent_Io is

    package Dio renames Device_Independent_Io;

    function "=" (X, Y : File_Kind) return Boolean renames Dio."=";
    function "=" (X, Y : File_Mode) return Boolean renames Dio."=";

    function "=" (X, Y : Os2000_Io.Path_Number) return Boolean
        renames Os2000_Io."=";

    subtype Byte is System_Types.Byte;

    function "=" (X, Y : Byte) return Boolean renames System_Types."=";

    subtype User_Kind     is File_Kind range Dio.Normal .. Dio.Temporary;
    subtype Standard_Kind is File_Kind
                                range Dio.Standard_Input .. Dio.Standard_Error;

    subtype String_Ptr is System_Types.Acc_Str;
    function "=" (X, Y : String_Ptr) return Boolean renames System_Types."=";

    Ptr_To_Empty : constant String_Ptr := new String'("");


    function Cnvt is new Unchecked_Conversion
                            (Source => String_Ptr, Target => Integer);

    type A is array (1 .. 6) of Integer;
    type T is access A;

    function Revt is new Unchecked_Conversion (Source => Integer, Target => T);

    function Convert_Control_Block_To_Address is
       new Unchecked_Conversion (Source => Os_Control_Block,
                                 Target => System.Address);

    function Convert_Address_To_Control_Block is
       new Unchecked_Conversion (Source => System.Address,
                                 Target => Os_Control_Block);

    package User is

        type Id is private;

        function Get_Current_Key return Id;
        pragma Suppress (Elaboration_Check, Get_Current_Key);

        function Not_Current (Key : Id) return Boolean;
        pragma Suppress (Elaboration_Check, Not_Current);

        function Less_Than (X, Y : Id) return Boolean;
        pragma Suppress (Elaboration_Check, Less_Than);
        function "<" (X, Y : Id) return Boolean renames Less_Than;

        function Image (Key : Id) return String;
        pragma Suppress (Elaboration_Check, Image);

    private

        type Id is
            record
                Value1 : Integer;
                Value2 : Integer;
                Value3 : Integer;
            end record;

    end User;

    function "=" (X, Y : User.Id) return Boolean renames User."=";


    type User_Node;

    type User_Link is access User_Node;

    type User_Node is
        record
            Key  : User.Id;
            Path : Os2000_Io.Path_Number;
            Next : User_Link;
        end record;


    type Control_Block (For_Kind : File_Kind := Device_Independent_Io.Normal) is
        record
            Path           : Os2000_Io.Path_Number;
            Is_Interactive : Boolean;
            Last_Key       : User.Id;
            Position       : Os2000_Io.File_Position;
            User_List      : User_Link;

            case For_Kind is
                when User_Kind =>
                    Name      : String_Ptr; -- external name, null terminated
                    Form      : String_Ptr; -- external form
                    Mode_Bits : Natural;

                when Standard_Kind =>
                    null;
            end case;
        end record;

    -- type Io_Operation is (Create_Op, Open_Op, Close_Op, Delete_Op,
    --                       Read_Op, Readln_Op, Write_Op, Seek_Op,
    --                       Get_Pos_Op, Eof_Op, Size_Op, Get_Option_Op);

    type Io_Operation is new Integer;

    Create_Op     : constant Io_Operation := 0;
    Open_Op       : constant Io_Operation := 1;
    Close_Op      : constant Io_Operation := 2;
    Delete_Op     : constant Io_Operation := 3;
    Read_Op       : constant Io_Operation := 4;
    Readln_Op     : constant Io_Operation := 5;
    Write_Op      : constant Io_Operation := 6;
    Seek_Op       : constant Io_Operation := 7;
    Get_Pos_Op    : constant Io_Operation := 8;
    Eof_Op        : constant Io_Operation := 9;
    Size_Op       : constant Io_Operation := 10;
    Get_Option_Op : constant Io_Operation := 11;

    subtype Access_Op is Io_Operation range Create_Op .. Open_Op;

    Null_Path : constant Os2000_Io.Path_Number := Os2000_Io.Standard_Error;

    Interactive_Buffer_Size : constant Natural := 400;
    -- large enough to hold max size enum literal plus reasonable formatting

    package Unique_Temp_Name is

        function Get return String;
        pragma Suppress (Elaboration_Check, Get);

    end Unique_Temp_Name;

    procedure Convert_Error (Status : Os2000_Io.Stratus; In_Op : Io_Operation);
    pragma Suppress (Elaboration_Check, Convert_Error);


    package Form_Handling is

        type Option is (Non_Sharable, Sharable);

        -- The only values currently supported for the Form parameter are:
        --
        --   NON_SHARABLE - Causes the file to be accessed in single-user
        --                  mode; default for Out and Inout mode.
        --   SHARABLE     - Causes the file to be accessed for sharable
        --                  use; default for In mode.

        function Sharable (Form : String; Mode : Dio.File_Mode) return Boolean;

        function Default_Image
                    (Form : String; Mode_Bits : Natural) return String;

    end Form_Handling;


    procedure Free is new Unchecked_Deallocation
                             (Control_Block, Os_Control_Block);
    procedure Free is new Unchecked_Deallocation (User_Node, User_Link);
    procedure Free is new Unchecked_Deallocation (String, String_Ptr);

    -- procedure Trace
    --              (S : String;
    --               Absorb_Output : Boolean := Primitive_Io.Global_Absorb_Output)
    --     renames Primitive_Io.Put_Line;

    Delete_Temp_Files : Boolean renames Primitive_Io.Global_Absorb_Output;

    package body User is separate;

    package body Unique_Temp_Name is separate;

    package body Form_Handling is separate;

    procedure Convert_Error (Status : Os2000_Io.Stratus;
                             In_Op  : Io_Operation) is separate;

    procedure Release (Tree : in out User_Link) is
        Next : User_Link := Tree;
        Temp : User_Link;
    begin
        while Next /= null loop
            Temp := Next.Next;
            Free (Next);
            Next := Temp;
        end loop;
    end Release;

    procedure Release (Cb : in out Os_Control_Block) is
    begin
        if Cb /= null then
            -- Trace ("Odi.Release - release user tree");
            Release (Cb.User_List);
            case Cb.For_Kind is
                when User_Kind =>
                    -- Trace ("Odi.Release - free name");
                    Free (Cb.Name);
                    if Cb.Form /= Ptr_To_Empty then
                        -- Trace ("Odi.Release - free form");
                        Free (Cb.Form);
                    end if;

                when Standard_Kind =>
                    null;
            end case;

            Free (Cb);
        end if;
    end Release;

    function Compute_Mode_Bits
                (Mode : File_Mode; Form : String) return Natural is
        Bits : Natural;
    begin
        case Mode is
            when Dio.Closed =>
                return 0;
            when Dio.In_File =>
                Bits := Os2000_Io.Read_Mode;
            when Dio.Inout_File =>
                Bits := Os2000_Io.Update_Mode;
            when Dio.Out_File =>
                Bits := Os2000_Io.Write_Mode;
        end case;

        if Form_Handling.Sharable (Form, Mode) then
            return Bits;
        else
            -- Due to record locking in OS9 2.1, an attempts
            -- to use a file when another process has it open
            -- for write will hang; so making it Single_User will
            -- cause Use_Error when the second process opens it.
            return Bits + Os2000_Io.Single_User;
        end if;
    end Compute_Mode_Bits;

    function Compute_Attribute_Bits
                (Mode : File_Mode; Form : String) return Natural is
    begin
        return Os2000_Io.Updatable + Os2000_Io.Public_Updatable;  
    end Compute_Attribute_Bits;

    function Initial_Control_Block
                (Name      : String;
                 Form      : String;
                 Kind      : File_Kind;
                 Mode_Bits : Natural) return Os_Control_Block is
        New_Cb : Os_Control_Block;
        My_Key : User.Id := User.Get_Current_Key;
    begin
        -- Trace ("Odi.Initial_Control_Block");
        New_Cb := new Control_Block (For_Kind => Kind);

        New_Cb.Path      := Null_Path;
        New_Cb.Last_Key  := My_Key;
        New_Cb.User_List :=
           new User_Node'(Key => My_Key, Path => Null_Path, Next => null);
        New_Cb.Position  := Os2000_Io.Null_Position;

        case Kind is
            when User_Kind =>
                -- Trace ("Odi.Initial_Control_Block - allocating name");
                New_Cb.Name := new String'(Name & Ascii.Nul);
                if Form'Length > 0 then
                    New_Cb.Form := new String'(Form);
                else
                    New_Cb.Form := Ptr_To_Empty;
                end if;
                New_Cb.Mode_Bits := Mode_Bits;

            when Dio.Standard_Input =>
                New_Cb.Path := Os2000_Io.Standard_In;

            when Dio.Standard_Output =>
                New_Cb.Path := Os2000_Io.Standard_Out;

            when Dio.Standard_Error =>
                New_Cb.Path := Os2000_Io.Standard_Error;
        end case;

        -- Trace ("Odi.Initial_Control_Block - successful");
        return New_Cb;
    exception
        when Storage_Error =>
            -- Trace ("Odi.Initial_Control_Block - Storage_Error");
            Release (New_Cb);
            raise Storage_Error;
    end Initial_Control_Block;


    function Strip_Nul (S : String) return String is
    begin
        return S (S'First .. S'Last - 1);
    end Strip_Nul;


    procedure Set_Initial_Path (Ctrl : Os_Control_Block;
                                Path : Os2000_Io.Path_Number) is
    begin
        Ctrl.Path           := Path;
        Ctrl.User_List.Path := Path;
    end Set_Initial_Path;


    procedure Set_Interactive (Ctrl : Os_Control_Block) is
        Option_Buffer : Byte_String (1 .. 128);
        Result        : Os2000_Io.Stratus;

        Class_Index : constant Natural := 1;
        -- device class is first byte of option table
        Scf_Class : constant Byte := 0; -- sequential character
        Rbf_Class : constant Byte := 1; -- random block
        Pip_Class : constant Byte := 2; -- pipes
        Sbf_Class : constant Byte := 3; -- sequential block
        Net_Class : constant Byte := 4; -- network
    begin
        -- Trace ("Odi.Set_Interactive");
        Os2000_Io.Get_Options (Ctrl.Path, Option_Buffer (1)'Address, Result);

        if Result = Os2000_Io.E_Success then
            case Option_Buffer (Class_Index) is
                when Scf_Class | Pip_Class =>
                    Ctrl.Is_Interactive := True;

                when Rbf_Class | Sbf_Class | Net_Class =>
                    Ctrl.Is_Interactive := False;

                when others =>
                    -- unknown device type; best to treat as non-interactive
                    Ctrl.Is_Interactive := False;
            end case;
        else
            Convert_Error (Result, In_Op => Get_Option_Op);
        end if;
    end Set_Interactive;


    procedure Access_File (Name   :     String;
                           Form   :     String;
                           Mode   :     File_Mode;
                           Kind   :     File_Kind;
                           For_Op :     Access_Op;
                           Ctrl   : out Os_Control_Block) is
        New_Cb   : Os_Control_Block;
        New_Path : Os2000_Io.Path_Number;
        Result   : Os2000_Io.Stratus;
    begin
        -- Trace ("Odi.Access_File, name is " & Name);

        New_Cb := Initial_Control_Block
                     (Name      => Name,
                      Form      => Form,
                      Kind      => Kind,
                      Mode_Bits => Compute_Mode_Bits (Mode, Form));

        case For_Op is
            when Create_Op =>
                Os2000_Io.Create
                   (Name => New_Cb.Name.all (New_Cb.Name.all'First)'Address,
                    Mode => New_Cb.Mode_Bits,
                    Attributes => Compute_Attribute_Bits (Mode, Form),
                    New_Path => New_Path,
                    Result => Result);

            when Open_Op =>
                Os2000_Io.Open
                   (Name     => New_Cb.Name.all (New_Cb.Name.all'First)'Address,
                    Mode     => New_Cb.Mode_Bits,
                    New_Path => New_Path,
                    Result   => Result);
        end case;

        if Result = Os2000_Io.E_Success then
            Set_Initial_Path (New_Cb, New_Path);  
            Set_Interactive (New_Cb);
            Ctrl := New_Cb;
            -- Trace ("Odi.Access_File - successful");
        else
            Release (New_Cb);
            Convert_Error (Result, In_Op => For_Op);
            -- ^ will raise in Io_Exception
        end if;
    end Access_File;


    procedure Access_File_For_User (Ctrl      :     Os_Control_Block;
                                    New_Key   :     User.Id;
                                    User_Path : out Os2000_Io.Path_Number) is
        New_Path : Os2000_Io.Path_Number;
        Result   : Os2000_Io.Stratus;
        function To_Int is new Unchecked_Conversion
                                  (Os2000_Io.Path_Number, Integer);

    begin
        -- Trace ("Odi.Access_File_For_User");

        case Ctrl.For_Kind is
            when User_Kind =>
                Os2000_Io.Open (Name     =>
                                   Ctrl.Name.all (Ctrl.Name.all'First)'Address,
                                Mode     => Ctrl.Mode_Bits,
                                New_Path => New_Path,
                                Result   => Result);

                if Result /= Os2000_Io.E_Success then
                    Convert_Error (Result, In_Op => Open_Op);
                    -- ^ will raise in Io_Exception
                end if;
                -- Trace ("  Opened file " & Strip_Nul (Ctrl.Name.all));

            when Dio.Standard_Input =>
                New_Path := Os2000_Io.Standard_In;

            when Dio.Standard_Output =>
                New_Path := Os2000_Io.Standard_Out;

            when Dio.Standard_Error =>
                New_Path := Os2000_Io.Standard_Error;
        end case;

        Ctrl.User_List := new User_Node'(Key  => New_Key,
                                         Path => New_Path,
                                         Next => Ctrl.User_List);
        -- Trace ("  New path is " & Integer'Image (To_Int (New_Path)));
        User_Path := New_Path;
    end Access_File_For_User;


    procedure Open (File : in out File_Type;
                    Ctrl : in out Os_Control_Block;
                    Mode : in File_Mode;
                    Kind : in File_Kind;
                    Name : in String;
                    Form : in String;
                    Recommended_Buffer_Size : in Natural;
                    Actual_Buffer_Size : out Natural;
                    Client : in Client_Kind := Device_Independent_Io.Unknown) is
        Result : Os2000_Io.Stratus;
    begin
        -- Trace ("Odi.Open, kind is " & File_Kind'Image (Kind));
        case Kind is
            when Dio.Normal =>
                Access_File (Name, Form, Mode, Kind, Open_Op, Ctrl);
                Dio.Set (File, Buffering.Allocate (Recommended_Buffer_Size));
                Actual_Buffer_Size := Recommended_Buffer_Size;
                if (Mode = Device_Independent_Io.Out_File) and then
                   Device_Independent_Io."="
                      (Client, Device_Independent_Io.Text_Io) then
                    -- Set file size to zero.
                    Os2000_Io.Set_File_Size
                       (Path => Ctrl.Path, New_Size => 0, Result => Result);
                    if Result /= Os2000_Io.E_Success then  
                        Convert_Error (Status => Result, In_Op => Open_Op);
                        -- Will raise Constraint_Error or some flavor
                        -- of Io_Exceptions.
                    end if;
                end if;

            when Dio.Temporary =>
                -- temporary files must be created, not opened
                raise Io_Exception_Flavors.Unsupported_Error;

            when Dio.Standard_Input =>
                Ctrl := Initial_Control_Block
                           (Name, Form, Dio.Standard_Input, 0);
                Set_Initial_Path (Ctrl, Os2000_Io.Standard_In);
                Set_Interactive (Ctrl);
                Dio.Set (File, Buffering.Allocate (Interactive_Buffer_Size));
                Actual_Buffer_Size := Interactive_Buffer_Size;

            when Dio.Standard_Output | Dio.Standard_Error =>
                raise Io_Exception_Flavors.Unsupported_Error;
                -- Standard_Output/_Error must be created, not opened
        end case;
    end Open;

    procedure Create (File                    : in out File_Type;
                      Ctrl                    : in out Os_Control_Block;
                      Mode                    : in     File_Mode;
                      Kind                    : in     File_Kind;
                      Name                    : in     String;
                      Form                    : in     String;
                      Recommended_Buffer_Size : in     Natural;
                      Actual_Buffer_Size      : out    Natural) is
    begin
        -- Trace ("Odi.Create, kind is " & File_Kind'Image (Kind));
        case Kind is
            when Dio.Normal =>
                Access_File (Name, Form, Mode, Kind, Create_Op, Ctrl);
                Dio.Set (File, Buffering.Allocate (Recommended_Buffer_Size));
                Actual_Buffer_Size := Recommended_Buffer_Size;

            when Dio.Temporary =>
                loop
                    begin
                        Access_File (Unique_Temp_Name.Get, Form,
                                     Mode, Kind, Create_Op, Ctrl);
                        exit;
                    exception
                        when Io_Exceptions.Name_Error |
                             Io_Exceptions.Use_Error =>
                            null;
                        when others =>
                            Primitive_Io.Global_Absorb_Output := False;
                            -- Trace
                            --   ("Odi.Create temporary - unexpected exception",
                            --    Absorb_Output => False);
                            raise;
                    end;
                end loop;
                Dio.Set (File, Buffering.Allocate (Recommended_Buffer_Size));
                Actual_Buffer_Size := Recommended_Buffer_Size;

            when Dio.Standard_Input =>
                raise Io_Exception_Flavors.Unsupported_Error;
                -- Standard_Input must be opened, not created

            when Dio.Standard_Output | Dio.Standard_Error =>
                Ctrl := Initial_Control_Block (Name, Form, Kind, 0);
                if Kind = Dio.Standard_Output then
                    Set_Initial_Path (Ctrl, Os2000_Io.Standard_Out);
                else
                    Set_Initial_Path (Ctrl, Os2000_Io.Standard_Error);
                end if;
                Ctrl.Is_Interactive := True;
                -- Since standard files are not explicitly closed, it is
                -- necessary to treat as interactive in order to flush.

                Dio.Set (File, Buffering.Allocate (Interactive_Buffer_Size));
                Actual_Buffer_Size := Interactive_Buffer_Size;
        end case;
        -- exception
        --     when others =>
        --         Trace ("Odi.Create - got exception");
        --         raise;
    end Create;

    function Current_Position
                (Path : Os2000_Io.Path_Number; Is_Interactive : Boolean)
                return Os2000_Io.File_Position is
        Result   : Os2000_Io.Stratus;
        Position : Os2000_Io.File_Position;
    begin
        if not Is_Interactive then
            Os2000_Io.Current_Position (Path, Position, Result);
            if Result = Os2000_Io.E_Success then
                return Position;
            else
                Convert_Error (Result, In_Op => Get_Pos_Op);  
            end if;
        else
            return 1;
        end if;
    end Current_Position;

    procedure Set_Position (Path : Os2000_Io.Path_Number;
                            To   : Os2000_Io.File_Position) is
        Result : Os2000_Io.Stratus;
    begin
        Os2000_Io.Seek (Path     => Path,
                        Position => Natural (To),
                        Result   => Result);
        if Result /= Os2000_Io.E_Success then
            Convert_Error (Result, In_Op => Seek_Op);
        end if;
    end Set_Position;

    procedure Check_And_Update_User_Data (Ctrl : Os_Control_Block) is
    begin
        if User.Not_Current (Ctrl.Last_Key) then
            -- Trace ("User_Data not current");

            declare
                Current_Key : User.Id   := User.Get_Current_Key;
                Next_User   : User_Link := Ctrl.User_List;
                New_Path    : Os2000_Io.Path_Number;
            begin
                while Next_User /= null and then
                         Next_User.Key /= Current_Key loop
                    Next_User := Next_User.Next;
                end loop;

                if Next_User /= null then
                    -- Trace ("  Found user data on list");
                    New_Path := Next_User.Path;
                else
                    -- Trace ("  Did not find user data on list");
                    -- Have to open the file for this user.

                    Access_File_For_User (Ctrl, Current_Key, New_Path);
                end if;

                -- Trace ("  Setting new position " &
                --        Integer'Image (Integer (Ctrl.Position)));

                Set_Position (New_Path, Ctrl.Position);
                Ctrl.Path     := New_Path;
                Ctrl.Last_Key := Current_Key;
            end;
        end if;
    end Check_And_Update_User_Data;


    procedure Read (File                     : in     File_Type;
                    Ctrl                     : in     Os_Control_Block;
                    Item                     : in out Byte_String;
                    Count                    : out    Natural;
                    Line_Terminator_Detected : out    Boolean;
                    Line_Last_Data_Index     : out    Natural;
                    Line_Terminator_Present  : out    Boolean) is
        Bytes_Read : Natural;
        Result     : Os2000_Io.Stratus;
    begin
        -- Trace ("Odi.Read");
        Check_And_Update_User_Data (Ctrl);
        if Ctrl.Is_Interactive then
            Os2000_Io.Readln (Path       => Ctrl.Path,
                              Count      => Item'Length,
                              Buffer     => Item (Item'First)'Address,
                              Bytes_Read => Bytes_Read,
                              Result     => Result);
            Line_Terminator_Detected := True;
            Line_Terminator_Present  := True;
            Line_Last_Data_Index     := Item'First + Bytes_Read - 1;
        else
            Os2000_Io.Read (Path       => Ctrl.Path,
                            Count      => Item'Length,
                            Buffer     => Item (Item'First)'Address,
                            Bytes_Read => Bytes_Read,
                            Result     => Result);
            Line_Terminator_Detected := False;
            Line_Last_Data_Index     := Item'First + Bytes_Read - 1;
            Line_Terminator_Present  := False;
        end if;

        if Result = Os2000_Io.E_Success then
            Ctrl.Position := Current_Position (Ctrl.Path, Ctrl.Is_Interactive);
            Count         := Bytes_Read;
        elsif Ctrl.Is_Interactive then
            Convert_Error (Result, In_Op => Readln_Op);
        else
            Convert_Error (Result, In_Op => Read_Op);
        end if;
    end Read;

    procedure Write (File                    : in File_Type;
                     Ctrl                    : in Os_Control_Block;
                     Item                    : in Byte_String;
                     Line_Terminator_Present : in Boolean) is
        Bytes_Written : Natural;
        Result        : Os2000_Io.Stratus;
        -- Data : String (1 .. Item'Length);
        Indx : Natural := 1;
    begin
        if Item'Length <= 0 then
            -- Trace ("Odi.Write zero length byte string");
            return;
        end if;

        -- for J in Item'Range loop
        --     Trace ("Odi.Write item is " & Integer'Image (Integer (Item (J))));
        --     Data (Indx) := Character'Val (Integer (Item (J)));
        --     Indx := Indx + 1;
        -- end loop;
        -- Trace ("Odi.Write " & Data);

        Check_And_Update_User_Data (Ctrl);
        Os2000_Io.Write (Path          => Ctrl.Path,
                         Count         => Item'Length,
                         Buffer        => Item (Item'First)'Address,
                         Bytes_Written => Bytes_Written,
                         Result        => Result);
        if Result /= Os2000_Io.E_Success then
            Convert_Error (Result, In_Op => Write_Op);
        end if;

        if Bytes_Written /= Item'Length then
            raise Io_Exceptions.Device_Error;
        end if;

        -- Trace ("Odi.Write - wrote " & Data);

        Ctrl.Position := Current_Position (Ctrl.Path, Ctrl.Is_Interactive);
    end Write;

    procedure Read_Bytes (Ctrl       : in  Os_Control_Block;
                          Bytes_Addr :     System.Address;
                          Byte_Count :     Natural;
                          Bytes_Read : out Natural) is
        Result : Os2000_Io.Stratus;
    begin
        -- Trace ("Odi.Read_Bytes");
        Check_And_Update_User_Data (Ctrl);
        Os2000_Io.Read (Path       => Ctrl.Path,
                        Count      => Byte_Count,
                        Buffer     => Bytes_Addr,
                        Bytes_Read => Bytes_Read,
                        Result     => Result);

        if Result = Os2000_Io.E_Success then
            Ctrl.Position := Current_Position (Ctrl.Path, Ctrl.Is_Interactive);
        else
            Convert_Error (Result, In_Op => Read_Op);
        end if;
    end Read_Bytes;


    procedure Write_Bytes (Ctrl       : Os_Control_Block;
                           Bytes_Addr : System.Address;
                           Byte_Count : Natural) is
        Result        : Os2000_Io.Stratus;
        Bytes_Written : Natural;
    begin
        if Byte_Count <= 0 then
            -- Trace ("Odi.Write_Bytes - zero bytes to write");
            return;
        end if;

        -- Trace ("Odi.Write_Bytes");
        Check_And_Update_User_Data (Ctrl);
        Os2000_Io.Write (Path          => Ctrl.Path,
                         Count         => Byte_Count,
                         Buffer        => Bytes_Addr,
                         Bytes_Written => Bytes_Written,
                         Result        => Result);

        if Result /= Os2000_Io.E_Success then
            Convert_Error (Result, In_Op => Write_Op);

        elsif Bytes_Written /= Byte_Count then
            raise Io_Exceptions.Device_Error;

        else
            Ctrl.Position := Current_Position (Ctrl.Path, Ctrl.Is_Interactive);
        end if;
    end Write_Bytes;

    function End_Of_File (File : in File_Type;  
                          Ctrl : in Os_Control_Block) return Boolean is
        At_End : Boolean;
        Result : Os2000_Io.Stratus;
    begin
        --Trace ("Odi.End_Of_File");
        Check_And_Update_User_Data (Ctrl);
        Os2000_Io.End_Of_File
           (Path => Ctrl.Path, At_End => At_End, Result => Result);
        if Result = Os2000_Io.E_Success or else Result = Os2000_Io.E_Eof then
            return At_End;
        else
            Convert_Error (Result, In_Op => Eof_Op);
        end if;
    end End_Of_File;

    procedure Close (File : in out File_Type;  
                     Ctrl : in out Os_Control_Block) is
        Result : Os2000_Io.Stratus;
    begin
        -- Trace ("Odi.Close");
        if Ctrl.For_Kind = Dio.Temporary and then Delete_Temp_Files then
            Delete (File, Ctrl);
        else
            Check_And_Update_User_Data (Ctrl);
            Os2000_Io.Close (Path => Ctrl.Path, Result => Result);
            if Result = Os2000_Io.E_Success then
                Release (Ctrl);
            else
                Convert_Error (Result, In_Op => Close_Op);
            end if;
        end if;
    end Close;

    procedure Reset (File : in out File_Type;  
                     Ctrl : in out Os_Control_Block;  
                     Mode : in     File_Mode) is
        Current_Mode : File_Mode := Dio.Mode (File, Already_Locked => True);
        Result       : Os2000_Io.Stratus;
        New_Ctrl     : Os_Control_Block;
    begin
        -- Trace ("Odi.Reset");
        Check_And_Update_User_Data (Ctrl);

        if Mode = Current_Mode then
            -- Trace ("Odi.Reset same mode");

            Os2000_Io.Seek (Path     => Ctrl.Path,
                            Position => Os2000_Io.Null_Position,
                            Result   => Result);
            if Result /= Os2000_Io.E_Success then
                Convert_Error (Result, In_Op => Seek_Op);
            end if;

        elsif Ctrl.For_Kind in User_Kind then
            -- Trace ("Odi.Reset new mode");

            Os2000_Io.Close (Path => Ctrl.Path, Result => Result);
            if Result /= Os2000_Io.E_Success then
                Convert_Error (Result, In_Op => Close_Op);
            end if;

            Access_File (Name   => Strip_Nul (Ctrl.Name.all),
                         Form   => Ctrl.Form.all,
                         Mode   => Mode,
                         Kind   => Ctrl.For_Kind,
                         For_Op => Open_Op,
                         Ctrl   => New_Ctrl);

            Release (Ctrl);
            Ctrl := New_Ctrl;

            -- if Mode = Dio.Out_File and then not Ctrl.Is_Interactive then
            --     -- Trace ("Setting file size to 0");
            --     Os2000_Io.Set_File_Size (Ctrl.Path, 0, Result);
            --
            --     if Result /= Os2000_Io.E_Success then
            --         Convert_Error (Result, In_Op => Size_Op);
            --     end if;
            -- end if;

        else -- can't change mode for standard_kinds
            raise Io_Exception_Flavors.Reset_Error;
        end if;

        Ctrl.Position := Current_Position (Ctrl.Path, Ctrl.Is_Interactive);
    end Reset;

    procedure Save (File             : in File_Type;
                    Ctrl             : in Os_Control_Block;
                    Immediate_Effect : in Boolean := True) is
    begin
        -- Trace ("Odi.Save");
        Check_And_Update_User_Data (Ctrl);
        null;  -- nothing to do???
    end Save;

    procedure Delete (File : in out File_Type;  
                      Ctrl : in out Os_Control_Block) is
        Close_Result, Delete_Result : Os2000_Io.Stratus;
    begin
        -- Trace ("Odi.Delete");
        Check_And_Update_User_Data (Ctrl);
        case Ctrl.For_Kind is
            when User_Kind =>
                Os2000_Io.Close (Path => Ctrl.Path, Result => Close_Result);
                -- How should the paths for other tasks be reclaimed???
                Os2000_Io.Delete (Name   => Ctrl.Name (Ctrl.Name'First)'Address,
                                  Result => Delete_Result);
                if Close_Result = Os2000_Io.E_Success and then
                   Delete_Result = Os2000_Io.E_Success then
                    Release (Ctrl);
                elsif Delete_Result /= Os2000_Io.E_Success then
                    Convert_Error (Delete_Result, In_Op => Delete_Op);
                end if;

            when Standard_Kind =>
                raise Io_Exceptions.Use_Error;
        end case;
    end Delete;

    function Name (File : in File_Type;  
                   Ctrl : in Os_Control_Block) return String is
    begin
        -- Trace ("Odi.Name");
        case Ctrl.For_Kind is
            when Dio.Normal | Dio.Temporary =>
                return Strip_Nul (Ctrl.Name.all);

            when Dio.Standard_Input | Dio.Standard_Output |
                 Dio.Standard_Error =>
                -- OS9 provides no uniform way of obtaining a string
                -- name for the standard paths
                raise Io_Exception_Flavors.Unsupported_Error;
        end case;
    end Name;

    function Form (File : in File_Type;  
                   Ctrl : in Os_Control_Block) return String is
    begin
        -- Trace ("Odi.Form");
        case Ctrl.For_Kind is
            when Dio.Normal | Dio.Temporary =>
                return Form_Handling.Default_Image
                          (Ctrl.Form.all, Ctrl.Mode_Bits);

            when Dio.Standard_Input | Dio.Standard_Output |
                 Dio.Standard_Error =>
                return "";
        end case;
    end Form;

    function Is_Interactive (File : in File_Type;  
                             Ctrl : in Os_Control_Block) return Boolean is
    begin
        -- Trace ("Odi.Is_Interactive " & Boolean'Image (Ctrl.Is_Interactive));
        return Ctrl.Is_Interactive;
    end Is_Interactive;

    function Size (Ctrl : Os_Control_Block) return Byte_Count is
        File_Size : Natural;
        Result    : Os2000_Io.Stratus;
    begin
        -- Trace ("Odi.Size");
        Check_And_Update_User_Data (Ctrl);
        Os2000_Io.File_Size
           (Path => Ctrl.Path, Size => File_Size, Result => Result);
        if Result = Os2000_Io.E_Success then
            return Byte_Count (File_Size);
        else
            Convert_Error (Result, In_Op => Size_Op);
        end if;
    end Size;

    function Is_Empty (File : in File_Type;  
                       Ctrl : in Os_Control_Block) return Boolean is
    begin
        -- Trace ("Odi.Is_Empty");
        return Size (Ctrl) = 0;
    end Is_Empty;

    function Index (Ctrl : Os_Control_Block) return Byte_Index is
        File_Index : Natural;
    begin
        -- Trace ("Odi.Index");
        Check_And_Update_User_Data (Ctrl);
        -- when Check_And_Update_User_Data sets postion for the user, then
        -- can just return Ctrl.Position;  however, for now
        File_Index := Current_Position (Ctrl.Path, Ctrl.Is_Interactive);

        return Byte_Index (File_Index);
    end Index;

    procedure Set_Index (Ctrl : Os_Control_Block; To : Byte_Index) is
    begin
        -- Trace ("Odi.Set_Index");
        Check_And_Update_User_Data (Ctrl);
        Set_Position (Ctrl.Path, Os2000_Io.File_Position (To));
    end Set_Index;

    function Identical_File (File1 : in File_Type;  
                             Ctrl1 : in Os_Control_Block;  
                             File2 : in File_Type;  
                             Ctrl2 : in Os_Control_Block) return Boolean is
    begin
        -- Trace ("Odi.Identical_File");
        if Ctrl1.For_Kind = Ctrl2.For_Kind then
            case Ctrl1.For_Kind is
                when User_Kind =>
                    return Ctrl1.Name.all = Ctrl2.Name.all;

                when Standard_Kind =>
                    return Ctrl1.Path = Ctrl2.Path;
            end case;
        else
            return False;
        end if;
    end Identical_File;

    function Address_For_Control
                (Ctrl : Os_Control_Block) return System.Address is
    begin
        return Convert_Control_Block_To_Address (Ctrl);
    end Address_For_Control;

    function Control_From_Address
                (Addr : System.Address) return Os_Control_Block is
    begin
        return Convert_Address_To_Control_Block (Addr);
    end Control_From_Address;


end Os_Dependent_Io;