|
|
DataMuseum.dkPresents historical artifacts from the history of: Rational R1000/400 Tapes |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about Rational R1000/400 Tapes Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - metrics - downloadIndex: B T
Length: 31495 (0x7b07)
Types: TextFile
Names: »B«
└─⟦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⟧
with Log, Transport_Defs, Device_Independent_Io, Debug_Tools, Io, Io_Exceptions;
with Byte_String_Io;
package body Tftp_Utilities is
Timeout_Wait : constant Duration := 5.0;
Max_Retries : constant := 5;
type Doublet is range 0 .. 65_535;
Read_Packet : constant Doublet := 1;
Write_Packet : constant Doublet := 2;
Data_Packet : constant Doublet := 3;
Ack_Packet : constant Doublet := 4;
Error_Packet : constant Doublet := 5;
Unknown_Transfer_Id : constant Doublet := 5;
function Decode_Doublet (Item : Byte_Defs.Byte_String) return Doublet;
function Decode_Doublet (Item : Byte_Defs.Byte_String) return Doublet is
begin
return Doublet (Byte_Defs.Byte'Pos (Item (Item'First)) * 256 +
Byte_Defs.Byte'Pos (Item (Item'First + 1)));
end Decode_Doublet;
function Encode_Doublet (Item : Doublet) return Byte_Defs.Byte_String;
function Encode_Doublet (Item : Doublet) return Byte_Defs.Byte_String is
Data : Byte_Defs.Byte_String (1 .. 2);
begin
Data (1) := Byte_Defs.Byte'Val (Item / 256);
Data (2) := Byte_Defs.Byte'Val (Item - (Item / 256) * 256);
return Data;
end Encode_Doublet;
function Previous_Sequence_Number (Sequence : Doublet) return Doublet;
function Previous_Sequence_Number (Sequence : Doublet) return Doublet is
begin
if Sequence = 0 then
return Doublet (0);
elsif Sequence = 1 then
return Doublet'Last;
else
return Doublet'Pred (Sequence);
end if;
end Previous_Sequence_Number;
function Next_Sequence_Number (Sequence : Doublet) return Doublet;
function Next_Sequence_Number (Sequence : Doublet) return Doublet is
begin
if Sequence = Doublet'Last then
return 1;
else
return Doublet'Succ (Sequence);
end if;
end Next_Sequence_Number;
procedure Insert_String (From : String; Into : out Byte_Defs.Byte_String);
procedure Insert_String (From : String; Into : out Byte_Defs.Byte_String) is
Ptr : Natural := Into'First;
begin
for I in From'Range loop
exit when Ptr = Into'Last;
Into (Ptr) := Byte_Defs.Byte'Val (Character'Pos (From (I)));
Ptr := Ptr + 1;
end loop;
Into (Ptr) := 0;
end Insert_String;
procedure Display_Error_Packet (Packet : Byte_Defs.Byte_String);
procedure Display_Error_Packet (Packet : Byte_Defs.Byte_String) is
Message : String (1 .. Packet'Length);
Message_Last : Natural;
begin
if Decode_Doublet (Packet (1 .. 2)) = Error_Packet then
case Decode_Doublet (Packet (3 .. 4)) is
when Error_Class'Pos (Not_Defined) =>
Log.Put_Line ("'Not Defined' error packet received:");
when Error_Class'Pos (File_Not_Found) =>
Log.Put_Line ("'File Not Found' error packet received:");
when Error_Class'Pos (Access_Violation) =>
Log.Put_Line ("'Access Violation' error packet received:");
when Error_Class'Pos (Medium_Full) =>
Log.Put_Line
("'Disk Full/Allocation Exceeded' error packet received:");
when Error_Class'Pos (Illegal_Operation) =>
Log.Put_Line
("'Illegal TFTP Operation' error packet received:");
when Error_Class'Pos (Unknown_Tid) =>
Log.Put_Line
("'Unknown Transfer ID' error packet received:");
when others =>
Log.Put_Line ("Illegal error packet type =>" &
Integer'Image (Integer
(Decode_Doublet
(Packet (3 .. 4)))) &
" received:");
end case;
Extract_String (Packet (5 .. Packet'Last), Message, Message_Last);
Log.Put_Line (Message (1 .. Message_Last));
else
Log.Put_Line ("Display_Error called with non-error packet:");
Log.Put_Line (Byte_String_Io.Image (Packet));
end if;
end Display_Error_Packet;
procedure Receive_Packet (From : Transport.Connection_Id;
Data : out Byte_Defs.Byte_String;
Count : out Natural);
procedure Receive_Packet (From : Transport.Connection_Id;
Data : out Byte_Defs.Byte_String;
Count : out Natural) is
Status : Transport_Defs.Status_Code;
begin
Transport.Receive (From, Status, Data, Count, Timeout_Wait);
if not Transport_Defs."=" (Status, Transport_Defs.Ok) then
if Transport_Defs."=" (Status, Transport_Defs.Timed_Out) then
raise Timeout;
else
Log.Put_Line ("Error on receive => " &
Transport_Defs.Image (Status));
raise Fatal_Error;
end if;
end if;
end Receive_Packet;
procedure Send_Packet (To : Transport.Connection_Id;
Data : Byte_Defs.Byte_String);
procedure Send_Packet (To : Transport.Connection_Id;
Data : Byte_Defs.Byte_String) is
Status : Transport_Defs.Status_Code;
Count : Natural;
begin
Transport.Transmit (To, Status, Data, Count, 5.0);
end Send_Packet;
procedure Send_Error (To : Transport.Connection_Id;
Class : Tftp_Utilities.Error_Class;
Error_Text : String) is
Packet : Byte_Defs.Byte_String (1 .. 1008);
Length : Natural;
begin
Packet (1 .. 2) := Encode_Doublet (Error_Packet);
Packet (3 .. 4) := Encode_Doublet (Error_Class'Pos (Class));
Insert_String (Error_Text, Packet (5 .. Packet'Last));
Send_Packet (To, Packet (1 .. Error_Text'Length + 5));
end Send_Error;
function Receive_Ack (From : Transport.Connection_Id; Sequence : Doublet)
return Boolean;
function Receive_Ack (From : Transport.Connection_Id; Sequence : Doublet)
return Boolean is
Expected_Tid : constant Transport_Defs.Socket_Id :=
Transport.Remote_Socket (From);
Packet : Byte_Defs.Byte_String (1 .. 1008);
Count : Natural;
begin
while True loop
Receive_Packet (From, Packet, Count);
if Sequence = 0 or else
Transport_Defs."=" (Expected_Tid,
Transport.Remote_Socket (From)) then
if Count >= 4 then
if Decode_Doublet (Packet (1 .. 2)) = Data_Packet then
return True;
elsif Decode_Doublet (Packet (1 .. 2)) = Ack_Packet and then
Decode_Doublet (Packet (3 .. 4)) = Sequence then
return True;
elsif Decode_Doublet (Packet (1 .. 2)) = Error_Packet then
if Decode_Doublet (Packet (3 .. 4)) =
Unknown_Transfer_Id then
raise Timeout;
else
Display_Error_Packet (Packet (1 .. Count));
raise Fatal_Error;
end if;
end if;
end if;
else
Send_Error (From, Unknown_Tid, "");
end if;
end loop;
end Receive_Ack;
procedure Send_Ack (To : Transport.Connection_Id; Sequence : Doublet);
procedure Send_Ack (To : Transport.Connection_Id; Sequence : Doublet) is
Data : Byte_Defs.Byte_String (1 .. 4);
begin
Data (1 .. 2) := Encode_Doublet (Ack_Packet);
Data (3 .. 4) := Encode_Doublet (Sequence);
Send_Packet (To, Data);
end Send_Ack;
procedure Send_Read (To : Transport.Connection_Id;
File : String;
Mode : Transfer_Mode);
procedure Send_Read (To : Transport.Connection_Id;
File : String;
Mode : Transfer_Mode) is
Data : Byte_Defs.Byte_String (1 .. 12 + File'Length);
Ptr : Natural := 4 + File'Length;
begin
Data (1 .. 2) := Encode_Doublet (Read_Packet);
Insert_String (File, Data (3 .. Data'Last));
case Mode is
when Binary =>
Insert_String ("binary", Data
(3 + File'Length + 1 .. Data'Last));
Ptr := Ptr + 6;
when Text =>
Insert_String ("netascii",
Data (3 + File'Length + 1 .. Data'Last));
Ptr := Ptr + 8;
when Mail =>
Insert_String ("mail", Data (3 + File'Length + 1 .. Data'Last));
Ptr := Ptr + 4;
end case;
Send_Packet (To, Data (1 .. Ptr));
end Send_Read;
procedure Send_Write (To : Transport.Connection_Id;
File : String;
Mode : Transfer_Mode);
procedure Send_Write (To : Transport.Connection_Id;
File : String;
Mode : Transfer_Mode) is
Data : Byte_Defs.Byte_String (1 .. 12 + File'Length);
Ptr : Natural := 4 + File'Length;
begin
Data (1 .. 2) := Encode_Doublet (Write_Packet);
Insert_String (File, Data (3 .. Data'Last));
case Mode is
when Binary =>
Insert_String ("binary", Data
(3 + File'Length + 1 .. Data'Last));
Ptr := Ptr + 6;
when Text =>
Insert_String ("netascii",
Data (3 + File'Length + 1 .. Data'Last));
Ptr := Ptr + 8;
when Mail =>
Insert_String ("mail", Data (3 + File'Length + 1 .. Data'Last));
Ptr := Ptr + 4;
end case;
Send_Packet (To, Data (1 .. Ptr));
end Send_Write;
procedure Receive_Data (From : Transport.Connection_Id;
Sequence : Doublet;
Data : out Byte_Defs.Byte_String;
Count : out Natural);
procedure Receive_Data (From : Transport.Connection_Id;
Sequence : Doublet;
Data : out Byte_Defs.Byte_String;
Count : out Natural) is
Expected_Tid : constant Transport_Defs.Socket_Id :=
Transport.Remote_Socket (From);
Packet : Byte_Defs.Byte_String (1 .. 516);
Ptr : Natural := Data'First;
Status : Transport_Defs.Status_Code;
Length : Natural;
Data_Received : Boolean := False;
Retries : Natural := 0;
begin
while not Data_Received loop
begin
Receive_Packet (From, Packet, Length);
if Sequence = 1 or else
Transport_Defs."=" (Expected_Tid,
Transport.Remote_Socket (From)) then
if Length > 4 then
if Decode_Doublet (Packet (1 .. 2)) =
Data_Packet and then
Decode_Doublet (Packet (3 .. 4)) = Sequence then
Data_Received := True;
elsif Decode_Doublet (Packet (1 .. 2)) =
Error_Packet then
if Decode_Doublet (Packet (3 .. 4)) =
Unknown_Transfer_Id then
raise Timeout;
else
Display_Error_Packet (Packet (1 .. Length));
raise Fatal_Error;
end if;
end if;
end if;
else
Send_Error (From, Unknown_Tid, "");
end if;
exception
when Timeout =>
Retries := Retries + 1;
if Retries < Max_Retries then
Send_Ack (From, Previous_Sequence_Number (Sequence));
else
raise Fatal_Error;
end if;
end;
end loop;
Send_Ack (From, Sequence);
for I in 5 .. Length loop
exit when Ptr > Data'Last;
Data (Ptr) := Packet (I);
Ptr := Ptr + 1;
end loop;
Count := Ptr - 1;
end Receive_Data;
procedure Send_Data (To : Transport.Connection_Id;
Data : Byte_Defs.Byte_String;
Sequence : Doublet);
procedure Send_Data (To : Transport.Connection_Id;
Data : Byte_Defs.Byte_String;
Sequence : Doublet) is
Packet : Byte_Defs.Byte_String (1 .. 516);
Ptr : Natural := 5;
Block_Acknowledged : Boolean;
Retries : Natural := 0;
begin
Packet (1 .. 2) := Encode_Doublet (Data_Packet);
Packet (3 .. 4) := Encode_Doublet (Sequence);
for I in Data'Range loop
exit when Ptr > Packet'Last;
Packet (Ptr) := Data (I);
Ptr := Ptr + 1;
end loop;
Block_Acknowledged := False;
while not Block_Acknowledged loop
Send_Packet (To, Packet (1 .. Ptr - 1));
begin
Block_Acknowledged := Receive_Ack (To, Sequence);
exception
when Timeout =>
Retries := Retries + 1;
if Retries = Max_Retries then
raise Fatal_Error;
end if;
when others =>
raise;
end;
end loop;
end Send_Data;
procedure Receive_A_File (Remote_Pathname : String;
Local_Pathname : String;
Mode : Tftp_Utilities.Transfer_Mode;
Requestor : Tftp_Utilities.Requestor_Type;
From : in out Transport.Connection_Id) is
B_File : Device_Independent_Io.File_Type;
T_File : Io.File_Type;
Data : Byte_Defs.Byte_String (1 .. 512);
Count : Natural := 512;
Block : Doublet := 1;
procedure Write_Buffer (File : Io.File_Type;
Data : Byte_Defs.Byte_String);
procedure Write_Buffer (File : Io.File_Type;
Data : Byte_Defs.Byte_String) is
Buff : String (1 .. 514);
Sptr : Natural := Data'First;
Dptr : Natural := Buff'First;
Char : Character;
begin
while Sptr <= Data'Last loop
Char := Character'Val (Byte_Defs.Byte'Pos (Data (Sptr)));
if Char = Ascii.Cr then
Io.Put_Line (File, Buff (1 .. Dptr - 1));
Dptr := Buff'First;
Sptr := Sptr + 2;
elsif Char = Ascii.Lf then
Sptr := Sptr + 1;
else
Buff (Dptr) := Char;
Dptr := Dptr + 1;
Sptr := Sptr + 1;
end if;
end loop;
if Dptr /= Buff'First then
Io.Put (File, Buff (1 .. Dptr - 1));
end if;
end Write_Buffer;
begin
case Mode is
when Binary =>
Device_Independent_Io.Create (B_File, Name => Local_Pathname);
when Text | Mail =>
Io.Create (T_File, Name => Local_Pathname);
end case;
case Requestor is
when Client =>
Send_Read (From, Remote_Pathname, Mode);
when Server =>
Send_Ack (From, 0);
end case;
Receive_Data (From, Block, Data, Count);
case Mode is
when Text | Mail =>
Write_Buffer (T_File, Data (1 .. Count));
when Binary =>
Device_Independent_Io.Write (B_File, Data (1 .. Count));
end case;
case Requestor is
when Client =>
declare
Remote_Socket : constant Transport_Defs.Socket_Id :=
Transport.Remote_Socket (From);
Remote_Host : constant Transport_Defs.Host_Id :=
Transport.Remote_Host (From);
Status : Transport_Defs.Status_Code;
begin
Transport.Disconnect (From);
Transport.Connect (From, Status, Remote_Host,
Remote_Socket, 5.0);
if not Transport_Defs."=" (Transport_Defs.Ok, Status) then
raise Fatal_Error;
end if;
end;
when Server =>
null;
end case;
while Count = 512 loop
Block := Next_Sequence_Number (Block);
Receive_Data (From, Block, Data, Count);
case Mode is
when Text | Mail =>
Write_Buffer (T_File, Data (1 .. Count));
when Binary =>
Device_Independent_Io.Write (B_File, Data (1 .. Count));
end case;
end loop;
case Mode is
when Binary =>
Device_Independent_Io.Close (B_File);
when Text | Mail =>
Io.Close (T_File);
end case;
exception
when Io_Exceptions.Name_Error =>
case Mode is
when Binary =>
if Device_Independent_Io.Is_Open (B_File) then
Device_Independent_Io.Delete (B_File);
end if;
when Text | Mail =>
if Io.Is_Open (T_File) then
Io.Delete (T_File);
end if;
end case;
case Requestor is
when Server =>
Send_Error (From, Not_Defined,
"Invalid file name => " & Local_Pathname);
when Client =>
Log.Put_Line ("Create of " & Local_Pathname &
" raised exception NAME_ERROR");
end case;
when Io_Exceptions.Status_Error =>
case Mode is
when Binary =>
if Device_Independent_Io.Is_Open (B_File) then
Device_Independent_Io.Delete (B_File);
end if;
when Text | Mail =>
if Io.Is_Open (T_File) then
Io.Delete (T_File);
end if;
end case;
case Requestor is
when Server =>
Send_Error (From, Not_Defined,
"File is in use. Please try again later.");
when Client =>
Log.Put_Line ("Create of " & Local_Pathname &
" raised exception NAME_ERROR");
end case;
when Io_Exceptions.Use_Error =>
case Mode is
when Binary =>
if Device_Independent_Io.Is_Open (B_File) then
Device_Independent_Io.Delete (B_File);
end if;
when Text | Mail =>
if Io.Is_Open (T_File) then
Io.Delete (T_File);
end if;
end case;
case Requestor is
when Server =>
Send_Error (From, Not_Defined,
"Invalid output file name => " &
Local_Pathname);
when Client =>
Log.Put_Line ("Create of " & Local_Pathname &
" raised exception USE_ERROR");
end case;
when others =>
case Mode is
when Binary =>
if Device_Independent_Io.Is_Open (B_File) then
Device_Independent_Io.Delete (B_File);
end if;
when Text | Mail =>
if Io.Is_Open (T_File) then
Io.Delete (T_File);
end if;
end case;
case Requestor is
when Server =>
Send_Error (From, Not_Defined,
"Unknown fatal error receiving file => " &
Local_Pathname);
when Client =>
Log.Put_Line ("Get of " & Local_Pathname &
" raised exception " &
Debug_Tools.Get_Exception_Name);
end case;
end Receive_A_File;
procedure Send_A_File (Local_Pathname : String;
Remote_Pathname : String;
Mode : Tftp_Utilities.Transfer_Mode;
Requestor : Tftp_Utilities.Requestor_Type;
To : in out Transport.Connection_Id) is
B_File : Device_Independent_Io.File_Type;
T_File : Io.File_Type;
Block : Doublet := 1;
Data : Byte_Defs.Byte_String (1 .. 512);
Length : Natural;
Ack_Received : Boolean := False;
Residual_Line : String (1 .. 510);
Residual_Length : Integer := -1;
Residual_Lf : Boolean := False;
Dptr : Natural := Data'First;
procedure Fill_Buffer is
procedure Process_Line is
Buff : constant String := Io.Get_Line (T_File);
Sptr : Natural := Buff'First;
begin
while Dptr <= Data'Last and Sptr <= Buff'Last loop
Data (Dptr) := Byte_Defs.Byte'Val
(Character'Pos (Buff (Sptr)));
Dptr := Dptr + 1;
Sptr := Sptr + 1;
end loop;
if Sptr <= Buff'Last then
Residual_Line (1 .. Buff'Length - (Sptr - Buff'First)) :=
Buff (Sptr .. Buff'Last);
Residual_Length := Buff'Length - (Sptr - Buff'First);
elsif Dptr < Data'Last then
Data (Dptr) := Byte_Defs.Byte'Val
(Character'Pos (Ascii.Cr));
Data (Dptr + 1) := Byte_Defs.Byte'Val
(Character'Pos (Ascii.Lf));
Dptr := Dptr + 2;
Residual_Length := -1;
elsif Dptr = Data'Last then
Data (Dptr) := Byte_Defs.Byte'Val
(Character'Pos (Ascii.Cr));
Dptr := Dptr + 1;
Residual_Length := -1;
Residual_Lf := True;
else
Residual_Length := 0;
end if;
end Process_Line;
begin
Dptr := Data'First;
if Residual_Length >= 0 then
for I in Residual_Line'First .. Residual_Length loop
Data (Dptr) := Byte_Defs.Byte'Val
(Character'Pos (Residual_Line (I)));
Dptr := Dptr + 1;
end loop;
Data (Dptr) := Byte_Defs.Byte'Val (Character'Pos (Ascii.Cr));
Data (Dptr + 1) := Byte_Defs.Byte'Val
(Character'Pos (Ascii.Lf));
Dptr := Dptr + 2;
Residual_Length := -1;
elsif Residual_Lf then
Data (Dptr) := Byte_Defs.Byte'Val (Character'Pos (Ascii.Lf));
Dptr := Dptr + 1;
Residual_Lf := False;
end if;
while Dptr <= Data'Last loop
Process_Line;
end loop;
exception
when Io.End_Error =>
null;
when others =>
raise;
end Fill_Buffer;
begin
case Mode is
when Binary =>
Device_Independent_Io.Open
(B_File, Device_Independent_Io.In_File, Local_Pathname);
when Text | Mail =>
Io.Open (T_File, Io.In_File, Local_Pathname);
end case;
case Requestor is
when Client =>
Send_Write (To, Remote_Pathname, Mode);
declare
Retries : Natural := 0;
begin
while not Ack_Received loop
begin
while not Receive_Ack (To, 0) loop
null;
end loop;
Ack_Received := True;
declare
Remote_Socket :
constant Transport_Defs.Socket_Id :=
Transport.Remote_Socket (To);
Remote_Host : constant Transport_Defs.Host_Id :=
Transport.Remote_Host (To);
Status : Transport_Defs.Status_Code;
begin
Transport.Disconnect (To);
Transport.Connect (To, Status, Remote_Host,
Remote_Socket, 5.0);
if not Transport_Defs."="
(Transport_Defs.Ok, Status) then
raise Fatal_Error;
end if;
end;
exception
when Timeout =>
Retries := Retries + 1;
if Retries = Max_Retries then
raise Fatal_Error;
end if;
end;
end loop;
end;
when Server =>
null;
end case;
case Mode is
when Text | Mail =>
while not Io.End_Of_File (T_File) loop
Fill_Buffer;
Send_Data (To, Data (1 .. Dptr - 1), Block);
Block := Next_Sequence_Number (Block);
end loop;
Io.Close (T_File);
when Binary =>
while not Device_Independent_Io.End_Of_File (B_File) loop
Device_Independent_Io.Read (B_File, Data, Length);
Send_Data (To, Data (1 .. Length), Block);
Block := Next_Sequence_Number (Block);
end loop;
Device_Independent_Io.Close (B_File);
end case;
exception
when Io_Exceptions.Name_Error =>
case Mode is
when Binary =>
if Device_Independent_Io.Is_Open (B_File) then
Device_Independent_Io.Close (B_File);
end if;
when Mail | Text =>
if Io.Is_Open (T_File) then
Io.Close (T_File);
end if;
end case;
case Requestor is
when Server =>
Send_Error (To, File_Not_Found,
"File does not exist => " & Local_Pathname);
when Client =>
Log.Put_Line ("Create of " & Local_Pathname &
" raised exception NAME_ERROR");
end case;
when Io_Exceptions.Status_Error =>
case Mode is
when Binary =>
if Device_Independent_Io.Is_Open (B_File) then
Device_Independent_Io.Close (B_File);
end if;
when Mail | Text =>
if Io.Is_Open (T_File) then
Io.Close (T_File);
end if;
end case;
case Requestor is
when Server =>
Send_Error (To, Not_Defined,
"File is in use. Please try again later.");
when Client =>
Log.Put_Line ("Create of " & Local_Pathname &
" raised exception STATUS_ERROR");
end case;
when Io_Exceptions.Use_Error =>
case Mode is
when Binary =>
if Device_Independent_Io.Is_Open (B_File) then
Device_Independent_Io.Close (B_File);
end if;
when Mail | Text =>
if Io.Is_Open (T_File) then
Io.Close (T_File);
end if;
end case;
case Requestor is
when Server =>
Send_Error (To, Not_Defined,
"Invalid input file name => " & Local_Pathname);
when Client =>
Log.Put_Line ("Create of " & Local_Pathname &
" raised exception USE_ERROR");
end case;
when others =>
case Mode is
when Binary =>
if Device_Independent_Io.Is_Open (B_File) then
Device_Independent_Io.Close (B_File);
end if;
when Mail | Text =>
if Io.Is_Open (T_File) then
Io.Close (T_File);
end if;
end case;
case Requestor is
when Server =>
Send_Error (To, Not_Defined,
"Unknown fatal error sending file => " &
Local_Pathname);
when Client =>
Log.Put_Line ("Put of " & Local_Pathname &
" raised exception " &
Debug_Tools.Get_Exception_Name);
end case;
end Send_A_File;
procedure Extract_String (From : Byte_Defs.Byte_String;
To : out String;
Last : out Natural) is
Ptr : Natural := To'First;
Char : Character;
begin
for I in From'Range loop
exit when Byte_Defs."=" (From (I), 0) or Ptr > To'Last;
Char := Character'Val (Byte_Defs.Byte'Pos (From (I)));
if Char in 'a' .. 'z' then
Char := Character'Val
(Character'Pos (Char) - Character'Pos (' '));
end if;
To (Ptr) := Char;
Ptr := Ptr + 1;
end loop;
Last := Ptr - 1;
end Extract_String;
end Tftp_Utilities;