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 D M R T V

⟦9b477e385⟧ R1K_ARCHIVE_DATA, TextFile

    Length: 228268 (0x37bac)
    Types: R1K_ARCHIVE_DATA, TextFile
    Names: »DATA«

Derivation

└─⟦a7d1ea751⟧ Bits:30000550 8mm tape, Rational 1000, !users!projects 94_04_11
    └─ ⟦129cab021⟧ »DATA« 
        └─⟦this⟧ 
└─⟦f64eaa120⟧ Bits:30000752 8mm tape, Rational 1000, !projects 93 02 16
    └─ ⟦6f12a12be⟧ »DATA« 
        └─⟦this⟧ 
└─⟦2f6cfab89⟧ Bits:30000547 8mm tape, Rational 1000, !projects 94-01-04
    └─ ⟦d65440be7⟧ »DATA« 
        └─⟦this⟧ 

TextFile

package Bounded_String is

    subtype String_Length is Natural;

    type Variable_String (Maximum_Length : String_Length) is private;
    -- initialized to have a length of 0

    procedure Copy (Target : in out Variable_String; Source : Variable_String);
    procedure Copy (Target : in out Variable_String; Source : String);
    procedure Copy (Target : in out Variable_String; Source : Character);

    procedure Move (Target : in out Variable_String;
                    Source : in out Variable_String);

    function Image (V : Variable_String) return String;

    -- Value function with maximum length = current length
    function Value (S : String) return Variable_String;

    -- Value function with specified maximum length
    function Value (S : String; Max_Length : Natural) return Variable_String;
    pragma Inline (Image);

    procedure Free (V : in out Variable_String);

    procedure Append (Target : in out Variable_String;
                      Source :        Variable_String);

    procedure Append (Target : in out Variable_String; Source : String);

    procedure Append (Target : in out Variable_String; Source : Character);

    procedure Append (Target : in out Variable_String;
                      Source :        Character;
                      Count  :        Natural);

    procedure Insert (Target : in out Variable_String;
                      At_Pos :        Positive;
                      Source :        Variable_String);

    procedure Insert (Target : in out Variable_String;
                      At_Pos :        Positive;
                      Source :        String);

    procedure Insert (Target : in out Variable_String;
                      At_Pos :        Positive;
                      Source :        Character);

    procedure Insert (Target : in out Variable_String;
                      At_Pos :        Positive;
                      Source :        Character;
                      Count  :        Natural);

    procedure Delete (Target : in out Variable_String;
                      At_Pos :        Positive;
                      Count  :        Natural := 1);

    procedure Replace (Target : in out Variable_String;
                       At_Pos :        Positive;
                       Source :        Character);

    procedure Replace (Target : in out Variable_String;
                       At_Pos :        Positive;
                       Source :        Character;
                       Count  :        Natural);

    procedure Replace (Target : in out Variable_String;
                       At_Pos :        Positive;
                       Source :        String);

    procedure Replace (Target : in out Variable_String;
                       At_Pos :        Positive;
                       Source :        Variable_String);

    -- Truncate or extend with fill
    procedure Set_Length (Target     : in out Variable_String;
                          New_Length :        Natural;
                          Fill_With  :        Character := ' ');

    -- Get information about or contents of a string
    function Length  (Source : Variable_String) return Natural;
    function Char_At (Source : Variable_String; At_Pos : Positive)
                     return Character;

    function Extract (Source    : Variable_String;
                      Start_Pos : Positive;
                      End_Pos   : Natural) return String;

    -- get the allocated length of the string
    function Max_Length (Source : Variable_String) return Natural;
    pragma Inline (Length);
    pragma Inline (Char_At);
    pragma Inline (Max_Length);
private
    type Variable_String (Maximum_Length : String_Length) is
        record
            Length   : String_Length := 0;
            Contents : String (1 .. Maximum_Length);
        end record;

end Bounded_String;package body Bounded_String is
    procedure Copy (Target : in out Variable_String;
                    Source :        Variable_String) is
    begin
        Target.Contents (1 .. Source.Length) :=
           Source.Contents (1 .. Source.Length);
        Target.Length                        := Source.Length;
    end Copy;


    procedure Copy (Target : in out Variable_String; Source : String) is
    begin
        Target.Contents (1 .. Source'Length) := Source;
        Target.Length                        := Source'Length;
    end Copy;

    procedure Copy (Target : in out Variable_String; Source : Character) is
    begin
        Target.Contents (1) := Source;
        Target.Length       := 1;
    end Copy;


    procedure Move (Target : in out Variable_String;
                    Source : in out Variable_String) is
    begin
        Target.Contents (1 .. Source.Length) :=
           Source.Contents (1 .. Source.Length);
        Target.Length                        := Source.Length;
        Source.Length                        := 0;
    end Move;


    function Image (V : Variable_String) return String is
    begin
        return V.Contents (1 .. V.Length);
    end Image;


    function Value (S : String; Max_Length : Natural) return Variable_String is
        String_Value : String (1 .. Max_Length);
    begin
        String_Value (1 .. S'Length) := S;
        return Variable_String'(Maximum_Length => Max_Length,
                                Length         => S'Length,
                                Contents       => String_Value);
    end Value;


    function Value (S : String) return Variable_String is
    begin
        return Variable_String'(Maximum_Length => S'Length,
                                Length         => S'Length,
                                Contents       => S);

    end Value;


    procedure Free (V : in out Variable_String) is
    begin
        V.Length := 0;
    end Free;


    procedure Append (Target : in out Variable_String; Source : String) is
        Len : Natural := Target.Length + Source'Length;
    begin
        Target.Contents (Target.Length + 1 .. Len) := Source;
        Target.Length := Len;
    end Append;


    procedure Append (Target : in out Variable_String;
                      Source :        Variable_String) is
    begin
        Append (Target, Image (Source));
    end Append;


    procedure Append (Target : in out Variable_String; Source : Character) is
        Len : Natural := Target.Length + 1;
    begin
        Target.Contents (Len) := Source;
        Target.Length         := Len;
    end Append;


    procedure Append (Target : in out Variable_String;
                      Source :        Character;
                      Count  :        Natural) is
        Value_String : String (1 .. Count) := String'(1 .. Count => Source);
    begin
        Append (Target, Value_String);
    end Append;


    procedure Insert (Target : in out Variable_String;
                      At_Pos :        Positive;
                      Source :        String) is
    begin
        if At_Pos = Target.Length + 1 then
            Append (Target, Source);
        elsif At_Pos <= Target.Length then
            declare
                Len : Natural := Target.Length + Source'Length;
            begin
                Target.Contents (At_Pos .. Len) :=
                   Source & Target.Contents (At_Pos .. Target.Length);
                Target.Length                   := Len;
            end;
        else
            raise Constraint_Error;
        end if;
    end Insert;


    procedure Insert (Target : in out Variable_String;
                      At_Pos :        Positive;
                      Source :        Variable_String) is
    begin
        Insert (Target, At_Pos, Source.Contents (1 .. Source.Length));
    end Insert;


    procedure Insert (Target : in out Variable_String;
                      At_Pos :        Positive;
                      Source :        Character) is
        New_Len : Natural := Target.Length + 1;
    begin
        if At_Pos = New_Len then
            Append (Target, Source);
        elsif At_Pos > New_Len then
            raise Constraint_Error;
        else
            Target.Contents (At_Pos + 1 .. New_Len) :=
               Target.Contents (At_Pos .. Target.Length);
            Target.Contents (At_Pos) := Source;
            Target.Length := New_Len;
        end if;
    end Insert;


    procedure Insert (Target : in out Variable_String;
                      At_Pos :        Positive;
                      Source :        Character;
                      Count  :        Natural) is
        Value_String : String (1 .. Count) := String'(1 .. Count => Source);
    begin
        Insert (Target, At_Pos, Value_String);
    end Insert;


    procedure Delete (Target : in out Variable_String;
                      At_Pos :        Positive;
                      Count  :        Natural := 1) is
        Len : Natural := Target.Length - Count;
    begin
        if At_Pos - 1 > Len then
            raise Constraint_Error;
        end if;
        if At_Pos <= Len then
            Target.Contents (At_Pos .. Len) :=
               Target.Contents (At_Pos + Count .. Target.Length);
        end if;
        Target.Length := Len;
    end Delete;


    procedure Replace (Target : in out Variable_String;
                       At_Pos :        Positive;
                       Source :        Character) is
    begin
        if At_Pos > Target.Length then
            raise Constraint_Error;
        else
            Target.Contents (At_Pos) := Source;
        end if;
    end Replace;


    procedure Replace (Target : in out Variable_String;
                       At_Pos :        Positive;
                       Source :        String) is
        End_Pos : constant Positive := At_Pos + Source'Length - 1;
    begin
        if End_Pos > Target.Length then
            raise Constraint_Error;
        else
            Target.Contents (At_Pos .. End_Pos) := Source;
        end if;
    end Replace;

    procedure Replace (Target : in out Variable_String;
                       At_Pos :        Positive;
                       Source :        Character;
                       Count  :        Natural) is
        Value_String : String (1 .. Count) := String'(1 .. Count => Source);
    begin
        Replace (Target, At_Pos, Value_String);
    end Replace;

    procedure Replace (Target : in out Variable_String;
                       At_Pos :        Positive;
                       Source :        Variable_String) is
    begin
        Replace (Target, At_Pos, Image (Source));
    end Replace;


    procedure Set_Length (Target     : in out Variable_String;
                          New_Length :        Natural;
                          Fill_With  :        Character := ' ') is
        Current_Length : Natural := Target.Length;
    begin
        for I in Current_Length + 1 .. New_Length loop
            Target.Contents (I) := Fill_With;
        end loop;
        Target.Length := New_Length;
    end Set_Length;


    function Length (Source : Variable_String) return Natural is
    begin
        return Source.Length;
    end Length;


    function Max_Length (Source : Variable_String) return Natural is
    begin
        return Source.Maximum_Length;
    end Max_Length;


    function Char_At (Source : Variable_String; At_Pos : Positive)
                     return Character is
    begin
        if At_Pos > Source.Length then
            raise Constraint_Error;
        else
            return Source.Contents (At_Pos);
        end if;
    end Char_At;

    function Extract (Source    : Variable_String;
                      Start_Pos : Positive;
                      End_Pos   : Natural) return String is
    begin
        if End_Pos > Source.Length then
            raise Constraint_Error;
        else
            return Source.Contents (Start_Pos .. End_Pos);
        end if;
    end Extract;

end Bounded_String;generic
    Size : Integer;
    -- number of buckets

    type Domain_Type is private;
    type Range_Type  is private;
    -- both types are pure values
    -- no initialization or finalization is necessary
    -- = and := can be used for equality and copy

    with function Hash (Key : Domain_Type) return Integer is <>;
    -- for efficiency, spread hash over an interval at least as great as size

    pragma Must_Be_Constrained (Yes => Domain_Type, Range_Type);

package Concurrent_Map_Generic is

    type Map is private;

    type Pair is
        record
            D : Domain_Type;
            R : Range_Type;
        end record;

    function  Eval (The_Map : Map; D : Domain_Type) return Range_Type;
    procedure Find (The_Map :        Map;
                    D       :        Domain_Type;
                    R       : in out Range_Type;
                    Success : out    Boolean);
    procedure Find (The_Map :        Map;
                    D       :        Domain_Type;
                    P       : in out Pair;
                    Success : out    Boolean);

    procedure Define   (The_Map        : in out Map;
                        D              :        Domain_Type;
                        R              :        Range_Type;
                        Trap_Multiples :        Boolean := False);
    procedure Undefine (The_Map : in out Map; D : Domain_Type);

    procedure Initialize (The_Map : out Map);
    function  Is_Empty   (The_Map : Map) return Boolean;
    procedure Make_Empty (The_Map : in out Map);

    procedure Copy (Target : in out Map; Source : Map);

    type Iterator is private;

    procedure Init  (Iter : out Iterator; The_Map : Map);
    procedure Next  (Iter : in out Iterator);
    function  Value (Iter : Iterator) return Domain_Type;
    function  Done  (Iter : Iterator) return Boolean;

    Undefined : exception;
    -- raised by eval if the domain value in not in the map

    Multiply_Defined : exception;
    -- raised by define if the domain value is already defined and
    -- the trap_multiples flag has been specified (ie. is true)

    function Nil                    return Map;
    function Is_Nil (The_Map : Map) return Boolean;

    function Cardinality (The_Map : Map) return Natural;

    ------------------------------------------------------
    -- Implementation Notes and Non-Standard Operations --
    ------------------------------------------------------

    -- := and = operate on references
    --   := implies sharing (introduces an alias)
    --   = means is the same map, not the same value of type map
    -- Initializing a map also makes it empty

    -- Maps must be initialized before use.

    -- garbage may be generated

    -- Concurrent Properties
    --    any number of find/eval/is_empty/copy may be safely done while one
    --   define/undefine/make_empty is taking place.
    --    Define/undefine/make_empty operations are serialized.
    --    Iterators may be used asynchronously, however the sequence of values
    --   yielded may never have been in the map at any one time.

private
    type Node;
    type Set is access Node;

    type Node is
        record
            Value : Pair;
            Link  : Set;
        end record;

    type Map_Data;

    type Map is access Map_Data;

    type Iterator is
        record
            The_Map     : Map;
            Index_Value : Natural;
            Set_Iter    : Set;
            Done        : Boolean;
        end record;

    subtype Index is Integer range 0 .. Size - 1;

    type Table is array (Index) of Set;

    type Map_Data is
        record
            Cache  : Set; -- of at most one node
            Bucket : Table;
            Size   : Natural := 0;
        end record;

end Concurrent_Map_Generic;package body Concurrent_Map_Generic is

    task Serialize is
        entry Define     (The_Map        : in out Map;
                          D              :        Domain_Type;
                          R              :        Range_Type;
                          Trap_Multiples :        Boolean := False);
        entry Undefine   (The_Map : in out Map; D : Domain_Type);
        entry Make_Empty (The_Map : in out Map);
    end Serialize;


    function Myhash (D : Domain_Type) return Index is
    begin
        return Index (Hash (D) mod Size);
    end Myhash;
    pragma Inline (Myhash);


    function Find (The_Map : Map; D : Domain_Type) return Set is
        -- result = null ==> D not in S
        Rest : Set := The_Map.Bucket (Myhash (D));
    begin
        while Rest /= null and then Rest.Value.D /= D loop
            Rest := Rest.Link;
        end loop;

        if Rest /= null then
            The_Map.Cache := Rest;
        end if;

        return Rest;
    end Find;

    procedure Find (S    :        Set;
                    D    :        Domain_Type;
                    Ptr  : in out Set;
                    Prev : in out Set) is
        -- ptr = null ==> D not in S
        -- ptr /= null and prev = null ==> D = first element of S
    begin
        Ptr  := S;
        Prev := null;
        while (Ptr /= null) and then (Ptr.Value.D /= D) loop
            Prev := Ptr;
            Ptr  := Ptr.Link;
        end loop;
    end Find;

    function Eval (The_Map : Map; D : Domain_Type) return Range_Type is
        Cache : Set := The_Map.Cache;
        -- cached pointer value must be fetched only once
        -- since cache may be concurrently updated
    begin
        if Cache /= null then
            declare
                Value : Pair renames Cache.Value;
            begin
                if Value.D = D then
                    return Value.R;
                end if;
            end;
        end if;

        declare
            Ptr : Set := Find (The_Map, D);
        begin
            if Ptr /= null then
                return Ptr.Value.R;
            else
                raise Undefined;
            end if;
        end;
    end Eval;

    procedure Find (The_Map :        Map;
                    D       :        Domain_Type;
                    R       : in out Range_Type;
                    Success : out    Boolean) is
        Cache : Set := The_Map.Cache;
        -- cached pointer value must be fetched only once
        -- since cache may be concurrently updated
    begin
        if Cache /= null then
            declare
                Value : Pair renames Cache.Value;
            begin
                if Value.D = D then
                    R       := Value.R;
                    Success := True;
                    return;
                end if;
            end;
        end if;

        declare
            Ptr : Set := Find (The_Map, D);
        begin
            if Ptr /= null then
                R       := Ptr.Value.R;
                Success := True;
            else
                Success := False;
            end if;
        end;
    end Find;

    procedure Find (The_Map :        Map;
                    D       :        Domain_Type;
                    P       : in out Pair;
                    Success : out    Boolean) is
        Cache : Set := The_Map.Cache;
        -- cached pointer value must be fetched only once
        -- since cache may be concurrently updated
    begin
        if Cache /= null then
            declare
                Value : Pair renames Cache.Value;
            begin
                if Value.D = D then
                    P       := Value;
                    Success := True;
                    return;
                end if;
            end;
        end if;

        declare
            Ptr : Set := Find (The_Map, D);
        begin
            if Ptr /= null then
                P       := Ptr.Value;
                Success := True;
            else
                Success := False;
            end if;
        end;
    end Find;

    procedure Define (The_Map        : in out Map;
                      D              :        Domain_Type;
                      R              :        Range_Type;
                      Trap_Multiples :        Boolean := False) is
    begin
        Serialize.Define (The_Map, D, R, Trap_Multiples);
    end Define;

    procedure Real_Define (The_Map        : in out Map;
                           D              :        Domain_Type;
                           R              :        Range_Type;
                           Trap_Multiples :        Boolean := False) is
        Cache : Set renames The_Map.Cache;
        -- cache can be written but not fetched
        -- since cache may be concurrently updated
        The_Set : Set renames The_Map.Bucket (Myhash (D));
        Ptr     : Set;
        Prev    : Set;
    begin
        Find (The_Set, D, Ptr, Prev);

        if Ptr = null then
            The_Set      := new Node'(Pair'(D => D, R => R), The_Set);
            Cache        := The_Set;
            The_Map.Size := The_Map.Size + 1;
        elsif Trap_Multiples then
            raise Multiply_Defined;
        elsif Prev = null then
            The_Set := new Node'(Pair'(D => D, R => R), Ptr.Link);
            Cache   := The_Set;
        else
            Prev.Link := new Node'(Pair'(D => D, R => R), Ptr.Link);
            Cache     := Prev.Link;
        end if;
    end Real_Define;

    procedure Undefine (The_Map : in out Map; D : Domain_Type) is
    begin
        Serialize.Undefine (The_Map, D);
    end Undefine;

    procedure Real_Undefine (The_Map : in out Map; D : Domain_Type) is
        Cache : Set renames The_Map.Cache;
        -- cache must be written but not fetched
        -- since cache may be concurrently updated
        Start    : Set renames The_Map.Bucket (Myhash (D));
        Current  : Set;
        Previous : Set;
    begin
        Find (Start, D, Current, Previous);

        if Current = null then
            raise Undefined;
        elsif Previous = null then
            -- old node cannot be reused due to concurrent readers
            Start := Current.Link;
        else
            -- old node cannot be reused due to concurrent readers
            Previous.Link := Current.Link;
        end if;
        The_Map.Size := The_Map.Size - 1;
        Cache        := null;
    end Real_Undefine;

    procedure Copy (Target : in out Map; Source : Map) is
        procedure Copy_Set (Target_Set : in out Set; Source_Set : Set) is
            Rest : Set := Source_Set;
        begin
            Target_Set := null;
            while Rest /= null loop
                Target_Set  := new Node'(Rest.Value, Target_Set);
                Target.Size := Target.Size + 1;
                Rest        := Rest.Link;
            end loop;
        end Copy_Set;
    begin
        Target.Size := 0;
        for I in Index loop
            Copy_Set (Target_Set => Target.Bucket (I),
                      Source_Set => Source.Bucket (I));
        end loop;
        Target.Cache := null;
    end Copy;

    procedure Initialize (The_Map : out Map) is
    begin
        The_Map := new Map_Data;
    end Initialize;

    function Is_Empty (The_Map : Map) return Boolean is
    begin
        for I in Index loop
            if The_Map.Bucket (I) /= null then
                return False;
            end if;
        end loop;
        return True;
    end Is_Empty;

    procedure Make_Empty (The_Map : in out Map) is
    begin
        Serialize.Make_Empty (The_Map);
    end Make_Empty;

    procedure Real_Make_Empty (The_Map : in out Map) is
    begin
        The_Map.Cache := null;
        for I in Index loop
            The_Map.Bucket (I) := null;
        end loop;
    end Real_Make_Empty;

    procedure Init (Iter : out Iterator; The_Map : Map) is
        The_Iter : Iterator;
    begin
        if The_Map = null then
            Iter.Done := True;
            return;
        end if;

        for I in Index loop
            The_Iter.Set_Iter := The_Map.Bucket (I);
            if The_Iter.Set_Iter /= null then
                The_Iter.Done        := False;
                The_Iter.Index_Value := I;
                The_Iter.The_Map     := The_Map;
                Iter                 := The_Iter;
                return;
            end if;
        end loop;
        The_Iter.Done := True;
        Iter          := The_Iter;
    end Init;

    procedure Next (Iter : in out Iterator) is
    begin
        Iter.Set_Iter := Iter.Set_Iter.Link;

        while Iter.Set_Iter = null loop
            if Iter.Index_Value = Index'Last then
                Iter.Done := True;
                return;
            end if;
            Iter.Index_Value := Iter.Index_Value + 1;
            Iter.Set_Iter    := Iter.The_Map.Bucket (Iter.Index_Value);
        end loop;
    end Next;

    function Value (Iter : Iterator) return Domain_Type is
    begin
        return Iter.Set_Iter.Value.D;
    end Value;

    function Done (Iter : Iterator) return Boolean is
    begin
        return Iter.Done;
    end Done;

    task body Serialize is
    begin
        loop
            begin
                select
                    accept Define (The_Map        : in out Map;
                                   D              :        Domain_Type;
                                   R              :        Range_Type;
                                   Trap_Multiples :        Boolean := False) do
                        Real_Define (The_Map, D, R, Trap_Multiples);
                    end Define;
                or
                    accept Undefine (The_Map : in out Map; D : Domain_Type) do
                        Real_Undefine (The_Map, D);
                    end Undefine;
                or
                    accept Make_Empty (The_Map : in out Map) do
                        Real_Make_Empty (The_Map);
                    end Make_Empty;
                or
                    terminate;
                end select;
            exception
                when others =>
                    null;
            end;
        end loop;
    end Serialize;

    function Nil return Map is
    begin
        return null;
    end Nil;

    function Is_Nil (The_Map : Map) return Boolean is
    begin
        return The_Map = null;
    end Is_Nil;

    function Cardinality (The_Map : Map) return Natural is
    begin
        return The_Map.Size;
    end Cardinality;

end Concurrent_Map_Generic;with Floating_Characteristics;
use Floating_Characteristics;

package Core_Functions is
    Exp_Large : Float;
    Exp_Small : Float;

    function Sqrt (X : Float) return Float;

    function Cbrt (X : Float) return Float;

    function Log (X : Float) return Float;

    function Log10 (X : Float) return Float;

    function Exp (X : Float) return Float;

    function "**" (X, Y : Float) return Float;
end Core_Functions;with Text_Io;
use Text_Io;
with Floating_Characteristics;
use Floating_Characteristics;
with Numeric_Io;
use Numeric_Io;
with Numeric_Primitives;
use Numeric_Primitives;

package body Core_Functions is

    --  The following routines are coded directly from the algorithms and
    --  coeficients given in "Software Manual for the Elementry Functions"
    --  by William J. Cody, Jr. and William Waite, Prentice_Hall, 1980
    --  CBRT by analogy
    --  A more general formulation uses MANTISSA_TYPE, etc.
    --  The coeficients are appropriate for 25 to 32 bits floating significance
    --  They will work for less but slightly shorter versions are possible
    --  The routines are coded to stand alone so they need not be compiled together

    --  These routines have been coded to accept a general MANTISSA_TYPE
    --  That is, they are designed to work with a manitssa either fixed of float
    --  There are some explicit conversions which are required but these will
    --  not cause any extra code to be generated

    --      16 JULY 1982       W A WHITAKER  AFATL EGLIN AFB FL 32542
    --                         T C EICHOLTZ  USAFA

    function Sqrt (X : Float) return Float is
        M, N : Exponent_Type;
        F, Y : Mantissa_Type;
        Result : Float;
        subtype Index is Integer range 0 ..
                                          100;    --  #########################
        Sqrt_L1 : Index := 3;
        --  Could get away with SQRT_L1 := 2 for 28 bits
        --  Using the better Cody-Waite coeficients overflows MANTISSA_TYPE
        Sqrt_C1 : Mantissa_Type := 8#0.3317777777#;
        Sqrt_C2 : Mantissa_Type := 8#0.4460000000#;
        Sqrt_C3 : Mantissa_Type := 8#0.55202_36314_77747_36311_0#;
    begin
        if X = Zero then
            Result := Zero;
            return Result;
        elsif X = One then
            --  To get exact SQRT(1.0)
            Result := One;
            return Result;
        elsif X < Zero then
            New_Line;
            Put ("CALLED SQRT FOR NEGATIVE ARGUMENT   ");
            raise Program_Error;
            --Put (X);
            Put ("   USED ABSOLUTE VALUE");
            New_Line;
            Result := Sqrt (abs (X));
            return Result;
        else
            Defloat (X, N, F);
            Y := Sqrt_C1 + Mantissa_Type (Sqrt_C2 * F);

            for J in 1 .. Sqrt_L1 loop
                Y := Y / Mantissa_Divisor_2 + Mantissa_Type
                                                 ((F / Mantissa_Divisor_2) / Y);
            end loop;

            if (N mod 2) /= 0 then
                Y := Mantissa_Type (Sqrt_C3 * Y);
                N := N + 1;
            end if;

            M := N / 2;
            Refloat (M, Y, Result);
            return Result;
        end if;

    exception
        when others =>
            New_Line;
            Put (" EXCEPTION IN SQRT, X = ");
            raise Program_Error;

            --Put (X);
            Put ("  RETURNED 1.0");
            New_Line;
            return One;
    end Sqrt;

    function Cbrt (X : Float) return Float is
        M, N : Exponent_Type;
        F, Y : Mantissa_Type;
        Result : Float;
        subtype Index is Integer range 0 ..
                                          100;    --  #########################
        Cbrt_L1 : Index := 3;
        Cbrt_C1 : Mantissa_Type := 0.5874009;
        Cbrt_C2 : Mantissa_Type := 0.4125990;
        Cbrt_C3 : Mantissa_Type := 0.62996_05249;
        Cbrt_C4 : Mantissa_Type := 0.79370_05260;
    begin
        if X = Zero then
            Result := Zero;
            return Result;
        else
            Defloat (X, N, F);
            F := abs (F);
            Y := Cbrt_C1 + Mantissa_Type (Cbrt_C2 * F);

            for J in 1 .. Cbrt_L1 loop
                Y := Y - (Y / Mantissa_Divisor_3 -
                          Mantissa_Type ((F / Mantissa_Divisor_3) /
                                         Mantissa_Type (Y * Y)));
            end loop;

            case (N mod 3) is
                when 0 =>
                    null;
                when 1 =>
                    Y := Mantissa_Type (Cbrt_C3 * Y);
                    N := N + 2;
                when 2 =>
                    Y := Mantissa_Type (Cbrt_C4 * Y);
                    N := N + 1;
                when others =>
                    null;
            end case;

            M := N / 3;

            if X < Zero then
                Y := -Y;
            end if;

            Refloat (M, Y, Result);
            return Result;
        end if;

    exception
        when others =>
            Result := One;

            if X < Zero then
                Result := -One;
            end if;

            New_Line;
            Put ("EXCEPTION IN CBRT, X = ");
            raise Program_Error;
            --Put (X);
            Put ("  RETURNED  ");
            raise Program_Error;
            --Put (Result);
            New_Line;
            return Result;
    end Cbrt;

    function Log (X : Float) return Float is
        --  Uses fixed formulation for generality
        Result : Float;
        N : Exponent_Type;
        Xn : Float;
        Y : Float;
        F : Mantissa_Type;
        Z, Zden, Znum : Mantissa_Type;
        C0 : constant Mantissa_Type := 0.20710_67811_86547_52440;
        --  SQRT(0.5) - 0.5
        C1 : constant Float := 8#0.543#;
        C2 : constant Float := -2.12194_44005_46905_82767_9E-4;

        function R (Z : Mantissa_Type) return Mantissa_Type is
            --  Use fixed formulation here because the float coeficents are > 1.0
            --  and would exceed the limits on a MANTISSA_TYPE
            A0 : constant Mantissa_Type := 0.04862_85276_587;
            B0 : constant Mantissa_Type := 0.69735_92187_803;
            B1 : constant Mantissa_Type := -0.125;
            C : constant Mantissa_Type := 0.01360_09546_862;
        begin
            return Z + Mantissa_Type
                          (Z * Mantissa_Type
                                  (Mantissa_Type (Z * Z) *
                                   (C + Mantissa_Type
                                           (A0 / (B0 +
                                                  Mantissa_Type
                                                     (B1 * Mantissa_Type
                                                              (Z * Z)))))));
        end R;
    begin
        if X < Zero then
            New_Line;
            Put ("CALLED LOG FOR NEGATIVE ");
            raise Program_Error; --put (X);;
            Put ("   USE ABS => ");
            Result := Log (abs (X));
            raise Program_Error;
            --Put (Result);
            New_Line;
        elsif X = Zero then
            New_Line;
            Put ("CALLED LOG FOR ZERO ARGUMENT, RETURNED ");
            Result := -Xmax;      --  SUPPOSED TO BE -LARGE
            raise Program_Error;--Put (Result);
            New_Line;
        else
            Defloat (X, N, F);
            Znum := F - Mantissa_Half;
            Y := Convert_To_Float (Znum);
            Zden := Znum / Mantissa_Divisor_2 + Mantissa_Half;

            if Znum > C0 then
                Y := Y - Mantissa_Half;
                Znum := Znum - Mantissa_Half;
                Zden := Zden + Mantissa_Half / Mantissa_Divisor_2;
            else
                N := N - 1;
            end if;

            Z := Mantissa_Type (Znum / Zden);
            Result := Convert_To_Float (R (Z));

            if N /= 0 then
                Xn := Convert_To_Float (N);
                Result := (Xn * C2 + Result) + Xn * C1;
            end if;
        end if;

        return Result;

    exception
        when others =>
            New_Line;
            Put (" EXCEPTION IN LOG, X = ");
            raise Program_Error; --put (X);;
            Put ("  RETURNED 0.0");
            New_Line;
            return Zero;
    end Log;

    function Log10 (X : Float) return Float is
        Log_10_Of_2 : constant Float :=
           Convert_To_Float (Mantissa_Type (

                                            8#0.33626_75425_11562_41615#));
    begin
        return Log (X) * Log_10_Of_2;
    end Log10;

    function Exp (X : Float) return Float is
        Result : Float;
        N : Exponent_Type;
        Xg, Xn, X1, X2 : Float;
        F, G : Mantissa_Type;
        Bigx : Float := Exp_Large;
        Smallx : Float := Exp_Small;
        One_Over_Log_2 : constant Float := 1.4426_95040_88896_34074;
        C1 : constant Float := 0.69335_9375;
        C2 : constant Float := -2.1219_44400_54690_58277E-4;

        function R (G : Mantissa_Type) return Mantissa_Type is
            Z, Gp, Q : Mantissa_Type;
            P0 : constant Mantissa_Type := 0.24999_99999_9992;
            P1 : constant Mantissa_Type := 0.00595_04254_9776;
            Q0 : constant Mantissa_Type := 0.5;
            Q1 : constant Mantissa_Type := 0.05356_75176_4522;
            Q2 : constant Mantissa_Type := 0.00029_72936_3682;
        begin
            Z := Mantissa_Type (G * G);
            Gp := Mantissa_Type ((Mantissa_Type (P1 * Z) + P0) * G);
            Q := Mantissa_Type ((Mantissa_Type (Q2 * Z) + Q1) * Z) + Q0;
            return Mantissa_Half + Mantissa_Type (Gp / (Q - Gp));
        end R;
    begin
        if X > Bigx then
            New_Line;
            Put ("  EXP CALLED WITH TOO BIG A POSITIVE ARGUMENT, ");
            raise Program_Error; --put (X);;
            Put ("   RETURNED XMAX");
            New_Line;
            Result := Xmax;
        elsif X < Smallx then
            New_Line;
            Put ("  EXP CALLED WITH TOO BIG A NEGATIVE ARGUMENT,  ");
            raise Program_Error; --put (X);;
            Put ("    RETURNED ZERO");
            New_Line;
            Result := Zero;
        elsif abs (X) < Eps then
            Result := One;
        else
            N := Exponent_Type (X * One_Over_Log_2);
            Xn := Convert_To_Float (N);
            X1 := Round (X);
            X2 := X - X1;
            Xg := ((X1 - Xn * C1) + X2) - Xn * C2;
            G := Mantissa_Type (Xg);
            N := N + 1;
            F := R (G);
            Refloat (N, F, Result);
        end if;

        return Result;

    exception
        when others =>
            New_Line;
            Put (" EXCEPTION IN EXP, X = ");
            raise Program_Error; --put (X);;
            Put ("  RETURNED 1.0");
            New_Line;
            return One;
    end Exp;

    function "**" (X, Y : Float) return Float is
        --  This is the last function to be coded since it appeared that it really
        --  was un-Ada-like and ought not be in the regular package
        --  Nevertheless it was included in this version
        --  It is specific for FLOAT and does not have the MANTISSA_TYPE generality
        M, N : Exponent_Type;
        G : Mantissa_Type;
        P, Temp, Iw1, I : Integer;
        Result, Z, V, R, U1, U2, W, W1, W2, W3, Y1, Y2 : Float;
        K : constant Float := 0.44269_50408_88963_40736;
        Ibigx : constant Integer := Integer
                                       (Truncate (16.0 * Log (Xmax) - 1.0));
        Ismallx : constant Integer := Integer
                                         (Truncate (16.0 * Log (Xmin) + 1.0));
        P1 : constant Float := 0.83333_32862_45E-1;
        P2 : constant Float := 0.12506_48500_52E-1;
        Q1 : constant Float := 0.69314_71805_56341;
        Q2 : constant Float := 0.24022_65061_44710;
        Q3 : constant Float := 0.55504_04881_30765E-1;
        Q4 : constant Float := 0.96162_06595_83789E-2;
        Q5 : constant Float := 0.13052_55159_42810E-2;
        A1 : array (1 .. 17) of Float :=
           (8#1.00000_0000#, 8#0.75222_5750#, 8#0.72540_3067#, 8#0.70146_3367#,
            8#0.65642_3746#, 8#0.63422_2140#, 8#0.61263_4520#, 8#0.57204_2434#,
            8#0.55202_3631#, 8#0.53254_0767#, 8#0.51377_3265#,
            8#0.47572_4623#, 8#0.46033_7602#, 8#0.44341_7233#,
            8#0.42712_7017#, 8#0.41325_3033#, 8#0.40000_0000#);
        A2 : array (1 .. 8) of Float :=
           (8#0.00000_00005_22220_66302_61734_72062#,
            8#0.00000_00003_02522_47021_04062_61124#,
            8#0.00000_00005_21760_44016_17421_53016#,
            8#0.00000_00007_65401_41553_72504_02177#,
            8#0.00000_00002_44124_12254_31114_01243#,
            8#0.00000_00000_11064_10432_66404_42174#,
            8#0.00000_00004_72542_16063_30176_55544#,
            8#0.00000_00001_74611_03661_23056_22556#);

        function Reduce (V : Float) return Float is
        begin
            return Float (Integer (16.0 * V)) * 0.0625;
        end Reduce;
    begin
        if X <= Zero then
            if X < Zero then
                Result := (abs (X)) ** Y;
                New_Line;
                Put ("X**Y CALLED WITH X = ");
                raise Program_Error; --put (X);
                New_Line;
                Put ("USED ABS, RETURNED ");
                raise Program_Error;--Put (Result);
                New_Line;
            else
                if Y <= Zero then
                    if Y = Zero then
                        Result := Zero;
                    else
                        Result := Xmax;
                    end if;

                    New_Line;
                    Put ("X**Y CALLED WITH X = 0, Y = ");
                    raise Program_Error; --put (Y);
                    New_Line;
                    Put ("RETURNED ");
                    raise Program_Error;--Put (Result);
                    New_Line;
                else
                    Result := Zero;
                end if;
            end if;
        else
            Defloat (X, M, G);
            P := 1;

            if G <= A1 (9) then
                P := 9;
            end if;

            if G <= A1 (P + 4) then
                P := P + 4;
            end if;

            if G <= A1 (P + 2) then
                P := P + 2;
            end if;

            Z := ((G - A1 (P + 1)) - A2 ((P + 1) / 2)) / (G + A1 (P + 1));
            Z := Z + Z;
            V := Z * Z;
            R := (P2 * V + P1) * V * Z;
            R := R + K * R;
            U2 := (R + Z * K) + Z;
            U1 := Float (Integer (M) * 16 - P) * 0.0625;
            Y1 := Reduce (Y);
            Y2 := Y - Y1;
            W := U2 * Y + U1 * Y2;
            W1 := Reduce (W);
            W2 := W - W1;
            W := W1 + U1 * Y1;
            W1 := Reduce (W);
            W2 := W2 + (W - W1);
            W3 := Reduce (W2);
            Iw1 := Integer (Truncate (16.0 * (W1 + W3)));
            W2 := W2 - W3;

            if W > Float (Ibigx) then
                Result := Xmax;
                Put ("X**Y CALLED  X =");
                raise Program_Error; --put (X);
                Put ("   Y =");
                raise Program_Error; --put (Y);
                Put ("   TOO LARGE  RETURNED ");
                raise Program_Error;--Put (Result);
                New_Line;
            elsif W < Float (Ismallx) then
                Result := Zero;
                Put ("X**Y CALLED  X =");
                raise Program_Error;
                --put(X);
                Put ("   Y =");
                raise Program_Error;
                Put ("   TOO SMALL  RETURNED ");
                raise Program_Error;--Put (Result);
                New_Line;
            else
                if W2 > Zero then
                    W2 := W2 - 0.0625;
                    Iw1 := Iw1 + 1;
                end if;

                if Iw1 < Integer (Zero) then
                    I := 0;
                else
                    I := 1;
                end if;

                M := Exponent_Type (I + Iw1 / 16);
                P := 16 * Integer (M) - Iw1;
                Z := ((((Q5 * W2 + Q4) * W2 + Q3) * W2 + Q2) * W2 + Q1) * W2;
                Z := A1 (P + 1) + (A1 (P + 1) * Z);
                Refloat (M, Z, Result);
            end if;
        end if;

        return Result;
    end "**";
begin
    Exp_Large := Log (Xmax) * (One - Eps);
    Exp_Small := Log (Xmin) * (One - Eps);
end Core_Functions;
generic
    type Enumeration is (<>);
procedure Enumeration_Value (S      :     String;
                             Result : out Enumeration;
                             Prefix : out Boolean;
                             Unique : out Boolean);with String_Utilities;
procedure Enumeration_Value (S      :     String;
                             Result : out Enumeration;
                             Prefix : out Boolean;
                             Unique : out Boolean) is
    Already_Matched : Boolean         := False;
    Exact           : Boolean;
    Match           : Boolean;
    Up_S            : constant String := String_Utilities.Upper_Case (S);
begin
    Prefix := False;
    Unique := False;
    Result := Enumeration'Last;
    for Enum in Enumeration loop
        declare
            Enum_Image : constant String := Enumeration'Image (Enum);
        begin
            Match := Up_S'Length <= Enum_Image'Length and then
                        Up_S = Enum_Image (1 .. Up_S'Length);
            Exact := Match and then (Up_S'Length = Enum_Image'Length);
        end;
        if Exact then
            Result := Enum;
            Unique := True;
            Prefix := False;
            return;
        elsif Match then
            Unique          := not Already_Matched;
            Already_Matched := True;
            Prefix          := True;
            Result          := Enum;
        end if;
    end loop;
end Enumeration_Value;package Floating_Characteristics is
    --  This package is a floating mantissa definition of a binary FLOAT
    --  It was first used on the DEC-10 and the VAX but should work for any
    --  since the parameters are obtained by initializing on the actual hardware
    --  Otherwise the parameters could be set in the spec if known
    --  This is a preliminary package that defines the properties
    --  of the particular floating point type for which we are going to
    --  generate the math routines
    --  The constants are those required by the routines described in
    --  "Software Manual for the Elementary Functions" W. Cody & W. Waite
    --  Prentice-Hall 1980
    --  Actually most are needed only for the test programs
    --  rather than the functions themselves, but might as well be here
    --  Most of these could be in the form of attributes if
    --  all the floating types to be considered were those built into the
    --  compiler, but we also want to be able to support user defined types
    --  such as software floating types of greater precision than
    --  the hardware affords, or types defined on one machine to
    --  simulate another
    --  So we use the Cody-Waite names and derive them from an adaptation of the
    --  MACHAR routine as given by Cody-Waite in Appendix B
    --
    Ibeta : Integer;
    --  The radix of the floating-point representation
    --
    It : Integer;
    --  The number of base IBETA digits in the DIS_FLOAT significand
    --
    Irnd : Integer;
    --  TRUE (1) if floating addition rounds, FALSE (0) if truncates
    --
    Ngrd : Integer;
    --  Number of guard digits for multiplication
    --
    Machep : Integer;
    --  The largest negative integer such that
    --    1.0 + FLOAT(IBETA) ** MACHEP /= 1.0
    --  except that MACHEP is bounded below by -(IT + 3)
    --
    Negep : Integer;
    --  The largest negative integer such that
    --    1.0 -0 FLOAT(IBETA) ** NEGEP /= 1.0
    --  except that NEGEP is bounded below by -(IT + 3)
    --
    Iexp : Integer;
    --  The number of bits (decimal places if IBETA = 10)
    --  reserved for the representation of the exponent (including
    --  the bias or sign) of a floating-point number
    --
    Minexp : Integer;
    --  The largest in magnitude negative integer such that
    --  FLOAT(IBETA) ** MINEXP is a positive floating-point number
    --
    Maxexp : Integer;
    --  The largest positive exponent for a finite floating-point number
    --
    Eps : Float;
    --  The smallest positive floating-point number such that
    --                              1.0 + EPS /= 1.0
    --  In particular, if IBETA = 2 or IRND = 0,
    --  EPS = FLOAT(IBETA) ** MACHEP
    --  Otherwise, EPS = (FLOAT(IBETA) ** MACHEP) / 2
    --
    Epsneg : Float;
    --  A small positive floating-point number such that 1.0-EPSNEG /= 1.0
    --
    Xmin : Float;
    --  The smallest non-vanishing floating-point power of the radix
    --  In particular, XMIN = FLOAT(IBETA) ** MINEXP
    --
    Xmax : Float;
    --  The largest finite floating-point number

    --  Here the structure of the floating type is defined
    --  I have assumed that the exponent is always some integer form
    --  The mantissa can vary
    --  Most often it will be a fixed type or the same floating type
    --  depending on the most efficient machine implementation
    --  Most efficient implementation may require details of the machine hardware
    --  In this version the simplest representation is used
    --  The mantissa is extracted into a FLOAT and uses the predefined operations
    --
    subtype Exponent_Type is Integer;    --  should be derived  ##########
    subtype Mantissa_Type is Float;     --   range -1.0..1.0;
    --
    --  A consequence of the rigorous constraints on MANTISSA_TYPE is that
    --  operations must be very carefully examined to make sure that no number
    --  greater than one results
    --  Actually this limitation is important in constructing algorithms
    --  which will also run when MANTISSA_TYPE is a fixed point type

    --  If we are not using the STANDARD type, we have to define all the
    --  operations at this point
    --  We also need PUT for the type if it is not otherwise available

    --  Now we do something strange
    --  Since we do not know in the following routines whether the mantissa
    --  will be carried as a fixed or floating type, we have to make some
    --  provision for dividing by two
    --  We cannot use the literals, since FIXED/2.0 and FLOAT/2 will fail
    --  We define a type-dependent factor that will work
    --
    Mantissa_Divisor_2 : constant Float := 2.0;
    Mantissa_Divisor_3 : constant Float := 3.0;
    --
    --  This will work for the MANTISSA_TYPE defined above
    --  The alternative of defining an operation "/" to take care of it
    --  is too sweeping and would allow unAda-like errors
    --
    Mantissa_Half : constant Mantissa_Type := 0.5;

    procedure Defloat (X : in Float;
                       N : in out Exponent_Type;
                       F : in out Mantissa_Type);

    procedure Refloat (N : in Exponent_Type;
                       F : in Mantissa_Type;
                       X : in out Float);
    --  Since the user may wish to define a floating type by some other name
    --  CONVERT_TO_FLOAT is used rather than just FLOAT for explicit coersion

    function Convert_To_Float (K : Integer) return Float;
    --  function CONVERT_TO_FLOAT(N : EXPONENT_TYPE) return FLOAT;

    function Convert_To_Float (F : Mantissa_Type) return Float;
end Floating_Characteristics;with Text_Io;
use Text_Io;

package body Floating_Characteristics is
    --  This package is a floating mantissa definition of a binary FLOAT
    A, B, Y, Z : Float;
    I, K, Mx, Iz : Integer;
    Beta, Betam1, Betain : Float;
    One : Float := 1.0;
    Zero : Float := 0.0;

    procedure Defloat (X : in Float;
                       N : in out Exponent_Type;
                       F : in out Mantissa_Type) is
        --  This is admittedly a slow method - but portable - for breaking down
        --  a floating point number into its exponent and mantissa
        --  Obviously with knowledge of the machine representation
        --  it could be replaced with a couple of simple extractions
        Exponent_Length : Integer := Iexp;
        M : Exponent_Type;
        W, Y, Z : Float;
    begin
        N := 0;
        F := 0.0;
        Y := abs (X);

        if Y = 0.0 then
            return;
        elsif Y < 0.5 then
            for J in reverse 0 .. (Exponent_Length - 2) loop
                --  Dont want to go all the way to 2.0**(EXPONENT_LENGTH - 1)
                --  Since that (or its reciprocal) will overflow if exponent biased
                --  Ought to use talbular values rather than compute each time
                M := Exponent_Type (2 ** J);
                Z := 1.0 / (2.0 ** M);
                W := Y / Z;

                if W < 1.0 then
                    Y := W;
                    N := N - M;
                end if;
            end loop;
        else
            for J in reverse 0 .. (Exponent_Length - 2) loop
                M := Exponent_Type (2 ** J);
                Z := 2.0 ** M;
                W := Y / Z;

                if W >= 0.5 then
                    Y := W;
                    N := N + M;
                end if;
            end loop;
            --  And just to clear up any loose ends from biased exponents
        end if;

        while Y < 0.5 loop
            Y := Y * 2.0;
            N := N - 1;
        end loop;

        while Y >= 1.0 loop
            Y := Y / 2.0;
            N := N + 1;
        end loop;

        F := Mantissa_Type (Y);

        if X < 0.0 then
            F := -F;
        end if;

        return;

    exception
        when others =>
            N := 0;
            F := 0.0;
            return;
    end Defloat;

    procedure Refloat (N : in Exponent_Type;
                       F : in Mantissa_Type;
                       X : in out Float) is
        --  Again a brute force method - but portable
        --  Watch out near MAXEXP
        M : Integer;
        Y : Float;
    begin
        if F = 0.0 then
            X := Zero;
            return;
        end if;

        M := Integer (N);
        Y := abs (Float (F));

        while Y < 0.5 loop
            M := M - 1;

            if M < Minexp then
                X := Zero;
            end if;

            Y := Y + Y;
            exit when M <= Minexp;
        end loop;

        if M = Maxexp then
            M := M - 1;
            X := Y * 2.0 ** M;
            X := X * 2.0;
        elsif M <= Minexp + 2 then
            M := M + 3;
            X := Y * 2.0 ** M;
            X := ((X / 2.0) / 2.0) / 2.0;
        else
            X := Y * 2.0 ** M;
        end if;

        if F < 0.0 then
            X := -X;
        end if;

        return;
    end Refloat;

    function Convert_To_Float (K : Integer) return Float is
    begin
        return Float (K);
    end Convert_To_Float;

    -- function CONVERT_TO_FLOAT(N : EXPONENT_TYPE) RETURN FLOAT is
    -- begin
    --    RETURN FLOAT(N);
    -- end CONVERT_TO_FLOAT;

    function Convert_To_Float (F : Mantissa_Type) return Float is
    begin
        return Float (F);
    end Convert_To_Float;
    --
begin
    --  Initialization for the VAX with values derived by MACHAR
    --  In place of running MACHAR as the actual initialization
    Ibeta := 2;
    It := 24;
    Irnd := 1;
    Negep := -24;
    Epsneg := 5.9604644E-008;
    Machep := -24;
    Eps := 5.9604644E-008;
    Ngrd := 0;
    Xmin := 5.9E-39;
    Minexp := -126;
    Iexp := 8;
    Maxexp := 127;
    Xmax := 8.5E37 * 2.0;


    ----  This initialization is the MACHAR routine of Cody and Waite Appendix B.
    --PUT("INITIALIZATING WITH MACHAR     -     ");
    --    A := ONE;
    --    while (((A + ONE) - A) - ONE) = ZERO  loop
    --      A := A + A;
    --    end loop;
    --    B := ONE;
    --    while ((A + B) - A) = ZERO  loop
    --      B := B + B;
    --    end loop;
    --    IBETA := INTEGER((A + B) - A);
    --    BETA := CONVERT_TO_FLOAT(IBETA);
    --
    --
    --    IT := 0;
    --    B := ONE;
    --    while (((B + ONE) - B) - ONE) = ZERO  loop
    --      IT := IT + 1;
    --      B := B * BETA;
    --    end loop;
    --
    --
    --    IRND := 0;
    --    BETAM1 := BETA - ONE;
    --    if ((A + BETAM1) - A) /= ZERO  then
    --      IRND := 1;
    --    end if;
    --
    --
    --    NEGEP := IT + 3;
    --    BETAIN := ONE / BETA;
    --    A := ONE;
    --  --  for I in 1..NEGEP  loop
    --  for I in 1..50  loop
    --  exit when I > NEGEP;
    --      A := A * BETAIN;
    --    end loop;
    --    B := A;
    --    while ((ONE - A) - ONE) = ZERO  loop
    --      A := A * BETA;
    --      NEGEP := NEGEP - 1;
    --    end loop;
    --    NEGEP := -NEGEP;
    --
    --
    --    EPSNEG := A;
    --    if (IBETA /= 2) and (IRND /= 0)  then
    --      A := (A * (ONE + A)) / (ONE + ONE);
    --      if ((ONE - A) - ONE) /= ZERO  then
    --        EPSNEG := A;
    --      end if;
    --    end if;
    --
    --
    --    MACHEP := -IT - 3;
    --    A := B;
    --    while ((ONE + A) - ONE) = ZERO  loop
    --      A := A * BETA;
    --      MACHEP := MACHEP + 1;
    --    end loop;
    --
    --
    --    EPS := A;
    --    if (IBETA /= 2) and (IRND /= 0)  then
    --      A := (A * (ONE + A)) / (ONE + ONE);
    --      if ((ONE + A) - ONE) /= ZERO  then
    --        EPS := A;
    --      end if;
    --    end if;
    --
    --
    --    NGRD := 0;
    --    if ((IRND = 0) and ((ONE + EPS) * ONE - ONE) /= ZERO)  then
    --      NGRD := 1;
    --    end if;
    --
    --
    --    I := 0;
    --    K := 1;
    --    Z := BETAIN;
    --    loop
    --      Y := Z;
    --      Z := Y * Y;
    --      A := Z * ONE;
    --      exit when ((A + A) = ZERO) or (ABS(Z) >= Y);
    --      I := I + 1;
    --      K := K + K;
    --    end loop;
    --    if (IBETA /= 10)  then
    --      IEXP := I + 1;
    --      MX := K + K;
    --    else
    --      IEXP := 2;
    --      IZ := IBETA;
    --      while (K >= IZ)  loop
    --        IZ := IZ * IBETA;
    --        IEXP := IEXP + 1;
    --      end loop;
    --      MX := IZ + IZ - 1;
    --    end if;
    --
    --    loop
    --      XMIN := Y;
    --      Y := Y * BETAIN;
    --      A := Y * ONE;
    --      exit when ((A + A) = ZERO) or (ABS(Y) >= XMIN);
    --      K := K + 1;
    --    end loop;
    --
    --
    --    MINEXP := -K;
    --
    --
    --    if ((MX <= (K + K - 3)) and (IBETA /= 10))  then
    --      MX := MX + MX;
    --      IEXP := IEXP + 1;
    --    end if;
    --
    --
    --    MAXEXP := MX + MINEXP;
    --    I := MAXEXP + MINEXP;
    --    if ((IBETA = 2) and (I = 0))  then
    --      MAXEXP := MAXEXP - 1;
    --    end if;
    --    if (I > 20)  then
    --      MAXEXP := MAXEXP - 1;
    --    end if;
    --    if (A /= Y)  then
    --      MAXEXP := MAXEXP - 2;
    --    end if;
    --
    --
    --    XMAX := ONE - EPSNEG;
    --    if ((XMAX * ONE) /= XMAX)  then
    --      XMAX := ONE - BETA * EPSNEG;
    --    end if;
    --    XMAX := XMAX / (BETA * BETA * BETA * XMIN);
    --    I := MAXEXP + MINEXP + 3;
    --    if I > 0  then
    --      for J in 1..50  loop
    --  exit when J > I;
    --        if IBETA = 2  then
    --          XMAX := XMAX + XMAX;
    --        else
    --          XMAX := XMAX * BETA;
    --        end if;
    --      end loop;
    --    end if;
    --
    --PUT("INITIALIZED"); NEW_LINE;
end Floating_Characteristics;

generic
    type Element is private;
    -- must be a pure value
    -- ie. no initialization or finalization is necessary
    -- = and := are equality and copy

    pragma Must_Be_Constrained (Yes => Element);

package List_Generic is

    type List is private;
    -- may generate garbage
    -- = and := operate on references
    -- "make" constructs lists with structural sharing

    -- constraint error is raised when nil i provided to any of
    --    first, rest, set_first, or set_rest

    function Make (X : Element; L : List) return List;

    function Nil                 return List;
    function Is_Empty (L : List) return Boolean;

    procedure Free (L : in out List);
    -- make L empty

    function  First     (L : List) return Element;
    function  Rest      (L : List) return List;
    procedure Set_Rest  (L : List; To_Be : List);
    procedure Set_First (L : List; To_Be : Element);

    function Length (L : List) return Natural;

    type Iterator is limited private;

    procedure Init  (Iter : out Iterator; L : List);
    procedure Next  (Iter : in out Iterator);
    function  Value (Iter : Iterator) return Element;
    function  Done  (Iter : Iterator) return Boolean;

private

    type Listdata;
    type List is access Listdata;
    -- variables of type list are initialized to null

    type Listdata is
        record
            First : Element;
            Rest  : List;
        end record;

    type Iterator is new List;

end List_Generic;package body List_Generic is

    function Nil return List is
    begin
        return null;
    end Nil;

    function Is_Empty (L : List) return Boolean is
    begin
        return L = Nil;
    end Is_Empty;

    function First (L : List) return Element is
    begin
        return L.First;
    end First;

    function Rest (L : List) return List is
    begin
        return L.Rest;
    end Rest;

    function Make (X : Element; L : List) return List is
    begin
        return new Listdata'(X, L);
    end Make;

    procedure Set_Rest (L : List; To_Be : List) is
    begin
        L.Rest := To_Be;
    end Set_Rest;

    procedure Set_First (L : List; To_Be : Element) is
    begin
        L.First := To_Be;
    end Set_First;

    procedure Free (L : in out List) is
    begin
        L := null;
    end Free;

    function Length (L : List) return Natural is
        Count : Natural := 0;
        Iter  : Iterator;
    begin
        Init (Iter, L);
        while not Done (Iter) loop
            Count := Count + 1;
            Next (Iter);
        end loop;
        return Count;
    end Length;


    procedure Init (Iter : out Iterator; L : List) is
    begin
        Iter := Iterator (L);
    end Init;

    procedure Next (Iter : in out Iterator) is
    begin
        Iter := Iterator (Iter.Rest);
    end Next;

    function Value (Iter : Iterator) return Element is
    begin
        return Iter.First;
    end Value;

    function Done (Iter : Iterator) return Boolean is
    begin
        return Iter = null;
    end Done;

end List_Generic;package Machine_Independent_Integer32 is
--
-- This package provides integer operations for signed integers that fit
-- comfortable into 32 bits.
-- This spec is "kludged" in that it assumes there is an existing
-- integer or fixed type that will support 32 bit integer operations.
--
-- Current minimal implementation is provided to support the functionality
-- required by the Time_Utilities package.
--
    type Integer32 is range Integer'First .. Integer'Last;
    function  "*"     (L : Integer32; R : Integer) return Integer32;
    function  "/"     (L : Integer32; R : Integer) return Integer32;
    procedure Div_Rem (L                   :     Integer32;
                       R                   :     Integer;
                       Quotient, Remainder : out Integer32);

end Machine_Independent_Integer32;package body Machine_Independent_Integer32 is

    function "*" (L : Integer32; R : Integer) return Integer32 is
    begin
        return L * Integer32 (R);
    end "*";

    function "/" (L : Integer32; R : Integer) return Integer32 is
    begin
        return L / Integer32 (R);
    end "/";

    procedure Div_Rem (L                   :     Integer32;
                       R                   :     Integer;
                       Quotient, Remainder : out Integer32) is
        Local_Quotient : Integer32 := L / R;
    begin
        Quotient  := Local_Quotient;
        Remainder := L - Local_Quotient * R;
    end Div_Rem;
end Machine_Independent_Integer32;generic
    Size : Integer;
    -- number of buckets

    type Domain_Type is private;
    type Range_Type  is private;
    -- both types are pure values
    -- no initialization or finalization of values of either
    --     domain_type or range_type is necessary
    -- = and := can be used for equality and copy

    with function Hash (Key : Domain_Type) return Integer is <>;
    -- efficiency => spread hash over an interval at least as great as size

    pragma Must_Be_Constrained (Yes => Domain_Type, Range_Type);

package Map_Generic is

    type Map is private;

    type Pair is
        record
            D : Domain_Type;
            R : Range_Type;
        end record;

    function  Eval (The_Map : Map; D : Domain_Type) return Range_Type;
    procedure Find (The_Map :        Map;
                    D       :        Domain_Type;
                    R       : in out Range_Type;
                    Success : out    Boolean);
    procedure Find (The_Map :        Map;
                    D       :        Domain_Type;
                    P       : in out Pair;
                    Success : out    Boolean);

    procedure Define   (The_Map        : in out Map;
                        D              :        Domain_Type;
                        R              :        Range_Type;
                        Trap_Multiples :        Boolean := False);
    procedure Undefine (The_Map : in out Map; D : Domain_Type);

    procedure Initialize (The_Map : out Map);
    function  Is_Empty   (The_Map : Map) return Boolean;
    procedure Make_Empty (The_Map : in out Map);

    procedure Copy (Target : in out Map; Source : Map);

    type Iterator is limited private;

    procedure Init  (Iter : out Iterator; The_Map : Map);
    procedure Next  (Iter : in out Iterator);
    function  Value (Iter : Iterator) return Domain_Type;
    function  Done  (Iter : Iterator) return Boolean;

    Undefined : exception;
    -- raised by eval if the domain value in not in the map

    Multiply_Defined : exception;
    -- raised by define if the domain value is already defined and
    -- the trap_multiples flag has been specified (ie. is true)

    function Cardinality (The_Map : Map) return Natural;
    function Nil                         return Map;
    function Is_Nil      (The_Map : Map) return Boolean;

    ------------------------------------------------------
    -- Implementation Notes and Non-Standard Operations --
    ------------------------------------------------------

    -- := and = operate on references
    --        := implies sharing (introduces an alias)
    --        = means is the same set, not the same value of type set
    -- Initializing a map also makes it empty
    -- Accessing an uninitialized map will raise CONSTRAINT_ERROR.

    -- garbage may be generated

    -- Concurrent Properties
    --    any number of find/eval/is_empty may be safely done while one
    --        define/undefine is taking place.  If the define is redefining
    -- an
    --        existing element in the domain of the map, concurrrent
    -- reading is
    --        safe if and only if := on range_type is atomic.

private
    type Node;
    type Set is access Node;

    type Node is
        record
            Value : Pair;
            Link  : Set;
        end record;

    subtype Index is Integer range 0 .. Size - 1;

    type Table is array (Index) of Set;

    type Map_Data is
        record
            Bucket : Table;
            Size   : Integer := 0;
        end record;

    type Map is access Map_Data;

    type Iterator is
        record
            The_Map     : Map;
            Index_Value : Index;
            Set_Iter    : Set;
            Done        : Boolean;
        end record;

end Map_Generic;package body Map_Generic is

    function Find (S : Set; D : Domain_Type) return Set is
        Rest : Set := S;
    begin
        while Rest /= null loop
            if Rest.Value.D = D then
                return Rest;
            end if;
            Rest := Rest.Link;
        end loop;
        return null;
    end Find;

    function Myhash (D : Domain_Type) return Index is
    begin
        return Index (Hash (D) mod Size);
    end Myhash;

    function Eval (The_Map : Map; D : Domain_Type) return Range_Type is
        Ptr : Set := Find (The_Map.Bucket (Myhash (D)), D);
    begin
        if Ptr /= null then
            return Ptr.Value.R;
        else
            raise Undefined;
        end if;
    end Eval;

    procedure Find (The_Map :        Map;
                    D       :        Domain_Type;
                    R       : in out Range_Type;
                    Success : out    Boolean) is
        Ptr : Set := Find (The_Map.Bucket (Myhash (D)), D);
    begin
        if Ptr /= null then
            R       := Ptr.Value.R;
            Success := True;
        else
            Success := False;
        end if;
    end Find;

    procedure Find (The_Map :        Map;
                    D       :        Domain_Type;
                    P       : in out Pair;
                    Success : out    Boolean) is
        Ptr : Set := Find (The_Map.Bucket (Myhash (D)), D);
    begin
        if Ptr /= null then
            P       := Ptr.Value;
            Success := True;
        else
            Success := False;
        end if;
    end Find;

    procedure Define (The_Map        : in out Map;
                      D              :        Domain_Type;
                      R              :        Range_Type;
                      Trap_Multiples :        Boolean := False) is
        The_Set : Set renames The_Map.Bucket (Myhash (D));
        Ptr     : Set := Find (The_Set, D);
        Success : Boolean;
    begin
        if Ptr = null then
            The_Set      := new Node'(Pair'(D => D, R => R), The_Set);
            The_Map.Size := The_Map.Size + 1;
        elsif Trap_Multiples then
            raise Multiply_Defined;
        else
            Ptr.Value.R := R;
        end if;
    end Define;

    procedure Undefine (The_Map : in out Map; D : Domain_Type) is
        Start    : Set renames The_Map.Bucket (Myhash (D));
        Current  : Set := Start;
        Previous : Set := null;
    begin
        while Current /= null loop
            if Current.Value.D = D then
                if Previous /= null then
                    Previous.Link := Current.Link;
                else
                    Start := Current.Link;
                end if;
                The_Map.Size := The_Map.Size - 1;
                return;
            else
                Previous := Current;
                Current  := Current.Link;
            end if;
        end loop;
        raise Undefined;
    end Undefine;

    procedure Copy (Target : in out Map; Source : Map) is
        procedure Copy_Set (Target : in out Set; Source : Set) is
            Rest : Set := Source;
        begin
            Target := null;
            while Rest /= null loop
                Target := new Node'(Rest.Value, Target);
                Rest   := Rest.Link;
            end loop;
        end Copy_Set;
    begin
        for I in Index loop
            Copy_Set (Target => Target.Bucket (I), Source => Source.Bucket (I));
        end loop;
        Target.Size := Source.Size;
    end Copy;

    procedure Initialize (The_Map : out Map) is
    begin
        The_Map := new Map_Data;
    end Initialize;

    function Is_Empty (The_Map : Map) return Boolean is
        Iter : Iterator;
    begin
        for I in Index loop
            if The_Map.Bucket (I) /= null then
                return False;
            end if;
        end loop;
        return True;
    end Is_Empty;

    procedure Make_Empty (The_Map : in out Map) is
    begin
        for I in Index loop
            The_Map.Bucket (I) := null;
        end loop;
    end Make_Empty;

    procedure Init (Iter : out Iterator; The_Map : Map) is
        The_Iter : Iterator;
    begin
        for I in Index loop
            The_Iter.Set_Iter := The_Map.Bucket (I);
            if The_Iter.Set_Iter /= null then
                The_Iter.Done        := False;
                The_Iter.Index_Value := I;
                The_Iter.The_Map     := The_Map;
                Iter                 := The_Iter;
                return;
            end if;
        end loop;
        The_Iter.Done := True;
        Iter          := The_Iter;
    end Init;

    procedure Next (Iter : in out Iterator) is
    begin
        Iter.Set_Iter := Iter.Set_Iter.Link;

        while Iter.Set_Iter = null loop
            if Iter.Index_Value = Index'Last then
                Iter.Done := True;
                return;
            end if;
            Iter.Index_Value := Iter.Index_Value + 1;
            Iter.Set_Iter    := Iter.The_Map.Bucket (Iter.Index_Value);
        end loop;

    end Next;

    function Value (Iter : Iterator) return Domain_Type is
    begin
        return Iter.Set_Iter.Value.D;
    end Value;

    function Done (Iter : Iterator) return Boolean is
    begin
        return Iter.Done;
    end Done;

    function Cardinality (The_Map : Map) return Natural is
    begin
        return The_Map.Size;
    end Cardinality;

    function Nil return Map is
    begin
        return null;
    end Nil;
    function Is_Nil (The_Map : Map) return Boolean is
    begin
        return The_Map = null;
    end Is_Nil;
end Map_Generic;with Floating_Characteristics;
use Floating_Characteristics;

package Numeric_Io is
    Exp_Large : Float;
    Exp_Small : Float;

    function Sqrt (X : Float) return Float;

    function Cbrt (X : Float) return Float;

    function Log (X : Float) return Float;

    function Log10 (X : Float) return Float;

    function Exp (X : Float) return Float;

    function "**" (X, Y : Float) return Float;
end Numeric_Io;with Text_Io;
use Text_Io;
with Floating_Characteristics;
use Floating_Characteristics;
--with Numeric_Io;
--use Numeric_Io;
with Numeric_Primitives;
use Numeric_Primitives;

package body Numeric_Io is

    --  The following routines are coded directly from the algorithms and
    --  coeficients given in "Software Manual for the Elementry Functions"
    --  by William J. Cody, Jr. and William Waite, Prentice_Hall, 1980
    --  CBRT by analogy
    --  A more general formulation uses MANTISSA_TYPE, etc.
    --  The coeficients are appropriate for 25 to 32 bits floating significance
    --  They will work for less but slightly shorter versions are possible
    --  The routines are coded to stand alone so they need not be compiled together

    --  These routines have been coded to accept a general MANTISSA_TYPE
    --  That is, they are designed to work with a manitssa either fixed of float
    --  There are some explicit conversions which are required but these will
    --  not cause any extra code to be generated

    --      16 JULY 1982       W A WHITAKER  AFATL EGLIN AFB FL 32542
    --                         T C EICHOLTZ  USAFA

    function Sqrt (X : Float) return Float is
        M, N : Exponent_Type;
        F, Y : Mantissa_Type;
        Result : Float;
        subtype Index is Integer range 0 ..
                                          100;    --  #########################
        Sqrt_L1 : Index := 3;
        --  Could get away with SQRT_L1 := 2 for 28 bits
        --  Using the better Cody-Waite coeficients overflows MANTISSA_TYPE
        Sqrt_C1 : Mantissa_Type := 8#0.3317777777#;
        Sqrt_C2 : Mantissa_Type := 8#0.4460000000#;
        Sqrt_C3 : Mantissa_Type := 8#0.55202_36314_77747_36311_0#;
    begin
        if X = Zero then
            Result := Zero;
            return Result;
        elsif X = One then
            --  To get exact SQRT(1.0)
            Result := One;
            return Result;
        elsif X < Zero then
            New_Line;
            Put ("CALLED SQRT FOR NEGATIVE ARGUMENT   ");
            raise Program_Error;
            --Put (X);
            Put ("   USED ABSOLUTE VALUE");
            New_Line;
            Result := Sqrt (abs (X));
            return Result;
        else
            Defloat (X, N, F);
            Y := Sqrt_C1 + Mantissa_Type (Sqrt_C2 * F);

            for J in 1 .. Sqrt_L1 loop
                Y := Y / Mantissa_Divisor_2 + Mantissa_Type
                                                 ((F / Mantissa_Divisor_2) / Y);
            end loop;

            if (N mod 2) /= 0 then
                Y := Mantissa_Type (Sqrt_C3 * Y);
                N := N + 1;
            end if;

            M := N / 2;
            Refloat (M, Y, Result);
            return Result;
        end if;

    exception
        when others =>
            New_Line;
            Put (" EXCEPTION IN SQRT, X = ");
            raise Program_Error
               --Put (X);
               ;
            Put ("  RETURNED 1.0");
            New_Line;
            return One;
    end Sqrt;

    function Cbrt (X : Float) return Float is
        M, N : Exponent_Type;
        F, Y : Mantissa_Type;
        Result : Float;
        subtype Index is Integer range 0 ..
                                          100;    --  #########################
        Cbrt_L1 : Index := 3;
        Cbrt_C1 : Mantissa_Type := 0.5874009;
        Cbrt_C2 : Mantissa_Type := 0.4125990;
        Cbrt_C3 : Mantissa_Type := 0.62996_05249;
        Cbrt_C4 : Mantissa_Type := 0.79370_05260;
    begin
        if X = Zero then
            Result := Zero;
            return Result;
        else
            Defloat (X, N, F);
            F := abs (F);
            Y := Cbrt_C1 + Mantissa_Type (Cbrt_C2 * F);

            for J in 1 .. Cbrt_L1 loop
                Y := Y - (Y / Mantissa_Divisor_3 -
                          Mantissa_Type ((F / Mantissa_Divisor_3) /
                                         Mantissa_Type (Y * Y)));
            end loop;

            case (N mod 3) is
                when 0 =>
                    null;
                when 1 =>
                    Y := Mantissa_Type (Cbrt_C3 * Y);
                    N := N + 2;
                when 2 =>
                    Y := Mantissa_Type (Cbrt_C4 * Y);
                    N := N + 1;
                when others =>
                    null;
            end case;

            M := N / 3;

            if X < Zero then
                Y := -Y;
            end if;

            Refloat (M, Y, Result);
            return Result;
        end if;

    exception
        when others =>
            Result := One;

            if X < Zero then
                Result := -One;
            end if;

            New_Line;
            Put ("EXCEPTION IN CBRT, X = ");
            raise Program_Error
               --Put (X);
               ;
            Put ("  RETURNED  ");
            raise Program_Error
               --Put (Result);
               ;
            New_Line;
            return Result;
    end Cbrt;

    function Log (X : Float) return Float is
        --  Uses fixed formulation for generality
        Result : Float;
        N : Exponent_Type;
        Xn : Float;
        Y : Float;
        F : Mantissa_Type;
        Z, Zden, Znum : Mantissa_Type;
        C0 : constant Mantissa_Type := 0.20710_67811_86547_52440;
        --  SQRT(0.5) - 0.5
        C1 : constant Float := 8#0.543#;
        C2 : constant Float := -2.12194_44005_46905_82767_9E-4;

        function R (Z : Mantissa_Type) return Mantissa_Type is
            --  Use fixed formulation here because the float coeficents are > 1.0
            --  and would exceed the limits on a MANTISSA_TYPE
            A0 : constant Mantissa_Type := 0.04862_85276_587;
            B0 : constant Mantissa_Type := 0.69735_92187_803;
            B1 : constant Mantissa_Type := -0.125;
            C : constant Mantissa_Type := 0.01360_09546_862;
        begin
            return Z + Mantissa_Type
                          (Z * Mantissa_Type
                                  (Mantissa_Type (Z * Z) *
                                   (C + Mantissa_Type
                                           (A0 / (B0 +
                                                  Mantissa_Type
                                                     (B1 * Mantissa_Type
                                                              (Z * Z)))))));
        end R;
    begin
        if X < Zero then
            New_Line;
            Put ("CALLED LOG FOR NEGATIVE ");
            raise Program_Error
               --Put (X);
               ;
            Put ("   USE ABS => ");
            Result := Log (abs (X));
            raise Program_Error
               --Put (Result);
               ;
            New_Line;
        elsif X = Zero then
            New_Line;
            Put ("CALLED LOG FOR ZERO ARGUMENT, RETURNED ");
            Result := -Xmax;      --  SUPPOSED TO BE -LARGE
            raise Program_Error
               --Put (Result);
               ;
            New_Line;
        else
            Defloat (X, N, F);
            Znum := F - Mantissa_Half;
            Y := Convert_To_Float (Znum);
            Zden := Znum / Mantissa_Divisor_2 + Mantissa_Half;

            if Znum > C0 then
                Y := Y - Mantissa_Half;
                Znum := Znum - Mantissa_Half;
                Zden := Zden + Mantissa_Half / Mantissa_Divisor_2;
            else
                N := N - 1;
            end if;

            Z := Mantissa_Type (Znum / Zden);
            Result := Convert_To_Float (R (Z));

            if N /= 0 then
                Xn := Convert_To_Float (N);
                Result := (Xn * C2 + Result) + Xn * C1;
            end if;
        end if;

        return Result;

    exception
        when others =>
            New_Line;
            Put (" EXCEPTION IN LOG, X = ");
            raise Program_Error;
            --Put (X);
            Put ("  RETURNED 0.0");
            New_Line;
            return Zero;
    end Log;

    function Log10 (X : Float) return Float is
        Log_10_Of_2 : constant Float :=
           Convert_To_Float (Mantissa_Type (

                                            8#0.33626_75425_11562_41615#));
    begin
        return Log (X) * Log_10_Of_2;
    end Log10;

    function Exp (X : Float) return Float is
        Result : Float;
        N : Exponent_Type;
        Xg, Xn, X1, X2 : Float;
        F, G : Mantissa_Type;
        Bigx : Float := Exp_Large;
        Smallx : Float := Exp_Small;
        One_Over_Log_2 : constant Float := 1.4426_95040_88896_34074;
        C1 : constant Float := 0.69335_9375;
        C2 : constant Float := -2.1219_44400_54690_58277E-4;

        function R (G : Mantissa_Type) return Mantissa_Type is
            Z, Gp, Q : Mantissa_Type;
            P0 : constant Mantissa_Type := 0.24999_99999_9992;
            P1 : constant Mantissa_Type := 0.00595_04254_9776;
            Q0 : constant Mantissa_Type := 0.5;
            Q1 : constant Mantissa_Type := 0.05356_75176_4522;
            Q2 : constant Mantissa_Type := 0.00029_72936_3682;
        begin
            Z := Mantissa_Type (G * G);
            Gp := Mantissa_Type ((Mantissa_Type (P1 * Z) + P0) * G);
            Q := Mantissa_Type ((Mantissa_Type (Q2 * Z) + Q1) * Z) + Q0;
            return Mantissa_Half + Mantissa_Type (Gp / (Q - Gp));
        end R;
    begin
        if X > Bigx then
            New_Line;
            Put ("  EXP CALLED WITH TOO BIG A POSITIVE ARGUMENT, ");
            raise Program_Error
               --Put (X);
               ;
            Put ("   RETURNED XMAX");
            New_Line;
            Result := Xmax;
        elsif X < Smallx then
            New_Line;
            Put ("  EXP CALLED WITH TOO BIG A NEGATIVE ARGUMENT,  ");
            raise Program_Error;
            --Put (X);
            Put ("    RETURNED ZERO");
            New_Line;
            Result := Zero;
        elsif abs (X) < Eps then
            Result := One;
        else
            N := Exponent_Type (X * One_Over_Log_2);
            Xn := Convert_To_Float (N);
            X1 := Round (X);
            X2 := X - X1;
            Xg := ((X1 - Xn * C1) + X2) - Xn * C2;
            G := Mantissa_Type (Xg);
            N := N + 1;
            F := R (G);
            Refloat (N, F, Result);
        end if;

        return Result;

    exception
        when others =>
            New_Line;
            Put (" EXCEPTION IN EXP, X = ");
            raise Program_Error;
            --Put (X);
            Put ("  RETURNED 1.0");
            New_Line;
            return One;
    end Exp;

    function "**" (X, Y : Float) return Float is
        --  This is the last function to be coded since it appeared that it really
        --  was un-Ada-like and ought not be in the regular package
        --  Nevertheless it was included in this version
        --  It is specific for FLOAT and does not have the MANTISSA_TYPE generality
        M, N : Exponent_Type;
        G : Mantissa_Type;
        P, Temp, Iw1, I : Integer;
        Result, Z, V, R, U1, U2, W, W1, W2, W3, Y1, Y2 : Float;
        K : constant Float := 0.44269_50408_88963_40736;
        Ibigx : constant Integer := Integer
                                       (Truncate (16.0 * Log (Xmax) - 1.0));
        Ismallx : constant Integer := Integer
                                         (Truncate (16.0 * Log (Xmin) + 1.0));
        P1 : constant Float := 0.83333_32862_45E-1;
        P2 : constant Float := 0.12506_48500_52E-1;
        Q1 : constant Float := 0.69314_71805_56341;
        Q2 : constant Float := 0.24022_65061_44710;
        Q3 : constant Float := 0.55504_04881_30765E-1;
        Q4 : constant Float := 0.96162_06595_83789E-2;
        Q5 : constant Float := 0.13052_55159_42810E-2;
        A1 : array (1 .. 17) of Float :=
           (8#1.00000_0000#, 8#0.75222_5750#, 8#0.72540_3067#, 8#0.70146_3367#,
            8#0.65642_3746#, 8#0.63422_2140#, 8#0.61263_4520#, 8#0.57204_2434#,
            8#0.55202_3631#, 8#0.53254_0767#, 8#0.51377_3265#,
            8#0.47572_4623#, 8#0.46033_7602#, 8#0.44341_7233#,
            8#0.42712_7017#, 8#0.41325_3033#, 8#0.40000_0000#);
        A2 : array (1 .. 8) of Float :=
           (8#0.00000_00005_22220_66302_61734_72062#,
            8#0.00000_00003_02522_47021_04062_61124#,
            8#0.00000_00005_21760_44016_17421_53016#,
            8#0.00000_00007_65401_41553_72504_02177#,
            8#0.00000_00002_44124_12254_31114_01243#,
            8#0.00000_00000_11064_10432_66404_42174#,
            8#0.00000_00004_72542_16063_30176_55544#,
            8#0.00000_00001_74611_03661_23056_22556#);

        function Reduce (V : Float) return Float is
        begin
            return Float (Integer (16.0 * V)) * 0.0625;
        end Reduce;
    begin
        if X <= Zero then
            if X < Zero then
                Result := (abs (X)) ** Y;
                New_Line;
                Put ("X**Y CALLED WITH X = ");
                raise Program_Error;
                --Put (X);
                New_Line;
                Put ("USED ABS, RETURNED ");
                raise Program_Error
                   --Put (Result);
                   ;
                New_Line;
            else
                if Y <= Zero then
                    if Y = Zero then
                        Result := Zero;
                    else
                        Result := Xmax;
                    end if;

                    New_Line;
                    Put ("X**Y CALLED WITH X = 0, Y = ");
                    raise Program_Error;
                    --Put (Y);
                    New_Line;
                    Put ("RETURNED ");
                    raise Program_Error
                       --Put (Result);
                       ;
                    New_Line;
                else
                    Result := Zero;
                end if;
            end if;
        else
            Defloat (X, M, G);
            P := 1;

            if G <= A1 (9) then
                P := 9;
            end if;

            if G <= A1 (P + 4) then
                P := P + 4;
            end if;

            if G <= A1 (P + 2) then
                P := P + 2;
            end if;

            Z := ((G - A1 (P + 1)) - A2 ((P + 1) / 2)) / (G + A1 (P + 1));
            Z := Z + Z;
            V := Z * Z;
            R := (P2 * V + P1) * V * Z;
            R := R + K * R;
            U2 := (R + Z * K) + Z;
            U1 := Float (Integer (M) * 16 - P) * 0.0625;
            Y1 := Reduce (Y);
            Y2 := Y - Y1;
            W := U2 * Y + U1 * Y2;
            W1 := Reduce (W);
            W2 := W - W1;
            W := W1 + U1 * Y1;
            W1 := Reduce (W);
            W2 := W2 + (W - W1);
            W3 := Reduce (W2);
            Iw1 := Integer (Truncate (16.0 * (W1 + W3)));
            W2 := W2 - W3;

            if W > Float (Ibigx) then
                Result := Xmax;
                Put ("X**Y CALLED  X =");
                raise Program_Error;
                --Put (X);
                Put ("   Y =");
                raise Program_Error
                   --Put (Y);
                   ;
                Put ("   TOO LARGE  RETURNED ");
                raise Program_Error;
                --Put (Result);
                New_Line;
            elsif W < Float (Ismallx) then
                Result := Zero;
                Put ("X**Y CALLED  X =");
                raise Program_Error;
                --Put (X);
                Put ("   Y =");
                raise Program_Error
                   --Put (Y);
                   ;
                Put ("   TOO SMALL  RETURNED ");
                raise Program_Error
                   --Put (Result);
                   ;
                New_Line;
            else
                if W2 > Zero then
                    W2 := W2 - 0.0625;
                    Iw1 := Iw1 + 1;
                end if;

                if Iw1 < Integer (Zero) then
                    I := 0;
                else
                    I := 1;
                end if;

                M := Exponent_Type (I + Iw1 / 16);
                P := 16 * Integer (M) - Iw1;
                Z := ((((Q5 * W2 + Q4) * W2 + Q3) * W2 + Q2) * W2 + Q1) * W2;
                Z := A1 (P + 1) + (A1 (P + 1) * Z);
                Refloat (M, Z, Result);
            end if;
        end if;

        return Result;
    end "**";
begin
    Exp_Large := Log (Xmax) * (One - Eps);
    Exp_Small := Log (Xmin) * (One - Eps);
end Numeric_Io;
with Floating_Characteristics;
use Floating_Characteristics;

package Numeric_Primitives is

    --  This may seem a little much but is put in this form to allow the
    --  same form to be used for a generic package
    --  If that is not needed, simple litterals could be substituted
    Zero : Float := Convert_To_Float (Integer (0));
    One : Float := Convert_To_Float (Integer (1));
    Two : Float := One + One;
    Three : Float := One + One + One;
    Half : Float := One / Two;

    --  The following "constants" are effectively deferred to
    --  the initialization part of the package body
    --  This is in order to make it possible to generalize the floating type
    --  If that capability is not desired, constants may be included here
    Pi : Float;
    One_Over_Pi : Float;
    Two_Over_Pi : Float;
    Pi_Over_Two : Float;
    Pi_Over_Three : Float;
    Pi_Over_Four : Float;
    Pi_Over_Six : Float;

    function Sign (X, Y : Float) return Float;
    --  Returns the value of X with the sign of Y

    function Max (X, Y : Float) return Float;
    --  Returns the algebraicly larger of X and Y

    function Min (X, Y : Float) return Float;
    --  Returns the algebraicly smaller of X and Y

    function Truncate (X : Float) return Float;
    --  Returns the floating value of the integer no larger than X
    --  AINT(X)

    function Round (X : Float) return Float;
    --  Returns the floating value nearest X
    --  AINTRND(X)

    function Ran return Float;
    --  This uses a portable algorithm and is included at this point
    --  Algorithms that presume unique machine hardware information
    --  should be initiated in FLOATING_CHARACTERISTICS
end Numeric_Primitives;with Floating_Characteristics;
use Floating_Characteristics;

package body Numeric_Primitives is

    function Sign (X, Y : Float) return Float is
        --  Returns the value of X with the sign of Y
    begin
        if Y >= 0.0 then
            return X;
        else
            return -X;
        end if;
    end Sign;

    function Max (X, Y : Float) return Float is
    begin
        if X >= Y then
            return X;
        else
            return Y;
        end if;
    end Max;

    function Min (X, Y : Float) return Float is
    begin
        if X <= Y then
            return X;
        else
            return Y;
        end if;
    end Min;

    function Truncate (X : Float) return Float is
        --  Optimum code depends on how the system rounds at exact halves
    begin
        if Float (Integer (X)) = X then
            return X;
        end if;

        if X > Zero then
            return Float (Integer (X - Half));
        elsif X = Zero then
            return Zero;
        else
            return Float (Integer (X + Half));
        end if;
    end Truncate;

    function Round (X : Float) return Float is
    begin
        return Float (Integer (X));
    end Round;

    package Key is
        X : Integer := 10_001;
        Y : Integer := 20_001;
        Z : Integer := 30_001;
    end Key;

    function Ran return Float is
        --  This rectangular random number routine is adapted from a report
        --  "A Pseudo-Random Number Generator" by B. A. Wichmann and I. D. Hill
        --  NPL Report DNACS XX (to be published)
        --  In this stripped version, it is suitable for machines supporting
        --  INTEGER at only 16 bits and is portable in Ada
        W : Float;
    begin
        Key.X := 171 * (Key.X mod 177 - 177) - 2 * (Key.X / 177);

        if Key.X < 0 then
            Key.X := Key.X + 30269;
        end if;

        Key.Y := 172 * (Key.Y mod 176 - 176) - 35 * (Key.Y / 176);

        if Key.Y < 0 then
            Key.Y := Key.Y + 30307;
        end if;

        Key.Z := 170 * (Key.Z mod 178 - 178) - 63 * (Key.Z / 178);

        if Key.Z < 0 then
            Key.Z := Key.Z + 30323;
        end if;

        --  CONVERT_TO_FLOAT is used instead of FLOAT since the floating
        --  type may be software defined
        W := Convert_To_Float (Key.X) / 30269.0 +
                Convert_To_Float (Key.Y) / 30307.0 +
                Convert_To_Float (Key.Z) / 30323.0;
        return W - Convert_To_Float (Integer (W - 0.5));
    end Ran;
begin
    Pi := Convert_To_Float (Integer (3)) +
             Convert_To_Float (Mantissa_Type (0.14159_26535_89793_23846));
    One_Over_Pi := Convert_To_Float (Mantissa_Type (0.31830_98861_83790_67154));
    Two_Over_Pi := Convert_To_Float (Mantissa_Type (0.63661_97723_67581_34308));
    Pi_Over_Two := Convert_To_Float (Integer (1)) +
                      Convert_To_Float
                         (Mantissa_Type (


                                         0.57079_63267_94896_61923));
    Pi_Over_Three := Convert_To_Float (Integer (1)) +
                        Convert_To_Float (Mantissa_Type
                                             (0.04719_75511_96597_74615));
    Pi_Over_Four := Convert_To_Float
                       (Mantissa_Type (0.78539_81633_97448_30962));
    Pi_Over_Six := Convert_To_Float (Mantissa_Type (0.52359_87755_98298_87308));
end Numeric_Primitives;

generic

    type Element is private;
    pragma Must_Be_Constrained (Yes => Element);

package Queue_Generic is

    type Queue is private;

    procedure Initialize (Q : out Queue);

    function  Is_Empty   (Q : Queue) return Boolean;
    procedure Make_Empty (Q : in out Queue);

    procedure Copy (Target : in out Queue; Source : Queue);

    procedure Add    (Q : in out Queue; X : Element);
    procedure Delete (Q : in out Queue);
    function  First  (Q : Queue) return Element;
    -- on calls to delete and first, not is_empty(q) is assumed
    -- constraint error will be raises is is_empty(q)

    type Iterator is limited private;

    procedure Init  (Iter : out Iterator; Q : Queue);
    procedure Next  (Iter : in out Iterator);
    function  Value (Iter : Iterator) return Element;
    function  Done  (Iter : Iterator) return Boolean;

    ------------------------------------------------------
    -- Implementation Notes and Non-Standard Operations --
    ------------------------------------------------------

    -- variables of type queue are initially empty
    --    therefore, the call to initialize is optional

    -- := and = are meaningless
    --   := implies sharing (introduces an alias) for sub-structures

    -- garbage may be generated

private

    type Node;
    type Pointer is access Node;

    type Node is
        record
            Value : Element;
            Link  : Pointer;
        end record;

    type Queue is
        record
            Head : Pointer;
            Tail : Pointer;
        end record;

    type Iterator is new Queue;

end Queue_Generic;package body Queue_Generic is

    procedure Initialize (Q : out Queue) is
    begin
        null;
    end Initialize;

    function Is_Empty (Q : Queue) return Boolean is
    begin
        return Q.Head = null;
    end Is_Empty;

    procedure Make_Empty (Q : in out Queue) is
    begin
        Q.Head := null;
        Q.Tail := null;
    end Make_Empty;

    procedure Init (Iter : out Iterator; Q : Queue) is
    begin
        Iter := Iterator (Q);
    end Init;

    procedure Next (Iter : in out Iterator) is
    begin
        Iter.Head := Iter.Head.Link;
    end Next;

    function Value (Iter : Iterator) return Element is
    begin
        return Iter.Head.Value;
    end Value;

    function Done (Iter : Iterator) return Boolean is
    begin
        return Iter.Head = null;
    end Done;

    procedure Copy (Target : in out Queue; Source : Queue) is
        Iter : Iterator;
    begin
        Make_Empty (Target);
        Init (Iter, Source);
        while not Done (Iter) loop
            Add (Target, Value (Iter));
            Next (Iter);
        end loop;
    end Copy;

    procedure Add (Q : in out Queue; X : Element) is
        New_Node : constant Pointer := new Node'(X, null);
    begin
        if Q.Head = null then
            Q.Head := New_Node;
        else
            Q.Tail.Link := New_Node;
        end if;
        Q.Tail := New_Node;
    end Add;

    procedure Delete (Q : in out Queue) is
        First : constant Pointer := Q.Head;
    begin
        Q.Head     := First.Link;
        First.Link := null;
        if Q.Head = null then
            Q.Tail := null;
        end if;
    end Delete;

    function First (Q : Queue) return Element is
    begin
        return Q.Head.Value;
    end First;

end Queue_Generic;generic
    type Element is private;
    -- must be a pure value
    -- ie. no initialization or finalization is necessary
    -- = and := are equality and copy

    pragma Must_Be_Constrained (Yes => Element);

package Set_Generic is

    type Set is private;

    procedure Initialize (S : out Set);

    function  Is_Empty   (S : Set) return Boolean;
    procedure Make_Empty (S : in out Set);

    procedure Copy (Target : in out Set; Source : Set);

    function Is_Member (S : Set; X : Element) return Boolean;

    procedure Add    (S : in out Set; X : Element);
    procedure Delete (S : in out Set; X : Element);
    -- X is (is not) in S then the operation add (delete) is a no op.

    type Iterator is limited private;

    procedure Init  (Iter : out Iterator; S : Set);
    procedure Next  (Iter : in out Iterator);
    function  Value (Iter : Iterator) return Element;
    function  Done  (Iter : Iterator) return Boolean;

    ------------------------------------------------------
    -- Implementation Notes and Non-Standard Operations --
    ------------------------------------------------------

    -- variables of type set are initially empty
    --    therefore, the call to initialize is optional
    --   initialize does make the set empty

    -- := and = operate on references
    --   := implies sharing (introduces an alias)
    --   = means is the same set, not the same value of type set

    -- garbage may be generated

    -- Concurrency Properties
    -- any number of read operations (is_empty,is_member) can procede
    -- concurrently with one write operations (add/delete/make_empty)

private

    type Node is
        record
            Value : Element;
            Link  : Set;
        end record;

    type Set is access Node;

    type Iterator is new Set;

end Set_Generic;package body Set_Generic is

    procedure Initialize (S : out Set) is
    begin
        S := null;
    end Initialize;

    function Is_Empty (S : Set) return Boolean is
    begin
        return S = null;
    end Is_Empty;

    procedure Make_Empty (S : in out Set) is
    begin
        S := null;
    end Make_Empty;

    procedure Init (Iter : out Iterator; S : Set) is
    begin
        Iter := Iterator (S);
    end Init;

    procedure Next (Iter : in out Iterator) is
    begin
        Iter := Iterator (Iter.Link);
    end Next;

    function Value (Iter : Iterator) return Element is
    begin
        return Iter.Value;
    end Value;

    function Done (Iter : Iterator) return Boolean is
    begin
        return Iter = null;
    end Done;

    procedure Copy (Target : in out Set; Source : Set) is
        Rest : Set := Source;
    begin
        Target := null;
        while Rest /= null loop
            Target := new Node'(Rest.Value, Target);
            Rest   := Rest.Link;
        end loop;
    end Copy;


    function Is_Member (S : Set; X : Element) return Boolean is
        Rest : Set := S;
    begin
        while Rest /= null loop
            if Rest.Value = X then
                return True;
            end if;
            Rest := Rest.Link;
        end loop;
        return False;
    end Is_Member;

    procedure Add (S : in out Set; X : Element) is
    begin
        if not Is_Member (S, X) then
            S := new Node'(X, S);
        end if;
    end Add;

    procedure Delete (S : in out Set; X : Element) is
        Current  : Set := S;
        Previous : Set := null;
    begin
        while Current /= null loop
            if Current.Value = X then
                if Previous /= null then
                    Previous.Link := Current.Link;
                else
                    S := Current.Link;
                end if;
                return;
            end if;
            Previous := Current;
            Current  := Current.Link;
        end loop;
    end Delete;

end Set_Generic;generic
    type Element is private;

    pragma Must_Be_Constrained (Yes => Element);

package Stack_Generic is

    type Stack is private;
    Empty_Stack : constant Stack;
    -- It is expected that a declared stack is initialized to Empty_Stack

    procedure Make_Empty (S : in out Stack);
    procedure Pop        (S : in out Stack);
    procedure Push       (X : Element; S : in out Stack);
    function  Empty      (S : Stack) return Boolean;
    function  Top        (S : Stack) return Element;

    procedure Copy (Target : in out Stack; Source : Stack);

    Underflow : exception;


    type Iterator is private;

    procedure Init (Iter : out Iterator; S : Stack);
    procedure Next (Iter : in out Iterator);

    function Value (Iter : Iterator) return Element;
    function Done  (Iter : Iterator) return Boolean;
private
    type Stack_Node;
    type Stack is access Stack_Node;
    Empty_Stack : constant Stack := null;
    type Iterator is new Stack;
end Stack_Generic;package body Stack_Generic is

    type Stack_Node is
        record
            Elt  : Element;
            Link : Stack;
        end record;

    procedure Make_Empty (S : in out Stack) is
    begin
        S := null;
    end Make_Empty;

    procedure Pop (S : in out Stack) is
    begin
        if S = null then
            raise Underflow;
        else
            S := S.Link;
        end if;
    end Pop;


    procedure Push (X : Element; S : in out Stack) is
        New_Node : Stack;
    begin
        New_Node := new Stack_Node'(Elt => X, Link => S);
        S        := New_Node;
    end Push;


    function Empty (S : Stack) return Boolean is
    begin
        return S = null;
    end Empty;


    function Top (S : Stack) return Element is
    begin
        if S = null then
            raise Underflow;
        else
            return S.Elt;
        end if;
    end Top;

    procedure Copy (Target : in out Stack; Source : Stack) is
        Rest_Of_Source : Stack;
        Last_Of_Target : Stack;
    begin
        if Source /= null then
            Target := new Stack_Node'(Elt => Source.Elt, Link => null);

            Last_Of_Target := Target;
            Rest_Of_Source := Source.Link;
            while Rest_Of_Source /= null loop
                Last_Of_Target.Link :=
                   new Stack_Node'(Elt => Rest_Of_Source.Elt, Link => null);
                Last_Of_Target      := Last_Of_Target.Link;
                Rest_Of_Source      := Rest_Of_Source.Link;
            end loop;
        else
            Target := null;
        end if;
    end Copy;

    procedure Init (Iter : out Iterator; S : Stack) is
    begin
        Iter := Iterator (S);
    end Init;

    procedure Next (Iter : in out Iterator) is
    begin
        Iter := Iterator (Iter.Link);
    end Next;

    function Value (Iter : Iterator) return Element is
    begin
        return Iter.Elt;
    end Value;

    function Done (Iter : Iterator) return Boolean is
    begin
        return Iter = null;
    end Done;

end Stack_Generic;generic
    Size : Integer;

    type Range_Type is private;
    -- Range_Type is a pure value
    -- no initialization or finalization of values of range_type is
    -- necessary
    -- = and := can be used for equality and copy

    Ignore_Case : Boolean := True;
    pragma Must_Be_Constrained (Yes => Range_Type);

package String_Map_Generic is

    type Map is private;

    function Eval (The_Map : Map; D : String) return Range_Type;

    procedure Find (The_Map :        Map;
                    D       :        String;
                    R       : in out Range_Type;
                    Success : out    Boolean);

    procedure Define   (The_Map        : in out Map;
                        D              :        String;
                        R              :        Range_Type;
                        Trap_Multiples :        Boolean := False);
    procedure Undefine (The_Map : in out Map; D : String);

    procedure Initialize (The_Map : out Map);
    function  Is_Empty   (The_Map : Map) return Boolean;
    procedure Make_Empty (The_Map : in out Map);

    procedure Copy (Target : in out Map; Source : Map);

    type Iterator is private;

    procedure Init  (Iter : out Iterator; The_Map : Map);
    procedure Next  (Iter : in out Iterator);
    function  Value (Iter : Iterator) return String;
    function  Done  (Iter : Iterator) return Boolean;

    Undefined : exception;
    -- raised by eval if the domain value in not in the map

    Multiply_Defined : exception;
    -- raised by define if the domain value is already defined and
    -- the trap_multiples flag has been specified (ie. is true)

    function Nil                    return Map;
    function Is_Nil (The_Map : Map) return Boolean;

    function Cardinality (The_Map : Map) return Natural;

    ------------------------------------------------------
    -- Implementation Notes and Non-Standard Operations --
    ------------------------------------------------------

    -- := and = operate on references
    --   := implies sharing (introduces an alias)
    --   = means is the same set, not the same value of type set
    -- Initializing a map also makes it empty
    -- Accessing an uninitialized map will raise CONSTRAINT_ERROR.

    -- garbage may be generated

private

    subtype Index is Natural range 0 .. Size - 1;

    type Node (Size : Natural);
    type Set is access Node;

    type Table is array (Index) of Set;

    type Map_Data is
        record
            Bucket : Table;
            Size   : Integer := 0;
        end record;

    type Map is access Map_Data;

    type Iterator is
        record
            The_Map     : Map;
            Index_Value : Index;
            Set_Iter    : Set;
            Done        : Boolean;
        end record;

    type Node (Size : Natural) is
        record
            Link  : Set;
            Value : Range_Type;
            Name  : String (1 .. Size);
        end record;

end String_Map_Generic;with String_Utilities;

package body String_Map_Generic is

    function Find (S : Set; Name : String) return Set is
        Rest : Set := S;
    begin
        if Ignore_Case then
            declare
                Upper_Name : constant String :=
                   String_Utilities.Upper_Case (Name);
            begin
                while Rest /= null loop
                    if Rest.Name'Length = Upper_Name'Length and then
                       String_Utilities.Upper_Case (Rest.Name) = Upper_Name then
                        return Rest;
                    end if;
                    Rest := Rest.Link;
                end loop;
            end;
        else
            while Rest /= null loop
                if Rest.Name = Name then
                    return Rest;
                end if;
                Rest := Rest.Link;
            end loop;
        end if;
        return null;
    end Find;

    function Hash (Name : String) return Index is
    begin
        return Index'(String_Utilities.Hash_String (Name) mod Size);
    end Hash;
    pragma Inline (Hash);


    function Eval (The_Map : Map; D : String) return Range_Type is
        Ptr : Set := Find (The_Map.Bucket (Hash (D)), D);
    begin
        if Ptr /= null then
            return Ptr.Value;
        else
            raise Undefined;
        end if;
    end Eval;

    procedure Find (The_Map :        Map;
                    D       :        String;
                    R       : in out Range_Type;
                    Success : out    Boolean) is
        Ptr : Set := Find (The_Map.Bucket (Hash (D)), D);
    begin
        if Ptr /= null then
            R       := Ptr.Value;
            Success := True;
        else
            Success := False;
        end if;
    end Find;

    procedure Define (The_Map        : in out Map;
                      D              :        String;
                      R              :        Range_Type;
                      Trap_Multiples :        Boolean := False) is
        This_Node : Set renames The_Map.Bucket (Hash (D));
        The_Set   : Set := This_Node;
        Ptr       : Set := Find (The_Set, D);
    begin
        if Ptr = null then
            This_Node := new Node (D'Length);
            declare
                N : Node renames This_Node.all;
            begin
                N.Link  := The_Set;
                N.Value := R;
                N.Name  := D;
            end;
            The_Map.Size := The_Map.Size + 1;
        elsif Trap_Multiples then
            raise Multiply_Defined;

        else
            Ptr.Value := R;
        end if;
    end Define;

    procedure Undefine (The_Map : in out Map; D : String) is
        The_Bucket : Index := Hash (D);
        Current    : Set   := The_Map.Bucket (The_Bucket);
        Previous   : Set   := null;
    begin
        while Current /= null loop
            if Current.Name = D then
                if Previous /= null then
                    Previous.Link := Current.Link;
                else
                    The_Map.Bucket (The_Bucket) := Current.Link;
                end if;
                The_Map.Size := The_Map.Size - 1;
                return;
            else
                Previous := Current;
                Current  := Current.Link;
            end if;
        end loop;
        raise Undefined;
    end Undefine;

    procedure Copy (Target : in out Map; Source : Map) is
        Rest : Set;
    begin
        for I in Index loop
            Rest              := Source.Bucket (I);
            Target.Bucket (I) := null;

            while Rest /= null loop
                Target.Bucket (I) := new Node'(Size  => Rest.Name'Length,
                                               Name  => Rest.Name,
                                               Value => Rest.Value,
                                               Link  => Target.Bucket (I));

                Rest := Rest.Link;
            end loop;
        end loop;
        Target.Size := Source.Size;
    end Copy;

    procedure Initialize (The_Map : out Map) is
    begin
        The_Map := new Map_Data;
    end Initialize;


    function Is_Empty (The_Map : Map) return Boolean is
        Iter : Iterator;
    begin
        for I in Index loop
            if The_Map.Bucket (I) /= null then
                return False;
            end if;
        end loop;
        return True;
    end Is_Empty;

    procedure Make_Empty (The_Map : in out Map) is
    begin
        for I in Index loop
            The_Map.Bucket (I) := null;
        end loop;
    end Make_Empty;

    procedure Init (Iter : out Iterator; The_Map : Map) is
        The_Iter : Iterator;
    begin
        for I in Index loop
            The_Iter.Set_Iter := The_Map.Bucket (I);
            if The_Iter.Set_Iter /= null then
                The_Iter.Done        := False;
                The_Iter.Index_Value := I;
                The_Iter.The_Map     := The_Map;
                Iter                 := The_Iter;
                return;
            end if;
        end loop;
        The_Iter.Done := True;
        Iter          := The_Iter;
    end Init;

    procedure Next (Iter : in out Iterator) is
    begin
        Iter.Set_Iter := Iter.Set_Iter.Link;

        while Iter.Set_Iter = null loop
            if Iter.Index_Value = Index'Last then
                Iter.Done := True;
                return;
            end if;
            Iter.Index_Value := Iter.Index_Value + 1;
            Iter.Set_Iter    := Iter.The_Map.Bucket (Iter.Index_Value);
        end loop;
    end Next;

    function Value (Iter : Iterator) return String is
    begin
        return Iter.Set_Iter.Name;
    end Value;

    function Done (Iter : Iterator) return Boolean is
    begin
        return Iter.Done;
    end Done;

    function Nil return Map is
    begin
        return null;
    end Nil;

    function Is_Nil (The_Map : Map) return Boolean is
    begin
        return The_Map = null;
    end Is_Nil;

    function Cardinality (The_Map : Map) return Natural is
    begin
        return The_Map.Size;
    end Cardinality;
end String_Map_Generic;package String_Table is

    type Item is private;

    type Table is private;

    Table_Full : exception;

    -- create a table for unique strings
    function New_Table (Minimum_Table_Size : Natural := 127) return Table;

    function Nil return Item;

    -- return unique item in table, ignore_case => upper_case storage
    function Unique (Source      : String;
                     In_Table    : Table;
                     Ignore_Case : Boolean := True) return Item;

    -- return item if present, otherwise Nil
    function Find (Source      : String;
                   In_Table    : Table;
                   Ignore_Case : Boolean := True) return Item;

    -- return an item without entering in table
    function Allocate (Source : String; In_Table : Table) return Item;

    -- compare strings for identity, then same contents
    function Equal (L, R : Item) return Boolean;

    -- representation of string, suitable for hashing
    function Unique_Index (U : Item) return Integer;

    -- value of character or entire string
    function Char_At (Source : Item; At_Pos : Natural) return Character;
    function Image   (Source : Item)                   return String;
    function Length  (Source : Item)                   return Natural;
    function Is_Nil  (Source : Item)                   return Boolean;

    type Iterator is private;

    procedure Init  (Iter : out Iterator; The_Table : Table);
    procedure Next  (Iter : in out Iterator);
    function  Value (Iter : Iterator) return Item;
    function  Done  (Iter : Iterator) return Boolean;
private
    type Table_Storage;

    type Table is access Table_Storage;

    type Item is access String;

    type Sym_Rec;
    type Long_Sym_Pointer is access Sym_Rec;

    type Sym_Pointer is new Long_Sym_Pointer;

    subtype Element_Index is Integer;

    type Iterator is
        record
            The_Table : Table;
            Bucket    : Element_Index;
            Member    : Long_Sym_Pointer;
        end record;

end String_Table;with String_Utilities;
with Unchecked_Conversion;

package body String_Table is


    function Item_To_Integer is new Unchecked_Conversion (Item, Integer);

    package Util renames String_Utilities;

    type Sym_Rec is
        record
            Value : Item;
            Next  : Sym_Pointer;
        end record;

    type Table_Storage is array (Element_Index range <>) of Sym_Pointer;

    function Nil return Item is
    begin
        return null;
    end Nil;

    function Hash_Code (S : String; Hash_Size : Positive)
                       return Element_Index is
    begin
        return Element_Index (abs (Util.Hash_String (S) mod Hash_Size));
    end Hash_Code;
    pragma Inline (Hash_Code);

    function New_Table (Minimum_Table_Size : Natural := 127) return Table is
    begin
        return new Table_Storage (0 .. Minimum_Table_Size);
    end New_Table;

    function Unique (Source      : String;
                     In_Table    : Table;
                     Ignore_Case : Boolean := True) return Item is
        Bucket : Sym_Pointer renames In_Table
                                        (Hash_Code (Source, In_Table'Length));
        Chain  : Sym_Pointer := Bucket;
    begin
        if Source'Length = 0 then
            return null;
        end if;
        if Ignore_Case then
            declare
                S : constant String := Util.Upper_Case (Source);
            begin
                while Chain /= null loop
                    if Util.Upper_Case (Chain.Value.all) = S then
                        return Chain.Value;
                    end if;
                    Chain := Chain.Next;
                end loop;
            end;
        else
            while Chain /= null loop
                if Chain.Value.all = Source then
                    return Chain.Value;
                end if;
                Chain := Chain.Next;
            end loop;
        end if;

        Chain       := new Sym_Rec;
        Chain.Value := new String'(Source);
        Chain.Next  := Bucket;
        Bucket      := Chain;
        return Chain.Value;
    end Unique;

    function Find (Source      : String;
                   In_Table    : Table;
                   Ignore_Case : Boolean := True) return Item is
        Chain : Sym_Pointer := In_Table (Hash_Code (Source, In_Table'Length));
    begin
        if Source'Length = 0 then
            return null;
        end if;
        if Ignore_Case then
            declare
                S : constant String := Util.Upper_Case (Source);
            begin
                while Chain /= null loop
                    if Util.Upper_Case (Chain.Value.all) = S then
                        return Chain.Value;
                    end if;
                    Chain := Chain.Next;
                end loop;
            end;
        else
            while Chain /= null loop
                if Chain.Value.all = Source then
                    return Chain.Value;
                end if;
                Chain := Chain.Next;
            end loop;
        end if;
        return null;
    end Find;

    function Allocate (Source : String; In_Table : Table) return Item is
    begin
        if Source'Length > 0 then
            return new String'(Source);
        else
            return Nil;
        end if;
    end Allocate;


    function Equal (L, R : Item) return Boolean is
    begin
        return L = R or else
                  ((L /= Nil and then R /= Nil) and then L.all = R.all);
    end Equal;

    function Unique_Index (U : Item) return Integer is
    begin
        return Item_To_Integer (U);
    end Unique_Index;

    function Char_At (Source : Item; At_Pos : Natural) return Character is
    begin
        return Source (At_Pos - 1 + Source'First);
    end Char_At;


    function Image (Source : Item) return String is
    begin
        if Source = Nil then
            return "";
        else
            return Source.all;
        end if;
    end Image;

    function Length (Source : Item) return Natural is
    begin
        if Source = Nil then
            return 0;
        else
            return Source.all'Length;
        end if;
    end Length;

    function Is_Nil (Source : Item) return Boolean is
    begin
        return Source = Nil;
    end Is_Nil;

    procedure Incr (Iter : in out Iterator) is
    begin
        loop
            Iter.Member := Long_Sym_Pointer (Iter.The_Table (Iter.Bucket));
            exit when Iter.Member /= null or else
                         Iter.Bucket = Iter.The_Table'Last;
            Iter.Bucket := Iter.Bucket + 1;
        end loop;
    end Incr;

    procedure Init (Iter : out Iterator; The_Table : Table) is
        The_Iter : Iterator;
    begin
        The_Iter.The_Table := The_Table;
        The_Iter.Bucket    := 0;
        Incr (The_Iter);
        Iter := The_Iter;
    end Init;

    procedure Next (Iter : in out Iterator) is
    begin
        Iter.Member := Long_Sym_Pointer (Iter.Member.Next);
        if Iter.Member = null and then Iter.Bucket /= Iter.The_Table'Last then
            Iter.Bucket := Iter.Bucket + 1;
            Incr (Iter);
        end if;
    end Next;

    function Value (Iter : Iterator) return Item is
    begin
        return Iter.Member.Value;
    end Value;

    function Done (Iter : Iterator) return Boolean is
    begin
        return Iter.Member = null;
    end Done;

end String_Table;package String_Utilities is

    function Hash_String (S : String) return Integer;

    procedure Upper_Case (C : in out Character);
    procedure Lower_Case (C : in out Character);

    function Upper_Case (C : Character) return Character;
    function Lower_Case (C : Character) return Character;

    procedure Upper_Case (S : in out String);
    procedure Lower_Case (S : in out String);

    -- string returned has same 'First and 'Last as S
    function Upper_Case (S : String) return String;
    function Lower_Case (S : String) return String;



    function Number_To_String (Value   : Integer;
                               Base    : Natural   := 10;
                               Width   : Natural   := 0;
                               Leading : Character := ' ') return String;

    -- function Number_To_String (Value : Long_Integer;
    --                            Base : Natural := 10;
    --                            Width : Natural := 0;
    --                            Leading : Character := ' ') return String;

    procedure String_To_Number (Source :     String;
                                Target : out Integer;
                                Worked : out Boolean;
                                Base   :     Natural := 10);

    -- procedure String_To_Number (Source : String;
    --                             Target : out Long_Integer;
    --                             Worked : out Boolean;
    --                             Base : Natural := 10);

    function Strip_Leading
                (From : String; Filler : Character := ' ')    return String;
    function Strip_Trailing
                (From : String; Filler : Character := ' ')    return String;
    function Strip (From : String; Filler : Character := ' ') return String;

    -- Searches and compares
    -- Locate returns the index value in Within if found, 0 otherwise
    function Locate (Fragment    : String;
                     Within      : String;
                     Ignore_Case : Boolean := False) return Natural;

    function Locate (Fragment    : Character;
                     Within      : String;
                     Ignore_Case : Boolean := False) return Natural;

    function Reverse_Locate (Fragment    : String;
                             Within      : String;
                             Ignore_Case : Boolean := False) return Natural;

    function Reverse_Locate (Fragment    : Character;
                             Within      : String;
                             Ignore_Case : Boolean := False) return Natural;

    function Equal
                (Str1 : String; Str2 : String; Ignore_Case : Boolean := False)
                return Boolean;

    function Less_Than
                (Str1 : String; Str2 : String; Ignore_Case : Boolean := False)
                return Boolean;

    function Greater_Than
                (Str1 : String; Str2 : String; Ignore_Case : Boolean := False)
                return Boolean;

    procedure Capitalize (S : in out String);
    function  Capitalize (S : String) return String;

end String_Utilities;with Bounded_String;
package body String_Utilities is

    type Translate_Table is array (Character) of Character;
    type Equality_Table  is array (Character, Character) of Boolean;
    pragma Pack (Equality_Table);

    Upper_Ascii : Translate_Table;
    Lower_Ascii : Translate_Table;

    Equal_Mod_Case : Equality_Table := (others => (others => False));

    subtype Translation is Integer range 0 .. 2 ** 8 - 1;
    -- Next_Cap      is 0..1   * 2**7
    -- Lower_Char    is 0..127

    type Caps_Array is array (Translation) of Translation;
    Caps : Caps_Array;

    Char : constant Translation := 2 ** 7;

    Base_Characters : array (0 .. 15) of Character :=
       ('0', '1', '2', '3', '4', '5', '6', '7',
        '8', '9', 'A', 'B', 'C', 'D', 'E', 'F');


    procedure Capitalize (S : in out String) is
        Upper : Translation := 0;
    begin
        for I in S'Range loop
            declare
                C : Character   renames S (I);
                T : Translation renames Caps (Character'Pos (C) + Upper);
            begin
                C     := Character'Val (T mod Char);
                Upper := T - Character'Pos (C);  
            end;
        end loop;
    end Capitalize;

    function Capitalize (S : String) return String is
        Upper : Translation      := 0;
        New_S : String (S'Range) := S;
    begin
        for I in New_S'Range loop
            declare
                C : Character   renames New_S (I);
                T : Translation renames Caps (Character'Pos (C) + Upper);
            begin
                C     := Character'Val (T mod Char);
                Upper := T - Character'Pos (C);
            end;
        end loop;

        return New_S;
    end Capitalize;

    function Upper_Case (C : Character) return Character is
    begin
        return Upper_Ascii (C);
    end Upper_Case;


    function Lower_Case (C : Character) return Character is
    begin
        return Lower_Ascii (C);
    end Lower_Case;


    procedure Upper_Case (C : in out Character) is
    begin
        C := Upper_Ascii (C);
    end Upper_Case;


    procedure Lower_Case (C : in out Character) is
    begin
        C := Lower_Ascii (C);
    end Lower_Case;


    procedure Upper_Case (S : in out String) is
    begin
        for I in S'Range loop
            S (I) := Upper_Ascii (S (I));
        end loop;
    end Upper_Case;


    procedure Lower_Case (S : in out String) is
    begin
        for I in S'Range loop
            S (I) := Lower_Ascii (S (I));
        end loop;
    end Lower_Case;


    function Upper_Case (S : String) return String is
        New_S : String (S'First .. S'Last);
    begin
        for I in S'Range loop
            New_S (I) := Upper_Ascii (S (I));
        end loop;
        return New_S;
    end Upper_Case;


    function Lower_Case (S : String) return String is
        New_S : String (S'First .. S'Last);
    begin
        for I in S'Range loop
            New_S (I) := Lower_Ascii (S (I));
        end loop;
        return New_S;
    end Lower_Case;

    -- It is expected that specific targets will be able to get better hashes
    -- using code insertions.

    function Hash_String (S : String) return Integer is
        L      : constant Integer := S'Length;
        Result : Integer          := L;
    begin
        if L > 0 then
            Result := Result +
                         2 ** 5 * Character'Pos (Upper_Ascii (S (S'First))) +
                         Character'Pos
                            (Upper_Ascii
                                (S (S'First + (1 + S'Last - S'First) / 2))) +
                         2 ** 3 * Character'Pos (Upper_Ascii (S (S'Last)));
        end if;
        return Result;
    end Hash_String;

    function Number_To_String (Value   : Integer;
                               Base    : Natural   := 10;
                               Width   : Natural   := 0;
                               Leading : Character := ' ') return String is
        Sign   : Boolean := False;
        Result : Bounded_String.Variable_String (80);
        Ch     : Integer;
        procedure N2s (Num : Integer; Width : Integer) is
        begin
            if Num = 0 then
                -- Handle leading stuff
                for I in 1 .. Width loop
                    Bounded_String.Append (Result, Leading);
                end loop;
                if Sign then
                    Bounded_String.Append (Result, '-');
                end if;
                if Value = 0 then
                    if Width > 0 then
                        Bounded_String.Replace
                           (Result, Bounded_String.Length (Result), '0');
                    else
                        Bounded_String.Append (Result, '0');
                    end if;
                end if;
            else
                N2s (Num / Base, Width - 1);
                if not Sign then
                    Ch := Num mod Base;
                else
                    Ch := Base - Num mod Base;
                    if Ch = Base then
                        Ch := 0;
                    end if;
                end if;
                Bounded_String.Append (Result, Base_Characters (Ch));
            end if;
        end N2s;
    begin
        Bounded_String.Set_Length (Result, 0);
        if Value < 0 then
            Sign := True;
            N2s (Value, Width - 1);
        else
            N2s (Value, Width);
        end if;
        return Bounded_String.Image (Result);
    end Number_To_String;
    -- the above used to be the long_integer version


    -- function Number_To_String (Value : Integer;
    --                            Base : Natural := 10;
    --                            Width : Natural := 0;
    --                            Leading : Character := ' ') return String is
    -- begin
    --     return Number_To_String (Long_Integer (Value), Base, Width, Leading);
    -- end Number_To_String;


    -- the following used to be the long_integer version
    procedure String_To_Number (Source :     String;
                                Target : out Integer;
                                Worked : out Boolean;
                                Base   :     Natural := 10) is
        Sign     : Integer;
        Result   : Integer;
        Ch       : Character;
        Char_Val : Integer;
        Prefix   : Boolean := True;
    begin
        Worked := False;
        Target := 0;
        Result := 0;
        Sign   := +1;

        for I in Source'Range loop
            Ch := Source (I);
            if Ch = ' ' then
                if not Prefix then
                    return;
                end if;
            else
                if Prefix and Ch = '-' then
                    Sign := -1;
                else
                    if Ch in '0' .. '9' then
                        Char_Val := (Character'Pos (Ch) - 48);
                    else
                        Upper_Case (Ch);
                        if Ch in 'A' .. 'F' then
                            Char_Val := Character'Pos (Ch) -
                                           Character'Pos ('A') + 10;
                        else
                            -- set Char_Val > any legal base
                            Char_Val := 500;
                        end if;
                    end if;
                    if Char_Val >= Base then
                        return;
                    end if;
                    Result := Result * Base + Char_Val;
                end if;
                Prefix := False;
            end if;
        end loop;

        if Source'Length /= 0 and then
           (Source'Length > 1 or else Sign = +1) then
            Target := Result * Sign;
            Worked := True;
        end if;

    exception
        when others =>
            Worked := False;
    end String_To_Number;


    -- procedure String_To_Number (Source : String;
    --                             Target : out Integer;
    --                             Worked : out Boolean;
    --                             Base : Natural := 10) is
    --     Result : Long_Integer;
    -- begin
    --     String_To_Number (Source, Result, Worked, Base);
    --     Target := Integer (Result);
    -- end String_To_Number;

    function Locate (Fragment    : Character;
                     Within      : String;
                     Ignore_Case : Boolean := False) return Natural is
    begin
        if Ignore_Case then
            for I in Within'Range loop
                if Equal_Mod_Case (Fragment, Within (I)) then
                    return I;
                end if;
            end loop;
        else
            for I in Within'Range loop
                if Fragment = Within (I) then
                    return I;
                end if;
            end loop;
        end if;
        return 0;
    end Locate;


    function Locate (Fragment    : String;
                     Within      : String;
                     Ignore_Case : Boolean := False) return Natural is
        Dec_Length : Integer  := Fragment'Length - 1;
        First      : Positive := Fragment'First;
        First_Char : Character;
    begin
        if Dec_Length >= 1 then
            First_Char := Fragment (First);

            if Ignore_Case then
                for I in Within'First .. Within'Last - Dec_Length loop
                    if Equal_Mod_Case (Within (I), First_Char) then
                        for J in reverse 1 .. Dec_Length loop
                            if not Equal_Mod_Case (Fragment (First + J),
                                                   Within (I + J)) then
                                exit;
                            elsif J = 1 then
                                return I;
                            end if;
                        end loop;
                    end if;
                end loop;
            else
                for I in Within'First .. Within'Last - Dec_Length loop
                    if Within (I) = First_Char then
                        for J in reverse 1 .. Dec_Length loop
                            if Fragment (First + J) /= Within (I + J) then
                                exit;
                            elsif J = 1 then
                                return I;
                            end if;
                        end loop;
                    end if;
                end loop;
            end if;

            return 0;

        elsif Dec_Length = 0 then
            return Locate (Fragment (First), Within, Ignore_Case);

        else
            return Within'First;
        end if;
    end Locate;

    function Reverse_Locate (Fragment    : Character;
                             Within      : String;
                             Ignore_Case : Boolean := False) return Natural is
    begin
        if Ignore_Case then
            for I in reverse Within'Range loop
                if Equal_Mod_Case (Fragment, Within (I)) then
                    return I;
                end if;
            end loop;
        else
            for I in reverse Within'Range loop
                if Fragment = Within (I) then
                    return I;
                end if;
            end loop;
        end if;
        return 0;
    end Reverse_Locate;


    function Reverse_Locate (Fragment    : String;
                             Within      : String;
                             Ignore_Case : Boolean := False) return Natural is
        Dec_Length : Integer  := Fragment'Length - 1;
        First      : Positive := Fragment'First;
        First_Char : Character;
    begin
        if Dec_Length >= 1 then
            First_Char := Fragment (First);

            if Ignore_Case then
                for I in reverse Within'First .. Within'Last - Dec_Length loop
                    if Equal_Mod_Case (Within (I), First_Char) then
                        for J in reverse 1 .. Dec_Length loop
                            if not Equal_Mod_Case (Fragment (First + J),
                                                   Within (I + J)) then
                                exit;
                            elsif J = 1 then
                                return I + Dec_Length;
                            end if;
                        end loop;
                    end if;
                end loop;
            else
                for I in reverse Within'First .. Within'Last - Dec_Length loop
                    if Within (I) = First_Char then
                        for J in reverse 1 .. Dec_Length loop
                            if Fragment (First + J) /= Within (I + J) then
                                exit;
                            elsif J = 1 then
                                return I + Dec_Length;
                            end if;
                        end loop;
                    end if;
                end loop;
            end if;

            return 0;

        elsif Dec_Length = 0 then
            return Reverse_Locate (Fragment (First), Within, Ignore_Case);

        else
            return Within'Last;
        end if;
    end Reverse_Locate;

    function Equal
                (Str1 : String; Str2 : String; Ignore_Case : Boolean := False)
                return Boolean is
        Length : Integer  := Str1'Length;
        First1 : Positive := Str1'First;
        First2 : Positive := Str2'First;
    begin
        if Length = Str2'Length then
            if Ignore_Case then
                for I in 0 .. Length - 1 loop
                    if not Equal_Mod_Case (Str1 (First1 + I),
                                           Str2 (First2 + I)) then
                        return False;
                    end if;
                end loop;

                return True;
            else
                return Str1 = Str2;
            end if;

        else
            return False;
        end if;
    end Equal;


    function Less_Than
                (Str1 : String; Str2 : String; Ignore_Case : Boolean := False)
                return Boolean is
    begin
        if Ignore_Case then
            return Lower_Case (Str1) < Lower_Case (Str2);
        else
            return Str1 < Str2;
        end if;
    end Less_Than;


    function Greater_Than
                (Str1 : String; Str2 : String; Ignore_Case : Boolean := False)
                return Boolean is
    begin
        if Ignore_Case then
            return Lower_Case (Str1) > Lower_Case (Str2);
        else
            return Str1 > Str2;
        end if;
    end Greater_Than;


    function Strip_Leading
                (From : String; Filler : Character := ' ') return String is
    begin
        for I in From'First .. From'Last loop
            if From (I) /= Filler then
                return From (I .. From'Last);
            end if;
        end loop;
        return "";
    end Strip_Leading;


    function Strip_Trailing
                (From : String; Filler : Character := ' ') return String is
    begin
        for I in reverse From'First .. From'Last loop
            if From (I) /= Filler then
                return From (From'First .. I);
            end if;
        end loop;
        return "";
    end Strip_Trailing;


    function Strip (From : String; Filler : Character := ' ') return String is
    begin
        return Strip_Leading (Strip_Trailing (From, Filler), Filler);
    end Strip;

begin
    for C in Character loop
        Upper_Ascii (C)       := C;
        Equal_Mod_Case (C, C) := True;
    end loop;

    Lower_Ascii := Upper_Ascii;

    for C in 'A' .. 'Z' loop
        Lower_Ascii (C) := Character'Val (Character'Pos (C) + 32);
        Equal_Mod_Case (C, Lower_Ascii (C)) := True;
    end loop;

    for C in 'a' .. 'z' loop
        Upper_Ascii (C) := Character'Val (Character'Pos (C) - 32);
        Equal_Mod_Case (C, Upper_Ascii (C)) := True;
    end loop;

    declare
        Alphanumeric : Integer;
        Upper        : Character;
        Lower        : Character;
    begin
        for C in Character loop
            Upper := Upper_Ascii (C);
            Lower := Lower_Ascii (C);
            Alphanumeric := Boolean'Pos
                               (Upper /= Lower or else C in '0' .. '9') * Char;
            Caps (Character'Pos (C)) := Alphanumeric + Character'Pos (Upper);
            Caps (Character'Pos (C) + Char) :=
               Alphanumeric + Character'Pos (Lower);
        end loop;
    end;

end String_Utilities;with Text_Io;

-- This package is used to produce neatly formatted tables with centered
-- headers and even amounts of white space between the columns.  The first
-- N calls should be to header, which defines a header and a type of
-- justification for the items that will go into each column.  Then the M*N
-- items of an M line table are sent into the package a row at a time.  An
-- item is defined by either a single call to Item, or a series of zero or
-- more calls to Subitem terminated by a call to Last_Subitem.  Multiple
-- parts of an item are separated by the subitem separator.  After all the
-- items have been defined, the table is output with a call to Display.

-- The package internally allocates enough memory to save a copy of the
-- entire table.   It is therefore a good idea to instantiate this
-- procedure in a local frame so that all the memory it allocates will go
-- away when the frame does.

generic
    Number_Of_Columns : Positive;
    Subitem_Separator : String := " ";
package Table_Formatter is

    type Adjust is (Left, Right, Centered);
    procedure Header  (S : String; Format : Adjust := Left);
    procedure Item    (S : String);
    procedure Subitem (S : String);
    procedure Last_Subitem;
    procedure Display (On_File : Text_Io.File_Type);


    type Field_List is array (Integer range <>) of Positive;
    procedure Sort (On_Field : Positive := 1);
    procedure Sort (On_Fields : Field_List);

end Table_Formatter;with Table_Sort_Generic;

package body Table_Formatter is
    Intercolumn_Spacing : constant := 2;
    subtype Column_Index is Natural range 1 .. Number_Of_Columns;

    type Width_List is array (Column_Index) of Natural;

    type A_String    is access String;
    type An_Item (Subitem_Length : Natural);
    type Access_Item is access An_Item;
    type An_Item (Subitem_Length : Natural) is
        record
            Subitem : String (1 .. Subitem_Length);
            Next    : Access_Item;
        end record;

    type Item_List is array (Column_Index) of Access_Item;

    type Line;
    type Access_Line       is access Line;
    type Access_Line_Array is array (Integer range <>) of Access_Line;

    Current_Line : Access_Line;

    type Line is
        record
            Values : Item_List;
            Width  : Width_List  := (others => 0);
            Next   : Access_Line := Current_Line;
        end record;

    Current_Column : Column_Index := Column_Index'Last;
    In_Subitem     : Boolean      := False;
    Max_Width      : Width_List   := (others => 0);
    Headers        : array (Column_Index) of A_String;
    Header_Column  : Natural      := 0;
    Column_Format  : array (Column_Index) of Adjust;

    function Max (Left, Right : Integer) return Integer is
    begin
        if Left >= Right then
            return Left;
        else
            return Right;
        end if;
    end Max;

    procedure Insert (S : String) is
        -- Put the String into the current row/column, appending it if
        -- there is already something there.

        Cell  : Access_Item renames Current_Line.Values (Current_Column);
        Width : Natural     renames Current_Line.Width (Current_Column);
        Max   : Natural     renames Max_Width (Current_Column);
    begin
        if Cell = null then
            Width := S'Length;
        else
            Width := Width + Subitem_Separator'Length + S'Length;
        end if;

        if Width > Max then
            Max := Width;
        end if;

        Cell := new An_Item'(S'Length, S, Cell);
    end Insert;

    procedure Item (S : String) is
        -- Begin a new cell, put S there, and mark the cell closed by
        -- setting In_Subitem to be false.
    begin
        if Current_Column = Column_Index'Last then
            Current_Line   := new Line;
            Current_Column := Column_Index'First;
        else
            Current_Column := Current_Column + 1;
        end if;

        Insert (S);
        In_Subitem := False;
    end Item;

    procedure Header (S : String; Format : Adjust := Left) is
        -- Set Header and Column Format
    begin
        Header_Column                 := Header_Column + 1;
        Column_Format (Header_Column) := Format;
        Headers (Header_Column)       := new String'(S);
    end Header;

    procedure Subitem (S : String) is
        -- If the current cell is open, add S to it.  Otherwise start a new
        -- cell, but leave it open.
    begin
        if In_Subitem then
            Insert (S);
        else
            Item (S);
        end if;

        In_Subitem := True;
    end Subitem;

    procedure Last_Subitem is
        -- If the current cell is open, close it.  If the current cell is
        -- closed, we have an item that consists of zero subitems.  Give it
        -- a visible representation.
    begin
        if In_Subitem then
            In_Subitem := False;
        else
            Item ("(none)");
        end if;
    end Last_Subitem;


    function Image (P : Access_Item) return String is
        -- P must be non-null
    begin
        if P.Next = null then
            return P.Subitem;
        end if;

        return Image (P.Next) & Subitem_Separator & P.Subitem;
        -- Recall that subitem lists are stored in reverse order
    end Image;


    procedure Display (On_File : Text_Io.File_Type) is
        -- Dump the data structure we have been building by traversing it
        -- recursively.  Note that all of the lists are stored in reverse
        -- order so that they were easy to build.

        procedure Replicate (C : Character; N : Natural) is
            -- Output N copies of C
            S : constant String (1 .. N) := (others => C);
        begin
            Text_Io.Put (On_File, S);
        end Replicate;

        procedure Display (P : Access_Item) is
        begin
            if P /= null then
                Text_Io.Put (On_File, Image (P));
            end if;
        end Display;

        procedure Display_Headers is
            Excess : Width_List;
        begin
            for J in Column_Index loop
                Excess (J) := Max (Headers (J).all'Length, Max_Width (J)) -
                                 Headers (J).all'Length;
            end loop;

            Replicate (' ', Excess (1) / 2);

            for J in Column_Index loop
                Text_Io.Put (On_File, Headers (J).all);

                if J /= Column_Index'Last then
                    Replicate (' ', (Excess (J) + 1) / 2 + Excess (J + 1) / 2 +
                                       Intercolumn_Spacing);
                end if;

            end loop;

            Text_Io.New_Line (On_File);
        end Display_Headers;

        procedure Display_Adjusted (L : Line) is
            Inner_Excess, Outer_Excess : Natural;
        begin
            for J in Column_Index loop
                Inner_Excess := Max_Width (J) - L.Width (J);
                Outer_Excess :=
                   Max (Headers (J).all'Length, Max_Width (J)) - Max_Width (J);

                case Column_Format (J) is
                    when Left =>
                        Replicate (' ', Outer_Excess / 2);
                        Display (L.Values (J));
                        if J /= Column_Index'Last then
                            Replicate (' ',
                                       (Outer_Excess + 1) / 2 + Inner_Excess +
                                          Intercolumn_Spacing);
                        end if;

                    when Right =>
                        Replicate (' ', Outer_Excess / 2 + Inner_Excess);
                        Display (L.Values (J));
                        if J /= Column_Index'Last then
                            Replicate (' ', (Outer_Excess + 1) / 2 +
                                               Intercolumn_Spacing);
                        end if;

                    when Centered =>
                        Replicate (' ', (Inner_Excess + Outer_Excess) / 2);
                        Display (L.Values (J));
                        if J /= Column_Index'Last then
                            Replicate (' ',
                                       (Inner_Excess + Outer_Excess + 1) / 2 +
                                          Intercolumn_Spacing);
                        end if;
                end case;
            end loop;

            Text_Io.New_Line (On_File);
        end Display_Adjusted;

        procedure Display (L : Access_Line) is
        begin
            if L = null then
                -- Center the header
                Display_Headers;

                -- A separator line
                for J in Column_Index loop
                    Replicate ('=', Max
                                       (Headers (J).all'Length, Max_Width (J)));
                    if J /= Column_Index'Last then
                        Replicate (' ', Intercolumn_Spacing);
                    end if;
                end loop;
                Text_Io.New_Line (On_File);
            else
                -- Display the head of the table
                Display (L.Next);

                -- Display the final line
                Display_Adjusted (L.all);
            end if;
        end Display;
    begin
        Display (Current_Line);
    end Display;


    function Normalize return Natural is
        -- Traverse the current structure looking for cells that consist
        -- of more than one subitem, and concatentate the subitems into
        -- a single item.

        -- Return the number of rows in the table.

        Result : Natural     := 0;
        Line   : Access_Line := Current_Line;
        P      : Access_Item;
    begin
        while Line /= null loop
            for J in Line.Values'Range loop
                P := Line.Values (J);

                if P = null then
                    Line.Values (J) := new An_Item'(0, "", null);
                elsif P.Next /= null then
                    Line.Values (J) :=
                       new An_Item'(Line.Width (J), Image (P), null);
                end if;
            end loop;

            Line   := Line.Next;
            Result := Result + 1;
        end loop;

        return Result;
    end Normalize;

    procedure Fill (Table : out Access_Line_Array) is
        -- Transfers the linked list pointed to by Current_Line into
        -- the sequential table.

        P : Access_Line;
    begin
        P := Current_Line;
        for J in reverse Table'Range loop
            Table (J) := P;
            P         := P.Next;
        end loop;
    end Fill;

    procedure Empty (Table : Access_Line_Array) is
        -- rebuilds the Current_Line link list from the sequential table,
        -- preserving the convention that lists are stored backwards.
    begin
        if Table'Length = 0 then
            Current_Line := null;
            return;
        end if;

        Table (Table'First).Next := null;

        for J in Table'First + 1 .. Table'Last loop
            Table (J).Next := Table (J - 1);
        end loop;

        Current_Line := Table (Table'Last);
    end Empty;


    procedure Sort (On_Field : Positive := 1) is
        Table : Access_Line_Array (1 .. Normalize);

        function "<" (Left, Right : Access_Line) return Boolean is
        begin
            return Left.Values (On_Field).Subitem <
                      Right.Values (On_Field).Subitem;
        end "<";

        procedure Table_Sort is
           new Table_Sort_Generic (Element       => Access_Line,
                                   Index         => Integer,
                                   Element_Array => Access_Line_Array);
    begin
        Fill (Table);
        Table_Sort (Table);
        Empty (Table);
    end Sort;


    procedure Sort (On_Fields : Field_List) is
        Table : Access_Line_Array (1 .. Normalize);

        function "<" (Left, Right : Access_Line) return Boolean is
        begin
            for J in On_Fields'Range loop
                if Left.Values (On_Fields (J)).Subitem <
                   Right.Values (On_Fields (J)).Subitem then
                    return True;
                end if;

                if Left.Values (On_Fields (J)).Subitem >
                   Right.Values (On_Fields (J)).Subitem then
                    return False;
                end if;
            end loop;

            return False;
        end "<";

        procedure Table_Sort is
           new Table_Sort_Generic (Element       => Access_Line,
                                   Index         => Integer,
                                   Element_Array => Access_Line_Array);
    begin
        Fill (Table);
        Table_Sort (Table);
        Empty (Table);
    end Sort;

begin

    -- Default to empty left justified headers.
    for J in Column_Index loop
        Column_Format (J) := Left;
        Headers (J)       := new String'("");
    end loop;

end Table_Formatter;generic
    type Element is private;
    pragma Must_Be_Constrained (Yes => Element);

    type Index         is (<>);
    type Element_Array is array (Index range <>) of Element;
    with function "<" (Left, Right : Element) return Boolean is <>;
procedure Table_Sort_Generic (Table : in out Element_Array);procedure Table_Sort_Generic (Table : in out Element_Array) is

    First_Index : Integer := Index'Pos (Table'First);
    Last_Index  : Integer := Index'Pos (Table'Last);
    J           : Integer;
    Jg          : Integer;
    Gap         : Integer;
    Temp        : Element;
begin
    Gap := Last_Index - First_Index;
    while Gap > 0 loop
        for I in Index'Val (Gap + First_Index) .. Table'Last loop
            J := Index'Pos (I) - Gap;
            while J >= First_Index loop
                Jg := J + Gap;
                declare
                    Op1 : Element renames Table (Index'Val (J));
                    Op2 : Element renames Table (Index'Val (Jg));
                begin
                    if Op2 < Op1 then
                        Temp := Op1;
                        Op1  := Op2;
                        Op2  := Temp;
                    else
                        exit;
                    end if;
                end;
                J := J - Gap;
            end loop;
        end loop;
        Gap := Gap / 2;
    end loop;
end Table_Sort_Generic;with Calendar;

package Time_Utilities is

    Minute : constant Duration := 60.0;
    Hour   : constant Duration := 3600.0;
    Day    : constant Duration := 86_400.0;

    --------------------------------------------------------------------
    -- Time_Utilities.Time is a segmented version of Calendar.Time
    --         with image and value functions
    --------------------------------------------------------------------

    type Years  is new Calendar.Year_Number;
    type Months is (January, February, March, April, May, June, July,
                    August, September, October, November, December);
    type Days   is new Calendar.Day_Number;

    type Hours   is new Integer range 1 .. 12;
    type Minutes is new Integer range 0 .. 59;
    type Seconds is new Integer range 0 .. 59;

    type Sun_Positions is (Am, Pm);

    type Time is
        record
            Year         : Years;
            Month        : Months;
            Day          : Days;
            Hour         : Hours;
            Minute       : Minutes;
            Second       : Seconds;
            Sun_Position : Sun_Positions;
        end record;

    function Get_Time return Time;

    function Convert_Time (Date : Calendar.Time) return Time;
    function Convert_Time (Date : Time)          return Calendar.Time;

    function Nil                  return Time;
    function Is_Nil (Date : Time) return Boolean;

    function Nil return Calendar.Time;
    function Is_Nil (Date : Calendar.Time) return Boolean;

    type Time_Format is (Expanded,             -- 11:00:00 PM
                         Military,             -- 23:00:00
                         Short,                -- 23:00
                         Ada                 -- 23_00_00
                         );

    type Date_Format is (Expanded,             -- September 29, 1983
                         Month_Day_Year,       -- 09/29/83
                         Day_Month_Year,       -- 29-SEP-83
                         Year_Month_Day,       -- 83/09/29
                         Ada                 -- 83_09_29
                         );

    type Image_Contents is (Both, Time_Only, Date_Only);

    function Image (Date       : Time;
                    Date_Style : Date_Format    := Time_Utilities.Expanded;
                    Time_Style : Time_Format    := Time_Utilities.Expanded;
                    Contents   : Image_Contents := Time_Utilities.Both)
                   return String;

    function Value (S : String) return Time;
    -- Gives incorrect results for dates earlier than 1924.

    --------------------------------------------------------------------
    -- Time_Utilities.Interval is a segmented version of Duration
    --        with image and value functions
    --------------------------------------------------------------------

    type Day_Count      is new Integer range 0 .. Integer'Last;
    type Military_Hours is new Integer range 0 .. 23;
    type Milliseconds   is new Integer range 0 .. 999;

    type Interval is
        record
            Elapsed_Days         : Day_Count;
            Elapsed_Hours        : Military_Hours;
            Elapsed_Minutes      : Minutes;
            Elapsed_Seconds      : Seconds;
            Elapsed_Milliseconds : Milliseconds;
        end record;


    function Convert (I : Interval) return Duration;
    function Convert (D : Duration) return Interval;

    function Image (I : Interval) return String;
    function Value (S : String)   return Interval;

    function Image (D : Duration) return String;

    function Duration_Until (T : Time)          return Duration;
    function Duration_Until (T : Calendar.Time) return Duration;
    function Duration_Until_Next
                (H : Military_Hours; M : Minutes := 0; S : Seconds := 0)
                return Duration;

    -- Day of week support; Monday is 1.
    type Weekday is new Positive range 1 .. 7;

    function Day_Of_Week (T : Calendar.Time)    return Weekday;
    function Day_Of_Week (T : Time := Get_Time) return Weekday;
    function Image       (D : Weekday)          return String;

    function "+" (D : Weekday; I : Integer) return Weekday;
    function "-" (D : Weekday; I : Integer) return Weekday;

end Time_Utilities;with Enumeration_Value;
with Machine_Independent_Integer32;
with String_Utilities;

package body Time_Utilities is

    package Mii renames Machine_Independent_Integer32;
    subtype Integer32 is Mii.Integer32;
    function "+" (L, R : Integer32)           return Integer32 renames Mii."+";
    function "-" (L, R : Integer32)           return Integer32 renames Mii."-";
    function "*" (L : Integer32; R : Integer) return Integer32 renames Mii."*";
    function "/" (L : Integer32; R : Integer) return Integer32 renames Mii."/";
    function "=" (L, R : Integer32)           return Boolean   renames Mii."=";
    function "<" (L, R : Integer32)           return Boolean   renames Mii."<";

    Zero                 : constant Integer32 := Integer32 (0);
    Seconds_Per_Minute   : constant           := 60;
    Seconds_Per_Hour     : constant           := 60 * Seconds_Per_Minute;
    Seconds_Per_Half_Day : constant           := 12 * Seconds_Per_Hour;
    Null_Calendar_Time   : Calendar.Time;

    type Number_Array is array (Positive range <>) of Natural;

    type Character_Map is array (Character) of Boolean;
    Is_Numeric : constant Character_Map :=
       Character_Map'('0' | '1' | '2' | '3' | '4' |
                      '5' | '6' | '7' | '8' | '9' => True,
                      others                      => False);

    Is_Alphabetic : constant Character_Map :=
       Character_Map'('a' .. 'z' | 'A' .. 'Z' => True, others => False);
    Null_Time     : constant Time := Time'(Year         => Years'First,
                                           Month        => Months'First,
                                           Day          => Days'First,
                                           Hour         => Hours'First,
                                           Minute       => Minutes'First,
                                           Second       => Seconds'First,
                                           Sun_Position => Sun_Positions'First);
    Null_Interval : constant Interval :=
       Interval'(Elapsed_Days         => Day_Count'First,
                 Elapsed_Hours        => Military_Hours'First,
                 Elapsed_Minutes      => Minutes'First,
                 Elapsed_Seconds      => Seconds'First,
                 Elapsed_Milliseconds => Milliseconds'First);

    Military_Hour : constant array (Sun_Positions, Hours) of Military_Hours :=
       (Am => (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 0),
        Pm => (13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 12));

    -- used in day of week calculation
    Days_In_Month : constant array (Months) of Integer :=
       (January | March | May | July | August | October | December => 31,
        April | June | September | November => 30,
        February => 28);

    function Image (Value   : Integer;
                    Base    : Natural   := 10;
                    Width   : Natural   := 2;
                    Leading : Character := '0') return String
        renames String_Utilities.Number_To_String;

    package Interval_Value is
        -- Hack to get around RCG bug

        function Value (S : String) return Interval;
    end Interval_Value;

    procedure Unique_Prefix is new Enumeration_Value (Months);
    function Convert_Time (Date : Calendar.Time) return Time is
        Result : Time;

        C_Year   : Calendar.Year_Number;
        C_Month  : Calendar.Month_Number;
        C_Day    : Calendar.Day_Number;
        C_Second : Calendar.Day_Duration;

        Total_Seconds  : Integer32;
        Hour_Offset    : Integer32;  
        Junk, Min, Sec : Integer32;
    begin
        Calendar.Split (Date, C_Year, C_Month, C_Day, C_Second);

        Result.Year  := Years (C_Year);
        Result.Month := Months'Val (C_Month - 1);
        Result.Day   := Days (C_Day);

        Total_Seconds := Integer32 (C_Second);

        if Total_Seconds < Integer32 (Seconds_Per_Half_Day) then
            Result.Sun_Position := Am;
        else
            Result.Sun_Position := Pm;
            Total_Seconds := Total_Seconds - Integer32 (Seconds_Per_Half_Day);
        end if;

        Hour_Offset := Total_Seconds / Seconds_Per_Hour;

        if Hour_Offset = Zero then
            Result.Hour         := 12;
            Result.Sun_Position := Pm;

        else
            Result.Hour := Hours (Hour_Offset);
        end if;

---        Total_Seconds := Total_Seconds rem Seconds_Per_Hour;  --tjl was MOD
        Mii.Div_Rem (Total_Seconds, Seconds_Per_Hour, Junk, Total_Seconds);

        Mii.Div_Rem (Total_Seconds, Seconds_Per_Minute, Min, Sec);
        Result.Minute := Minutes (Min);
        Result.Second := Seconds (Sec);
---        Result.Minute := Minutes (Total_Seconds / Seconds_Per_Minute);
---        Result.Second := Seconds (Total_Seconds rem Seconds_Per_Minute);--tjl

        return Result;
    end Convert_Time;

    function Convert_Time (Date : Time) return Calendar.Time is
        C_Year  : Calendar.Year_Number;
        C_Month : Calendar.Month_Number;
        C_Day   : Calendar.Day_Number;

        Total_Seconds : Integer32;
    begin
        C_Year  := Calendar.Year_Number (Date.Year);
        C_Month := Calendar.Month_Number (Months'Pos (Date.Month) + 1);
        C_Day   := Calendar.Day_Number (Date.Day);

        Total_Seconds := Integer32 (Date.Second) +
                            Integer32 (Date.Minute) * Seconds_Per_Minute;

        if Date.Hour /= 12 then
            Total_Seconds := Total_Seconds +
                                Integer32 (Date.Hour) * Seconds_Per_Hour;
        end if;

        if Date.Sun_Position = Pm then
            Total_Seconds := Total_Seconds + Integer32 (Seconds_Per_Half_Day);
        end if;

        return Calendar.Time_Of (C_Year, C_Month, C_Day,
                                 Duration (Total_Seconds));
    exception
        when Calendar.Time_Error =>
            return Calendar.Clock;
    end Convert_Time;

    function Get_Time return Time is
    begin
        return Convert_Time (Calendar.Clock);
    end Get_Time;

    function Image (Month : Months; Full_Width : Boolean := True)
                   return String is
        Name : constant String := Months'Image (Month);
    begin
        if Full_Width then
            return String_Utilities.Capitalize (Name);
        else
            return Name (Name'First .. Name'First + 2);
        end if;
    end Image;

    function Time_Image (Date : Time; Time_Style : Time_Format) return String is
        Sep  : Character := ':';
        Hour : Integer   := Integer (Military_Hour
                                        (Date.Sun_Position, Date.Hour));
    begin
        case Time_Style is
            when Expanded =>
                return Image (Integer (Date.Hour), Width => 0) &
                          Sep & Image (Integer (Date.Minute)) & Sep &
                          Image (Integer (Date.Second)) & ' ' &
                          Sun_Positions'Image (Date.Sun_Position);
            when Military | Ada =>
                if Time_Style = Ada then
                    Sep := '_';
                end if;

                return Image (Hour) & Sep & Image (Integer (Date.Minute)) &
                          Sep & Image (Integer (Date.Second));
            when Short =>
                return Image (Hour) & Sep & Image (Integer (Date.Minute));
        end case;
    end Time_Image;

    function Date_Image (Date : Time; Date_Style : Date_Format) return String is
        Sep : Character := '/';

        Year  : Integer := Integer (Date.Year) mod 100;
        Month : Integer := Months'Pos (Date.Month) + 1;
    begin
        case Date_Style is
            when Expanded =>
                return Image (Date.Month) & ' ' &
                          Image (Integer (Date.Day), Width => 0) & ',' &
                          Image (Integer (Date.Year),
                                 Leading => ' ',
                                 Width   => 5);

            when Month_Day_Year =>
                return Image (Month, Leading => ' ') & Sep &
                          Image (Integer (Date.Day)) & Sep & Image (Year);

            when Day_Month_Year =>
                Sep := '-';
                return Image (Integer (Date.Day), Leading => ' ') & Sep &
                          Image (Date.Month, Full_Width => False) &
                          Sep & Image (Year);

            when Year_Month_Day | Ada =>
                if Date_Style = Ada then
                    Sep := '_';
                end if;

                return Image (Year) & Sep & Image (Month) &
                          Sep & Image (Integer (Date.Day));
        end case;
    end Date_Image;

    function Separator (Date_Style : Date_Format; Time_Style : Time_Format)
                       return String is
    begin
        if Date_Style = Ada and then Time_Style = Ada then
            return "_at_";
        elsif Date_Style = Expanded then
            return " at ";
        else
            return " ";
        end if;
    end Separator;

    function Image (Date       : Time;
                    Date_Style : Date_Format    := Expanded;
                    Time_Style : Time_Format    := Expanded;
                    Contents   : Image_Contents := Both) return String is
    begin
        case Contents is
            when Both =>
                return Date_Image (Date, Date_Style) &
                          Separator (Date_Style, Time_Style) &
                          Time_Image (Date, Time_Style);
            when Date_Only =>
                return Date_Image (Date, Date_Style);
            when Time_Only =>
                return Time_Image (Date, Time_Style);
        end case;
    end Image;

    function Time_Stamp_Image
                (Date : Time := Get_Time; Style : Time_Format := Military)
                return String is
    begin
        if Style = Short then
            return Image (Integer (Date.Minute)) & ':' &
                      Image (Integer (Date.Second));
        else
            return Time_Image (Date, Style);
        end if;
    end Time_Stamp_Image;



    function Convert (I : Interval) return Duration is
        Seconds : Duration := Duration (I.Elapsed_Milliseconds) / 1000;
    begin
        Seconds := Duration (I.Elapsed_Seconds) + Seconds;
        Seconds := Duration (Duration (I.Elapsed_Minutes) * Minute) + Seconds;
        Seconds := Duration (Duration (I.Elapsed_Hours) * Hour) + Seconds;
        Seconds := Duration (Duration (I.Elapsed_Days) * Day) + Seconds;
        return Seconds;
    end Convert;


    function Convert (D : Duration) return Interval is
        I : Interval;

        Milliseconds_Per_Second : constant := 1000;
        Milliseconds_Per_Minute : constant := 60 * Milliseconds_Per_Second;
        Milliseconds_Per_Hour   : constant := 60 * Milliseconds_Per_Minute;
        Milliseconds_Per_Day    : constant := 24 * Milliseconds_Per_Hour;

        Rest : Integer32 := Integer32 (D) * Milliseconds_Per_Second


           ;
    begin
        if D < 0.0 then
            return Null_Interval;
        end if;

        I.Elapsed_Days := Day_Count (Rest / Milliseconds_Per_Day);
        Rest := Rest - (Integer32 (I.Elapsed_Days) * Milliseconds_Per_Day);

        I.Elapsed_Hours := Military_Hours (Rest / Milliseconds_Per_Hour);
        Rest := Rest - (Integer32 (I.Elapsed_Hours) * Milliseconds_Per_Hour);

        I.Elapsed_Minutes := Minutes (Rest / Milliseconds_Per_Minute);
        Rest              := Rest - (Integer32 (I.Elapsed_Minutes) *
                                     Milliseconds_Per_Minute);

        I.Elapsed_Seconds := Seconds (Rest / Milliseconds_Per_Second);
        Rest              := Rest - (Integer32 (I.Elapsed_Seconds) *
                                     Milliseconds_Per_Second);

        I.Elapsed_Milliseconds := Milliseconds (Rest);

        return I;
    end Convert;


    package body Interval_Value is separate;
    function Value (S : String) return Interval is
    begin
        return Interval_Value.Value (S);
    end Value;


    function Time_Value (S : String) return Time is separate;

    function Value (S : String) return Time is
    begin
        return Time_Value (S);
    end Value;

    function Image (D : Duration) return String is
    begin
        return Image (Convert (D));
    end Image;


    function Image (I : Interval) return String is
    begin
        if I.Elapsed_Days > 99999 then
            return Image (Natural (I.Elapsed_Days), Width => 0) & 'D';

        elsif I.Elapsed_Days > 99 then
            return Image
                      (Natural (I.Elapsed_Days), Width => 5, Leading => ' ') &
                   '/' & Image (Natural (I.Elapsed_Hours));

        elsif I.Elapsed_Days > 0 then
            return Image (Natural (I.Elapsed_Days), Leading => ' ') &
                      '/' & Image (Natural (I.Elapsed_Hours)) &
                      ':' & Image (Natural (I.Elapsed_Minutes));

        elsif I.Elapsed_Hours > 0 then
            return Image (Natural (I.Elapsed_Hours), Leading => ' ') &
                      ':' & Image (Natural (I.Elapsed_Minutes)) &
                      ':' & Image (Natural (I.Elapsed_Seconds));

        elsif I.Elapsed_Minutes > 0 then
            return Image (Natural (I.Elapsed_Minutes), Leading => ' ') &
                      ':' & Image (Natural (I.Elapsed_Seconds)) & '.' &
                      Image (Natural (I.Elapsed_Milliseconds), Width => 3);
        else
            return Image (Natural (I.Elapsed_Seconds), Leading => ' ') & '.' &
                      Image (Natural (I.Elapsed_Milliseconds), Width => 3);

        end if;
    end Image;


    function Nil return Time is
    begin
        return Null_Time;
    end Nil;

    function Is_Nil (Date : Time) return Boolean is
    begin
        return Date = Nil;
    end Is_Nil;

    function Nil return Calendar.Time is
    begin
        return Null_Calendar_Time;
    end Nil;

    function Is_Nil (Date : Calendar.Time) return Boolean is

    begin
        return Calendar."=" (Date, Nil);
    end Is_Nil;

    function Image (D : Weekday) return String is
    begin
        case D is
            when 1 =>
                return "Monday";
            when 2 =>
                return "Tuesday";
            when 3 =>
                return "Wednesday";
            when 4 =>
                return "Thursday";
            when 5 =>
                return "Friday";
            when 6 =>
                return "Saturday";
            when 7 =>
                return "Sunday";
        end case;
    end Image;

    function Make_Weekday (D : Integer) return Weekday is
        Day : Integer := D mod 7;
    begin
        if Day = 0 then
            return 7;
        else
            return Weekday (Day);
        end if;
    end Make_Weekday;

    pragma Inline (Make_Weekday);

    function Day_Of_Week (T : Time := Get_Time) return Weekday is
        -- Uses Zeller's congruence to compute the day of week of given date.
        -- See "Problems for Computer Solutions", Gruenberger & Jaffray, Wiley,
        -- 1965, p. 255ff.
        Zyear, Zmonth, Zcentury, Zyy : Integer;
    begin
        -- Remap month# so Mar=1 & Jan, Feb=11, 12 of PRECEDING year
        if Months'Pos (T.Month) >= 3 then
            Zyear  := Integer (T.Year);  
            Zmonth := Months'Pos (T.Month) - 1;
        else  -- Jan or Feb
            Zyear  := Integer (T.Year) - 1;
            Zmonth := Months'Pos (T.Month) + 11;
        end if;  
        Zcentury := Zyear / 100;
        Zyy      := Zyear rem 100;
        return Make_Weekday (((26 * Zmonth - 2) / 10) + Integer (T.Day) +
                             Zyy + (Zyy / 4) + (Zcentury / 4) - 2 * Zcentury);
    end Day_Of_Week;

    function Day_Of_Week (T : Calendar.Time) return Weekday is
    begin
        return Day_Of_Week (Convert_Time (T));
    end Day_Of_Week;

    function "+" (D : Weekday; I : Integer) return Weekday is
    begin
        return Make_Weekday (Integer (D) + I);
    end "+";

    function "-" (D : Weekday; I : Integer) return Weekday is
    begin
        return Make_Weekday (Integer (D) - I);
    end "-";

    function Duration_Until (T : Calendar.Time) return Duration is
    begin
        return Calendar."-" (T, Calendar.Clock);
    end Duration_Until;

    function Duration_Until (T : Time) return Duration is
    begin
        return Duration_Until (Convert_Time (T));
    end Duration_Until;

    function Duration_Until_Next
                (H : Military_Hours; M : Minutes := 0; S : Seconds := 0)
                return Duration is
        T  : Time    := Get_Time;
        D  : Duration;
        Hr : Natural := Natural (H);
    begin
        T.Minute := M;
        T.Second := S;
        if Hr >= 12 then
            T.Sun_Position := Pm;
            Hr             := Hr - 12;
        else
            T.Sun_Position := Am;
        end if;
        if Hr = 0 then
            T.Hour := 12;
        else
            T.Hour := Hours (Hr);
        end if;
        D := Duration_Until (T);
        if D < 0.0 then
            D := Day + D;
        end if;
        return D;
    end Duration_Until_Next;

begin
    Null_Calendar_Time := Convert_Time (Null_Time);
end Time_Utilities;separate (Time_Utilities)
package body Interval_Value is
    function Value (S : String) return Interval is
        -- format is ddDhh:mm:ss.milli
        -- upper or lower case D is a deliminator
        -- all non-numeric non delimiters are ignored
        -- if only one : is given, it is assumed to separate hrs and seconds
        --    10:17 is 10hrs 17min, :10:17 is 0hrs 10min 17sec
        Position : Natural := S'First;
        Result   : Interval;

        type Kind_Value is (Day, Hour, Minute, Second, Millisecond, Number);
        type Item;
        type Item_Ptr   is access Item;

        type Item is
            record
                Kind  : Kind_Value;
                Value : Natural;
                Next  : Item_Ptr;
            end record;

        First_Item : Item_Ptr;
        Last_Item  : Item_Ptr;

        Dot_Observed    : Boolean := False;
        Colons_Observed : Natural := 0;


        function Is_Digit (Char : Character) return Boolean is
        begin
            case Char is
                when '0' .. '9' =>
                    return True;
                when others =>
                    return False;
            end case;
        end Is_Digit;

        function Is_Delimiter (Char : Character) return Boolean is
        begin
            case Char is
                when ':' | 'D' | 'd' | '/' | '.' =>
                    return True;
                when others =>
                    return False;
            end case;
        end Is_Delimiter;

        function Get_Number return Item_Ptr is
            Start : Natural := Position;
            Last  : Natural;

            function Pad_To_Three_Digits (S : String) return Natural is
            begin
                if S'Length = 1 then
                    return Natural'Value (S & "00");
                elsif S'Length = 2 then
                    return Natural'Value (S & '0');
                else
                    return Natural'Value (S (S'First .. S'First + 2));
                end if;
            end Pad_To_Three_Digits;

            function Get_Item (N : Natural) return Item_Ptr is
            begin
                return new Item'(Kind => Number, Value => N, Next => null);
            end Get_Item;
        begin
            while Position <= S'Last and then Is_Digit (S (Position)) loop
                Position := Position + 1;
            end loop;

            if Position <= S'Last then
                Last := Position - 1;
            else
                Last := S'Last;
            end if;

            if Dot_Observed then
                return Get_Item (Pad_To_Three_Digits (S (Start .. Last)));
            else
                return Get_Item (Natural'Value (S (Start .. Last)));
            end if;
        end Get_Number;

        function Get_Item return Item_Ptr is
            Char : Character;

            function Item_Value (Ch : Character) return Item_Ptr is
                Result : Item_Ptr := new Item;
            begin
                case Ch is

                    when 'D' | 'd' | '/' =>
                        Result.Kind := Day;

                    when ':' =>
                        Result.Kind     := Hour;
                        Colons_Observed := Colons_Observed + 1;

                        if Colons_Observed > 2 then
                            raise Constraint_Error;
                        end if;

                    when '.' =>
                        Result.Kind  := Second;
                        Dot_Observed := True;

                    when others =>
                        raise Constraint_Error;
                end case;

                return Result;
            end Item_Value;
        begin
            while Position <= S'Last loop
                Char := S (Position);

                if Is_Delimiter (Char) then
                    Position := Position + 1;
                    return Item_Value (Char);
                elsif Is_Digit (Char) then
                    return Get_Number;
                else
                    Position := Position + 1;
                end if;
            end loop;

            return null;
        end Get_Item;

        procedure Build_List (First, Last : in out Item_Ptr) is
            Next_Item : Item_Ptr;
        begin
            -- build list of items
            Next_Item := Get_Item;
            First     := Next_Item;
            Last      := First;

            loop
                Next_Item := Get_Item;
                exit when Next_Item = null;

                Last.Next := Next_Item;
                Last      := Next_Item;
            end loop;
        end Build_List;

        procedure Normalize (First, Last : in out Item_Ptr) is
            Hour_Item : Item_Ptr;
            Next_Item : Item_Ptr := First;

            procedure Add (Kind : Kind_Value) is
                New_Item : Item_Ptr := new Item'(Kind, 0, null);
            begin
                Last.Next := New_Item;
                Last      := New_Item;
            end Add;
        begin
            if Colons_Observed = 2 or else Dot_Observed then
                -- find right_most hour and make it minute
                while Next_Item /= null loop
                    if Next_Item.Kind = Hour then
                        Hour_Item := Next_Item;
                    end if;

                    Next_Item := Next_Item.Next;
                end loop;

                if Hour_Item /= null then
                    Hour_Item.Kind := Minute;
                end if;
            end if;

            if Last.Kind = Number then
                if Dot_Observed then
                    Add (Millisecond);
                else
                    case Colons_Observed is
                        when 2 =>
                            Add (Second);
                        when 1 =>
                            Add (Minute);
                        when 0 =>
                            Add (Hour);
                        when others =>
                            raise Constraint_Error;
                    end case;
                end if;
            end if;
        end Normalize;

        function Build_Value (First, Last : Item_Ptr) return Interval is
            Number_Kind : constant Kind_Value := Number;

            Result    : Interval := Null_Interval;
            Next_Item : Item_Ptr := First;
            Number    : Natural  := 0;

            procedure Get_Number (Ptr   : in out Item_Ptr;
                                  Value : in out Natural) is
            begin
                if Ptr.Kind = Number_Kind then
                    Value := Ptr.Value;
                    Ptr   := Ptr.Next;
                else
                    Value := 0;
                end if;
            end Get_Number;

            procedure Set_Field (Kind   :        Kind_Value;
                                 Number :        Natural;
                                 Result : in out Interval) is
                Value : Natural := Number;
            begin
                if Value = 0 then
                    return;
                end if;

                case Next_Item.Kind is

                    when Day =>
                        Result.Elapsed_Days :=
                           Result.Elapsed_Days + Day_Count (Value);

                    when Hour =>
                        Value := Value + Natural (Result.Elapsed_Hours);
                        Set_Field (Day, Value / 24, Result);
                        Result.Elapsed_Hours := Military_Hours (Value mod 24);

                    when Minute =>
                        Value := Value + Natural (Result.Elapsed_Minutes);
                        Set_Field (Hour, Value / 60, Result);
                        Result.Elapsed_Minutes := Minutes (Value mod 60);

                    when Second =>
                        Value := Value + Natural (Result.Elapsed_Seconds);
                        Set_Field (Minute, Value / 60, Result);
                        Result.Elapsed_Seconds := Seconds (Value mod 60);

                    when Millisecond =>
                        Value := Value + Natural (Result.Elapsed_Milliseconds);
                        Set_Field (Second, Value / 1000, Result);
                        Result.Elapsed_Milliseconds :=
                           Milliseconds (Value mod 1000);

                    when others =>
                        raise Constraint_Error;
                end case;
            end Set_Field;

        begin
            while Next_Item /= null loop
                Get_Number (Next_Item, Number);
                -- increments next_item (if appropriate)

                Set_Field (Next_Item.Kind, Number, Result);
                Next_Item := Next_Item.Next;
            end loop;

            return Result;
        end Build_Value;
    begin
        Build_List (First_Item, Last_Item);
        Normalize (First_Item, Last_Item);
        return Build_Value (First_Item, Last_Item);
    end Value;
end Interval_Value;separate (Time_Utilities)
function Time_Value (S : String) return Time is
    -- accepts all of the formats output by value
    -- algorithm consists of parsing for a series of numbers
    -- and assigning them to positions in the date according
    -- to heuristics about size and position.
    -- recognizes unique prefixes of month names


    Pm_Detected    : Boolean := False;
    Month_Position : Integer := 0;

    function Value (Month  : Positive;
                    Day    : Natural;
                    Year   : Natural;
                    Hour   : Natural;
                    Minute : Natural;
                    Second : Natural) return Time is
        Result : Time;
    begin
        if Year < 100 then
            Result.Year := Years (Integer'(1900 + Year));
        else
            Result.Year := Years (Year);
        end if;

        Result.Month := Months'Val (Month - 1);
        Result.Day   := Days (Day);

        Result.Minute := Minutes (Minute);
        Result.Second := Seconds (Second);

        case Hour is
            when 0 =>
                Result.Sun_Position := Am;
                Result.Hour         := 12;
            when 12 =>
                Result.Sun_Position := Pm;
                Result.Hour         := 12;
            when others =>
                if Hour > 12 then
                    Result.Sun_Position := Pm;
                    Result.Hour         := Hours (Hour - 12);
                else
                    if Pm_Detected then
                        Result.Sun_Position := Pm;
                    else
                        Result.Sun_Position := Am;
                    end if;

                    Result.Hour := Hours (Hour);
                end if;
        end case;

        return Result;
    end Value;

    function This_Year return Natural is
    begin
        return Natural (Get_Time.Year);
    end This_Year;

    function Value (Number : Number_Array) return Time is
        Now : Time;
    begin
        case Number'Length is
            when 6 =>
                case Month_Position is
                    when 1 =>
                        -- May 1, 1985 at 00:00:00
                        return Value (Number (1), Number (2), Number (3),
                                      Number (4), Number (5), Number (6));
                    when 2 =>
                        -- 1-May-85 at 00:00:00
                        return Value (Number (2), Number (1), Number (3),
                                      Number (4), Number (5), Number (6));
                    when 4 =>
                        -- 00:00:00 May 1, 1985
                        return Value (Number (4), Number (5), Number (6),
                                      Number (1), Number (2), Number (3));
                    when 5 =>
                        -- 00:00:00 1-May-85
                        return Value (Number (5), Number (4), Number (6),
                                      Number (1), Number (2), Number (3));
                    when 0 =>
                        -- no alphabetic year given
                        if Number (1) > 23 then
                            -- 85/5/1 00:00:00
                            return Value (Number (2), Number (3), Number (1),
                                          Number (4), Number (5), Number (6));
                        else
                            -- 5/1/85 00:00:00
                            return Value (Number (1), Number (2), Number (3),
                                          Number (4), Number (5), Number (6));
                        end if;
                    when others =>
                        raise Constraint_Error;
                end case;
            when 5 =>
                case Month_Position is
                    when 1 =>
                        -- May 1, 1985 at 00:00
                        return Value (Number (1), Number (2), Number (3),
                                      Number (4), Number (5), 0);
                    when 2 =>
                        -- 1-May-85 at 00:00
                        return Value (Number (2), Number (1), Number (3),
                                      Number (4), Number (5), 0);
                    when 3 =>
                        -- 00:00 May 1, 1985
                        return Value (Number (3), Number (4), Number (5),
                                      Number (1), Number (2), 0);
                    when 5 =>
                        -- 00:00:00 1-May
                        return Value (Number (5), Number (4),
                                      Natural (Get_Time.Year), Number (1),
                                      Number (2), Number (3));
                    when 0 =>
                        -- no alphabetic year given
                        if Number (1) > 23 then
                            -- 85/5/1 00:00
                            return Value (Number (2), Number (3), Number (1),
                                          Number (4), Number (5), 0);
                        elsif Number (3) > 23 then
                            -- 5/1/85 00:00
                            return Value (Number (1), Number (2), Number (3),
                                          Number (4), Number (5), 0);
                        else
                            -- 5/1 00:00:00
                            return Value (Number (1), Number (2),
                                          Natural (Get_Time.Year), Number (3),
                                          Number (4), Number (5));
                        end if;
                    when others =>
                        raise Constraint_Error;
                end case;
            when 4 =>
                case Month_Position is
                    when 0 | 1 =>
                        -- 5/1 00:00
                        -- May 1 00:00
                        return Value (Number (1), Number (2),
                                      Natural (Get_Time.Year),
                                      Number (3), Number (4), 0);
                    when 2 =>
                        -- 1-May 00:00
                        return Value (Number (2), Number (1),
                                      Natural (Get_Time.Year),
                                      Number (3), Number (4), 0);
                    when others =>
                        raise Constraint_Error;
                end case;
            when 3 =>
                Now := Get_Time;

                case Month_Position is
                    when 0 =>
                        if Number (1) > 23 then
                            -- 85/5/1
                            Pm_Detected := Now.Sun_Position = Pm;
                            return Value (Number (2), Number (3),
                                          Number (1), Natural (Now.Hour),
                                          Natural (Now.Minute),
                                          Natural (Now.Second));
                        elsif Number (3) > 59 then
                            -- 5/1/85
                            Pm_Detected := Now.Sun_Position = Pm;
                            return Value (Number (1), Number (2),
                                          Number (3), Natural (Now.Hour),
                                          Natural (Now.Minute),
                                          Natural (Now.Second));
                        else
                            -- 00:00:00
                            return Value (Natural (Months'Pos (Now.Month) + 1),
                                          Natural (Now.Day), Natural (Now.Year),
                                          Number (1), Number (2), Number (3));
                        end if;
                    when 1 =>
                        -- May 1, 1985
                        Pm_Detected := Now.Sun_Position = Pm;
                        return Value (Number (1), Number (2), Number (3),
                                      Natural (Now.Hour), Natural (Now.Minute),
                                      Natural (Now.Second));

                    when 2 =>
                        -- 1-May-85
                        Pm_Detected := Now.Sun_Position = Pm;
                        return Value (Number (2), Number (1), Number (3),
                                      Natural (Now.Hour), Natural (Now.Minute),
                                      Natural (Now.Second));

                    when others =>
                        raise Constraint_Error;
                end case;
            when 2 =>
                Now := Get_Time;

                case Month_Position is
                    when 0 =>
                        -- 00:00
                        return Value (Natural (Months'Pos (Now.Month) + 1),
                                      Natural (Now.Day), Natural (Now.Year),
                                      Number (1), Number (2), 0);
                    when 1 =>
                        -- May 1
                        Pm_Detected := Now.Sun_Position = Pm;
                        return Value (Number (1), Number (2),
                                      Natural (Now.Year), Natural (Now.Hour),
                                      Natural (Now.Minute),
                                      Natural (Now.Second));

                    when 2 =>
                        -- 1-May
                        Pm_Detected := Now.Sun_Position = Pm;
                        return Value (Number (2), Number (1),
                                      Natural (Now.Year), Natural (Now.Hour),
                                      Natural (Now.Minute),
                                      Natural (Now.Second));

                    when others =>
                        raise Constraint_Error;
                end case;
            when others =>
                raise Constraint_Error;
        end case;
    end Value;

    procedure Find_Number (S        :     String;
                           First    :     Positive;
                           Position : out Positive;
                           Success  : out Boolean) is
    begin
        for I in First .. S'Last loop
            if Is_Numeric (S (I)) then
                Success  := True;
                Position := I;
                return;
            end if;
        end loop;

        Position := First;
        Success  := False;
    end Find_Number;

    procedure Find_Non_Number
                 (S : String; First : Positive; Position : out Positive) is
    begin
        for I in First .. S'Last loop
            if not Is_Numeric (S (I)) then
                Position := I;
                return;
            end if;
        end loop;

        Position := S'Last + 1;
    end Find_Non_Number;

    procedure Find_Alphabetic (S        :     String;
                               First    :     Positive;
                               Position : out Positive;
                               Success  : out Boolean) is
    begin
        for I in First .. S'Last loop
            exit when Is_Numeric (S (I));

            if Is_Alphabetic (S (I)) then
                Success  := True;
                Position := I;
                return;
            end if;
        end loop;

        Position := First;
        Success  := False;
    end Find_Alphabetic;

    procedure Find_Non_Alphabetic
                 (S : String; First : Positive; Position : out Positive) is
    begin
        for I in First .. S'Last loop
            if not Is_Alphabetic (S (I)) then
                Position := I;
                return;
            end if;
        end loop;

        Position := S'Last + 1;
    end Find_Non_Alphabetic;

    procedure Get_Number (S       :        String;
                          First   : in out Positive;
                          Result  : out    Natural;
                          Success : out    Boolean) is
        Found : Boolean;
        Start : Positive;
    begin
        Find_Number (S, First, Start, Found);

        if not Found then
            Success := False;
            Result  := 0;
            return;
        end if;

        Find_Non_Number (S, Start, First);
        Success := True;
        Result  := Natural'Value (S (Start .. First - 1));
    end Get_Number;


    procedure Get_Month (S       :        String;
                         First   : in out Positive;
                         Result  : out    Natural;
                         Success : out    Boolean) is
        Found  : Boolean;
        Start  : Natural;
        Stop   : Natural;
        Prefix : Boolean;
        M      : Months;
    begin
        Find_Alphabetic (S, First, Start, Found);

        if Found then
            Find_Non_Alphabetic (S, Start, Stop);
            Unique_Prefix (S (Start .. Stop - 1), M, Prefix, Found);

            if Found then
                Result  := Months'Pos (M) + 1;
                First   := Stop;
                Success := True;
                return;
            end if;
        end if;

        Success := False;
        Result  := 0;
    exception
        when others =>
            Result  := 0;
            Success := False;
    end Get_Month;

    function Get_Number_Array (S : String) return Number_Array is
        Result  : Number_Array (1 .. 6);
        First   : Positive := S'First;
        Success : Boolean;
        I       : Integer  := Result'First;
    begin
        Pm_Detected :=
           String_Utilities.Locate ("PM", S, Ignore_Case => True) /= 0;

        while I <= Result'Last loop
            if Month_Position = 0 and then First <= S'Last and then
               not Is_Numeric (S (First)) then
                Get_Month (S, First, Result (I), Success);

                if Success then
                    Month_Position := I;
                    I              := I + 1;
                    exit when I > Result'Last;
                end if;
            end if;

            Get_Number (S, First, Result (I), Success);

            if not Success then
                return Result (1 .. I - 1);
            end if;

            I := I + 1;
        end loop;

        return Result;
    end Get_Number_Array;
begin
    return Value (Get_Number_Array (String_Utilities.Strip (S)));
end Time_Value;package Trig_Lib is

    function Sin (X : Float) return Float;

    function Cos (X : Float) return Float;

    function Tan (X : Float) return Float;

    function Cot (X : Float) return Float;

    function Asin (X : Float) return Float;

    function Acos (X : Float) return Float;

    function Atan (X : Float) return Float;

    function Atan2 (V, U : Float) return Float;

    function Sinh (X : Float) return Float;

    function Cosh (X : Float) return Float;

    function Tanh (X : Float) return Float;
end Trig_Lib;with Text_Io;
use Text_Io;
with Floating_Characteristics;
use Floating_Characteristics;
with Numeric_Io;
use Numeric_Io;
with Numeric_Primitives;
use Numeric_Primitives;
with Core_Functions;
use Core_Functions;

package body Trig_Lib is

    --  PRELIMINARY VERSION *********************************

    --  The following routines are coded directly from the algorithms and
    --  coeficients given in "Software Manual for the Elementry Functions"
    --  by William J. Cody, Jr. and William Waite, Prentice_Hall, 1980
    --  This particular version is stripped to work with FLOAT and INTEGER
    --  and uses a mantissa represented as a FLOAT
    --  A more general formulation uses MANTISSA_TYPE, etc.
    --  The coeficients are appropriate for 25 to 32 bits floating significance
    --  They will work for less but slightly shorter versions are possible
    --  The routines are coded to stand alone so they need not be compiled together

    --      16 JULY 1982       W A WHITAKER  AFATL EGLIN AFB FL 32542
    --                         T C EICHOLTZ  USAFA

    function Sin (X : Float) return Float is
        Sgn, Y : Float;
        N : Integer;
        Xn : Float;
        F, G, X1, X2 : Float;
        Result : Float;
        Ymax : Float := Float (Integer (Pi * Two ** (It / 2)));
        Beta : Float := Convert_To_Float (Ibeta);
        Epsilon : Float := Beta ** (-It / 2);
        C1 : constant Float := 3.140625;
        C2 : constant Float := 9.6765_35897_93E-4;

        function R (G : Float) return Float is
            R1 : constant Float := -0.16666_66660_883;
            R2 : constant Float := 0.83333_30720_556E-2;
            R3 : constant Float := -0.19840_83282_313E-3;
            R4 : constant Float := 0.27523_97106_775E-5;
            R5 : constant Float := -0.23868_34640_601E-7;
        begin
            return ((((R5 * G + R4) * G + R3) * G + R2) * G + R1) * G;
        end R;
    begin
        if X < Zero then
            Sgn := -One;
            Y := -X;
        else
            Sgn := One;
            Y := X;
        end if;

        if Y > Ymax then
            New_Line;
            Put (" SIN CALLED WITH ARGUMENT TOO LARGE FOR ACCURACY ");
            New_Line;
        end if;

        N := Integer (Y * One_Over_Pi);
        Xn := Convert_To_Float (N);

        if N mod 2 /= 0 then
            Sgn := -Sgn;
        end if;

        X1 := Truncate (abs (X));
        X2 := abs (X) - X1;
        F := ((X1 - Xn * C1) + X2) - Xn * C2;

        if abs (F) < Epsilon then
            Result := F;
        else
            G := F * F;
            Result := F + F * R (G);
        end if;

        return (Sgn * Result);
    end Sin;

    function Cos (X : Float) return Float is
        Sgn, Y : Float;
        N : Integer;
        Xn : Float;
        F, G, X1, X2 : Float;
        Result : Float;
        Ymax : Float := Float (Integer (Pi * Two ** (It / 2)));
        Beta : Float := Convert_To_Float (Ibeta);
        Epsilon : Float := Beta ** (-It / 2);
        C1 : constant Float := 3.140625;
        C2 : constant Float := 9.6765_35897_93E-4;

        function R (G : Float) return Float is
            R1 : constant Float := -0.16666_66660_883;
            R2 : constant Float := 0.83333_30720_556E-2;
            R3 : constant Float := -0.19840_83282_313E-3;
            R4 : constant Float := 0.27523_97106_775E-5;
            R5 : constant Float := -0.23868_34640_601E-7;
        begin
            return ((((R5 * G + R4) * G + R3) * G + R2) * G + R1) * G;
        end R;
    begin
        Sgn := 1.0;
        Y := abs (X) + Pi_Over_Two;

        if Y > Ymax then
            New_Line;
            Put (" COS CALLED WITH ARGUMENT TOO LARGE FOR ACCURACY ");
            New_Line;
        end if;

        N := Integer (Y * One_Over_Pi);
        Xn := Convert_To_Float (N);

        if N mod 2 /= 0 then
            Sgn := -Sgn;
        end if;

        Xn := Xn - 0.5;          -- TO FORM COS INSTEAD OF SIN
        X1 := Truncate (abs (X));
        X2 := abs (X) - X1;
        F := ((X1 - Xn * C1) + X2) - Xn * C2;

        if abs (F) < Epsilon then
            Result := F;
        else
            G := F * F;
            Result := F + F * R (G);
        end if;

        return (Sgn * Result);
    end Cos;

    function Tan (X : Float) return Float is
        Sgn, Y : Float;
        N : Integer;
        Xn : Float;
        F, G, X1, X2 : Float;
        Result : Float;
        Ymax : Float := Float (Integer (Pi * Two ** (It / 2))) / 2.0;
        Beta : Float := Convert_To_Float (Ibeta);
        Epsilon : Float := Beta ** (-It / 2);
        C1 : constant Float := 8#1.444#;
        C2 : constant Float := 4.8382_67948_97E-4;

        function R (G : Float) return Float is
            P0 : constant Float := 1.0;
            P1 : constant Float := -0.11136_14403_566;
            P2 : constant Float := 0.10751_54738_488E-2;
            Q0 : constant Float := 1.0;
            Q1 : constant Float := -0.44469_47720_281;
            Q2 : constant Float := 0.15973_39213_300E-1;
        begin
            return ((P2 * G + P1) * G * F + F) /
                      (((Q2 * G + Q1) * G + 0.5) + 0.5);
        end R;
    begin
        Y := abs (X);

        if Y > Ymax then
            New_Line;
            Put (" TAN CALLED WITH ARGUMENT TOO LARGE FOR ACCURACY ");
            New_Line;
        end if;

        N := Integer (X * Two_Over_Pi);
        Xn := Convert_To_Float (N);
        X1 := Truncate (X);
        X2 := X - X1;
        F := ((X1 - Xn * C1) + X2) - Xn * C2;

        if abs (F) < Epsilon then
            Result := F;
        else
            G := F * F;
            Result := R (G);
        end if;

        if N mod 2 = 0 then
            return Result;
        else
            return -1.0 / Result;
        end if;
    end Tan;

    function Cot (X : Float) return Float is
        Sgn, Y : Float;
        N : Integer;
        Xn : Float;
        F, G, X1, X2 : Float;
        Result : Float;
        Ymax : Float := Float (Integer (Pi * Two ** (It / 2))) / 2.0;
        Beta : Float := Convert_To_Float (Ibeta);
        Epsilon : Float := Beta ** (-It / 2);
        Epsilon1 : Float := 1.0 / Xmax;
        C1 : constant Float := 8#1.444#;
        C2 : constant Float := 4.8382_67948_97E-4;

        function R (G : Float) return Float is
            P0 : constant Float := 1.0;
            P1 : constant Float := -0.11136_14403_566;
            P2 : constant Float := 0.10751_54738_488E-2;
            Q0 : constant Float := 1.0;
            Q1 : constant Float := -0.44469_47720_281;
            Q2 : constant Float := 0.15973_39213_300E-1;
        begin
            return ((P2 * G + P1) * G * F + F) /
                      (((Q2 * G + Q1) * G + 0.5) + 0.5);
        end R;
    begin
        Y := abs (X);

        if Y < Epsilon1 then
            New_Line;
            Put (" COT CALLED WITH ARGUMENT TOO NEAR ZERO ");
            New_Line;

            if X < 0.0 then
                return -Xmax;
            else
                return Xmax;
            end if;
        end if;

        if Y > Ymax then
            New_Line;
            Put (" COT CALLED WITH ARGUMENT TOO LARGE FOR ACCURACY ");
            New_Line;
        end if;

        N := Integer (X * Two_Over_Pi);
        Xn := Convert_To_Float (N);
        X1 := Truncate (X);
        X2 := X - X1;
        F := ((X1 - Xn * C1) + X2) - Xn * C2;

        if abs (F) < Epsilon then
            Result := F;
        else
            G := F * F;
            Result := R (G);
        end if;

        if N mod 2 /= 0 then
            return -Result;
        else
            return 1.0 / Result;
        end if;
    end Cot;

    function Asin (X : Float) return Float is
        G, Y : Float;
        Result : Float;
        Beta : Float := Convert_To_Float (Ibeta);
        Epsilon : Float := Beta ** (-It / 2);

        function R (G : Float) return Float is
            P1 : constant Float := -0.27516_55529_0596E1;
            P2 : constant Float := 0.29058_76237_4859E1;
            P3 : constant Float := -0.59450_14419_3246;
            Q0 : constant Float := -0.16509_93320_2424E2;
            Q1 : constant Float := 0.24864_72896_9164E2;
            Q2 : constant Float := -0.10333_86707_2113E2;
            Q3 : constant Float := 1.0;
        begin
            return (((P3 * G + P2) * G + P1) * G) /
                      (((G + Q2) * G + Q1) * G + Q0);
        end R;
    begin
        return X;
    end Asin;

    function Acos (X : Float) return Float is
        G, Y : Float;
        Result : Float;
        Beta : Float := Convert_To_Float (Ibeta);
        Epsilon : Float := Beta ** (-It / 2);

        function R (G : Float) return Float is
            P1 : constant Float := -0.27516_55529_0596E1;
            P2 : constant Float := 0.29058_76237_4859E1;
            P3 : constant Float := -0.59450_14419_3246;
            Q0 : constant Float := -0.16509_93320_2424E2;
            Q1 : constant Float := 0.24864_72896_9164E2;
            Q2 : constant Float := -0.10333_86707_2113E2;
            Q3 : constant Float := 1.0;
        begin
            return (((P3 * G + P2) * G + P1) * G) /
                      (((G + Q2) * G + Q1) * G + Q0);
        end R;
    begin
        return X;
    end Acos;

    function Atan (X : Float) return Float is
        F, G : Float;
        subtype Region is Integer range 0 .. 3;    --  ##########
        N : Region;
        Result : Float;
        Beta : Float := Convert_To_Float (Ibeta);
        Epsilon : Float := Beta ** (-It / 2);
        Sqrt_3 : constant Float := 1.73205_08075_68877_29353;
        Sqrt_3_Minus_1 : constant Float := 0.73205_08075_68877_29353;
        Two_Minus_Sqrt_3 : constant Float := 0.26794_91924_31122_70647;

        function R (G : Float) return Float is
            P0 : constant Float := -0.14400_83448_74E1;
            P1 : constant Float := -0.72002_68488_98;
            Q0 : constant Float := 0.43202_50389_19E1;
            Q1 : constant Float := 0.47522_25845_99E1;
            Q2 : constant Float := 1.0;
        begin
            return ((P1 * G + P0) * G) / ((G + Q1) * G + Q0);
        end R;
    begin
        F := abs (X);

        if F > 1.0 then
            F := 1.0 / F;
            N := 2;
        else
            N := 0;
        end if;

        if F > Two_Minus_Sqrt_3 then
            F := (((Sqrt_3_Minus_1 * F - 0.5) - 0.5) + F) / (Sqrt_3 + F);
            N := N + 1;
        end if;

        if abs (F) < Epsilon then
            Result := F;
        else
            G := F * F;
            Result := F + F * R (G);
        end if;

        if N > 1 then
            Result := -Result;
        end if;

        case N is
            when 0 =>
                Result := Result;
            when 1 =>
                Result := Pi_Over_Six + Result;
            when 2 =>
                Result := Pi_Over_Two + Result;
            when 3 =>
                Result := Pi_Over_Three + Result;
        end case;

        if X < 0.0 then
            Result := -Result;
        end if;

        return Result;
    end Atan;

    function Atan2 (V, U : Float) return Float is
        X, Result : Float;
    begin
        if U = 0.0 then
            if V = 0.0 then
                Result := 0.0;
                New_Line;
                Put (" ATAN2 CALLED WITH 0/0   RETURNED ");
                New_Line;
            elsif V > 0.0 then
                Result := Pi_Over_Two;
            else
                Result := -Pi_Over_Two;
            end if;
        else
            X := abs (V / U);
            --  If underflow or overflow is detected, go to the exception
            Result := Atan (X);

            if U < 0.0 then
                Result := Pi - Result;
            end if;

            if V < 0.0 then
                Result := -Result;
            end if;
        end if;

        return Result;

    exception
        when Numeric_Error =>
            if abs (V) > abs (U) then
                Result := Pi_Over_Two;

                if V < 0.0 then
                    Result := -Result;
                end if;
            else
                Result := 0.0;

                if U < 0.0 then
                    Result := Pi - Result;
                end if;
            end if;

            return Result;
    end Atan2;

    function Sinh (X : Float) return Float is
    begin
        return X;
    end Sinh;

    function Cosh (X : Float) return Float is
    begin
        return X;
    end Cosh;

    function Tanh (X : Float) return Float is
    begin
        return X;
    end Tanh;
begin
    null;
end Trig_Lib;generic
    Default_Maximum_Length : Natural := 20;
package Unbounded_String is

    -------------------------------------------------------------------------------
    --  Managed Pointer Sequential Unbounded Strings:
    --  Restrictions and assumptions
    -- Storage management performed
    -- All new allocations for extensions are twice requirements
    -- CANNOT be used by multiple tasks unless user guarantees sequential use
    -- := is reference copy, use copy to assign contents
    --    uninitialized or Free'd objects are true null's and changes to one
    --    of the referents will not be reflected in the other;
    --    use Free prior to assignment to prevent garbage
    -- = is object identity, use string_utilities for comparison
    --
    -------------------------------------------------------------------------------


    subtype String_Length   is Natural;
    type    Variable_String is private;

    -- release storage associated with a string
    procedure Free (V : in out Variable_String);

    -- Get information about current length or contents of a string
    function Length  (Source : Variable_String) return String_Length;
    function Char_At (Source : Variable_String; At_Pos : Positive)
                     return Character;

    function Extract (Source    : Variable_String;
                      Start_Pos : Positive;
                      End_Pos   : Natural) return String;

    function Image (V : Variable_String) return String;
    function Value (S : String)          return Variable_String;

    -- Image (Target) := Image (Source);
    procedure Copy (Target : in out Variable_String; Source : Variable_String);
    procedure Copy (Target : in out Variable_String; Source : String);
    procedure Copy (Target : in out Variable_String; Source : Character);

    -- Target := Source; Source := ""; with appropriate storage management
    procedure Move (Target : in out Variable_String;
                    Source : in out Variable_String);

    -- Target := Target & Source;
    procedure Append (Target : in out Variable_String;
                      Source :        Variable_String);

    procedure Append (Target : in out Variable_String; Source : String);

    procedure Append (Target : in out Variable_String; Source : Character);

    procedure Append (Target : in out Variable_String;
                      Source :        Character;
                      Count  :        String_Length);

    -- Target := Target (1..At_Pos-1) & Source & Target (At_Pos..Target'Length)
    procedure Insert (Target : in out Variable_String;
                      At_Pos :        Positive;
                      Source :        Variable_String);

    procedure Insert (Target : in out Variable_String;
                      At_Pos :        Positive;
                      Source :        String);

    procedure Insert (Target : in out Variable_String;
                      At_Pos :        Positive;
                      Source :        Character);

    procedure Insert (Target : in out Variable_String;
                      At_Pos :        Positive;
                      Source :        Character;
                      Count  :        String_Length);

    -- Target (At_Pos .. At_Pos + Count -1) := "";
    procedure Delete (Target : in out Variable_String;
                      At_Pos :        Positive;
                      Count  :        String_Length := 1);

    -- Target (At_Pos .. At_Pos + Source'Length - 1) := Source;
    procedure Replace (Target : in out Variable_String;
                       At_Pos :        Positive;
                       Source :        Character);

    procedure Replace (Target : in out Variable_String;
                       At_Pos :        Positive;
                       Source :        Character;
                       Count  :        String_Length);

    procedure Replace (Target : in out Variable_String;
                       At_Pos :        Positive;
                       Source :        String);

    procedure Replace (Target : in out Variable_String;
                       At_Pos :        Positive;
                       Source :        Variable_String);

    -- Target'Length := New_Length;
    -- Target (Target'Length .. New_Length) := Fill_With;
    procedure Set_Length (Target     : in out Variable_String;
                          New_Length :        String_Length;
                          Fill_With  :        Character := ' ');

private
    type Pointer is access String;

    type    Real_String;
    type    Variable_String is access Real_String;
    subtype String_Bound    is Integer range -1 .. Integer'Last;

    type Real_String is
        record
            Length    : String_Bound;
            Contents  : Pointer;
            Next_Free : Variable_String;
        end record;

    Null_String : Pointer := new String (1 .. 0);

    Free_List_Item : constant String_Bound := -1;

    Free_List : Real_String :=
       Real_String'(Free_List_Item, Null_String,
                    new Real_String'(Free_List_Item, Null_String, null));
end Unbounded_String;package body Unbounded_String is

    function Max (X : Integer; Y : Integer) return Integer is
    begin
        if X > Y then
            return X;
        else
            return Y;
        end if;
    end Max;
    pragma Inline (Max);

    procedure Free (V : in out Variable_String) is
    begin
        if V /= null then
            if V.Length /= Free_List_Item then
                V.Next_Free         := Free_List.Next_Free;
                V.Length            := Free_List_Item;
                Free_List.Next_Free := V;
            end if;
            V := null;
        end if;
    end Free;


    function Length (Source : Variable_String) return String_Length is
    begin
        if Source /= null then
            return Source.Length;
        else
            return 0;
        end if;
    exception
        when others =>
            return 0;
    end Length;

    function Allocated_Length (Source : Variable_String) return String_Length is
    begin
        if Source /= null and then Source.Length /= Free_List_Item then
            return Source.Contents'Length;
        else
            return 0;
        end if;
    end Allocated_Length;

    procedure Real_Allocate (Target          : in out Variable_String;
                             Length          :        String_Length;
                             Room_For_Growth :        Boolean := True) is

        function Allocation (Length : String_Length) return String_Length is
        begin
            if Room_For_Growth then
                return Max (2 * Length, Default_Maximum_Length);
            else
                return Max (Length, Default_Maximum_Length);
            end if;
        end Allocation;

        procedure Find (Free : in out Real_String;
                        This : in out Variable_String) is
        begin
            This := Free.Next_Free;
            if This /= null then
                if This.Contents'Length > Length then
                    Free.Next_Free := This.Next_Free;
                    This.Next_Free := null;
                else
                    Find (This.all, This);
                end if;
            end if;
        end Find;

    begin
        Find (Free_List, Target);
        if Target = null then
            Target := new Real_String'
                             (Length => Length,
                              Contents => new String (1 .. Allocation (Length)),
                              Next_Free => null);
        else
            Target.Length    := Length;
            Target.Next_Free := null;
        end if;
    end Real_Allocate;

    procedure Move (Target : in out Variable_String;
                    Source : in out Variable_String) is
    begin
        Free (Target);
        Target := Source;
        Source := null;
    end Move;

    procedure Allocate (Target            : in out Variable_String;
                        Length            :        String_Length;
                        Preserve_Contents :        Boolean := True) is
        Max_Length : String_Length := Allocated_Length (Target);
    begin
        -- check for alias of freed string and remove pointer to free list
        if Max_Length = 0 then
            Real_Allocate (Target, Length, Room_For_Growth => False);
        elsif Max_Length >= Length then
            Target.Length := Length;
        else
            declare
                Temp : Variable_String;
            begin
                Real_Allocate (Temp, Length, Preserve_Contents);
                if Preserve_Contents then
                    Temp.Contents (1 .. Target.Length) :=
                       Target.Contents (1 .. Target.Length);
                end if;
                Move (Target, Temp);
            end;
        end if;
    end Allocate;

    function Value (S : String) return Variable_String is
        Result : Variable_String;
    begin
        Real_Allocate (Result, S'Length, Room_For_Growth => False);
        Copy (Result, S);
        return Result;
    end Value;

    procedure Copy (Target : in out Variable_String;
                    Source :        Variable_String) is
    begin
        Copy (Target, Image (Source));
    end Copy;

    procedure Copy (Target : in out Variable_String; Source : String) is
    begin
        Allocate (Target, Source'Length, Preserve_Contents => False);
        declare
            T : Real_String renames Target.all;
        begin
            T.Contents (1 .. Source'Length) := Source;
            T.Length                        := Source'Length;
        end;
    end Copy;

    procedure Copy (Target : in out Variable_String; Source : Character) is
    begin
        Allocate (Target, 1, Preserve_Contents => False);
        Target.Contents (1) := Source;
    end Copy;


    function Image (V : Variable_String) return String is
    begin
        return V.all.Contents (1 .. V.all.Length);
    exception
        when others =>
            return String'(1 .. 0 => ' ');
    end Image;


    procedure Append (Target : in out Variable_String; Source : String) is
        Len : String_Length := Length (Target);
    begin
        Allocate (Target, Len + Source'Length, Preserve_Contents => True);
        declare
            T : Real_String renames Target.all;
        begin
            T.Contents (Len + 1 .. T.Length) := Source;
        end;
    end Append;


    procedure Append (Target : in out Variable_String;
                      Source :        Variable_String) is
    begin
        Append (Target, Image (Source));
    end Append;


    procedure Append (Target : in out Variable_String; Source : Character) is
        Len : String_Length := Length (Target) + 1;
    begin
        Allocate (Target, Len, Preserve_Contents => True);
        Target.Contents (Len) := Source;
    end Append;


    procedure Append (Target : in out Variable_String;
                      Source :        Character;
                      Count  :        String_Length) is
        Value_String : String (1 .. Count) := String'(1 .. Count => Source);
    begin
        Append (Target, Value_String);
    end Append;


    procedure Insert (Target : in out Variable_String;
                      At_Pos :        Positive;
                      Source :        String) is
        Len : String_Length := Length (Target);
    begin
        if At_Pos = Len + 1 then
            Append (Target, Source);
        elsif At_Pos <= Len then
            Allocate (Target, Len + Source'Length);
            declare
                T : Real_String renames Target.all;
            begin
                T.Contents (At_Pos .. T.Length) :=
                   Source & T.Contents (At_Pos .. Len);
            end;
        else
            raise Constraint_Error;
        end if;
    end Insert;


    procedure Insert (Target : in out Variable_String;
                      At_Pos :        Positive;
                      Source :        Variable_String) is
    begin
        Insert (Target, At_Pos, Image (Source));
    end Insert;


    procedure Insert (Target : in out Variable_String;
                      At_Pos :        Positive;
                      Source :        Character) is
        Len : String_Length := Length (Target) + 1;
    begin
        if At_Pos = Len then
            Append (Target, Source);
        elsif At_Pos > Len then
            raise Constraint_Error;
        else
            Allocate (Target, Len, Preserve_Contents => True);
            declare
                T : Real_String renames Target.all;
            begin
                T.Contents (At_Pos + 1 .. Len) :=
                   T.Contents (At_Pos .. Len - 1);
                T.Contents (At_Pos)            := Source;
            end;
        end if;
    end Insert;


    procedure Insert (Target : in out Variable_String;
                      At_Pos :        Positive;
                      Source :        Character;
                      Count  :        String_Length) is
        Value_String : String (1 .. Count) := String'(1 .. Count => Source);
    begin
        Insert (Target, At_Pos, Value_String);
    end Insert;


    procedure Delete (Target : in out Variable_String;
                      At_Pos :        Positive;
                      Count  :        String_Length := 1) is
        T   : Real_String renames Target.all;
        Len : String_Length := T.Length - Count;
    begin
        if At_Pos - 1 > Len then
            raise Constraint_Error;
        end if;
        if At_Pos <= Len then
            T.Contents (At_Pos .. Len) :=
               T.Contents (At_Pos + Count .. T.Length);
        end if;
        T.Length := Len;
    end Delete;


    procedure Replace (Target : in out Variable_String;
                       At_Pos :        Positive;
                       Source :        Character) is
        T : Real_String renames Target.all;
    begin
        if At_Pos > T.Length then
            raise Constraint_Error;
        else
            T.Contents (At_Pos) := Source;
        end if;
    end Replace;


    procedure Replace (Target : in out Variable_String;
                       At_Pos :        Positive;
                       Source :        String) is
        T       : Real_String renames Target.all;
        End_Pos : constant Natural -- not positive JMK 28 Sep 84
            := At_Pos + Source'Length - 1;
    begin
        if End_Pos > T.Length then
            raise Constraint_Error;
        else
            T.Contents (At_Pos .. End_Pos) := Source;
        end if;
    end Replace;

    procedure Replace (Target : in out Variable_String;
                       At_Pos :        Positive;
                       Source :        Character;
                       Count  :        String_Length) is
        Value_String : String (1 .. Count) := String'(1 .. Count => Source);
    begin
        Replace (Target, At_Pos, Value_String);
    end Replace;

    procedure Replace (Target : in out Variable_String;
                       At_Pos :        Positive;
                       Source :        Variable_String) is
    begin
        Replace (Target, At_Pos, Image (Source));
    end Replace;


    procedure Set_Length (Target     : in out Variable_String;
                          New_Length :        String_Length;
                          Fill_With  :        Character := ' ') is
        Current_Length : String_Length := Length (Target);
    begin
        if New_Length > Current_Length then
            Allocate (Target, New_Length, Preserve_Contents => True);
            declare
                C : String renames Target.Contents.all;
            begin
                for I in Current_Length + 1 .. New_Length loop
                    C (I) := Fill_With;
                end loop;
            end;
        elsif Target /= null then
            Target.Length := New_Length;
        end if;
    end Set_Length;

    function Char_At (Source : Variable_String; At_Pos : Positive)
                     return Character is
        S : Real_String renames Source.all;
    begin
        if At_Pos > S.Length then
            raise Constraint_Error;
        else
            return S.Contents (At_Pos);
        end if;
    end Char_At;

    function Extract (Source    : Variable_String;
                      Start_Pos : Positive;
                      End_Pos   : Natural) return String is
    begin
        if End_Pos > Source.Length then
            raise Constraint_Error;
        else
            return Source.Contents (Start_Pos .. End_Pos);
        end if;
    end Extract;
end Unbounded_String;

ARCHIVE PAIR

INDEX: ⟦6c5555414⟧ R1K_ARCHIVE_INDEX
DATA:  ⟦9b477e385⟧ R1K_ARCHIVE_DATA, TextFile

OctetView

0x00000…00ef7 ⟦a61fc1b33⟧
0x00ef7…02e21 ⟦b1a22725d⟧
0x02e21…03cdc ⟦4771a9fdb⟧
0x03cdc…065ce ⟦e2acccd93⟧
0x065ce…06777 ⟦b3867145c⟧
0x06777…0a62b ⟦fed769ff7⟧
0x0a62b…0a720 ⟦3234ae6f9⟧
0x0a720…0abd6 ⟦e2101317a⟧
0x0abd6…0c1c8 ⟦a5f87a3e3⟧
0x0c1c8…0e128 ⟦9d78b1705⟧
0x0e128…0e6f3 ⟦542922de3⟧
0x0e6f3…0ed0a ⟦0bd5f6717⟧
0x0ed0a…0f03b ⟦8fe15431f⟧
0x0f03b…0f2d3 ⟦7fcfa08b6⟧
0x0f2d3…1017a ⟦e895802c4⟧
0x1017a…11758 ⟦00165936c⟧
0x11758…118f9 ⟦bf031df25⟧
0x118f9…15990 ⟦fc4cf5bf4⟧
0x15990…1603a ⟦1c0bbedf7⟧
0x1603a…16d81 ⟦b9a400e68⟧
0x16d81…173c8 ⟦e77559783⟧
0x173c8…17aa1 ⟦5ac55847a⟧
0x17aa1…181bb ⟦f53809862⟧
0x181bb…189ae ⟦83d22651a⟧
0x189ae…18d8b ⟦45771e695⟧
0x18d8b…19580 ⟦aa5d4c50f⟧
0x19580…1a110 ⟦ca85a278a⟧
0x1a110…1b8e0 ⟦cf7e9341c⟧
0x1b8e0…1c0c2 ⟦38a93f2bb⟧
0x1c0c2…1d5bf ⟦90180af14⟧
0x1d5bf…1e1c9 ⟦5237038ed⟧
0x1e1c9…221c3 ⟦49ee8ac96⟧
0x221c3…2277c ⟦14c84e96e⟧
0x2277c…25411 ⟦90b99a8d4⟧
0x25411…25545 ⟦ccd5b9857⟧
0x25545…2597f ⟦3b498eefe⟧
0x2597f…26a0e ⟦0f1fd616e⟧
0x26a0e…2ad23 ⟦c33d138f9⟧
0x2ad23…2d026 ⟦bef1e4ed8⟧
0x2d026…3079b ⟦03ee9b8d7⟧
0x3079b…309ab ⟦f72d7a424⟧
0x309ab…33aeb ⟦0319a08b0⟧
0x33aeb…34ecb ⟦e556502e5⟧
0x34ecb…37bac ⟦1510af14f⟧