File : reps-io.adb



package body Reps.IO is

  package Txt_Rep_IO is new Ada.Text_IO.Float_IO(Rep);

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

  function Val(S: String) return Rep is

    function V(C: Character) return Integer is
    begin
      for K in 1 .. 15 loop
        if C=HexDig(K) then return K; end if;
      end loop;
      return 0;
    end V;

    E1,E2,Ed1,Es2,Ms: Integer := 0;
    R: Rep := Zero;
  begin
    for K in S'Range loop
      if S(K)=' ' then
        null;
      elsif S(K)='+' then
        if Ms=0 then Ms := 1; else Es2 := 1; end if;
      elsif S(K)='-' then
        if Ms=0 then Ms := -1; else Es2 := -1; end if;
      elsif Es2=0 then
        if Ms=0 then Ms := 1; end if;
        if S(K)='.' then
          Ed1 := -1;
        else
          R := Rep(16)*R+Rep(V(S(K)));
          E1 := E1+Ed1;
        end if;
      else
        E2 := 16*E2+V(S(K));
      end if;
    end loop;
    R := Rep(Ms)*Rep'Scaling(R,4*(E1+Es2*E2));
    return R;
  end Val;

  function HexStr(I: Integer) return String is
    Nhex: constant Integer := 1+Integer'Size/4;
    S: String(1 .. Nhex);
    J: Integer := Abs(I);
  begin
    for N in reverse 1 .. Nhex loop
      S(N) := HexDig(J mod 16);
      J := J/16;
      if J=0 then
        if I<0 then return "-" & S(N .. Nhex);
        else return "+" & S(N .. Nhex); end if;
      end if;
    end loop;
    raise Constraint_Error;
    return "+0";
  end HexStr;

  function HexStr(R: Rep) return String is
    Nhex: constant Integer := 1+Rep'Machine_Mantissa/4;
    E,F: Integer;
    M,L: Rep;
    S: String(1 .. Nhex+2);
  begin
    if R=0.0 then
      return " 0.0+0";
    end if;
    if R<0.0 then S(1) := '-'; else S(1) := '+'; end if;
    E := Rep'Exponent(R)-1;
    F := E mod 4;
    M := Rep'Compose(Abs(R),F+1);
    L := Rep'Leading_Part(M,F+1);
    S(2) := HexDig(Integer(Rep'Floor(L)));
    S(3) := '.';
    for N in 1 .. Nhex-1 loop
      L := M-Rep'Leading_Part(M,F-3+4*N);
      S(N+3) := HexDig(Integer(Rep'Floor(L*Rep(16)**N)));
    end loop;
    return S & HexStr((E-F)/4);
  end HexStr;

  procedure Txt_Get(F: in File_Type; R: out Rep; Decimal: in Boolean := True) is
    I: Integer;
    S: String(1..32);
  begin
    if Decimal then
      Txt_Rep_IO.Get(F,R);
    else
      I := 0;
      while I=0 loop
        Get_Line(File=>F, Item=>S, Last=>I);
      end loop;
      R := Val(S(1..I));
    end if;
  end Txt_Get;

  procedure Txt_Get(F: in File_Type; R1,R2: out Rep; Decimal: in Boolean := True) is
    I: Integer;
    S: String(1..64);
  begin
    if Decimal then
      Txt_Rep_IO.Get(F,R1);
      R2 := Zero;             --- no decimal pairs, according to Txt_Put
    else
      I := 0;
      while I=0 loop
        Get_Line(File=>F, Item=>S, Last=>I);
      end loop;
      for N in 2 .. I-1 loop
        if S(N)=',' then
          R1 := Val(S(1 .. N-1));
          R2 := Val(S(N+1 .. I));
          return;
        end if;
      end loop;
      R1 := Val(S(1..I));
      R2 := Zero;
    end if;
  end Txt_Get;

  procedure Txt_Put(F: in File_Type; R: in Rep; Decimal: in Boolean := True) is
--- Long_Float approx 16 decimal digits
--- Long_Long_Float only 17 decimal digits
  begin
    if Decimal then
      Txt_Rep_IO.Put(File=>F, Item=>R, Aft=>17, Exp=>4);  --- approximate
    else
      Put(F,HexStr(R));
    end if;
  end Txt_Put;

  procedure Txt_Put(F: in File_Type; R1,R2: in Rep; Decimal: in Boolean := True) is
  begin
    if Decimal then                                        --- ignore R2
      Txt_Rep_IO.Put(File=>F, Item=>R1, Aft=>17, Exp=>4);  --- approximate
    elsif R2=Zero then
      Put(F,HexStr(R1));
    else
      Put(F,HexStr(R1) & "," & HexStr(R2));
    end if;
  end Txt_Put;

end Reps.IO;