-- CharIOImpl.Mesa
-- last edited by Russ Atkinson on 29-Oct-80 10:23:47
-- last edited by Satterthwaite on May 21, 1982 12:46 pm 

DIRECTORY
  CharIO: TYPE USING [CR, Handle, NumberFormat, SP],
  Stream: TYPE USING [GetChar, PutChar],
  Strings: TYPE USING [AppendChar, String, SubString];

CharIOImpl: PROGRAM IMPORTS Strings, Stream EXPORTS CharIO = {
  OPEN CharIO, Strings;

  -- String i/o
  
  GetChar: PUBLIC PROC [in: Handle] RETURNS [CHAR] = {
    RETURN [in.GetChar]};

  GetString: PUBLIC PROC [
    in: Handle, s: String, test: PROC [CHAR] RETURNS [BOOL]] = {
    DO
      c: CHAR ← 0C;
      c ← in.GetChar[ ! ANY => EXIT];
      IF test[c] THEN EXIT;
      AppendChar[s, c];
      ENDLOOP};
    
  PutChar: PUBLIC PROC [out: Handle, c: CHAR] = {out.PutChar[c]};

  PutString: PUBLIC PROC [out: Handle, s: String] = {
    IF s # NIL THEN FOR i: CARDINAL IN [0..s.length) DO out.PutChar[s[i]] ENDLOOP};
    
  PutLine: PUBLIC PROC [out: Handle, s: Strings.String] = {
    PutString[out, s]; PutChar[out, CR]};

  PutSubString: PUBLIC PROC [out: Handle, ss: SubString] = {
    s: String = ss.base;
    IF s # NIL THEN
      FOR i: CARDINAL IN [ss.offset..ss.offset + ss.length) DO
        out.PutChar[s[i]] ENDLOOP};
    
  GetLine: PUBLIC PROC [in: Handle, s: String] = {
    GetString[in, s, IsCR]};
    
  IsCR: PROC [c: CHAR] RETURNS [BOOL] = {RETURN [c = CR]};
    
  GetId: PUBLIC PROC [in: Handle, s: String] = {
    c: CHAR ← SP;
    DO
      c ← GetChar[in ! ANY => EXIT];
      IF c # SP THEN EXIT;
      ENDLOOP;
    DO
      IF c = SP OR c = CR THEN EXIT;
      AppendChar[s, c];
      c ← GetChar[in ! ANY => EXIT];
      ENDLOOP};
    
  --  Numerical i/o
  
  GetNumber: PUBLIC PROC [in: Handle, radix: CARDINAL] RETURNS [UNSPECIFIED] = {
    number: CARDINAL ← 0;
    negative: BOOL ← FALSE;
    s: STRING = [10];
    pos, len: CARDINAL ← 0;
    GetId[in, s];
    len ← s.length;
    IF len > 0 THEN
      SELECT s[len-1] FROM
	'b, 'B => {radix ← 8; len ← len-1};
	'd, 'D => {radix ← 10; len ← len-1};
	ENDCASE;
    IF pos < len AND s[pos] = '- THEN {pos ← pos + 1; negative ← TRUE};
    FOR pos IN [pos..len) DO
      number ← number*radix + (s[pos] - '0);
      ENDLOOP;
    IF negative THEN number ← -number;
    RETURN [number]};
    
  PutNumber: PUBLIC PROC [out: Handle, val: INTEGER, format: NumberFormat] = {
    i: CARDINAL ← 0;
    neg: BOOL ← FALSE;
    fill: CHAR = (IF format.zerofill THEN '0 ELSE ' );
    s: STRING = [17];
    card: CARDINAL ← val;
    radix: CARDINAL = format.base;
    IF radix < 2 OR radix > 36 THEN ERROR;
    IF val < 0 AND ~format.unsigned THEN {card ← -card; neg ← TRUE};
    DO
      digit: CARDINAL = card MOD radix; 
      s[i] ← IF digit >= 10 THEN 'A + (digit-10) ELSE '0 + digit;
      i ← i + 1;
      IF (card ← card/radix) = 0 THEN EXIT;
      ENDLOOP;
    s.length ← i;
    IF neg THEN {
      i ← i + 1;
      IF format.zerofill THEN {PutChar[out, '-]; neg ← FALSE}}; 
    THROUGH (i..format.columns] DO PutChar[out, fill] ENDLOOP;
    IF neg THEN PutChar[out, '-];
    i ← s.length;
    WHILE i > 0 DO PutChar[out, s[i ← i-1]] ENDLOOP};
    
  PutDecimal: PUBLIC PROC [out: Handle, n: INTEGER] = {
    PutNumber[out, n, NumberFormat[10, FALSE, FALSE, 0]]};
    
  PutOctal: PUBLIC PROC [out: Handle, n: UNSPECIFIED] = {
    PutNumber[out, n, NumberFormat[8, FALSE, TRUE, 0]];
    IF CARDINAL[n] > 7 THEN PutChar[out, 'b]};
  
  }.