-- File Output.mesa  
--   Last edited by Sandman on July 8, 1980  8:38 AM
--   Last edited by Sweet on September 19, 1980  4:01 PM
-- Copyright  Xerox Corporation 1979, 1980

DIRECTORY
  IODefs USING [CR, NumberFormat, TAB, SP],
  OutputDefs USING [],
  SegmentDefs USING [Append, DefaultVersion, NewFile, Write],
  StreamDefs USING [CreateByteStream, StreamHandle],
  StringDefs USING [AppendNumber, AppendString, SubString, SubStringDescriptor],
  TimeDefs USING [AppendDayTime, UnpackDT];

Output: PROGRAM
  IMPORTS SegmentDefs, StreamDefs, StringDefs, TimeDefs EXPORTS OutputDefs =
  BEGIN
  
  outStream: PUBLIC StreamDefs.StreamHandle ← NIL;

  GetOutputStream: PUBLIC PROCEDURE RETURNS [StreamDefs.StreamHandle] =
    {RETURN[outStream]}; -- calling this start traps the module where
      -- simply reading outStream does not
  
  PutTab: PUBLIC PROCEDURE = {PutChar[IODefs.TAB]};
    
  PutCR: PUBLIC PROCEDURE = {PutChar[IODefs.CR]};
    
  PutChar: PUBLIC PROCEDURE [c: CHARACTER] = {outStream.put[outStream, c]};
    
  PutString: PUBLIC PROCEDURE [s: STRING] =
    BEGIN
    i: CARDINAL;
    FOR i IN [0..s.length) DO outStream.put[outStream, s[i]]; ENDLOOP;
    END;
    
  PutSubString: PUBLIC PROCEDURE [s: StringDefs.SubString] =
    BEGIN
    i: CARDINAL;
    FOR i IN [s.offset..s.offset + s.length) DO
      outStream.put[outStream, s.base[i]]; ENDLOOP;
    END;
    
  PutTime: PUBLIC PROCEDURE [t: LONG CARDINAL] =
    BEGIN
    s: STRING ← [20];
    TimeDefs.AppendDayTime[s, TimeDefs.UnpackDT[LOOPHOLE[t]]];
    IF s[0] = IODefs.SP THEN
      BEGIN
      desc: StringDefs.SubStringDescriptor ←
	[base: s, offset: 1, length: s.length - 1];
      PutSubString[@desc];
      END
    ELSE PutString[s];
    END;
    
  PutNumber: PUBLIC PROCEDURE [val: CARDINAL, format: IODefs.NumberFormat] =
    BEGIN
    i: CARDINAL;
    neg: BOOLEAN ← FALSE;
    fill: CHARACTER ← (IF format.zerofill THEN '0 ELSE ' );
    s: STRING ← [10];
    IF INTEGER[val] < 0 AND ~format.unsigned THEN
      {val ← -INTEGER[val]; neg ← TRUE};
    StringDefs.AppendNumber[s, val, format.base];
    i ← s.length;
    IF neg THEN
      BEGIN
      i ← i + 1;
      IF format.zerofill THEN {outStream.put[outStream, '-]; neg ← FALSE};
      END;
    THROUGH (i..format.columns] DO outStream.put[outStream, fill] ENDLOOP;
    IF neg THEN outStream.put[outStream, '-];
    PutString[s];
    END;
    
  PutDecimal: PUBLIC PROCEDURE [val: CARDINAL] =
    {PutNumber[val, [10, FALSE, FALSE, 1]]};
    
  PutOctal: PUBLIC PROCEDURE [val: UNSPECIFIED] =
    BEGIN
    PutNumber[val, [8, FALSE, TRUE, 1]];
    IF val ~ IN [0..7] THEN outStream.put[outStream, 'B];
    END;
    
  OpenOutput: PUBLIC PROCEDURE [root: STRING, ext: STRING] =
    BEGIN OPEN StringDefs, SegmentDefs;
    i: CARDINAL;
    name: STRING ← [40];
    AppendString[name, root];
    FOR i IN [0..name.length) DO
      IF name[i] = '. THEN {name.length ← i; EXIT}; ENDLOOP;
    AppendString[name, ext];
    outStream ← StreamDefs.CreateByteStream[
      NewFile[name, Write + Append, DefaultVersion], Write + Append];
    END;
    
  CloseOutput: PUBLIC PROCEDURE = {outStream.destroy[outStream]; outStream ← NIL};
    
  
  END.