A Wr.T (or ``writer'') is a character output stream.  The basic
   operation on a writer is PutChar, which extends a writer's
   character sequence by one character. Some writers (called
   ``seekable writers'') also allow overwriting in the middle of the
   sequence.  For example, writers to random access files are
   seekable, but writers to terminals and sequential files are not.
   \index{character output stream}
   \index{output stream}
   \index{stream!output}
   \index{writer}
Writers can be (and usually are) buffered. This means that operations on the writer don't immediately affect the underlying target of the writer, but are saved up and performed later. For example, a writer to a disk file is not likely to update the disk after each character.
   Abstractly, a writer wr consists of:
      len(wr)       a non-negative integer
      c(wr)         a character sequence of length len(wr)
      cur(wr)       an integer in the range [0..len(wr)]
      target(wr)    a character sequence
      closed(wr)    a boolean
      seekable(wr)  a boolean
      buffered(wr)  a boolean
   These values are generally not directly represented in the data
   fields of a writer object, but in principle they determine the
   state of the writer.
   The sequence c(wr) is zero-based: c(wr)[i] is valid for i
   from 0 through len(wr)-1.  The value of cur(wr) is the index of
   the character in c(wr) that will be replaced or appended by the
   next call to PutChar.  If wr is not seekable, then cur(wr) is
   always equal to len(wr), since in this case all writing happens
   at the end.
   The difference between c(wr) and target(wr) reflects the
   buffering: if wr is not buffered, then target(wr) is updated to
   equal c(wr) after every operation; if wr is buffered, then
   updates to target(wr) can be delayed.  For example, in a writer
   to a file, target(wr) is the actual sequence of characters on the
   disk; in a writer to a terminal, target(wr) is the sequence of
   characters that have actually been transmitted.  (This sequence may
   not exist in any data structure, but it still exists abstractly.)
   If wr is buffered, then the assignment target(wr) := c(wr) can
   happen asynchronously at any time, although the procedures in this
   interface are atomic with respect to such assignments.
   Every writer is a monitor; that is, it contains an internal lock
   that is acquired and held for each operation in this interface, so
   that concurrent operations will appear atomic.  For faster,
   unmonitored access, see the UnsafeWr interface.
If you are implementing a long-lived writer class, such as a pipe or TCP stream, the index of the writer may eventually overflow, causing the program to crash with a bounds fault. We recommend that you provide an operation to reset the writer index, which the client can call periodically.
   It is useful to specify the effect of several of the procedures in
   this interface in terms of the action PutC(wr, ch), which outputs
   the character ch to the writer wr:
      PutC(wr, ch) =
        IF closed(wr) THEN Cause checked runtime error END;
        IF cur(wr) = len(wr) THEN
          Extend c(wr) by one character, incrementing len(wr)
        END;
        c(wr)[cur(wr)] := ch;
        INC(cur(wr));
   PutC is used only in specifying the interface; it is not a real
   procedure.
   Like PutC, PutWC is used to specify how wide characters are written.
   Wide characters are written in little-endian order, the low-order
   8-bits first, followed by the high-order 8-bits:
      PutWC(wr, wch) =
        PutC(wr, VAL (Word.Extract (ORD (wch), 0, 8), CHAR));
        PutC(wr, VAL (Word.Extract (ORD (wch), 8, 8), CHAR));
INTERFACESince there are many classes of writers, there are many ways that a writer can break---for example, the network can go down, the disk can fill up, etc. All problems of this sort are reported by raising the exceptionWr ; IMPORT AtomList, OSConfig; FROM Thread IMPORT Alerted; TYPE T <: ROOT; EXCEPTION Failure(AtomList.T);
Failure.  The documentation of each writer
   class should specify what failures the class can raise and how they
   are encoded in the argument to Failure.
Illegal operations (for example, writing to a closed writer) cause checked runtime errors.
CONST EOL = OSConfig.LineSep;
End of line.
On POSIX,
EOL is {\tt "\n"}; on Win32,
   EOL is {\tt "\r\n"}. 
PROCEDURE PutChar(wr: T; ch: CHAR) RAISES {Failure, Alerted};
Outputchtowr. More precisely, this is equivalent to:
      PutC(wr, ch); IF NOT buffered(wr) THEN Flush(wr) END
PROCEDURE PutWideChar(wr: T; ch: WIDECHAR) RAISES {Failure, Alerted};
 Output ch to wr.  More precisely, this is equivalent to: 
      PutWC(wr, ch); IF NOT buffered(wr) THEN Flush(wr) END
 
Many operations on a writer can wait indefinitely.  For example,
   PutChar can wait if the user has suspended output to his
   terminal.  These waits can be alertable, so each procedure that
   might wait includes Thread.Alerted in its raises clause. 
PROCEDURE PutText(wr: T; t: TEXT) RAISES {Failure, Alerted};
 Output t to wr.  More precisely, this is equivalent to: 
      FOR i := 0 TO Text.Length(t) - 1 DO
        PutC(wr, Text.GetChar(t, i))
      END;
      IF NOT buffered(wr) THEN Flush(wr) END
   except that, like all operations in this interface, it is atomic
   with respect to other operations in the interface. (It would be
   wrong to write PutChar instead of PutC, since PutChar always
   flushes if the writer is unbuffered.)
PROCEDURE PutWideText(wr: T; t: TEXT) RAISES {Failure, Alerted};
 Output t to wr.  More precisely, this is equivalent to: 
      FOR i := 0 TO Text.Length(t) - 1 DO
        PutWC(wr, Text.GetChar(t, i))
      END;
      IF NOT buffered(wr) THEN Flush(wr) END
PROCEDURE PutString(wr: T; READONLY a: ARRAY OF CHAR)
  RAISES {Failure, Alerted};
 Output a to wr.  More precisely, other than the fact that this
   is atomic, it is equivalent to: 
      FOR i := FIRST(a) TO LAST(a) DO PutC(wr, a[i]) END;
      IF NOT buffered(wr) THEN Flush(wr) END
PROCEDURE PutWideString(wr: T; READONLY a: ARRAY OF WIDECHAR)
  RAISES {Failure, Alerted};
 Output a to wr.  More precisely, other than the fact that this
   is atomic, it is equivalent to: 
      FOR i := FIRST(a) TO LAST(a) DO PutWC(wr, a[i]) END;
      IF NOT buffered(wr) THEN Flush(wr) END
PROCEDURE Seek(wr: T; n: CARDINAL) RAISES {Failure, Alerted};
 Set the current position of wr to n.  This is an error if wr
   is closed. More precisely, this is equivalent to: 
      IF wr.closed OR NOT seekable(wr) THEN
        Cause checked runtime error
      END;
      cur(wr) := MIN(n, len(wr))
PROCEDURE Flush(wr: T) RAISES {Failure, Alerted};
 Perform all buffered operations.  That is, set target(wr) :=
   c(wr).  It is a checked runtime error if wr is closed. 
PROCEDURE Close(wr: T) RAISES {Failure, Alerted};
 Flush wr, release any resources associated with wr, and set
   closed(wr) := TRUE.  The documentation for a procedure that
   creates a writer should specify what resources are released when
   the writer is closed.  This leaves closed(wr) equal to TRUE
   even if it raises an exception, and is a no-op if wr is closed.
   
PROCEDURE Length(wr: T): CARDINAL RAISES {Failure, Alerted};
PROCEDURE Index(wr: T): CARDINAL RAISES {};
PROCEDURE Seekable(wr: T): BOOLEAN RAISES {};
PROCEDURE Closed(wr: T): BOOLEAN RAISES {};
PROCEDURE Buffered(wr: T): BOOLEAN RAISES {};
 These procedures return len(wr), cur(wr), seekable(wr),
   closed(wr), and buffered(wr), respectively. Length and
   Index cause a checked runtime error if wr is closed; the other
   three procedures do not. 
END Wr.