-- IeeeIOB.mesa
-- String munging for IO
-- Last Modified By Paul Rovner On May 4, 1983 10:08 am
-- Last Edited by: Levin, August 8, 1983 6:21 pm
-- Last Edited by: MBrown, January 16, 1984 2:51 pm PST

DIRECTORY
  Basics USING [LongNumber],
  ConvertReal USING [],  -- EXPORTS only
  Ieee USING [BitOn, HiBit],
  Real USING [NumberType, RealToPair];

IeeeIOB: CEDAR PROGRAM IMPORTS Ieee, Real EXPORTS ConvertReal =
  BEGIN

  AppendReal: PUBLIC PROC [s: STRING, r: REAL, precision: CARDINAL, forceE: BOOL] =
    TRUSTED {
    exp: INTEGER;
    z: INT;
    ty: Real.NumberType;
    sign: BOOL;
    Zeros: PROC [n: CARDINAL] = TRUSTED {
      THROUGH [1..n] DO AppendChar[s, '0] ENDLOOP
      };
    {
    sign ← Ieee.BitOn[LOOPHOLE[r, Basics.LongNumber].highbits, Ieee.HiBit];
    [type: ty, fr: z, exp10: exp] ← Real.RealToPair[r, precision];
    IF sign THEN z ← -z;
    SELECT ty FROM
      nan => AppendString[to: s, from: ".."];
      infinity => AppendString[to: s, from: IF sign THEN "--" ELSE "++"];
      zero => AppendString[to: s, from: IF sign THEN "-0.0" ELSE "0.0"];
      ENDCASE => GOTO Ok;
    EXITS
      Ok => {
	lds: STRING ← [20];
	rds: STRING ← [20];
	i, digit, digits, ld, rd: CARDINAL;
	IF sign THEN AppendChar[s, '-];
	IF z = 0 THEN { AppendChar[s, '0]; RETURN }; -- leading zeros
	digits ← precision ← MAX[1, MIN[precision, 9]];
	WHILE (z MOD 10) = 0 DO
	  -- strip trailing zeros
	  z ← z/10;
	  exp ← exp + 1;
	  digits ← digits - 1;
	  ENDLOOP;
	IF digits = 0 THEN ERROR;
	rd ← MAX[0, -exp];
	rds.length ← MIN[digits, rd]; -- right digit string
	FOR i DECREASING IN [0..rds.length) DO
	  digit ← LOOPHOLE[z MOD 10, Basics.LongNumber].lowbits;
	  z ← z/10;
	  rds[i] ← digit + '0;
	  ENDLOOP;
	ld ← MAX[0, LOOPHOLE[digits, INTEGER] + exp];
	lds.length ← MIN[digits, ld]; -- left digit string
	FOR i DECREASING IN [0..lds.length) DO
	  digit ← LOOPHOLE[z MOD 10, Basics.LongNumber].lowbits;
	  z ← z/10;
	  lds[i] ← digit + '0;
	  ENDLOOP;
	forceE ← forceE OR ld > 6 OR rd > 6;
	IF NOT forceE THEN
	  SELECT TRUE FROM
	    ld = 0 => {
	      -- number entirely to right of decimal point
	      AppendString[to: s, from: "0."];
	      Zeros[rd - rds.length];
	      AppendString[to: s, from: rds];
	      };
	    rd = 0 => {
	      -- number entirely to left of decimal point
	      AppendString[to: s, from: lds];
	      Zeros[ld - lds.length];
	      AppendString[to: s, from: ".0"];
	      };
	    ENDCASE => {
	      -- some of each
	      AppendString[to: s, from: lds];
	      AppendChar[s, '.];
	      AppendString[to: s, from: rds];
	      }
	ELSE {
	  -- e format
	  AppendString[to: lds, from: rds];
	  AppendChar[s, lds[0]];
	  lds.length ← lds.length;
	  exp ← exp + lds.length - 1;
	  SELECT TRUE FROM
	    precision = 1 => AppendChar[s, '.];
	    lds.length = 1 => AppendString[to: s, from: ".0"];
	    ENDCASE => {
	      AppendChar[s, '.];
	      FOR i IN [1..lds.length) DO AppendChar[s, lds[i]]; ENDLOOP;
	      }; -- print exponent
	  IF exp = 0 THEN RETURN;
	  AppendChar[s, 'e];
	  AppendChar[s, IF exp < 0 THEN '- ELSE '+];
	  exp ← ABS[exp];
	  IF exp > 9 THEN AppendChar[s, '0 + (exp/10)];
	  AppendChar[s, '0 + (exp MOD 10)];
	  };
	};
    };
    };

  AppendChar: PROC [s: STRING, c: CHARACTER] = TRUSTED {
    IF s = NIL THEN RETURN;
    IF s.length >= s.maxlength THEN ERROR;
    s[s.length] ← c;
    s.length ← s.length + 1;
    };

  AppendString: PROC [to: STRING, from: STRING] = TRUSTED {
    i, j, n: CARDINAL;
    IF to = NIL OR from = NIL THEN RETURN;
    IF from.length + to.length > to.maxlength THEN ERROR;
    n ← MIN[from.length, LOOPHOLE[to.maxlength - to.length, CARDINAL]];
    i ← to.length;
    j ← 0;
    WHILE j < n DO to[i] ← from[j]; i ← i + 1; j ← j + 1; ENDLOOP;
    to.length ← i;
    };

END.
L. Stewart, July 12, 1980  10:37 PM, Name changes
L. Stewart, July 13, 1980  8:57 PM, delete WF procwedures (Moved to WFReal)
August 24, 1980  8:42 PM, L. Stewart; formatting, fix ReadReal
December 11, 1980  11:06 AM, L. Stewart; Use Ascii instead of IODefs
June 5, 1982 5:58 pm, L. Stewart, removed STRING conversions
August 27, 1982 1:05 pm, L. Stewart, CEDAR
January 16, 1984 2:35 pm PST, MBrown, toss unused stuff.