-- file: RESIOPack.mesa  Edited by Bruce, September 22, 1980  10:15 AM

DIRECTORY
  Ascii USING [CR, SP],
  Format USING [NumberFormat],
  Inline USING [LongNumber],
  RESOut USING [MakeRoom, PChar],
  String USING [AppendLongNumber, AppendNumber, SubString];

RESIOPack: PROGRAM IMPORTS RESOut, String EXPORTS RESOut =
  BEGIN OPEN RESOut;

  Log10: PUBLIC PROCEDURE [num: CARDINAL] RETURNS [CARDINAL] =
    BEGIN
    IF num < 1000 THEN
      IF num < 10 THEN RETURN[1]
      ELSE 
        IF num >= 100 THEN RETURN[3]
        ELSE RETURN[2]
    ELSE
      IF num >= 10000 THEN RETURN[5]
      ELSE RETURN[4];
    END;
  
  LongLog10: PUBLIC PROCEDURE [num: LONG CARDINAL] RETURNS [CARDINAL] =
    BEGIN
    power: ARRAY [1..10] OF LONG CARDINAL = 
      [0, 1D1, 1D2, 1D3, 1D4, 1D5, 1D6, 1D7, 1D8, 1D9];
    u, l, i: CARDINAL;
    l ← 1; u ← 11;
    UNTIL u < l DO
      i ← (l+u)/2;
      SELECT power[i] FROM
        = num => RETURN [i];
        > num => u ← i-1;
        ENDCASE => l ← i+1;
      ENDLOOP;
    RETURN [u]; -- see Knuth, 6.2.1 Exercise 1.
    END;
  
  Log8: PUBLIC PROCEDURE [num: CARDINAL] RETURNS [CARDINAL] =
    BEGIN
    IF num < 1000B THEN
      IF num < 10B THEN RETURN[1]
      ELSE 
        IF num >= 100B THEN RETURN[3]
        ELSE RETURN[2]
    ELSE
      IF num >= 100000B THEN RETURN[6]
      ELSE 
        IF num >= 10000B THEN RETURN[5]
        ELSE RETURN[4];
    END;
  
  LongLog8: PUBLIC PROCEDURE [num: LONG CARDINAL] RETURNS [CARDINAL] =
    BEGIN
    power: ARRAY [1..11] OF LONG CARDINAL = 
      [0, 1B1, 1B2, 1B3, 1B4, 1B5, 1B6, 1B7, 
       1B8, 1B9, 1B10];
    u, l, i: CARDINAL;
    l ← 1; u ← 11;
    UNTIL u < l DO
      i ← (l+u)/2;
      SELECT power[i] FROM
        = num => RETURN [i];
        > num => u ← i-1;
        ENDCASE => l ← i+1;
      ENDLOOP;
    RETURN [u];
    END;

  PNextUnsigned: PUBLIC PROCEDURE [
      s: STRING, num: CARDINAL, indent: CARDINAL ← 2] =
    BEGIN
    extra: CARDINAL ← Log10[num];
    PNext[s, extra+2, indent];
    PString[": "L];
    PUnsigned[num];
    END;

  PNextNull: PUBLIC PROCEDURE [
      s: STRING, val, null: UNSPECIFIED, indent: CARDINAL ← 2] =
    BEGIN
    extra: CARDINAL ← IF val = null THEN 4 ELSE Log10[val];
    PNext[s, extra+2, indent];
    PString[": "L];
    PNull[val, null];
    END;

  PNextOctal: PUBLIC PROCEDURE [
      s: STRING, num: CARDINAL, indent: CARDINAL ← 2] =
    BEGIN
    extra: CARDINAL ← Log8[num];
    IF num > 7 THEN extra ← extra+1;
    PNext[s, extra+2, indent];
    PString[": "L];
    POctal[num];
    END;

  PNextLong: PUBLIC PROCEDURE [
      s: STRING, num: LONG INTEGER, indent: CARDINAL ← 2] =
    BEGIN
    neg: BOOLEAN ← num < 0;
    extra: CARDINAL;
    extra ← IF neg THEN LongLog10[-num]+1 ELSE LongLog10[num];
    PNext[s, extra+2, indent];
    PString[": "L];
    PLongNumber[num,
      [base: 10, unsigned: FALSE, zerofill: FALSE, columns: 0]];
    END;

  PDecimal: PUBLIC PROCEDURE [i: INTEGER] =
    BEGIN
    BEGIN PNumber[i, [10,FALSE,FALSE,1]] END;
    END;

  PNull: PUBLIC PROCEDURE [val, null: UNSPECIFIED] =
    BEGIN
    IF val = null THEN PString["Null"L]
    ELSE PUnsigned[val];
    END;

  PSubString: PUBLIC PROCEDURE [ss: String.SubString] =
    BEGIN
    i: CARDINAL;
    FOR i IN [ss.offset..ss.offset+ss.length)
      DO
      PChar[ss.base[i]];
      ENDLOOP;
    END;

  PNext: PUBLIC PROCEDURE [s: STRING, extra: CARDINAL ← 0, indent: CARDINAL ← 2] =
    BEGIN
    PChar[',];
    IF MakeRoom[s.length+1+extra, indent] THEN PChar[Ascii.SP];
    PString[s];
    END;

  PUnsigned: PUBLIC PROCEDURE [i: CARDINAL] =
    BEGIN
    BEGIN PNumber[i, [10,FALSE,TRUE,1]] END;
    END;

  POctal: PUBLIC PROCEDURE [i: CARDINAL] =
    BEGIN
    PNumber[i, [8,FALSE,TRUE,1]];
    IF i > 7 THEN PChar['B];
    END;

  PNumber: PUBLIC PROCEDURE [num: UNSPECIFIED, format: Format.NumberFormat] =
    BEGIN
    i: CARDINAL;
    neg: BOOLEAN ← FALSE;
    fill: CHARACTER ← (IF format.zerofill THEN '0 ELSE ' );
    s: STRING ← [10];
    IF INTEGER[num] < 0 AND ~format.unsigned THEN
      BEGIN num ← -INTEGER[num]; neg ← TRUE END;
    String.AppendNumber[s, num, format.base];
    i ← s.length;
    IF neg THEN
      BEGIN
      i ← i + 1;
      IF fill = '0 THEN BEGIN PChar['-]; neg ← FALSE END;
      END;
    THROUGH (i..format.columns] DO PChar[fill] ENDLOOP;
    IF neg THEN BEGIN PChar['-]; END;
    PString[s];
    RETURN
    END;

  PLongNumber: PUBLIC PROCEDURE [
      num: LONG UNSPECIFIED, format: Format.NumberFormat] =
    BEGIN
    n: Inline.LongNumber ← LOOPHOLE[num];
    i: CARDINAL;
    neg: BOOLEAN ← FALSE;
    fill: CHARACTER ← (IF format.zerofill THEN '0 ELSE ' );
    s: STRING ← [20];
    IF n.li < 0 AND ~format.unsigned THEN
      BEGIN n.li ← -n.li; neg ← TRUE END;
    String.AppendLongNumber[s, n.lc, format.base];
    i ← s.length;
    IF neg THEN
      BEGIN
      i ← i + 1;
      IF fill = '0 THEN BEGIN PChar['-]; neg ← FALSE END;
      END;
    THROUGH (i..format.columns] DO PChar[fill] ENDLOOP;
    IF neg THEN BEGIN PChar['-]; END;
    PString[s];
    RETURN
    END;

  PCr: PUBLIC PROCEDURE =
    BEGIN
    PChar[Ascii.CR];
    END;

  PString: PUBLIC PROCEDURE [s: STRING] =
    BEGIN
    i: CARDINAL;
    FOR i IN [0..s.length) DO
      PChar[s[i]];
      ENDLOOP;
    END;

  END.