-- XDDOutModule.mesa Edited by
  -- Bruce on September 30, 1980  3:52 PM
  -- Mark on September 30, 1980  4:22 PM
  -- Evans on Aug 20, 1980 10:00 AM

DIRECTORY
  Ascii USING [CR, SP],
  DebugFormat USING [LongSubString, NumberFormat],
  DebugOps USING [],
  DebugUsefulDefs USING [fileSW],
  DiskKDDefs USING [DiskFull],
  DOutput USING [],
  FileSW USING [GetFile],
  Format,
  Inline USING [LowHalf],
  IODefs USING [],
  StreamDefs USING [StreamHandle],
  Strings USING [String, SubString, SubStringDescriptor],
  TextSW USING [InsertChar, InsertString, InsertSubString, SetEOF],
  UserInput USING [userAbort];

DOutModule: PROGRAM
  IMPORTS
    DebugUsefulDefs, DiskKDDefs, FileSW, Format, Inline, TextSW, UserInput
  EXPORTS DebugOps, DebugUsefulDefs, DOutput, IODefs =
  PUBLIC BEGIN OPEN DebugFormat;

UserAborted: PUBLIC SIGNAL = CODE;
CallSapsford: ERROR [STRING] = CODE;

-- DOutput
newLine: BOOLEAN ← TRUE;

DiskFull: PROC = {
  OPEN StreamDefs;
  s: StreamHandle ← FileSW.GetFile[DebugUsefulDefs.fileSW].s;
  WITH s SELECT FROM
    Disk => {index ← index - 1; size ← size - 1};
    ENDCASE => ERROR CallSapsford["Can only reset a disk stream!"L];
  TextSW.SetEOF[DebugUsefulDefs.fileSW,0];
  EOL[]; Line["Disk full! Typescript reset to beginning."L]};

OutChar: PROC [c: CHARACTER] = 
  BEGIN
  TextSW.InsertChar[DebugUsefulDefs.fileSW,c ! DiskKDDefs.DiskFull => GOTO mark];
  EXITS
    mark => {DiskFull[]; TextSW.InsertChar[DebugUsefulDefs.fileSW,c]}
  END;

NewLine: PROCEDURE RETURNS [BOOLEAN] = BEGIN RETURN[newLine] END;

EOL: PROCEDURE =
  BEGIN
  IF ~newLine THEN OutChar[Ascii.CR];
  newLine ← TRUE;
  END;

Blanks: PROCEDURE [n: CARDINAL] =
  BEGIN
  THROUGH [0..n) DO OutChar[Ascii.SP] ENDLOOP;
  IF n # 0 THEN newLine ← FALSE;
  END;

WriteChar, Char: PROCEDURE [c: CHARACTER] = {OutChar[c]; newLine ← c = Ascii.CR};

WriteString, Text: PROCEDURE [s: Strings.String] =
  BEGIN
  IF UserInput.userAbort THEN SIGNAL UserAborted;
  IF s.length # 0 THEN newLine ← s[s.length-1] = Ascii.CR;
  TextSW.InsertString[DebugUsefulDefs.fileSW,s ! DiskKDDefs.DiskFull => GOTO mark];
  EXITS
    mark => {DiskFull[]; TextSW.InsertString[DebugUsefulDefs.fileSW,s]}
  END;

SubString: PROCEDURE [s: Strings.SubString] =
  BEGIN
  IF UserInput.userAbort THEN SIGNAL UserAborted;
  IF s.length # 0 THEN newLine ← s.base[s.length-1] = Ascii.CR;
  TextSW.InsertSubString[DebugUsefulDefs.fileSW,LOOPHOLE[s]
    ! DiskKDDefs.DiskFull => GOTO mark];
  EXITS
    mark => {DiskFull[]; TextSW.InsertSubString[DebugUsefulDefs.fileSW,LOOPHOLE[s]]}
  END;

LongSubString: PROCEDURE [s: DebugFormat.LongSubString] =
  BEGIN
  ss: Strings.SubStringDescriptor ← 
    [base: Inline.LowHalf[s.base], offset: s.offset, length: s.length];
  SubString[@ss]
  END;

WriteLine, Line: PROCEDURE [s: Strings.String] = BEGIN Text[s]; Char[Ascii.CR] END;

WriteNumber, Number: PROCEDURE [n: UNSPECIFIED, f: NumberFormat] =
  BEGIN Format.Number[n,f, Text] END;

LongNumber: PROCEDURE [n: LONG CARDINAL, f: NumberFormat] =
  BEGIN Format.LongNumber[n, f, Text]; END;

WriteDecimal, Decimal: PROCEDURE [n: INTEGER] = {Format.Decimal[n,Text]};
WriteOctal, Octal: PROCEDURE [n: UNSPECIFIED] = {Format.Octal[n, Text]};

LongDecimal: PROCEDURE [n: LONG INTEGER] = {Format.LongDecimal[n, Text]};
LongOctal: PROCEDURE [n: LONG CARDINAL] = {Format.LongOctal[n, Text]};

END.