-- File: LongStringsB.Mesa
--  Edited by Sandman on July 1, 1980  8:40 AM
--  Edited by Forrest on October 16, 1980  4:21 PM
--  Edited by Johnsson on  5-Dec-80 14:55:50

DIRECTORY
  Inline USING [BITAND, DIVMOD],
  LongString USING [AppendChar, AppendString],
  Mopcodes USING [zKFCB, zPOP],
  SDDefs USING [sULongDivMod];

LongStringsB: PROGRAM
  IMPORTS Inline, LongString EXPORTS LongString = PUBLIC
  BEGIN OPEN LongString;

  Overflow: SIGNAL = CODE;
  InvalidNumber: SIGNAL = CODE;
  NUL: CHARACTER = 0C;
  Space: CHARACTER = ' ;

  UpperCase: PROCEDURE [c: CHARACTER] RETURNS [CHARACTER] =
    BEGIN IF c IN ['a..'z] THEN c ← c + ('A - 'a); RETURN[c] END;

  LowerCase: PROCEDURE [c: CHARACTER] RETURNS [CHARACTER] =
    BEGIN IF c IN ['A..'Z] THEN c ← c + ('a - 'A); RETURN[c] END;

  CompareStrings: PROCEDURE [s1, s2: LONG STRING, ignoreCase: BOOLEAN ← TRUE]
    RETURNS [INTEGER] =
    BEGIN
    i: CARDINAL;
    l1: CARDINAL = s1.length;
    l2: CARDINAL = s2.length;
    c1, c2: CHARACTER;
    FOR i IN [0..MIN[l1, l2]) DO
      c1 ← s1[i];
      c2 ← s2[i];
      IF ignoreCase AND c1 # c2 THEN BEGIN c1 ← LowerCase[c1]; c2 ← LowerCase[c2]; END;
      SELECT c1 FROM < c2 => RETURN[-1]; > c2 => RETURN[1]; ENDCASE;
      ENDLOOP;
    RETURN[SELECT l1 FROM < l2 => -1, > l2 => 1, ENDCASE => 0]
    END;

  StringToNumber: PROCEDURE [s: LONG STRING, radix: CARDINAL ← 10] RETURNS [v: UNSPECIFIED] =
    BEGIN OPEN Inline;
    char: CHARACTER;
    cp: CARDINAL ← 0;
    v8, v10: CARDINAL ← 0;
    neg: BOOLEAN ← FALSE;

    getchar: PROCEDURE =
      BEGIN char ← s[cp]; IF (cp ← cp + 1) > s.length THEN char ← NUL; END;

    getchar[];
    WHILE char <= Space DO
      IF char = NUL THEN SIGNAL InvalidNumber; getchar[]; ENDLOOP;
    IF char = '- THEN BEGIN neg ← TRUE; getchar[] END;
    WHILE char IN ['0..'9] DO
      v10 ← v10*10 + (char - '0); v8 ← v8*8 + (char - '0); getchar[]; ENDLOOP;
    BEGIN
    SELECT LOOPHOLE[BITAND[char, 137B], CHARACTER] FROM
      NUL => GOTO noexponent;
      'B => BEGIN v ← v8; radix ← 8; END;
      'D => BEGIN v ← v10; radix ← 10; END;
      ENDCASE => GOTO noexponent;
    getchar[];
    v10 ← 0;
    WHILE char IN ['0..'9] DO v10 ← v10*10 + char - '0; getchar[]; ENDLOOP;
    THROUGH [1..v10] DO v ← v*radix ENDLOOP;
    EXITS noexponent => v ← IF radix = 8 THEN v8 ELSE v10;
    END;
    IF char # NUL THEN SIGNAL InvalidNumber;
    IF neg THEN RETURN[-v];
    END;

  AppendNumber: PROCEDURE [s: LONG STRING, n: CARDINAL, radix: CARDINAL] =
    BEGIN

    xn: PROCEDURE [n: CARDINAL] =
      BEGIN
      r: CARDINAL;
      [n, r] ← Inline.DIVMOD[n, radix];
      IF n # 0 THEN xn[n];
      IF r > 9 THEN r ← r + 'A - '0 - 10;
      AppendChar[s, r + '0];
      END;

    xn[n];
    END;

  AppendDecimal: PROCEDURE [s: LONG STRING, n: INTEGER] =
    BEGIN
    IF n < 0 THEN
      BEGIN
      IF n = LAST[INTEGER] THEN BEGIN AppendString[s, "-32768"L]; RETURN END;
      AppendChar[s, '-];
      n ← -n
      END;
    AppendNumber[s, n, 10];
    END;

  AppendOctal: PROCEDURE [s: LONG STRING, n: UNSPECIFIED] =
    BEGIN AppendNumber[s, n, 8]; AppendChar[s, 'B]; END;

  AppendLongDecimal: PROCEDURE [s: LONG STRING, n: LONG INTEGER] =
    BEGIN
    IF n < 0 THEN
      BEGIN
      IF n = LAST[LONG INTEGER] THEN
	BEGIN AppendString[s, "-2147483648"L]; RETURN END;
      AppendChar[s, '-];
      n ← -n
      END;
    AppendLongNumber[s, n, 10];
    END;

  AppendLongNumber: PROCEDURE [s: LONG STRING, n: LONG UNSPECIFIED, radix: CARDINAL] =
    BEGIN OPEN Mopcodes;

    DivMod: PROCEDURE [n, d: LONG CARDINAL]
      RETURNS [q: LONG CARDINAL, r: INTEGER] = MACHINE CODE
      BEGIN zKFCB, SDDefs.sULongDivMod; zPOP END;

    xn: PROCEDURE [n: LONG CARDINAL] =
      BEGIN
      r: CARDINAL;
      [n, r] ← DivMod[n, radix];
      IF n # 0 THEN xn[n];
      IF r > 9 THEN r ← r + 'A - '0 - 10;
      AppendChar[s, r + '0];
      END;

    xn[n];
    END;

  StringToLongNumber: PROCEDURE [s: LONG STRING, radix: CARDINAL]
    RETURNS [v: LONG CARDINAL] =
    BEGIN OPEN Inline;
    char: CHARACTER;
    cp: CARDINAL ← 0;
    exp: CARDINAL;
    v8, v10: LONG INTEGER ← 0;
    neg: BOOLEAN ← FALSE;

    getchar: PROCEDURE =
      BEGIN char ← s[cp]; IF (cp ← cp + 1) > s.length THEN char ← NUL; END;

    getchar[];
    WHILE char <= Space DO
      IF char = NUL THEN SIGNAL InvalidNumber; getchar[]; ENDLOOP;
    IF char = '- THEN BEGIN neg ← TRUE; getchar[] END;
    WHILE char IN ['0..'9] DO
      v10 ← v10*10 + CARDINAL[char - '0];
      v8 ← v8*8 + CARDINAL[char - '0];
      getchar[];
      ENDLOOP;
    BEGIN
    SELECT LOOPHOLE[BITAND[char, 137B], CHARACTER] FROM
      NUL => GOTO noexponent;
      'B => BEGIN v ← v8; radix ← 8; END;
      'D => BEGIN v ← v10; radix ← 10; END;
      ENDCASE => GOTO noexponent;
    getchar[];
    exp ← 0;
    WHILE char IN ['0..'9] DO exp ← exp*10 + char - '0; getchar[]; ENDLOOP;
    THROUGH [1..exp] DO v ← v*radix ENDLOOP;
    EXITS noexponent => v ← IF radix = 8 THEN v8 ELSE v10;
    END;
    IF char # NUL THEN SIGNAL InvalidNumber;
    IF neg THEN RETURN[-v];
    END;

  END....