-- 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
--   Last edited by Lewis on  9-Dec-80 10:18:06
--   Last edited by Satterthwaite on August 13, 1982 2:28 pm

DIRECTORY
  Ascii USING [CR, TAB, SP],
  Format USING [NumberFormat],
  LongString USING [SubString],
  OutputDefs USING [],
  Segments USING [DefaultVersion, NewFile, Write],
  Streams USING [CreateStream, Destroy, Handle, PutChar],
  String USING [AppendNumber, AppendString, SubString, SubStringDescriptor],
  Time USING [Append, Packed, Unpack];

Output: PROGRAM
    IMPORTS Segments, Streams, String, Time 
    EXPORTS OutputDefs =
  BEGIN
  
  outStream: PUBLIC Streams.Handle ← NIL;
  

  GetOutputStream: PUBLIC PROC RETURNS [Streams.Handle] =
    {RETURN[outStream]}; -- calling this start traps the module where
      -- simply reading outStream does not
  
  PutTab: PUBLIC PROC = {PutChar[Ascii.TAB]};
    
  PutCR: PUBLIC PROC = {PutChar[Ascii.CR]};
    
  PutChar: PUBLIC PROC [c: CHARACTER] = {Streams.PutChar[outStream, c]};
    
  PutString: PUBLIC PROC [s: STRING] =
    {FOR i: CARDINAL IN [0..s.length) DO Streams.PutChar[outStream, s[i]]; ENDLOOP};
    
  PutLongString: PUBLIC PROC [s: LONG STRING] =
    {FOR i: CARDINAL IN [0..s.length) DO Streams.PutChar[outStream, s[i]]; ENDLOOP};
    
  PutSubString: PUBLIC PROC [s: String.SubString] =
    BEGIN
    FOR i: CARDINAL IN [s.offset..s.offset + s.length) DO
      Streams.PutChar[outStream, s.base[i]]; 
      ENDLOOP;
    END;
    
  PutLongSubString: PUBLIC PROC [s: LongString.SubString] =
    BEGIN
    FOR i: CARDINAL IN [s.offset..s.offset + s.length) DO
      Streams.PutChar[outStream, s.base[i]]; 
      ENDLOOP;
    END;
        
  PutTime: PUBLIC PROC [t: Time.Packed] =
    BEGIN
    s: STRING ← [20];
    Time.Append[s, Time.Unpack[t]];
    IF s[0] = Ascii.SP THEN
      BEGIN
      desc: String.SubStringDescriptor ←
	[base: s, offset: 1, length: (s.length - 1)];
      PutSubString[@desc];
      END
    ELSE PutString[s];
    END;
    
  PutNumber: PUBLIC PROC [val: CARDINAL, format: Format.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};
    String.AppendNumber[s, val, format.base];
    i ← s.length;
    IF neg THEN
      BEGIN
      i ← i + 1;
      IF format.zerofill THEN {Streams.PutChar[outStream, '-];  neg ← FALSE};
      END;
    THROUGH (i..format.columns] DO Streams.PutChar[outStream, fill] ENDLOOP;
    IF neg THEN Streams.PutChar[outStream, '-];
    PutString[s];
    END;
    
  PutDecimal: PUBLIC PROC [val: CARDINAL] =
    {PutNumber[val, [10, FALSE, FALSE, 1]]};
    
  PutOctal: PUBLIC PROC [val: UNSPECIFIED] =
    BEGIN
    PutNumber[val, [8, FALSE, TRUE, 1]];
    IF val NOT IN [0..7] THEN Streams.PutChar[outStream, 'B];
    END;
    
  OpenOutput: PUBLIC PROC [root: STRING, ext: STRING] =
    BEGIN
    name: STRING ← [40];
    String.AppendString[name, root];
    FOR i: CARDINAL IN [0..name.length) DO
      IF name[i] = '. THEN {name.length ← i;  EXIT}; 
      ENDLOOP;
    String.AppendString[name, ext];
    outStream ← Streams.CreateStream[
      file: Segments.NewFile[
              name: name, access: Segments.Write, version: Segments.DefaultVersion], 
      access: Segments.Write];
    END;
    
  CloseOutput: PUBLIC PROC = {Streams.Destroy[outStream]; outStream ← NIL};
    
  
  END.