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

⟦3d3eb3bb7⟧ TextFile

    Length: 80474 (0x13a5a)
    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 Buffering;
with Device_Independent_Io;
with Io_Exceptions;
with Io_Exception_Flavors;
with Machine_Primitive_Operations;
with Primitive_Io;
with Semaphore;
with System;
with System_Types;
with Text_Io;
with Unchecked_Conversion;


pragma Elaborate (Device_Independent_Io);


package body Common_Text_Io is

    package Iox renames Io_Exceptions;
    package Iof renames Io_Exception_Flavors;
    package Dio renames Device_Independent_Io;
    --
    subtype Byte         is System_Types.Byte;
    subtype Byte_String  is System_Types.Byte_String;
    subtype Long_Integer is System_Types.Long_Integer;

    function "=" (L, R : Byte) return Boolean renames System_Types."=";
    function To_Byte (C : Character) return Byte renames System_Types.To_Byte;
    function To_Character (B : Byte) return Character
        renames System_Types.To_Character;
    -- ** function To_Byte_String (S : String) return Byte_String;
    -- ** function To_String (Bs : Byte_String) return String;

    function "=" (L, R : Dio.File_Mode) return Boolean renames Dio."=";
    function "=" (L, R : Text_Io.File_Mode) return Boolean renames Text_Io."=";
    function "=" (L, R : Buffering.Data_Buffer) return Boolean
        renames Buffering."=";
    function "=" (L, R : Text_Io.Count) return Boolean renames Text_Io."=";
    function "+" (L, R : Text_Io.Count) return Text_Io.Count
        renames Text_Io."+";
    function "-" (L, R : Text_Io.Count) return Text_Io.Count
        renames Text_Io."-";
    function "=" (L, R : System.Address) return Boolean renames System."=";


    Status_Error : exception renames Text_Io.Status_Error;
    Mode_Error   : exception renames Text_Io.Mode_Error;
    Name_Error   : exception renames Text_Io.Name_Error;
    Use_Error    : exception renames Text_Io.Use_Error;
    Device_Error : exception renames Text_Io.Device_Error;
    End_Error    : exception renames Text_Io.End_Error;
    Data_Error   : exception renames Text_Io.Data_Error;
    Layout_Error : exception renames Text_Io.Layout_Error;

    --\f

    type Terminator is (Eol, Eop, Eof);

    Line_Terminator : constant Character := Ascii.Cr;
    Page_Terminator : constant Character := Ascii.Ff;

    Line_Term_Byte : constant Byte := To_Byte (Line_Terminator);
    Page_Term_Byte : constant Byte := To_Byte (Page_Terminator);

    Line_Terminator_Str : constant String (1 .. 1) := (1 => Line_Terminator);
    Page_Terminator_Str : constant String (1 .. 2) :=
       (1 => Page_Terminator, 2 => Line_Terminator);
    Line_Terminator_Bs  : constant Byte_String (1 .. 2) :=
       (1 => To_Byte (Ascii.Cr), 2 => To_Byte (Ascii.Lf));

    Page_Terminator_Bs : constant Byte_String (1 .. 1) :=
       (1 => To_Byte (Page_Terminator));

    --\f

    -- Ada Text_Io has been carefully specified so that every file has at
    -- least one page and every page has at least one line.  This property
    -- makes it possible to define a one-to-one correspondence between Text
    -- files and Device_Independent_Io files.  That is, every text file has
    -- exactly one valid representation as a stream of bytes, and every
    -- possible stream of bytes has exactly one interpretation as a text file.

    -- The correspondence is this: every line is represented by the stream of
    -- characters that comprise the line, followed by an ASCII LF.  An
    -- exception to this rule is that the last line of a page is terminated by
    -- an ASCII FF instead of an LF.  Finally, there is an exception to the
    -- exception: the last line of the last page of a file is not terminated by
    -- anything.  File terminators have no explicit representation.

    -- It is the task of Text_Io to hide all these exceptions from its clients.
    -- When reading a file, Text_Io must supply an extra line terminator before
    -- every page terminator that is actually in the file.  Likewise, it must
    -- supply an extra line, page, and file terminator at the very end of the
    -- file.  On output, it must omit these terminators.

    -- All this simulation is not as messy as it sounds.  For example, most of
    -- the read calls are supposed to skip over the extra terminators that are
    -- being simulated, so that the simulation requires less work than if the
    -- terminators were actually present.  However, users who wish to read or
    -- write text files directly with Device-Independent I/O must be aware of
    -- these conventions, or they will not get the expected results.


    type Count_Repr is range 0 .. Count'Last + 2;
    Unbounded_Repr : constant Count_Repr := Count_Repr'Last;

    subtype Count_Limit    is Count_Repr range 1 .. Unbounded_Repr;
    subtype Extended_Count is Count_Repr range 1 .. Unbounded_Repr - 1;

    -- The Ada LRM requires that Column, Line, and Page counts can overflow
    -- without raising any exceptions unless their numerical value is
    -- requested.  This feature is implemented by storing the counts as
    -- an Extended_Count, which has one more value at the high end than Count.
    -- If the incrementing of a count raises an exception, the exception is
    -- caught and the count is left at Extended_Count'LAST.

    -- The limits on line lengths and page lengths are stored as the type
    -- Count_Limit.  This type has one additional value, Unbounded_Repr, which
    -- is larger than any value ever stored for a count.  This representation
    -- slightly simplifies checking for end-of-line and end-of-page.

    --\f

    Default_Buffer_Size : constant := 400;  -- bytes/characters

    type Funny_Boolean is (True, False, Simulated_False);

    type Input_State is
        record
            File            : File_Type;
            Line_Start      : Integer;
            Eob_Is_Eol      : Boolean;
            Line_Number     : Extended_Count;
            Page_Number     : Extended_Count;
            Eof_Encountered : Funny_Boolean;
        end record;

    type Access_Input_State is access Input_State;


    -- Notes on Input_State:

    -- File is a back pointer to the file that the Input_State belongs too.

    -- Line_Start is the index within Buffer of the first character of the
    -- current line.  The column number of the next character to be read is
    -- computed by Tail + 1 - Line_Start.  If the start of the current
    -- line is not in the buffer, Line_Start is an appropriate negative number
    -- so that the formula will still work.

    -- Eob_Is_Eol is true iff the buffer contains exactly one text line and
    -- the last character in the buffer is a Line_Terminator.

    -- Encountered_EOF indicates whether Device-Independent I/O has responded
    -- to a read request with an End_Error.  Since we need to keep track of
    -- this event to properly simulate a line and page terminator at the end of
    -- the file, we do not require Device-Independent I/O to raise End_Error
    -- more than once on a file.

    -- The literal parsers need one character of lookahead.  Normally they can
    -- "put back" a character by decrementing Next_To_Read.  This technique
    -- does not work for the simulated terminators at the end of a file.  The
    -- code Simulated_False allows for the simulated file terminator to be put
    -- back without requiring Device_Independent_IO to support multiple
    -- End_Errors.  Clients who want to be fooled by this charade should test
    -- if EOF_Encountered = True.  Clients who want to know the truth should
    -- test whether EOF_Encountered = False.

    --\f

    type Output_State is
        record
            File            : File_Type;
            Column_Number   : Extended_Count;
            Line_Number     : Extended_Count;
            Page_Number     : Extended_Count;
            Line_Length     : Count_Limit;
            Page_Length     : Count_Limit;
            Line_Terminated : Boolean;
        end record;

    type Access_Output_State is access Output_State;


    -- Output to interactive files is not buffered.  In the interactive case,
    -- we always output a Line Terminator before each Page Terminator.  The
    -- Line_Terminated boolean is used by New_Page to determine if it needs to
    -- output two terminators.

    -- Conversely, noninteractive output is not buffered.  In this case, every
    -- page terminator represents a line terminator followed by a page
    -- terminator.  Thus, if the user outputs a line terminator followed by a
    -- page terminator, that sequence is normalized to a page terminator.
    -- The state needed to do this normalization is part of the buffer.

    -- The buffer fields and the Line_Terminated bit could be part of a variant
    -- record whose discriminant is Is_Interactive, that implementation would
    -- be less efficient on the R1000.

    --\f

    package State_Handling is


        procedure Initialize (File : File_Type; S : out Input_State);
        procedure Initialize (File : File_Type; S : out Output_State);

        -- The routines Get_Input_State and Get_Output_State are
        -- called by every user-visible entry to Common_Text_Io
        -- that requires a file argument to be open for a specific
        -- mode.  The routines check that the file has this state,
        -- returning a pointer to the state if it is there, and
        -- raising the appropriate exception if it is not.  These
        -- routines also acquire the file's lock, which must be
        -- released with a call to Dio.Release.

        function Get_Output_State (File : File_Type) return Access_Output_State;
        function Get_Input_State  (File : File_Type) return Access_Input_State;

        -- The routine Get_File_State is called by routines that work
        -- with files that are open for input or output.  If the file
        -- is not open, Status_Error is raised.  Otherwise the mode
        -- of the file, along with the corresponding Input_State or
        -- Output_State is returned.  The file is not locked.

        procedure Get_File_State (File      :     File_Type;
                                  Mode      : out File_Mode;
                                  In_State  : out Access_Input_State;
                                  Out_State : out Access_Output_State);

        -- Allocate_State is called with a file that is open as far
        -- as Dio is concerned, but has not Text_Io state.  The file
        -- is given an appropriate state, which is initialized, and
        -- Dio is told about it.

        procedure Allocate_State (File : File_Type; Mode : File_Mode);
        procedure Free_State     (File : File_Type);
        procedure Free_State     (File : File_Type; Mode : File_Mode);

        -- ** Replaced due to cross-compiler problems
        -- package Input_State_Ops is new Dio.Client_Specific
        --      (Control_Block => Input_State,
        --       Pointer => Access_Input_State);

        procedure Iset (File : File_Type; Ais : Access_Input_State);
        function  Iget (File : File_Type) return Access_Input_State;

        -- ** Replaced due to cross-compiler problem
        -- package Output_State_Ops is new Dio.Client_Specific
        --      (Control_Block => Output_State,
        --       Pointer => Access_Output_State);

        procedure Oset (File : File_Type; Aos : Access_Output_State);
        function  Oget (File : File_Type) return Access_Output_State;

    private

        pragma Suppress (Elaboration_Check, On => Initialize);
        pragma Suppress (Elaboration_Check, On => Get_Output_State);
        pragma Suppress (Elaboration_Check, On => Get_Input_State);
        pragma Suppress (Elaboration_Check, On => Get_File_State);
        pragma Suppress (Elaboration_Check, On => Allocate_State);
        pragma Suppress (Elaboration_Check, On => Free_State);
        pragma Suppress (Elaboration_Check, On => Iset);
        pragma Suppress (Elaboration_Check, On => Iget);
        pragma Suppress (Elaboration_Check, On => Oset);
        pragma Suppress (Elaboration_Check, On => Oget);

    end State_Handling;

    --\f

    -- This package manages the standard files for Text_Io.

    package Standard_Files is

        type Kind is (Input, Output, Error);

        -- Does whatever necessary to open Standard_Input, Standard_Output,
        -- and Standard_Error, and set Current_Input, Current_Output,
        -- and Current_Error to their initial values.

        procedure Initialize;

        -- Used to set the "current" file.
        procedure Set (K : Kind; F : File_Type);

        -- Gets the value of the "current" file.
        -- function Get (K : Kind) return File_Type;
        -- Semantics bug won't allow suppress on Get, so change name
        function Egt (K : Kind) return File_Type;

        -- Gets the value of the original "standard" file.
        function Std_Get (K : Kind) return File_Type;

        -- When closing or deleting a file, it is necessary to check
        -- whether that file has been set to Current_Input/_Output,
        -- so that the relationship between the file variable and
        -- the Current file can be maintained.  This is done by
        -- setting both the file and the Current file are set to
        -- a special closed value.
        procedure Check_If_Closing_Current (File : in out File_Type);

        -- When creating, opening, or resetting a file, it is necessary
        -- to check whether the file has been set to Current_Input/_Output,
        -- and, if so, whether the new mode will be compatible.  Mode_Error
        -- will be raise if the new mode is incompatible.
        procedure Check_If_Current_Compatible_Mode
                     (File : File_Type; New_Mode : File_Mode);

        -- After creating or opening a file, it is necessary to check
        -- whether the file has been set to Current_Input/_Output,
        -- and, if so, to establish the association of the appropriate
        -- current file to the new file descriptor.
        procedure Check_If_Reassociating_Current
                     (Old_File : File_Type; New_File : File_Type);

    private

        pragma Suppress (Elaboration_Check, On => Initialize);
        pragma Suppress (Elaboration_Check, On => Set);
        --pragma Suppress (Elaboration_Check, On => Get);  -- Semantics bug!
        pragma Suppress (Elaboration_Check, On => Egt);  -- Semantics bug!
        pragma Suppress (Elaboration_Check, On => Std_Get);

    end Standard_Files;

    function Get_Current_Input
                (Kind : Standard_Files.Kind := Standard_Files.Input)
                return File_Type renames Standard_Files.Egt;

    function Get_Current_Output
                (Kind : Standard_Files.Kind := Standard_Files.Output)
                return File_Type renames Standard_Files.Egt;

    --\f

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


    procedure Set_Input (File : File_Type) is
    begin
        Standard_Files.Set (Standard_Files.Input, File);
    end Set_Input;

    procedure Set_Output (File : File_Type) is
    begin
        Standard_Files.Set (Standard_Files.Output, File);
    end Set_Output;

    procedure Set_Error (File : File_Type) is
    begin
        Standard_Files.Set (Standard_Files.Error, File);
    end Set_Error;

    function Standard_Input return File_Type is
    begin
        return Standard_Files.Std_Get (Standard_Files.Input);
    end Standard_Input;

    function Standard_Output return File_Type is
    begin
        return Standard_Files.Std_Get (Standard_Files.Output);
    end Standard_Output;

    function Standard_Error return File_Type is
    begin
        return Standard_Files.Std_Get (Standard_Files.Error);
    end Standard_Error;

    function Current_Input return File_Type is
    begin
        return Get_Current_Input;
    end Current_Input;

    function Current_Output return File_Type is
    begin
        return Get_Current_Output;
    end Current_Output;

    function Current_Error return File_Type is
    begin
        return Standard_Files.Egt (Standard_Files.Error);
    end Current_Error;

    --\f

    function Convert (From : File_Mode) return Dio.File_Mode is
    begin
        case From is
            when In_File =>
                return Dio.In_File;
            when Out_File =>
                return Dio.Out_File;
        end case;
    end Convert;



    -- Editorial : there really ought to be only one kind of file mode,
    -- so that this nonsense is not necessary.

    --\f

    procedure Append (File : in out File_Type;
                      Name :        String;
                      Form :        String := "") is
        Actual_Buffer_Size : Natural;
    begin
        begin
            Dio.Acquire (File);
            -- if Name /= "" then  -- why not?
            if Name'Length /= 0 then
                Dio.Append (File, Dio.Out_File, Dio.Normal, Name, Form,
                            Default_Buffer_Size, Actual_Buffer_Size);
            else
                Dio.Append (File, Dio.Out_File, Dio.Temporary, "", Form,
                            Default_Buffer_Size, Actual_Buffer_Size);
            end if;
        exception
            when Status_Error =>
                -- As far as DIO is concerned, the file is open.  See if the file
                -- has been opened by Text_Io.
                if Dio.Mode (File) = Dio.In_File then
                    Dio.Release (File);
                    raise Iof.Illegal_Operation_On_Infile;
                end if;

                if State_Handling.Oget (File) /= null then
                    Dio.Release (File);
                    raise Iof.Already_Open_Error;
                end if;
            when others =>
                -- Name_Error, Device_Error, etc.
                Dio.Release (File);
                raise;
        end;
        State_Handling.Allocate_State (File, Out_File);
        Dio.Release (File);
    end Append;

    --\f

    procedure Save (File : File_Type) is
    begin
        Dio.Acquire (File);
        Flush (File, Clear_Terminators => True);
        Dio.Save (File);
        Dio.Release (File);
    exception
        when others =>
            Dio.Release (File);
            raise;
    end Save;


    procedure Close (File : in out File_Type) is
        Closed_File : File_Type := File;
    begin
        Dio.Acquire (File);
        Flush (File, Clear_Terminators => True);
        State_Handling.Free_State (File);
        Standard_Files.Check_If_Closing_Current (File);
        Dio.Close (Closed_File);
        -- A successful close releases the file's lock
    exception
        when others =>
            Dio.Release (Closed_File);
            raise;
    end Close;


    procedure Delete (File : in out File_Type) is
        Mode         : File_Mode;
        In_State     : Access_Input_State;
        Out_State    : Access_Output_State;
        Deleted_File : File_Type := File;
    begin
        Dio.Acquire (File);

        -- The file state is not really needed.  We call Get_File_State to make
        -- sure an exception is raised if there is no state, only for
        -- consistency with all the other visible entry points.
        State_Handling.Get_File_State (File, Mode, In_State, Out_State);
        State_Handling.Free_State (File);
        Standard_Files.Check_If_Closing_Current (File);
        Dio.Delete (Deleted_File);
        -- Release isn't necessary:  The file doesn't exist anymore!
    exception
        when others =>
            Dio.Release (Deleted_File);
            raise;
    end Delete;

    --\f

    procedure Reset (File          : in out File_Type;
                     Original_Mode : in     File_Mode;
                     New_Mode      : in     File_Mode) is

        Different_Mode : constant Boolean := Original_Mode /= New_Mode;

    begin
        if Different_Mode then
            Standard_Files.Check_If_Current_Compatible_Mode (File, New_Mode);
        end if;

        Dio.Acquire (File);

        -- Make sure there won't be a file open for output and input at
        -- the same time
        begin
            if Different_Mode and New_Mode = Out_File then
                declare
                    Oin, Oinout, Oout : Natural;
                begin
                    Dio.Identical_Files (File, Oin, Oout, Oinout);
                    -- This file counts as 1 open for input
                    if Oin > 1 then
                        raise Iox.Use_Error;
                    end if;
                end;
            end if;
        exception
            when others =>
                Dio.Release (File);
                raise;
        end;

        -- Flush the file's buffer (if necessary) and do the actual reset,
        -- then adjust the Text_Io state for the file
        begin
            Flush (File, Clear_Terminators => True);
            Dio.Reset (File, Convert (New_Mode));
            if Different_Mode then
                State_Handling.Free_State (File, Original_Mode);
                State_Handling.Allocate_State (File, New_Mode);
            elsif New_Mode = In_File then
                State_Handling.Initialize (File,
                                           State_Handling.Iget (File).all);
            else
                State_Handling.Initialize (File,
                                           State_Handling.Oget (File).all);
            end if;
            Dio.Release (File);
        exception
            when others =>
                Dio.Release (File);
                raise;
        end;

    end Reset;


    -----------------------------------------------------------------
    -- Visible procedure RESET with explicit mode:
    -----------------------------------------------------------------

    procedure Reset (File : in out File_Type; Mode : File_Mode) is
    begin
        Reset (File,
               Original_Mode => Common_Text_Io.Mode (File), -- checks for open
               New_Mode      => Mode);
    end Reset;


    -----------------------------------------------------------------
    -- Visible procedure RESET to same mode:
    -----------------------------------------------------------------

    procedure Reset (File : in out File_Type) is
        The_Mode : File_Mode := Mode (File); -- checks for open
    begin
        Reset (File, Original_Mode => The_Mode, New_Mode => The_Mode);
    end Reset;

    --\f

    -----------------------------------------------------------------
    -- Visible function MODE to return the mode of an open file:
    -----------------------------------------------------------------

    function Mode (File : File_Type) return File_Mode is
        Result    : File_Mode;
        In_State  : Access_Input_State;
        Out_State : Access_Output_State;
    begin
        Dio.Acquire (File);
        State_Handling.Get_File_State (File, Result, In_State, Out_State);
        Dio.Release (File);
        return Result;
    exception
        when others =>
            Dio.Release (File);
            raise;
    end Mode;


    -----------------------------------------------------------------
    -- Visible function NAME to return the full name of the file:
    -----------------------------------------------------------------

    function Name (File : File_Type) return String is
        Mode      : File_Mode;
        In_State  : Access_Input_State;
        Out_State : Access_Output_State;
    begin
        Dio.Acquire (File);
        State_Handling.Get_File_State (File, Mode, In_State, Out_State);
        -- The file state is not really needed.  We call Get_File_State to make
        -- sure an exception is raised if there is no state, only for
        -- consistency with all the other visible entry points.

        declare
            Name : constant String := Dio.Name (File);
        begin
            Dio.Release (File);
            return Name;
        end;

    exception
        when others =>
            Dio.Release (File);
            raise;
    end Name;


    -----------------------------------------------------------------
    -- Visible function FORM to return the FORM string of a file:
    -----------------------------------------------------------------

    function Form (File : File_Type) return String is
        Mode      : File_Mode;
        In_State  : Access_Input_State;
        Out_State : Access_Output_State;
    begin
        Dio.Acquire (File);
        State_Handling.Get_File_State (File, Mode, In_State, Out_State);
        -- The file state is not really needed.  We call Get_File_State to make
        -- sure an exception is raised if there is no state, only for
        -- consistency with all the other visible entry points.

        declare
            Form : constant String := Dio.Form (File);
        begin
            Dio.Release (File);
            return Form;
        end;

    exception
        when others =>
            Dio.Release (File);
            raise;
    end Form;

    --\f

    function Is_Open (File : File_Type) return Boolean is
        Mode      : File_Mode;
        In_State  : Access_Input_State;
        Out_State : Access_Output_State;
    begin
        State_Handling.Get_File_State (File, Mode, In_State, Out_State);
        return True;
    exception
        when Status_Error =>
            return False;
    end Is_Open;


    procedure Set_Line_Length (File : File_Type; To : Count) is
        S : Output_State renames State_Handling.Get_Output_State (File).all;
    begin
        if To = Unbounded then
            S.Line_Length := Unbounded_Repr;
        else
            S.Line_Length := Count_Limit (To);
        end if;
        Dio.Release (File);
    exception
        when others =>
            Dio.Release (File);
            raise;
    end Set_Line_Length;


    procedure Set_Line_Length (To : Count) is
    begin
        Set_Line_Length (Current_Output, To);
    end Set_Line_Length;


    procedure Set_Page_Length (File : File_Type; To : Count) is
        S : Output_State renames State_Handling.Get_Output_State (File).all;
    begin
        if To = Unbounded then
            S.Page_Length := Unbounded_Repr;
        else
            S.Page_Length := Count_Limit (To);
        end if;
        Dio.Release (File);
    exception
        when others =>
            Dio.Release (File);
            raise;
    end Set_Page_Length;


    procedure Set_Page_Length (To : Count) is
    begin
        Set_Page_Length (Current_Output, To);
    end Set_Page_Length;


    function Line_Length (File : File_Type) return Count is
        S : Output_State renames State_Handling.Get_Output_State (File).all;
        C : Count;
    begin
        if S.Line_Length = Unbounded_Repr then
            C := Unbounded;
        else
            C := Count (S.Line_Length);
        end if;
        Dio.Release (File);
        return C;
    exception
        when others =>
            Dio.Release (File);
            raise;
    end Line_Length;


    function Line_Length return Count is
    begin
        return Line_Length (Current_Output);
    end Line_Length;


    function Page_Length (File : File_Type) return Count is
        S : Output_State renames State_Handling.Get_Output_State (File).all;
        C : Count;
    begin
        if S.Page_Length = Unbounded_Repr then
            C := Unbounded;
        else
            C := Count (S.Page_Length);
        end if;
        Dio.Release (File);
        return C;
    exception
        when others =>
            Dio.Release (File);
            raise;
    end Page_Length;


    function Page_Length return Count is
    begin
        return Page_Length (Current_Output);
    end Page_Length;

    --\f

    ------------------------
    ---  Input routines  ---
    ------------------------

    procedure New_Line (S : in out Input_State) is
        -- This routine should be called when the next character to be read
        -- is the first character of a line, and the preceding character
        -- is a line terminator.
    begin
        -- Set the Line_Start to the current position in the buffer,
        -- and bump the Line_Number.

        begin
            -- The file must have a buffer when used for input
            S.Line_Start := Dio.Get (S.File).Tail;
        exception
            when Constraint_Error =>
                raise Use_Error;
        end;

        begin
            S.Line_Number := S.Line_Number + 1;  -- may overflow
        exception
            when Numeric_Error | Constraint_Error =>
                null;
        end;
    end New_Line;


    procedure New_Page (S : in out Input_State) is
        -- This routine should be called when the next character to be read
        -- is the first character of a line, and the preceding character
        -- is a page terminator.
    begin
        -- Set the Line_Start to the current position in the buffer,
        -- set the Line_Number to the first line on a page, and bump
        -- the Page_Number.

        begin
            -- The file must have a buffer when used for input
            S.Line_Start := Dio.Get (S.File).Tail;
        exception
            when Constraint_Error =>
                raise Use_Error;
        end;

        S.Line_Number := 1;

        begin
            S.Page_Number := S.Page_Number + 1;  -- may overflow
        exception
            when Numeric_Error | Constraint_Error =>
                null;
        end;
    end New_Page;

    --\f

    -----------------------------------------------------------------
    -- The procedure FILL_BUFFER which is the interface to
    -- DEVICE_INDEPENDENT_IO for all COMMON_TEXT_IO input:
    -----------------------------------------------------------------

    -- All input from Device-Independent I/O to Text I/O goes through
    -- Fill_Buffer.  Fill_Buffer should be called when the file buffer
    -- is empty.  Fill_Buffer will return with at least one character in the
    -- buffer or with S.EOF_Encountered /= False.  In the latter case,
    -- the buffer Head and Tail will be left unchanged so that the normal
    -- test will cause another call into Fill_Buffer.

    -- The mystical flag Undo_Eof controls what Fill_Buffer does when DIO
    -- returns with an End_Error.  The default action is to set EOF_Encountered
    -- to True and call New_Page to final page terminator.  If the client is
    -- only interested in seeing if the end-of-file is out there without
    -- having the New_Page invoked if it is there, he should use the Undo_Eof
    -- flag.  Note that client only has to worry about getting back
    -- Simulated_False if he is using the Undo_Eof flag.


    procedure Fill_Buffer (File     :        File_Type;
                           S        : in out Input_State;
                           B        : in out Buffering.Data_Buffer;
                           Undo_Eof :        Boolean := False);

    pragma Suppress (Elaboration_Check, On => Fill_Buffer);

    function Has_No_Terminator (B : Buffering.Data_Buffer) return Boolean is
        Data : Byte_String renames B.Buffer;
    begin
        for I in B.Tail .. B.Head loop
            if Data (I) = Line_Term_Byte then
                return False;
            end if;
        end loop;
        return True;
    end Has_No_Terminator;

    -- This procedure fills the buffer if it is empty, raising End_Error
    -- if there is no more data.
    procedure Next_Buffer (File     :        File_Type;
                           S        : in out Input_State;
                           B        : in out Buffering.Data_Buffer;
                           Undo_Eof :        Boolean := False) is
    begin
        -- if Buffering.Is_Empty (B) then
        --     Pput ("Cti.Next_Buffer when buffer is empty");
        -- else
        --     Pput ("Cti.Next_Buffer when buffer is not empty");
        -- end if;
        if Buffering.Is_Empty (B) or else
           (Has_No_Terminator (B) and then S.Eof_Encountered = False) then
            Fill_Buffer (File, S, B, Undo_Eof);
            if S.Eof_Encountered = True then
                raise End_Error;
            end if;
        end if;
    end Next_Buffer;


    --\f

    --------------------------------------------------------------------
    -- Visible procedure GET returning character:
    -- After skipping any line terminators and any page terminators,
    -- reads the next character from the specified input file and
    -- returns the value of this character in the out parameter Item.
    -- The exception END_ERROR is raised if an attempt is made to skip
    -- a file terminator.  [RM 14.3.6 (1)]
    --------------------------------------------------------------------
    procedure Get (File : File_Type; Item : out Character) is

        S : Input_State renames State_Handling.Get_Input_State (File).all;
        B : Buffering.Data_Buffer := Dio.Get (File);

    begin
        -- if not Primitive_Io.Absorb_Output then
        --     Pput ("Cti.Get(character) from " & Dio.Name (File));
        -- end if;
        loop
            -- Pput ("Cti.Get(character) loop start");
            Next_Buffer (File, S, B);

            -- Pput ("Cti.Get(character) buffer has" &
            --       Integer'Image (Buffering.Left (B)) & " characters remaining");

            declare
                C : Character := Buffering.Next (B);
            begin
                case C is
                    when Line_Terminator =>
                        -- Pput ("Cti.Get(character) have line terminator");
                        New_Line (S);

                    when Page_Terminator =>
                        -- Pput ("Cti.Get(character) have page terminator");
                        New_Page (S);

                    when others =>
                        --if not Primitive_Io.Absorb_Output then
                        -- if C in ' ' .. '~' then
                        --     Pput ("Cti.Get(character) have '" & C & ''');
                        -- else
                        --     Pput ("Cti.Get(character) have" &
                        --           Integer'Image (Character'Pos (C)));
                        -- end if;
                        Item := C;
                        Dio.Release (File);
                        return;
                end case;
            end;
        end loop;
    exception
        when others =>
            Dio.Release (File);
            raise;
    end Get;

    --\f

    --------------------------------------------------------------------
    -- Visible procedure GET_ANY:
    -- Similar to GET but does not interpret control characters as
    -- terminators.  [Not a routine in the RM]
    --------------------------------------------------------------------
    procedure Get_Any (File : File_Type; Item : out Character) is

        S : Input_State renames State_Handling.Get_Input_State (File).all;
        B : Buffering.Data_Buffer := Dio.Get (File);

    begin
        -- This function was put in as a hack to allow the Core Editor use use
        -- Simple_Text_IO to read in its key definition tables, which have
        -- control characters in the middle of lines.

        -- It is not clear what it is supposed to do in all the weird boundary
        -- cases.

        Next_Buffer (File, S, B);

        Item := Buffering.Next (B);
        Dio.Release (File);

    exception
        when others =>
            Dio.Release (File);
            raise;
    end Get_Any;


    --\f

    -----------------------------------------------------------------
    -- Get all or part of a line.  The intent is for each call to return
    -- as many characters from the current line as possible, but
    -- Last /= Item'Last doesn't imply End_Of_Line.
    -----------------------------------------------------------------


    procedure Get_A_Line (File             : in     File_Type;
                          S                : in out Input_State;
                          Item             : out    String;
                          Last             : out    Natural;
                          Skip_Terminators : in     Boolean;
                          End_Of_Line      : out    Boolean;
                          End_Of_Page      : out    Boolean;
                          End_Of_File      : out    Boolean);

    pragma Suppress (Elaboration_Check, On => Get_A_Line);

    --\f

    --------------------------------------------------------------------
    -- Visible procedure GET returning string:
    -- Determines the length of the given string and attempts that
    -- number of GET operations for successive characters of the string
    -- (in particular, no operation is performed if the string is null).
    -- [RM 14.3.6 (9)]
    --------------------------------------------------------------------

    procedure Get (File : File_Type; Item : out String) is

        S : Input_State renames State_Handling.Get_Input_State (File).all;
        B : Buffering.Data_Buffer := Dio.Get (File);
        --
        Item_First  : Natural          := Item'First;
        Item_Last   : constant Natural := Item'Last;
        Item_Filled : Natural;
        --
        Eol, Eop, Eof : Boolean;
        --
        C : Character;
        --
        Ignore_Eol : Boolean := False;

    begin

        -- Definition implies that this operation can cross line and
        -- page boundaries.  It is undefined (by the RM) what happens
        -- to Item if END_ERROR is raised before Item is filled;  this
        -- implementation will trash the first characters of Item.

        -- if not Primitive_Io.Absorb_Output then
        --     Pput ("Cti.Get(string) getting" & Integer'Image (Item'Length) &
        --           " bytes");
        -- end if;

        -- Fill the Item in chunks of lines.
        if Item'Length = 0 then
            Dio.Release (File);
            return;
        end if;

        loop
            Get_A_Line (File, S, Item (Item_First .. Item_Last), Item_Filled,
                        Skip_Terminators => False,
                        End_Of_Line      => Eol,
                        End_Of_Page      => Eop,
                        End_Of_File      => Eof);

            if Item_Filled = Item_Last then
                -- The string is filled, we're done.
                -- Pput ("Cti.Get(string) have filled string");
                Dio.Release (File);
                return;
            else
                -- There is more to read to fill the string.
                -- Skip the terminator that blocked us, and continue
                -- with the next chunk.
                -- Eof, Eop, and Eol are unreliable since Skip_Terminators
                -- was False.
                C := Buffering.Next (B);
                -- ^ Can raise End_Error, which is fine
                if C = Page_Terminator then
                    -- Pput ("Cti.Get(string) have EOP");
                    New_Page (S);
                    Ignore_Eol := True;  -- since page terminators are FF & LF
                elsif C = Line_Terminator then
                    -- Pput ("Cti.Get(string) have EOL");
                    if not Ignore_Eol then
                        New_Line (S);
                    else -- still need to set line start in order to get
                         -- correct column numbering
                        begin
                            S.Line_Start := Dio.Get (S.File).Tail;
                        exception
                            when Constraint_Error =>
                                raise Use_Error;
                        end;
                    end if;
                    Ignore_Eol := False;
                else
                    -- if not Primitive_Io.Absorb_Output then
                    --     Pput ("Cti.Get(string) have '" & C &
                    --           "' as terminator ???");
                    -- end if;
                    raise Constraint_Error;  -- ?? or programming_error eh?
                    -- Buffering.Throwback (B, 1);
                end if;
                Item_First := Item_Filled + 1;
            end if;
        end loop;
    exception
        when others =>
            Dio.Release (File);
            raise;
    end Get;

    --\f

    --------------------------------------------------------------------
    -- Visible procedure GET_LINE returns into a string and length.
    --------------------------------------------------------------------

    -- Replaces successive characters of the specified string by successive
    -- characters read from the specified input file.  Reading stops if the
    -- end of line is met (*), in which case the procedure SKIP_LINE is then
    -- called (in effect) with a spacing of one; reading also stops if the
    -- end of the string is met.  Characters not replaced are left undefined.
    -- If characters are read, returns in LAST the index value such that
    -- ITEM(LAST) is the last character replaced (the index of the first
    -- character replaced is ITEM'FIRST).  If no characters are read, returns
    -- in LAST an index value that is one less than ITEM'FIRST.  The exception
    -- END_ERROR is raised if an attempt is made to skip a file terminator.
    -- [RM 14.3.6 (13-15)]

    -- (*) Except that AI-00050 provides that SKIP_LINE is only called
    -- if the output string has not been exhausted and End_Of_Line is
    -- true.

    -- For a SPACING of one reads the line terminator and sets the current
    -- column number to one.  If the line terminator is not immediately
    -- followed by a page terminator the current line number is incremented
    -- by one.  Otherwise, ifthe line terminator is immediately followed by
    -- a page terminator then the page terminator is skipped, the current
    -- page number is incremented by one, and the current line number is
    -- set to one.  [RM 14.3.4 (8)]

    -- This procedure behaves as described above if Skip_Terminators is
    -- True.  If Skip_Terminators is false it will read up to a Line_Terminator
    -- but not skip past it.


    procedure Get_Line
                 (File : File_Type; Item : out String; Last : out Natural) is

        S : Input_State renames State_Handling.Get_Input_State (File).all;
        Eol, Eop, Eof : Boolean;

    begin
        Get_A_Line (File, S, Item, Last,
                    Skip_Terminators => True,
                    End_Of_Line      => Eol,
                    End_Of_Page      => Eop,
                    End_Of_File      => Eof);
        Dio.Release (File);
    exception
        when others =>
            Dio.Release (File);
            raise;
    end Get_Line;

    --\f

    -----------------------------------------------------------------
    -- Visible procedure GET_LINE returns string, length, and
    -- indicators of terminators (not in TEXT_IO).
    -----------------------------------------------------------------

    procedure Get (File        :     File_Type;
                   Item        : out String;
                   Last        : out Natural;
                   End_Of_Line : out Boolean;
                   End_Of_Page : out Boolean;
                   End_Of_File : out Boolean) is

        S : Input_State renames State_Handling.Get_Input_State (File).all;

    begin
        Get_A_Line (File, S, Item, Last,
                    Skip_Terminators => True,
                    End_Of_Line      => End_Of_Line,
                    End_Of_Page      => End_Of_Page,
                    End_Of_File      => End_Of_File);
        Dio.Release (File);
    exception
        when others =>
            Dio.Release (File);
            raise;
    end Get;

    -- \f

    --------------------------------------------------------------------
    -- Visible function GET_LINE returning string:
    -- Similar to the RM procedure GET_LINE except returns its result
    -- as a function.
    --------------------------------------------------------------------

    function Get_Line (File : File_Type) return String is

        S : Input_State renames State_Handling.Get_Input_State (File).all;

        -- This implementation is sort of sick, but probably isn't worth
        -- too much effort to improve.

        function Get_Line return String is
            Result        : String (1 .. 512);
            Res_Len       : Natural;
            Eol, Eop, Eof : Boolean;
        begin
            Get_A_Line (File, S, Result, Res_Len,
                        Skip_Terminators => False,
                        End_Of_Line      => Eol,
                        End_Of_Page      => Eop,
                        End_Of_File      => Eof);
            if Eol then
                -- Found an entire line, skip the terminators
                New_Line (S);
                return Result (1 .. Res_Len);
            else
                -- Didn't find the entire line yet, so put the pieces
                -- together
                return Result & Get_Line;
            end if;
        end Get_Line;

    begin
        declare
            Result : constant String := Get_Line;
        begin
            Dio.Release (File);
            return Result;
        end;
    exception
        when others =>
            Dio.Release (File);
            raise;
    end Get_Line;

    --\f

    --------------------------------------------------------------------
    -- Advances to the N'th terminator in the file, where N = Spacing.
    -- If Count_Lines, we count any terminator; otherwise we only count
    -- page terminators.
    --------------------------------------------------------------------

    procedure Skip (File        :        File_Type;
                    S           : in out Input_State;
                    Spacing     :        Positive_Count := 1;
                    Count_Lines :        Boolean) is

        B          : Buffering.Data_Buffer := Dio.Get (File);
        Space_Left : Positive_Count        := Spacing;
        C          : Character;

    begin
        -- if not Primitive_Io.Absorb_Output then
        --     if Count_Lines then
        --         Pput ("Cti.Skip skipping" & Positive_Count'Image (Spacing) &
        --               " lines");
        --     else
        --         Pput ("Cti.Skip skipping" & Positive_Count'Image (Spacing) &
        --               " pages");
        --     end if;
        -- end if;

        -- Get rid of the do-nothing case first
        if Spacing = 0 then
            return;
        end if;


        loop
            if Buffering.Is_Empty (B) then
                if S.Eof_Encountered = True then
                    -- See Get_Line for details on what is going on here.
                    raise End_Error;
                end if;
                Fill_Buffer (File, S, B);
                if S.Eof_Encountered = True then
                    -- Page_Terminators are simulated at EOF, but
                    -- Line_Terminators aren't!
                    if (not Count_Lines) and Space_Left = 1 then
                        -- The final simulated terminator was the one we
                        -- were looking for.  Just in the nick of time!
                        return;
                    else
                        -- There are not enough terminators in the file to
                        -- satisfy the request.
                        raise End_Error;
                    end if;
                end if;
            end if;

            -- Do we have a known line terminator?
            if S.Eob_Is_Eol then
                -- Line-at-a-time case
                declare
                    Have_Page : constant Boolean :=
                       Buffering.Peek_At_Last (B) = Page_Terminator;
                begin
                    -- Eat up the rest of the line in one fell swoop
                    Buffering.Consume (B, Buffering.Left (B));

                    if Have_Page then
                        New_Page (S);
                    else
                        New_Line (S);
                    end if;
                    if Count_Lines then
                        if Space_Left = 1 then
                            return;
                        end if;
                        Space_Left := Space_Left - 1;
                    elsif Have_Page then
                        if Space_Left = 1 then
                            return;
                        end if;
                        Space_Left := Space_Left - 1;
                    end if;
                end;
            else
                -- Character-at-a-time case
                C := Buffering.Next (B);
                case C is
                    when Line_Terminator =>
                        New_Line (S);
                        if Count_Lines then
                            if Space_Left = 1 then
                                return;
                            end if;
                            Space_Left := Space_Left - 1;
                        end if;

                    when Page_Terminator =>
                        -- Pput ("Cti.Skip - testing for Line_Terminator");
                        if Buffering.Is_Empty (B) then
                            Fill_Buffer (File, S, B, Undo_Eof => True);
                            if S.Eof_Encountered /= False then
                                S.Eof_Encountered := True;
                            end if;
                        end if;

                        if S.Eof_Encountered /= True and then
                           Buffering.Peek (B) = Line_Terminator then
                            Buffering.Consume (B);
                            -- Pput ("Cti.Skip - consumed Line_Terminator");
                        end if;

                        New_Page (S);
                        if Space_Left = 1 then
                            return;
                        end if;
                        Space_Left := Space_Left - 1;

                    when others =>
                        null;
                end case;
            end if;
        end loop;

    end Skip;

    --\f

    --------------------------------------------------------------------
    -- Visible procedure SKIP_LINE:
    -- For a SPACING of one:  Reads and discards all characters until a
    -- line terminator has been read, and then sets the current column
    -- number to one.  If the line terminator is not immediately
    -- followed by a page terminator, the current line number is
    -- incremented by one.  Otherwise, if the line terminatoris
    -- immediately followed by a page terminator, then the page
    -- terminator is skipped, the current page number is incremented
    -- by one, and the current line number is set to one.  For a
    -- SPACING greater than one, the above actions are performed
    -- SPACING times.  The exception END_ERROR is raised if an attempt
    -- is made to read a file terminator.  [RM 14.3.4 (8-10)]
    --------------------------------------------------------------------
    procedure Skip_Line (File : File_Type; Spacing : Positive_Count := 1) is
        S : Input_State renames State_Handling.Get_Input_State (File).all;
    begin
        Skip (File, S, Spacing, Count_Lines => True);
        Dio.Release (File);
    exception
        when others =>
            Dio.Release (File);
            raise;
    end Skip_Line;


    --------------------------------------------------------------------
    -- Visible procedure SKIP_PAGE:
    -- Reads and discards all characters and line terminators until a
    -- page terminator has been read.  Then adds one to the current
    -- page number, and sets the current column and line numbers to one.
    -- The exception END_ERROR is raised if an attempt is made to read
    -- a file terminator.
    -- [RM 14.3.4 (18-19)]
    --------------------------------------------------------------------
    procedure Skip_Page (File : File_Type) is
        S : Input_State renames State_Handling.Get_Input_State (File).all;
    begin
        Skip (File, S, Count_Lines => False);
        Dio.Release (File);
    exception
        when others =>
            Dio.Release (File);
            raise;
    end Skip_Page;

    --\f

    function End_Of (File : File_Type; Level : Terminator) return Boolean is

        -- Determine whether we are at end of (line, page, file), depending on
        -- Level.

        S : Input_State renames State_Handling.Get_Input_State (File).all;
        B : Buffering.Data_Buffer := Dio.Get (File);
        C : Character;

    begin

        -- This is a lookahead function.  Unlike most functions, it does NOT
        -- scan past terminators.  Instead, it peeks ahead to see if there are
        -- terminators out there.

        -- if not Primitive_Io.Absorb_Output then
        --     if Buffering.Is_Empty (B) then
        --         Pput ("Cti.End_Of " & Terminator'Image (Level) &
        --               " with empty buffer");
        --     else
        --         Pput ("Cti.End_Of " & Terminator'Image (Level) &
        --               " with non-empty buffer");
        --     end if;
        -- end if;

        if Buffering.Is_Empty (B) then
            Fill_Buffer (File, S, B, Undo_Eof => True);
            if S.Eof_Encountered /= False then
                -- We are not letting ourselves be fooled by the
                -- simulation requested by the Undo_Eof flag.
                Dio.Release (File);
                return True;
            end if;
        end if;

        C := Buffering.Peek (B);

        -- if not Primitive_Io.Absorb_Output then
        --     Pput ("Cti.End_Of peeking at " & Character'Image (C));
        -- end if;

        case C is
            when Line_Terminator =>
                -- There is a special case of looking for EOF or EOP
                -- at the End_Of_File, which requires a look-ahead for
                -- EOF -- but only if we're at the end of a buffer.
                if Level >= Eop and then B.Tail = B.Head then
                    -- Pput ("Cti.End_Of have special EOF or EOP condition");
                    Fill_Buffer (File, S, B, Undo_Eof => True);
                    declare
                        Result : constant Boolean := S.Eof_Encountered /= False;
                    begin
                        Dio.Release (File);
                        -- if not Primitive_Io.Absorb_Output then
                        --     Pput ("Cti.End_Of EOF or EOP = " &
                        --           Boolean'Image (Result));
                        -- end if;
                        return Result;
                    end;
                else
                    Dio.Release (File);
                    -- if not Primitive_Io.Absorb_Output then
                    --     Pput ("Cti.End_Of returning " &
                    --           Boolean'Image (Level = Eol));
                    -- end if;
                    return Level = Eol;
                end if;
                -- Only return True if we are looking for end-of-line

            when Page_Terminator =>
                Dio.Release (File);
                -- if not Primitive_Io.Absorb_Output then
                --     Pput ("Cti.End_Of returning " &
                --           Boolean'Image (Level <= Eop));
                -- end if;
                return Level <= Eop;  -- or:  Level /= Eof
                -- A Page_Terminator is EOL as well as EOP

            when others =>
                Dio.Release (File);
                -- Pput ("Cti.End_Of returning false");
                return False;
        end case;

    exception
        when others =>
            Dio.Release (File);
            raise;
    end End_Of;

    --\f

    --------------------------------------------------------------------
    -- Visible function END_OF_LINE:
    -- Returns TRUE if a line terminator or a file terminator is next;
    -- otherwise returns FALSE.  [RM 14.3.4 (12)]
    --------------------------------------------------------------------
    function End_Of_Line (File : File_Type) return Boolean is
    begin
        return End_Of (File, Eol);
    end End_Of_Line;


    --------------------------------------------------------------------
    -- Visible function END_OF_PAGE:
    -- Returns TRUE if the combination of a line terminator and a page
    -- terminator is next, or if a file terminator is next; otherwise
    -- returns FALSE.  [RM 14.3.4 (21)]
    --------------------------------------------------------------------
    function End_Of_Page (File : File_Type) return Boolean is
    begin
        return End_Of (File, Eop);
    end End_Of_Page;


    --------------------------------------------------------------------
    -- Visible function END_OF_FILE:
    -- Returns TRUE if a file terminator is next, or if the combination
    -- of a line, a page, and a file terminator is next; otherwise
    -- returns FALSE.
    --------------------------------------------------------------------
    function End_Of_File (File : File_Type) return Boolean is
    begin
        return End_Of (File, Eof);
    end End_Of_File;

    --\f

    -- Next come all the input functions in which the file defaults to
    -- Current_Input.  All of these are implemented by calling the
    -- corresponding routine, passing Current_Input as a parameter.  It is hard
    -- to do to much better than than this, because each of these routines must
    -- check if Current_Output has been initialized, and open Standard_Input if
    -- not.  A program that uses Simple_Text_Io to read Current_Input will be
    -- more efficient if it calls Current_Input once at the beginning, saves
    -- the value in a variable, and then never uses the following routines.
    -- It is annoying that we can't do this for him!

    procedure Get (Item : out Character) is
    begin
        Get (Get_Current_Input, Item);
    end Get;

    procedure Get (Item : out String) is
    begin
        Get (Get_Current_Input, Item);
    end Get;

    procedure Get_Line (Item : out String; Last : out Natural) is
    begin
        Get_Line (Get_Current_Input, Item, Last);
    end Get_Line;

    function Get_Line return String is
    begin
        return Get_Line (Get_Current_Input);
    end Get_Line;

    procedure Skip_Line (Spacing : Positive_Count := 1) is
    begin
        Skip_Line (Get_Current_Input, Spacing);
    end Skip_Line;

    procedure Skip_Page is
    begin
        Skip_Page (Get_Current_Input);
    end Skip_Page;

    function End_Of_Line return Boolean is
    begin
        return End_Of_Line (Get_Current_Input);
    end End_Of_Line;

    function End_Of_Page return Boolean is
    begin
        return End_Of_Page (Get_Current_Input);
    end End_Of_Page;

    function End_Of_File return Boolean is
    begin
        return End_Of_File (Get_Current_Input);
    end End_Of_File;

    --\f

    -----------------------
    --- Output routines ---
    -----------------------

    package Buffering_Puts is

        -- The  following two Put procedures implement a small buffer between
        -- Text IO and Device-Independent IO.  There are two reasons for using
        -- this buffer.  First, if the user is doing character-at-a-time output,
        -- we can avoid the overhead of calling Device-Independent I/O for every
        -- character.  Second, it allows us to normalize out redundant line and
        -- page terminators.

        -- These procedures do not keep track of column, line and page counts.
        -- That is the responsibility of the next level up.

        -- Semantics bug!
        --procedure Put (F : File_Type; S : in out Output_State; Item : String);
        procedure Upt (F : File_Type; S : in out Output_State; Item : String);
        procedure Put_Line_Terminator (F : File_Type; S : in out Output_State);
        procedure Put_Page_Terminator (F : File_Type; S : in out Output_State);

    private

        --pragma Suppress (Elaboration_Check, On => Put); -- Semantics bug!
        pragma Suppress (Elaboration_Check, On => Upt); -- Semantics bug!
        pragma Suppress (Elaboration_Check, On => Put_Line_Terminator);
        pragma Suppress (Elaboration_Check, On => Put_Page_Terminator);

    end Buffering_Puts;

    package Formatting_Puts is

        procedure Put_Unbroken
                     (F : File_Type; S : in out Output_State; Item : String);
        procedure Put_Broken
                     (F : File_Type; S : in out Output_State; Item : String);

    private

        pragma Suppress (Elaboration_Check, On => Put_Unbroken);
        pragma Suppress (Elaboration_Check, On => Put_Broken);

    end Formatting_Puts;

    use Buffering_Puts;
    use Formatting_Puts;

    --\f

    -- The next level of procedures handles counts and terminators.
    -- These are not user-visible routines; they assume that the file parameter
    -- is open for output.

    procedure New_Line (F : File_Type; S : in out Output_State) is
    begin
        -- No matter what happens, we will start a new line
        S.Column_Number := 1;

        -- We are buffering lines so that the page terminator can go
        -- in front of the line terminator.  Therefore, we always
        -- end the line first.
        Put_Line_Terminator (F, S);

        -- See if a new page must be begun
        if S.Line_Number >= S.Page_Length then
            Put_Page_Terminator (F, S);
            S.Line_Number := 1;
            S.Page_Number := S.Page_Number + 1;  -- may overflow
        else
            S.Line_Number := S.Line_Number + 1;  -- may overflow
        end if;

    exception
        when Numeric_Error | Constraint_Error =>
            null;
    end New_Line;


    procedure New_Page (F : File_Type; S : in out Output_State) is
    begin
        Put_Page_Terminator (F, S);

        S.Column_Number := 1;
        S.Line_Number   := 1;
        S.Page_Number   := S.Page_Number + 1;  -- may overflow
    exception
        when Numeric_Error | Constraint_Error =>
            null;
    end New_Page;


    --\f

    procedure Set_Col (File :        File_Type;
                       S    : in out Input_State;
                       To   :        Positive_Count) is

        C                   : Character;
        Next_To_Read_Target : Integer;
        B                   : Buffering.Data_Buffer := Dio.Get (File);

        procedure Reset_Target is
            -- For input files, the current column number is not stored; it is
            -- computed from the buffer pointer and the variable S.Line_Start.
            -- This routine computes the value that the buffer pointer must
            -- have to equal the desired column number.  This target must be
            -- recomputed every time S.Line_Start changes:  when we fill the
            -- buffer or encounter a terminator.
        begin
            Next_To_Read_Target := S.Line_Start + Integer (To) - 1;
        exception
            when Numeric_Error =>
                -- It is sufficent to set the target to be outside the buffer.
                Next_To_Read_Target := 0;
        end Reset_Target;

    begin

        Reset_Target;

        -- This if statement implements the requirement from the LRM that if
        -- the current column number equals the argument, then the call has no
        -- effect.  This is the only way we can return with a line terminator
        -- as the next item to be read.
        if B.Tail = Next_To_Read_Target then
            return;
        end if;

        loop
            -- Sliding the buffer could change Next_To_Read_Target
            Next_Buffer (File, S, B);
            Reset_Target;  -- really needed here only if buffer slides

            C := Buffering.Peek (B);

            -- According to validation test CE3409D, it is not acceptable for
            -- SET_COL to return with a line terminator as the next item to be
            -- read, even if the line terminator has the desired column number.
            -- Therefore we keep reading until we have read a real character
            -- with the desired column number and then back up B.Tail
            -- so that the next I/O call will get this character.

            case C is
                when Line_Terminator =>
                    Buffering.Consume (B, 1);
                    New_Line (S);
                    -- Reset_Target;

                when Page_Terminator =>
                    Buffering.Consume (B, 1);
                    New_Page (S);
                    -- Reset_Target;

                when others =>
                    exit when B.Tail = Next_To_Read_Target;
                    Buffering.Consume (B, 1);
            end case;
        end loop;

    end Set_Col;

    --\f

    procedure Set_Col (F : File_Type; S : in out Output_State; To : Count) is
        New_Number : constant Extended_Count := Extended_Count (To);
    begin
        -- Pput ("Cti.Set_Col output file To" & Count'Image (To) &
        --     " where current column is" & Extended_Count'Image (S.Column_Number));
        if New_Number > S.Line_Length then
            raise Iof.Column_Error;
        end if;

        if New_Number < S.Column_Number then
            -- Pput ("Cti.Set_Col to earlier column, doing New_Line");
            New_Line (F, S);
            -- Pput ("Cti.Set_Col Column_Number is now" &
            --     Extended_Count'Image (S.Column_Number));
        end if;

        declare
            Str : String (1 .. Integer (New_Number - S.Column_Number));
        begin
            -- Pput ("Cti.Set_Col dumping" & Integer'Image (Str'Length) & " blanks");
            if Str'Length > 0 then
                Machine_Primitive_Operations.Blank_Fill (Str, Str'Length);
            end if;
            Upt (F, S, Str);
        end;
        S.Column_Number := New_Number;
    end Set_Col;

    --\f

    procedure Set_Line (File :        File_Type;
                        S    : in out Input_State;
                        To   :        Positive_Count) is
        New_Line_Number : constant Extended_Count := Extended_Count (To);
    begin
        -- if not Primitive_Io.Absorb_Output then
        --     Pput ("Cti.Set_Line for output file to" &
        --           Extended_Count'Image (New_Line_Number) & " from" &
        --           Extended_Count'Image (S.Line_Number));
        -- end if;
        while (S.Line_Number /= New_Line_Number) loop
            -- if not Primitive_Io.Absorb_Output then
            --     Pput ("Cti.Set_Line to" &
            --           Extended_Count'Image (New_Line_Number) & " now at" &
            --           Extended_Count'Image (S.Line_Number));
            -- end if;
            Skip (File, S, Count_Lines => True);
        end loop;

        -- The line we're currently at must exist (see CE3410E).
        -- Thus we fill the buffer.  This read-ahead is necessary.
        declare
            B : Buffering.Data_Buffer := Dio.Get (File);
        begin
            if Buffering.Is_Empty (B) then
                -- And how can this be?
                if S.Eof_Encountered = True then
                    raise End_Error;
                end if;
                Fill_Buffer (File, S, B, Undo_Eof => False);
                if S.Eof_Encountered = True then
                    -- Hah!  The line didn't exist after all.
                    raise End_Error;
                end if;
            end if;
        end;
    end Set_Line;


    procedure Set_Line (F : File_Type; S : in out Output_State; To : Count) is

        New_Number : constant Extended_Count := Extended_Count (To);
    begin
        if New_Number = S.Line_Number then
            return;
        end if;

        if New_Number > S.Page_Length then
            raise Iof.Illegal_Position_Error;
        end if;

        if New_Number < S.Line_Number then
            New_Page (F, S);
        end if;

        -- Output an appropriate number of line terminators.
        for I in 1 .. New_Number - S.Line_Number loop
            Put_Line_Terminator (F, S);
        end loop;

        S.Column_Number := 1;
        S.Line_Number   := New_Number;

    end Set_Line;

    --\f

    --------------------------------------------------------------------
    -- User-visible output routines that take an explicit file parameter.
    -- These routines all call Get_Output_State, which checks to see that
    -- the file is open for output, raising the appropriate exception if
    -- not Then lower-level routines are called to peform the requested
    -- function(s).
    --------------------------------------------------------------------


    --------------------------------------------------------------------
    -- Visible procedure PUT for writing a character:
    -- If the line length of the specified output file is bounded (that
    -- is, does not have the conventional value zero), and the current
    -- column number exceeds it, has the effect of calling NEW_LINE with
    -- a spacng of one.  Then, or otherwise, outputs the given
    -- character to the file.  [RM 14.3.6 (6)]
    --------------------------------------------------------------------

    procedure Put (File : File_Type; Item : Character) is
        S : Output_State renames State_Handling.Get_Output_State (File).all;
    begin
        Put_Unbroken (File, S, String'(1 => Item));
        Dio.Release (File);
    exception
        when others =>
            Dio.Release (File);
            raise;
    end Put;


    --------------------------------------------------------------------
    -- Visible procedure PUT for writing a string:
    -- Determines the length of the given string and attempts that
    -- number of PUT operations for successive characters of the string
    -- (in particular, no operation is performed if the string is null).
    -- [RM 14.3.6 (11)]
    --------------------------------------------------------------------
    procedure Put (File : File_Type; Item : String) is
        S : Output_State renames State_Handling.Get_Output_State (File).all;
    begin
        Put_Broken (File, S, Item);
        Dio.Release (File);
    exception
        when others =>
            Dio.Release (File);
            raise;
    end Put;

    --\f

    --------------------------------------------------------------------
    -- Visible procedure PUT_LINE for writing a string:
    -- Calls the procedure PUT for the given string, and then the
    -- procedure NEW_LINE with a spacing of one.  [RM 14.3.6 (17)]
    --------------------------------------------------------------------

    procedure Put_Line (File : File_Type; Item : String) is
        S : Output_State renames State_Handling.Get_Output_State (File).all;
    begin
        Put_Broken (File, S, Item);
        New_Line (File, S);
        Dio.Release (File);
    exception
        when others =>
            Dio.Release (File);
            raise;
    end Put_Line;

    --\f

    --------------------------------------------------------------------
    -- Visible procedure NEW_LINE:
    -- For a SPACING of one:  Outputs a line terminator and sets the
    -- current column number to one.  Then increments the current line
    -- number by one, except in the case that the current line number
    -- is already greater than or equal to the maximum page length, for a
    -- bounded page length;  in that case a page terminator is output,
    -- the current page number is incremented by one, and the current
    -- line number is set to one.  For a SPACING greater than one, the
    -- above actions are performed SPACING times.  [RM 14.3.4 (3-4)]
    --------------------------------------------------------------------

    procedure New_Line (File : File_Type; Spacing : Positive_Count := 1) is
        S : Output_State renames State_Handling.Get_Output_State (File).all;
    begin
        for J in 1 .. Spacing loop
            New_Line (File, S);
        end loop;
        Dio.Release (File);
    exception
        when others =>
            Dio.Release (File);
            raise;
    end New_Line;


    --------------------------------------------------------------------
    -- Visible procedure NEW_PAGE:
    -- Outputs a line terminator if the current line is not terminated,
    -- or if the current page is empty (that is, if the current column
    -- and line numbers are both equal to one).  Then outputs a page
    -- terminator, which terminates the current page.  Adds one to the
    -- current page number and sets the current column and line numbers
    -- to one.  [RM 14.3.4 (15)]
    --------------------------------------------------------------------

    procedure New_Page (File : File_Type) is
        S : Output_State renames State_Handling.Get_Output_State (File).all;
    begin
        New_Page (File, S);
        Dio.Release (File);
    exception
        when others =>
            Dio.Release (File);
            raise;
    end New_Page;

    --\f

    -- User-visible output procedures with file parameters that default to
    -- Current_Output.  Each simply calls the corresponding user-visible
    -- procedure, passing it Current_Output.  Since the current design insists
    -- that any of these procedures can create Current_Output, it is hard to do
    -- too much better than this.

    procedure Put (Item : Character) is
    begin
        Put (Get_Current_Output, Item);
    end Put;

    procedure Put (Item : String) is
    begin
        Put (Get_Current_Output, Item);
    end Put;

    procedure Put_Line (Item : String) is
    begin
        Put_Line (Get_Current_Output, Item);
    end Put_Line;

    procedure New_Page is
    begin
        New_Page (Get_Current_Output);
    end New_Page;


    procedure New_Line (Spacing : Positive_Count := 1) is
    begin
        New_Line (Get_Current_Output, Spacing);
    end New_Line;

    --\f

    -- The following routines work on files that are open for either input or
    -- output.  In each case, the routine Get_File_State is called, which
    -- raises Status_Error if the file is not open, and returns its mode and
    -- the appropriate state if it is.  The routines then do different things,
    -- depending on the mode.

    -- The default file is Current_Output, so the default routines could simply
    -- call Get_Output_State, but the lock isn't necessary, so just call
    -- the corresponding visible routine with Current_Output.


    procedure Set_Col (File : File_Type; To : Positive_Count) is
        In_State  : Access_Input_State;
        Out_State : Access_Output_State;
        Mode      : File_Mode;
    begin
        State_Handling.Get_File_State (File, Mode, In_State, Out_State);

        if Mode = In_File then
            Set_Col (File, In_State.all, To);
        else
            Set_Col (File, Out_State.all, To);
        end if;
    end Set_Col;


    procedure Set_Col (To : Positive_Count) is
    begin
        Set_Col (Get_Current_Output, To);
    end Set_Col;


    function Col (File : File_Type) return Positive_Count is
        In_State  : Access_Input_State;
        Out_State : Access_Output_State;
        Mode      : File_Mode;
        B         : Buffering.Data_Buffer;
    begin
        State_Handling.Get_File_State (File, Mode, In_State, Out_State);

        if Mode = In_File then
            B := Dio.Get (File);
            return Positive_Count (B.Tail + 1 - In_State.Line_Start);
        else
            return Positive_Count (Out_State.Column_Number);
        end if;
    exception
        when Constraint_Error | Numeric_Error =>
            raise Iof.Column_Error;
    end Col;


    function Col return Positive_Count is
    begin
        return Col (Get_Current_Output);
    end Col;

    --\f

    procedure Set_Line (File : File_Type; To : Positive_Count) is
        In_State  : Access_Input_State;
        Out_State : Access_Output_State;
        Mode      : File_Mode;
    begin
        State_Handling.Get_File_State (File, Mode, In_State, Out_State);

        if Mode = In_File then
            Set_Line (File, In_State.all, To);
        else
            Set_Line (File, Out_State.all, To);
        end if;
    end Set_Line;


    procedure Set_Line (To : Positive_Count) is
    begin
        Set_Line (Get_Current_Output, To);
    end Set_Line;


    function Line (File : File_Type) return Positive_Count is
        In_State  : Access_Input_State;
        Out_State : Access_Output_State;
        Mode      : File_Mode;
    begin
        State_Handling.Get_File_State (File, Mode, In_State, Out_State);

        if Mode = Out_File then
            return Positive_Count (Out_State.Line_Number);
        else
            return Positive_Count (In_State.Line_Number);
        end if;
    exception
        when Constraint_Error | Numeric_Error =>
            raise Iof.Illegal_Position_Error;
    end Line;


    function Line return Positive_Count is
    begin
        return Line (Get_Current_Output);
    end Line;

    --\f

    function Page (File : File_Type) return Positive_Count is
        In_State  : Access_Input_State;
        Out_State : Access_Output_State;
        Mode      : File_Mode;
    begin
        State_Handling.Get_File_State (File, Mode, In_State, Out_State);

        if Mode = Out_File then
            return Positive_Count (Out_State.Page_Number);
        else
            return Positive_Count (In_State.Page_Number);
        end if;
    exception
        when Constraint_Error | Numeric_Error =>
            raise Iof.Illegal_Position_Error;
    end Page;


    function Page return Positive_Count is
    begin
        return Page (Get_Current_Output);
    end Page;

    -- \f

    -----------------------------------------------------------------


    procedure Create (File : in out File_Type;
                      Mode :        File_Mode := Out_File;
                      Name :        String    := "";
                      Form :        String    := "") is separate;

    procedure Open (File : in out File_Type;
                    Mode :        File_Mode := Out_File;
                    Name :        String;
                    Form :        String    := "") is separate;

    -- This procedure is called when a file is closed, reset, or saved.
    -- If the file is an output file then the partial output buffer is
    -- flushed immediately.  For some implementations (e.g., VMS) this
    -- will force a line terminator at the end of the buffer.

    procedure Flush (File              : File_Type;
                     Clear_Terminators : Boolean := True) is separate;

    procedure Fill_Buffer (File     :        File_Type;
                           S        : in out Input_State;
                           B        : in out Buffering.Data_Buffer;
                           Undo_Eof :        Boolean := False) is separate;

    procedure Get_A_Line (File             : in     File_Type;
                          S                : in out Input_State;
                          Item             : out    String;
                          Last             : out    Natural;
                          Skip_Terminators : in     Boolean;
                          End_Of_Line      : out    Boolean;
                          End_Of_Page      : out    Boolean;
                          End_Of_File      : out    Boolean) is separate;

    package body State_Handling is separate;
    package body Buffering_Puts is separate;
    package body Formatting_Puts is separate;
    package body Enumeration_Io is separate;
    package body Standard_Files is separate;
    package body Enum_Io is separate;
    package body Integer_Io is separate;
    package body Float_Io is separate;

    -----------------------------------------------------------------

begin

    -- COMMON_TEXT_IO elaboration:

    -- Remember to initialize the standard files here.
    Standard_Files.Initialize;

end Common_Text_Io;