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 - metrics - download
Index: B T

⟦af31c7a5b⟧ TextFile

    Length: 30642 (0x77b2)
    Types: TextFile
    Names: »B«

Derivation

└─⟦180fe333a⟧ Bits:30000405 8mm tape, Rational 1000, SW CATALOG, 10_20_0
└─⟦180fe333a⟧ Bits:30000537 8mm tape, Rational 1000, SW Catalog 10_20_0
    └─⟦5cb1d1d7f⟧ »DATA« 
        └─⟦3b1ee7bd8⟧ 
            └─⟦this⟧ 

TextFile

with Io;
with Io_Exceptions;
with Device_Independent_Io;
with Terminal_Specific;
with String_Utilities;
with System_Utilities;
with System;
with Operator;
with Editor;
with Terminal;
with Job;
with Debug_Tools;
with Time_Utilities;
with Directory_Tools;
procedure Xmodem is
    package Dio renames Device_Independent_Io;
    package Tio renames Terminal_Specific;
    package Su renames String_Utilities;
    package Object renames Directory_Tools.Object;
    package Naming renames Directory_Tools.Naming;
    package Statistics renames Directory_Tools.Statistics;
    package Traversal renames Directory_Tools.Traversal;
    package Any_Object renames Directory_Tools.Any_Object;

    function "+" (L, R : Dio.Byte) return Dio.Byte renames System."+";
    function "*" (L, R : Dio.Byte) return Dio.Byte renames System."*";
    function "-" (L, R : Dio.Byte) return Dio.Byte renames System."-";
    function "mod" (L, R : Dio.Byte) return Dio.Byte renames System."mod";
    function "=" (L, R : Dio.Byte) return Boolean renames System."=";
    function Image (N : Integer;
                    B : Integer := 10;
                    W : Integer := 1;
                    Lead : Character := ' ') return String
        renames Su.Number_To_String;
    type Xmit_Error is (None, Duplicate_Sector, Ignored_Character,
                        Bad_Sector_Check_Byte, Bad_Sector_Number,
                        Bad_Checksum, Timeout, No_Nak, No_Ack);
    type Write_State is (Start, Text_1, Text_2, Text_3, Text_4, Nulls, Stop);

    Error : Xmit_Error := None;
    Error_Ring : array (0 .. 19) of Xmit_Error;
    Error_Byte : array (0 .. 19) of Integer;
    Ring_Ptr : Integer := 0;
    Secsiz : constant := 128;
    Ttime : constant := 60.0;
    Bufsize : constant := Secsiz;
    Errormax : constant := 20;
    Retrymax : constant := 20;
    Nul : constant := Character'Pos (Ascii.Nul);
    Soh : constant := Character'Pos (Ascii.Soh);
    Eot : constant := Character'Pos (Ascii.Eot);
    Ack : constant := Character'Pos (Ascii.Ack);
    Nak : constant := Character'Pos (Ascii.Nak);
    Space : constant := Character'Pos (' ');
    Tilde : constant := Character'Pos ('~');
    Lf : constant := Character'Pos (Ascii.Lf);
    Cr : constant := Character'Pos (Ascii.Cr);

    Bufr : Dio.Byte_String (1 .. Bufsize);
    Bytes_Xferred : Integer;

    subtype String_Of_One_Byte is Tio.Byte_String (1 .. 1);

    Error_Stream : Io.File_Type := Io.Standard_Error;
    Output : Dio.File_Type;
    Input : Dio.File_Type;

    Time_Out : exception;
    Term : Terminal.Port := Terminal.Current;
    N : Integer;
    S : String (1 .. 100);
    Status : Object.Error_Code;

    procedure Open_Terminal (Terminal : Integer) is
        Name : constant String := System_Utilities.Terminal_Name (Terminal);
    begin
        for I in 1 .. 30 loop
            begin
                Operator.Disable_Terminal (Terminal);
                Dio.Open (Input, Dio.In_File, Name);
                exit;
            exception
                when Io_Exceptions.Use_Error =>
                    delay (1.0);
            end;
        end loop;

        Dio.Open (Output, Dio.Out_File, Name);
        Tio.Input.Flush (Input);
    end Open_Terminal;


    procedure Close_Terminal (Terminal : Integer) is
    begin
        Dio.Close (Input);
        Dio.Close (Output);
        Operator.Enable_Terminal (Terminal);
    end Close_Terminal;


    procedure Emitt (S : String) is
        N : Integer;
    begin
        Tio.Write (Output, S & Ascii.Cr & Ascii.Lf, N, Duration'Last);
    end Emitt;

    procedure Emits (S : String) is
    begin
        Io.Put_Line (Error_Stream, S);
    end Emits;

    --***********************************************************
    -- send char and read char functions for the xmodem function
    --***********************************************************

    procedure Prompt (P : String; S : out String; Count : out Integer) is
        N, M, Actual : Integer;
        Inp : String (1 .. S'Length);
        Raw : System.Byte_String (1 .. S'Length);
        C : Integer := S'First - 1;
    begin
        Tio.Write (Output, P, Actual, 1.0);

        Pole:
            loop
                Tio.Read (Input, Raw, M, Duration'Last);

                for I in 1 .. M loop
                    if System.">" (Raw (I), 127) then
                        Inp (I) := '%';
                    else
                        Inp (I) := Character'Val (Raw (I));
                    end if;

                    Ring_Ptr := (Ring_Ptr + 1) mod 20;
                    Error_Ring (Ring_Ptr) := None;
                    Error_Byte (Ring_Ptr) := Integer (Raw (I));

                    case Inp (I) is
                        when Ascii.Lf | Ascii.Cr | Ascii.Eot =>
                            Tio.Write (Output, Ascii.Cr & Ascii.Lf,
                                       N, Duration'Last);
                            exit Pole;

                        when Ascii.Bs | Ascii.Del =>
                            if C >= S'First then
                                C := C - 1;
                            end if;

                            Tio.Write (Output, Ascii.Bs & ' ' & Ascii.Bs,
                                       N, Duration'Last);

                        when Ascii.Can | Ascii.Nak =>
                            while C >= S'First loop
                                Tio.Write (Output, Ascii.Bs & ' ' & Ascii.Bs,
                                           N, Duration'Last);
                                C := C - 1;
                            end loop;

                        when others =>
                            Tio.Write (Output, Inp (I .. I), N, Duration'Last);
                            C := C + 1;
                            S (C) := Inp (I);
                    end case;
                end loop;
            end loop Pole;

        Count := C;
    end Prompt;

    procedure Sendchar (Ch : Dio.Byte) is
        Actual : Integer;
    begin
        Tio.Write (Output, String_Of_One_Byte'(1 => Ch), Actual, 30.0);

        if Actual = 0 then
            raise Time_Out;
        end if;
    end Sendchar;


    function Readchar (Wait : Duration := Duration (Ttime)) return Dio.Byte is
        Ch : Dio.Byte_String (1 .. 1);
        N : Integer;
    begin
        Tio.Read (Input, Ch, N, Wait);

        if N = 0 then
            raise Time_Out;
        end if;

        return (Ch (1));
    end Readchar;

    --***********************************
    -- xmodem send and recieve functions
    --***********************************

    procedure Write (Fd : Dio.File_Type;
                     B : Dio.Byte;
                     State : in out Write_State;
                     Null_Count : in out Natural) is
        -- The procedure implements a simple state machine necessary to
        -- absorb the preamble sent by Xmodem from a Macintosh for text only
        -- files. This preamble consists of the tokens:
        --    <garbage>TEXT<garbage><29 null characters>
        -- All graphic characters following this preamble may be written to an
        -- R1000 file, although carriage returns must be translated into
        -- linefeeds, in order to follow the R1000 Text_Io conventions for
        -- New_Line.
    begin
        case State is
            when Start =>
                if B = Character'Pos ('T') then
                    State := Text_1;
                end if;
            when Text_1 =>
                if B = Character'Pos ('E') then
                    State := Text_2;
                else
                    State := Start;
                end if;
            when Text_2 =>
                if B = Character'Pos ('X') then
                    State := Text_3;
                else
                    State := Start;
                end if;
            when Text_3 =>
                if B = Character'Pos ('T') then
                    State := Text_4;
                else
                    State := Start;
                end if;
            when Text_4 =>
                if B = Character'Pos (Ascii.Nul) then
                    State := Nulls;
                end if;
            when Nulls =>
                if B = Character'Pos (Ascii.Nul) then
                    Null_Count := Null_Count + 1;
                    if Null_Count = 29 then
                        State := Stop;
                    end if;
                else
                    State := Text_4;
                end if;
            when Stop =>
                case B is
                    when Cr =>
                        Dio.Write (Fd, Ascii.Lf);
                    when Space .. Tilde =>
                        Dio.Write (Fd, B);
                    when others =>
                        null;
                end case;
        end case;
    end Write;

    function Receive (Fd : Dio.File_Type;
                      Truncate : Boolean := True;
                      As_Text : Boolean := False) return Xmit_Error is
        Sectcurr : Dio.Byte;
        Errors : Integer := 0;
        Bufptr : Integer := 0;
        Sectnum : Integer := 1;
        Checksum : Integer;
        Error : Xmit_Error := None;
        State : Write_State := Start;
        Null_Count : Natural := 0;
    begin
        while Errors < Errormax loop
            begin
                case Readchar (10.0) is
                    when Eot =>
                        if Errors = 0 then
                            Sendchar (Ack);
                            if Truncate then
                                while Bufptr > 0 and then
                                         Bufr (Bufptr) = Nul loop
                                    Bufptr := Bufptr - 1;
                                    Bytes_Xferred := Bytes_Xferred - 1;
                                end loop;
                            end if;
                            if not As_Text then
                                Dio.Write (Fd, Bufr (1 .. Bufptr));
                            else
                                for Index in 1 .. Bufptr loop
                                    Write (Fd, Bufr (Index), State, Null_Count);
                                end loop;
                            end if;
                            return None;
                        end if;

                    when Soh =>
                        Sectcurr := Readchar;

                        if Sectcurr + Readchar = 255 then
                            if Integer (Sectcurr) = Sectnum mod 256 then
                                if Bufptr >= Bufsize then
                                    if not As_Text then
                                        Dio.Write (Fd, Bufr);
                                    else
                                        for Index in Bufr'Range loop
                                            Write (Fd, Bufr (Index),
                                                   State, Null_Count);
                                        end loop;
                                    end if;
                                    Bufptr := 0;
                                end if;

                                Checksum := 0;

                                for J in Bufptr + 1 .. Bufptr + Secsiz loop
                                    Bufr (J) := Readchar;
                                    Checksum := Checksum + Integer (Bufr (J));
                                end loop;

                                if Dio.Byte (Checksum mod 256) = Readchar then
                                    Errors := 0;
                                    Sectnum := Sectnum + 1;
                                    Bufptr := Bufptr + Secsiz;
                                    Bytes_Xferred := Bytes_Xferred + Secsiz;
                                    Error := None;
                                else
                                    Error := Bad_Checksum;
                                end if;
                            else
                                Error := Bad_Sector_Number;
                            end if;
                        else
                            Error := Bad_Sector_Check_Byte;
                        end if;

                        if Error /= None then
                            Ring_Ptr := (Ring_Ptr + 1) mod 20;
                            Error_Ring (Ring_Ptr) := Error;
                            Error_Byte (Ring_Ptr) := Bytes_Xferred;

                            if Error > Bad_Sector_Number then
                                Errors := Errors + 1;
                                Sendchar (Nak);
                            end if;
                        else
                            Sendchar (Ack);
                        end if;

                    when others =>
                        Ring_Ptr := (Ring_Ptr + 1) mod 20;
                        Error_Ring (Ring_Ptr) := Ignored_Character;
                        Error_Byte (Ring_Ptr) := Bytes_Xferred;
                end case;

            exception
                when Time_Out =>
                    Sendchar (Nak);
            end;
        end loop;

        return Error;
    end Receive;

    procedure Receive (File : String; From_Mac : Boolean := False) is
        Fd : Dio.File_Type;
        Forks : Integer := 0;
    begin
        Bytes_Xferred := 0;
        Error := None;
        Error_Ring := (others => None);
        Error_Byte := (others => 0);
        Ring_Ptr := 19;

        begin
            Dio.Create (Fd, Dio.Out_File, File);
        exception
            when others =>
                Emitt ("Can't create " & File & " (" &
                       Debug_Tools.Get_Exception_Name & ')');
                return;
        end;

        Emitt ("Ready to receive " & Dio.Name (Fd));
        Emitt ("Send three ^D's at end of transmission.");

        if not From_Mac then
            Error := Receive (Fd, True, False);
        else
            while Readchar /= Character'Pos (Ascii.Esc) loop
                null;
            end loop;

            while Readchar /= Character'Pos ('a') loop
                null;
            end loop;

            Sendchar (Ack);

            Error := Receive (Fd, False, False);

            if Error = None then
                if Bufr (1 + 86) /= 0 or else Bufr (1 + 85) /= 0 or else
                   Bufr (1 + 84) /= 0 or else Bufr (1 + 83) /= 0 then
                    Forks := Forks + 1;
                end if;

                if Bufr (1 + 90) /= 0 or else Bufr (1 + 89) /= 0 or else
                   Bufr (1 + 88) /= 0 or else Bufr (1 + 87) /= 0 then
                    Forks := Forks + 1;
                end if;
            end if;

            for J in 1 .. Forks loop
                Error := Receive (Fd, J = Forks, False);
                exit when Error /= None;
            end loop;
        end if;

        Tio.Input.Flush (Input);
        Dio.Close (Fd);

        loop
            exit when Readchar = Eot and then
                         Readchar = Eot and then Readchar = Eot;
        end loop;

        if Error = None then
            Emitt (Su.Number_To_String (Bytes_Xferred) & " bytes received.");
        else
            Emitt ("*** Too many errors! (" & Xmit_Error'Image (Error) & ')');
        end if;

    exception
        when others =>
            if Dio.Is_Open (Fd) then
                Dio.Close (Fd);
            end if;

            Terminal_Specific.Input.Flush (Input);
            Emitt ("Transmission failed with " &
                   Debug_Tools.Get_Exception_Name);
    end Receive;

    procedure Receive_Text (File : String; From_Mac : Boolean := False) is
        Fd : Dio.File_Type;
        Forks : Integer := 0;
    begin
        Bytes_Xferred := 0;
        Error := None;
        Error_Ring := (others => None);
        Error_Byte := (others => 0);
        Ring_Ptr := 19;

        begin
            Dio.Create (Fd, Dio.Out_File, File);
        exception
            when others =>
                Emitt ("Can't create " & File & " (" &
                       Debug_Tools.Get_Exception_Name & ')');
                return;
        end;

        Emitt ("Ready to receive " & Dio.Name (Fd) & " as text file");
        Emitt ("Send three ^D's at end of transmission.");

        if not From_Mac then
            Error := Receive (Fd, True, True);
        else
            while Readchar /= Character'Pos (Ascii.Esc) loop
                null;
            end loop;

            while Readchar /= Character'Pos ('a') loop
                null;
            end loop;

            Sendchar (Ack);

            Error := Receive (Fd, False, True);

            if Error = None then
                if Bufr (1 + 86) /= 0 or else Bufr (1 + 85) /= 0 or else
                   Bufr (1 + 84) /= 0 or else Bufr (1 + 83) /= 0 then
                    Forks := Forks + 1;
                end if;

                if Bufr (1 + 90) /= 0 or else Bufr (1 + 89) /= 0 or else
                   Bufr (1 + 88) /= 0 or else Bufr (1 + 87) /= 0 then
                    Forks := Forks + 1;
                end if;
            end if;

            for J in 1 .. Forks loop
                Error := Receive (Fd, J = Forks, True);
                exit when Error /= None;
            end loop;
        end if;

        Tio.Input.Flush (Input);
        Dio.Close (Fd);

        loop
            exit when Readchar = Eot and then
                         Readchar = Eot and then Readchar = Eot;
        end loop;

        if Error = None then
            Emitt (Su.Number_To_String (Bytes_Xferred) & " bytes received.");
        else
            Emitt ("*** Too many errors! (" & Xmit_Error'Image (Error) & ')');
        end if;

    exception
        when others =>
            if Dio.Is_Open (Fd) then
                Dio.Close (Fd);
            end if;

            Terminal_Specific.Input.Flush (Input);
            Emitt ("Transmission failed with " &
                   Debug_Tools.Get_Exception_Name);
    end Receive_Text;

    function Send (Fd : Dio.File_Type;
                   N : Integer := Integer'Last;
                   As_Text : Boolean := False) return Xmit_Error is
        Sectnum : Integer := 1;
        Bytes : Integer;
        Checksum : Integer;
        Bufptr : Integer;
    begin
        for J in 1 .. Errormax loop
            exit when Readchar = Nak;

            if J = Errormax then
                return No_Nak;
            end if;
        end loop;

        for I in 1 .. N loop
            exit when Dio.End_Of_File (Fd);
            Dio.Read (Fd, Bufr, Bytes);

            for J in Bytes + 1 .. Secsiz * ((Bytes + Secsiz - 1) / Secsiz) loop
                Bufr (J) := Nul;
            end loop;

            Bufptr := 0;

            while Bufptr < Bytes loop
                for Attempt in 1 .. Retrymax loop
                    Sendchar (Soh);
                    Sendchar (Dio.Byte (Sectnum mod 256));
                    Sendchar (Dio.Byte (255 - Sectnum mod 256));
                    Checksum := 0;

                    for J in Bufptr + 1 .. Bufptr + Secsiz loop
                        if As_Text and then Bufr (J) = Lf then
                            Bufr (J) := Cr;
                        end if;
                        Sendchar (Bufr (J));
                        Checksum := Checksum + Integer (Bufr (J));
                    end loop;

                    Sendchar (Dio.Byte (Checksum mod 256));

                    exit when Readchar = Ack;

                    if Attempt = Retrymax then
                        return No_Ack;
                    end if;
                end loop;

                Bufptr := Bufptr + Secsiz;
                Sectnum := Sectnum + 1;
            end loop;

            Bytes_Xferred := Bytes_Xferred + Bytes;
        end loop;

        for Attempt in 1 .. Retrymax loop
            Sendchar (Eot);

            if Readchar = Ack then
                return None;
            end if;
        end loop;
    end Send;

    procedure Send (File : String; To_Mac : Boolean := False) is
        Fd : Dio.File_Type;
        Error : Xmit_Error := None;
        Df, Rf : Integer;
    begin
        begin
            Dio.Open (Fd, Dio.In_File, File);
        exception
            when others =>
                Emitt ("Can't open " & File & " (" &
                       Debug_Tools.Get_Exception_Name & ')');
                return;
        end;

        Emitt ("Sending File " & Dio.Name (Fd));
        Bytes_Xferred := 0;

        if not To_Mac then
            Error := Send (Fd, Integer'Last, False);
        else
            delay 10.0;
            Sendchar (Character'Pos (Ascii.Esc));
            Sendchar (Character'Pos ('a'));

            while Readchar /= Ack loop
                null;
            end loop;

            Error := Send (Fd, 1, False);

            if Error = None then
                Df := Integer (Bufr (1 + 86) +
                               256 * (Bufr (1 + 85) +
                                      256 * (Bufr (1 + 84) +
                                             256 * (Bufr (1 + 83)))));
                Rf := Integer (Bufr (1 + 90) +
                               256 * (Bufr (1 + 89) +
                                      256 * (Bufr (1 + 88) +
                                             256 * (Bufr (1 + 87)))));

                if Df > 0 then
                    Error := Send (Fd, (Df + 127) / 128, False);
                end if;

                if Error = None and then Rf > 0 then
                    Error := Send (Fd, (Rf + 127) / 128, False);
                end if;
            end if;
        end if;

        Dio.Close (Fd);

        if Error = None then
            delay 5.0;
            Emitt (Su.Number_To_String (Bytes_Xferred) & " bytes transmitted.");
        else
            Emitt ("*** Too many errors! (" & Xmit_Error'Image (Error) & ')');
        end if;
    exception
        when others =>
            Emitt ("Transmission failed with " &
                   Debug_Tools.Get_Exception_Name);

            if Dio.Is_Open (Fd) then
                Dio.Close (Fd);
            end if;
    end Send;

    procedure Send_Text (File : String; To_Mac : Boolean := False) is
        Fd : Dio.File_Type;
        Error : Xmit_Error := None;
        Df, Rf : Integer;
    begin
        begin
            Dio.Open (Fd, Dio.In_File, File);
        exception
            when others =>
                Emitt ("Can't open " & File & " (" &
                       Debug_Tools.Get_Exception_Name & ')');
                return;
        end;

        Emitt ("Sending File " & Dio.Name (Fd) & " as text");
        Bytes_Xferred := 0;

        if not To_Mac then
            Error := Send (Fd, Integer'Last, True);
        else
            delay 10.0;
            Sendchar (Character'Pos (Ascii.Esc));
            Sendchar (Character'Pos ('a'));

            while Readchar /= Ack loop
                null;
            end loop;

            Error := Send (Fd, 1, True);

            if Error = None then
                Df := Integer (Bufr (1 + 86) +
                               256 * (Bufr (1 + 85) +
                                      256 * (Bufr (1 + 84) +
                                             256 * (Bufr (1 + 83)))));
                Rf := Integer (Bufr (1 + 90) +
                               256 * (Bufr (1 + 89) +
                                      256 * (Bufr (1 + 88) +
                                             256 * (Bufr (1 + 87)))));

                if Df > 0 then
                    Error := Send (Fd, (Df + 127) / 128, True);
                end if;

                if Error = None and then Rf > 0 then
                    Error := Send (Fd, (Rf + 127) / 128, True);
                end if;
            end if;
        end if;

        Dio.Close (Fd);

        if Error = None then
            delay 5.0;
            Emitt (Su.Number_To_String (Bytes_Xferred) & " bytes transmitted.");
        else
            Emitt ("*** Too many errors! (" & Xmit_Error'Image (Error) & ')');
        end if;
    exception
        when others =>
            Emitt ("Transmission failed with " &
                   Debug_Tools.Get_Exception_Name);

            if Dio.Is_Open (Fd) then
                Dio.Close (Fd);
            end if;
    end Send_Text;

    procedure Show_Usage is
    begin
        Emitt ("Usage:");
        Emitt ("..> sx <file>   -- send a file via Xmodem");
        Emitt ("..> st <file>   -- send a text file via Xmodem");
        Emitt ("..> rx <file>   -- receive a file via Xmodem");
        Emitt ("..> rt <file>   -- receive a text file via Xmodem");
        Emitt ("..> cd <dir>    -- connect to another directory");
        Emitt ("..> vd <pat>    -- display selected objects");
        Emitt ("..> ty <file>   -- type a file to the screen");
        Emitt ("..> ex          -- exit Xmodem and release terminal");
    end Show_Usage;

    function Ok (Status : Object.Error_Code; Msg : String) return Boolean is
    begin
        if Object.Is_Bad (Status) then
            Emitt (Msg);
            Emitt (Object.Message (Status));
            return False;
        else
            return True;
        end if;
    end Ok;

    function Maxlength (S : String; W : Integer) return Integer is
    begin
        if S'Length > W then
            return S'Length;
        else
            return W;
        end if;
    end Maxlength;

    function Padded (S : String; W : Integer) return String is
    begin
        return S & String'(S'Length .. W => ' ');
    end Padded;

    procedure Vd (Dir : String) is
        Children : Object.Iterator := Naming.Resolution (Dir);
        Width : Integer := 0;
        Child : Object.Handle;
        Parent : Object.Handle := Object.Nil;
        Last_Parent : Object.Handle := Object.Nil;
    begin
        if Object.Is_Bad (Children) then
            Emitt (Object.Message (Children));
        else
            while not Object.Done (Children) loop
                Child := Object.Value (Children);
                Width := Maxlength (Naming.Unique_Simple_Name (Child), Width);
                Object.Next (Children);
            end loop;

            Object.Reset (Children);

            while not Object.Done (Children) loop
                Child := Object.Value (Children);
                Parent := Traversal.Parent (Child);

                if Object.Is_Ok (Parent) and then
                   not Object.Same_Object (Parent, Last_Parent) then
                    Last_Parent := Parent;
                    Emitt ("");
                    Emitt ("Selected objects in """ &
                           Naming.Unique_Full_Name (Parent) & '"');
                    Emitt ("");
                end if;

                Emitt (Padded (Naming.Unique_Simple_Name (Child), Width) &
                       Time_Utilities.Image
                          (Time_Utilities.Convert_Time
                              (Statistics.Time_Of_Last_Update (Child)),
                           Time_Utilities.Year_Month_Day,
                           Time_Utilities.Short) &
                       Su.Number_To_String
                          (Statistics.Object_Size (Child) / 8, 10, 7));
                Object.Next (Children);
            end loop;
        end if;
    end Vd;

    procedure Ty (F : String) is
        package Sio renames Io;
        File : Sio.File_Type;
        S : String (1 .. 1);
    begin
        Sio.Open (File, Sio.In_File, F);

        while not Sio.End_Of_File (File) loop
            Emitt (Sio.Get_Line (File));
            Tio.Read (Input, S, N, 0.0);
            exit when N > 0;
        end loop;

        Sio.Close (File);

    exception
        when others =>
            if Sio.Is_Open (File) then
                Sio.Close (File);
            end if;

            Emitt ("Abandoning file dump: " & Debug_Tools.Get_Exception_Name);
    end Ty;

begin
    Emits ("You will be using terminal >>> " &
           Su.Number_To_String (Term) & " <<<");
    Terminal.Set_Disconnect_On_Logoff (Term, False);
    Job.Disconnect;
    Operator.Force_Logoff (Term);
    Open_Terminal (Term);
    Emitt (Ascii.Esc & "[H" & Ascii.Esc & "[J");
    Emitt ("Xmodem Transfer Subsystem, V1.0");

    Main:
        loop
            begin
                loop
                    Prompt ("Xmodem> ", S, N);

                    case N is
                        when 0 =>
                            null;
                        when 1 =>
                            if S (1) = '?' then
                                Show_Usage;
                            else
                                Emitt ((1 => Ascii.Bel));
                            end if;
                        when others =>
                            exit Main when S (1 .. 2) = "ex";

                            if S (1 .. 3) = "sx " then
                                Send (S (4 .. N), False);
                            elsif S (1 .. 3) = "st " then
                                Send_Text (S (4 .. N), False);
                            elsif S (1 .. 3) = "rx " then
                                Receive (S (4 .. N), False);
                            elsif S (1 .. 3) = "rt " then
                                Receive_Text (S (4 .. N), False);
                            elsif S (1 .. 3) = "cd " then
                                Naming.Set_Default_Context (S (4 .. N), Status);
                                if Ok (Status,
                                       "Can't set current directory to " &
                                          S (4 .. N)) then
                                    Emitt ("Current directory is " &
                                           Naming.Default_Context);
                                end if;
                            elsif S (1 .. N) = "vd" then
                                Vd ("@");
                            elsif S (1 .. 3) = "vd " then
                                Vd (S (3 .. N));
                            elsif S (1 .. 3) = "ty " then
                                Ty (S (3 .. N));
                            else
                                Emitt ((1 => Ascii.Bel));
                            end if;
                    end case;
                end loop;
            exception
                when others =>
                    Tio.Input.Flush (Input);
                    Emitt ("unexpected exception: " &
                           Debug_Tools.Get_Exception_Name);
            end;
        end loop Main;

    raise Io_Exceptions.End_Error;
exception
    when others =>
        Close_Terminal (Term);

        if Term >= 240 then

            Terminal.Set_Disconnect_On_Logoff (Term, True);
        end if;

end Xmodem;