<?xml version="1.0" encoding="UTF-8"?>

<!-- ====================================================================== -->
<!-- = chapter-1.xml                                                      = -->
<!-- = standard i/o module guide - chapter 1                              = -->
<!-- ====================================================================== -->
<!-- = This  program  is  free  software; you  can redistribute it and/or = -->
<!-- = modify it provided that this copyright notice is kept intact.      = -->
<!-- = This program is distributed in the hope that it will be useful but = -->
<!-- = without  any  warranty;  without  even  the  implied  warranty  of = -->
<!-- = merchantability or fitness for  a  particular purpose. In no event = -->
<!-- = shall  the  copyright  holder be liable for any  direct, indirect, = -->
<!-- = incidental  or special  damages arising  in any way out of the use = -->
<!-- = of this software.                                                  = -->
<!-- ====================================================================== -->
<!-- = copyright (c) 2005-2007 - amaury darsch                            = -->
<!-- ====================================================================== -->

<chapter module="sio" number="1">
  <title>Standard i/o services</title>
  
  <p>
  This chapter covers the input/output facilities available in the
  <em>standard i/o</em> module. The basic operations are related to
  file manipulations and are later extended to any input or output
  streams. Later, various file system calls are described. 
  </p>

  <p>
  All <afnix/> standard i/o objects are located in the
  <code>afnix-sio</code> module. This module must be loaded prior
  any operation. Multiple calls to the module initialization routine
  are harmless. The interpreter method <code>module</code> loads a
  specific module by name. When the module has been loaded, the
  object are available in the <code>afnix:sio</code> nameset.
  </p>
  
  <example>
  interp:library "afnix-sio"
  </example>

  <!-- input/output streams -->
  <section>
    <title>Input and output streams</title>

    <p>
    The <code>afnix-sio</code> module is based on facilities provided
    by two base classes, namely, the <code>Input</code> stream and
    the <code>Output</code> stream. Both classes have associated
    predicates with the name <code>input-p</code> and
    <code>output-p</code>. The base class associated is the
    <code>Stream</code> class those sole purpose is to define the
    stream coding mode.
    </p>

    <!-- input stream -->
    <subsect>
      <title>Stream base class</title>

      <p>
      The <code>Stream</code> class is the base class for the
      <code>Input</code> and <code>Output</code> classes. The
      <code>Stream</code> class is used to define the stream coding
      mode that affects how characters are read or written. When a
      stream operates in <em>byte mode</em>, each character is assumed
      to be encoded in one byte. In that case, the input stream methods
      <code>read</code> and <code>rduc</code> are equivalent and no
      transformation is performed when writing characters. This
      behavior is the default stream behavior. For certain stream,
      like terminal, this behavior is changed depending on the current
      localization settings. For instance, if the current locale is
      operating with an <em>UTF-8</em> codeset, the <code>Terminal</code>
      stream coding mode is automatically adjusted to reflect this
      situation. Since the <em>US-ASCII</em> codeset is predominant
      and the default steam coding mode is the byte mode, there should
      be no conflict during the read and write operations.
      </p>
    </subsect>

    <!-- stream coding mode -->
    <subsect>
      <title>Stream transcoding</title>
      
      <p>
      The <code>Stream</code> class provides the support for the
      transcoding of different codesets. All <em>ISO-8859</em>
      codesets are supported. Since the <afnix/> engine operates
      internally with Unicode characters, the transcoding operation
      takes care of changing a character in one particular codeset into
      its equivalent Unicode representation. This operation is done
      for an input stream that operates in byte mode. For an output
      stream, the opposite operation is done. An internal Unicode
      characters representation is therefore mapped into a particular
      codeset. Note that only the codeset characters can be mapped.
      </p>

      <table>
        <title>Supported stream codesets</title>
        <thead>
        <tr>
          <td>Codeset</td><td>Description</td>
        </tr>
        </thead>
        <tbody>
        <tr><td>DEFAULT</td><td>Default codeset, i.e US-ASCII</td></tr>
        <tr><td>ISO-01</td> <td>ISO-8859-1 codeset</td></tr>
        <tr><td>ISO-02</td> <td>ISO-8859-2 codeset</td></tr>
        <tr><td>ISO-03</td> <td>ISO-8859-3 codeset</td></tr>
        <tr><td>ISO-04</td> <td>ISO-8859-4 codeset</td></tr>
        <tr><td>ISO-05</td> <td>ISO-8859-5 codeset</td></tr>
        <tr><td>ISO-06</td> <td>ISO-8859-6 codeset</td></tr>
        <tr><td>ISO-07</td> <td>ISO-8859-7 codeset</td></tr>
        <tr><td>ISO-08</td> <td>ISO-8859-8 codeset</td></tr>
        <tr><td>ISO-09</td> <td>ISO-8859-9 codeset</td></tr>
        <tr><td>ISO-10</td> <td>ISO-8859-10 codeset</td></tr>
        <tr><td>ISO-11</td> <td>ISO-8859-11 codeset</td></tr>
        <tr><td>ISO-13</td> <td>ISO-8859-13 codeset</td></tr>
        <tr><td>ISO-14</td> <td>ISO-8859-14 codeset</td></tr>
        <tr><td>ISO-15</td> <td>ISO-8859-15 codeset</td></tr>
        <tr><td>ISO-16</td> <td>ISO-8859-16 codeset</td></tr>
        <tr><td>UTF-08</td> <td>Unicode UTF-8 codeset</td></tr>
        </tbody>
      </table>
    </subsect>

    <p>
    The <code>set-encoding-mode</code> can be used to set the stream
    encoding codeset. The operates either by enumeration or
    string. The <code>get-encoding-mode</code> returns the stream
    encoding mode. There are some time good reasons to force a stream
    encoding mode. For example, a file encoded in UTF-8 that is read
    will require this call since the default stream mode is to work
    in byte mode. It should be noted that there is a difference
    between the enumeration and the string encoding mode. The
    enumeration mode defines whether the stream operates in byte or
    UTF-8 mode. When the stream operates in byte mode, it is also
    necessary to define the transcoding mode with
    the <code>set-transcoding-mode</code> method. For simplicity, the
    string version of the <code>set-encoding-mode</code> takes care of
    setting both the stream mode and the transcoding mode. It is also
    worth to note that internally, the <code>Stream</code> class is
    derived from the <code>Transcoder</code> class.
    </p>

    <!-- input stream -->
    <subsect>
      <title>Input stream </title>

      <p>
      The <code>Input</code> base class has several method for reading
      and testing for byte availability. Moreover, the class
      provides a push-back buffer. Reading bytes is in the form of
      three methods. The <code>read</code> method without argument
      returns the next available byte or the <tt>end-of-file</tt>
      <code>eof</code>. With an integer argument, the <code>read</code>
      method returns a <code>Buffer</code> with at most the number of
      requested bytes. The <code>readln</code> method returns the
      next available line. When it is necessary to read characters
      instead of bytes, the <code>rduc</code> is more appropriate
      since it returns an Unicode character.
      </p>
    </subsect>

    <!-- output stream -->
    <subsect>
      <title>Output stream</title>

      <p>
      The <code>Output</code> base class provides the base methods to
      write to an output stream. The <code>write</code> method takes
      literal objects which are automatically converted to string
      representation and then written to the output stream. Note that
      for the case of a <code>Buffer</code> object, it is the buffer
      itself that take a stream argument and not the opposite.
      </p>
    </subsect>

    <!-- valid-p predicate -->
    <subsect>
      <title>The valid-p predicate</title>

      <p>
      The input stream provides a general mechanism to test and read
      for bytes. The base method is the <code>valid-p</code>
      predicate that returns <code>true</code> if a byte can be
      read from the stream. It is important to understand its behavior
      which depends on the stream type.

      Without argument, the <code>valid-p</code> predicate checks for
      an available byte from the input stream. This predicate
      will block if no byte is available. On the other end, for a
      bounded stream like an input file, the method will not block at
      the end of file. With one integer argument, the
      <code>valid-p</code> predicate will timeout after the specified
      time specified in milliseconds. This second behavior is
      particularly useful with unbound stream like socket stream.
      </p>
    </subsect>

    <!-- eof-p predicate -->
    <subsect>
      <title>The eof-p predicate</title>

      <p>
      The <code>eof-p</code> predicate does not take argument. The
      predicate behaves like <code>not (valid-p 0)</code>. However,
      there are more subtle behaviors. For an input file, the
      predicate will return <code>true</code> if and only if a
      byte cannot be read. If a byte has been pushed-back
      and the <tt>end-of-file</tt> marker is reached, the method will 
      return false. For an input terminal, the method returns
      true if the user and entered the <tt>end-of-file</tt> byte.
      Once again, the method reacts to the contents of the push-back
      buffer. For certain input stream, like a tcp socket, the method
      will return true when no byte can be read, that is here,
      the connection has been closed. For an udp socket, the method
      will return <code>true</code> when all datagram bytes have
      be read.
      </p>
    </subsect>

    <!-- read method -->
    <subsect>
      <title>The read method</title>

      <p>
      The <code>read</code> method is sometimes disturbing. Nevertheless, 
      the method is a blocking one and will return a byte when
      completed. The noticeable exception is the returned byte
      when an <tt>end-of-file</tt> marker has been reached. The method
      returns the <tt>ctrl-d</tt> byte. Since a binary file might
      contains valid byte like <tt>ctrl-d</tt> it is necessary to
      use the <code>valid-p</code> or <code>eof-p</code> predicate to
      check for a file reading completion. This remark apply also to
      bounded streams like a tcp socket. For some type of streams like
      a udp socket, the method will block when all datagram bytes
      have been consumed and no more datagram has arrived. With this
      kind of stream, there is no <tt>end-of-file</tt> condition and
      therefore care should be taken to properly assert the stream
      content. This last remark is especially true for the
      <code>readln</code> method. The method will return when the
      <tt>end-of-file</tt> marker is reached, even if a newline
      byte has not been read. With an udp socket, such behavior
      will not happen.
      </p>
    </subsect>

    <!-- buffer read mode -->
    <subsect>
      <title>Buffer read mode</title>

      <p>
      The <code>read</code> method with an integer argument, returns a
      buffer with at least the number of bytes specified as an
      argument. This method is particularly useful when the contents
      has a precise size. The method returns a <code>Buffer</code>
      object which can later be used to read, or transform
      bytes. Multi-byte conversion to number should use such
      approach. The <code>read</code> method does not necessarily
      returns the number of requested bytes. Once the buffer is
      returned, the <code>length</code> method can be used to check
      the buffer size. Note also the existence of the
      <code>to-string</code> method which returns a string
      representation of the buffer.
      </p>

      <example>
      # try to read 256 bytes
      const buf (is:read 256)
      # get the buffer size
      println (buf:length)
      # get a string representation
      println (buf:to-string)
      </example>
    </subsect>
  </section>

  <!-- file stream -->
  <section>
    <title>File stream</title>

    <p>
    The <code>afnix-sio</code> module provides two classes for file
    access. The <code>InputFile</code> class open a file for input. The 
    <code>OutputFile</code> class opens a file for output. The
    <code>InputFile</code> class is derived from the
    <code>Input</code> base class. The <code>OutputFile</code> class
    is derived from the <code>Output</code> class. By default an
    output file is created if it does not exist. If the file already
    exist, the file is truncated to 0. Another constructor for the
    output file gives more control about this behavior. It takes two
    boolean flags that defines the truncate and append mode.
    </p>

    <example>
    # load the module
    interp:library "afnix-sio"
    # create an input file by name
    const if (afnix:sio:InputFile "orig.txt")
    # create an output file by name
    const of (afnix:sio:OutputFile "copy.txt")
    </example>

    <!-- stream information -->
    <subsect>
      <title>Stream information</title>
      
      <p>
      Both <code>InputFile</code> and <code>OutputFile</code> supports
      the <code>get-name</code> method which returns the file name.
      </p>

      <example>
      println (if:get-name)
      println (of:get-name)
      </example>

      <p>
      Predicates are also available for these classes. The
      <code>input-file-p</code> returns true for an input file
      object.The <code>output-file-p</code> returns true for an output
      file object. 
      </p>

      <example>
      afnix:sio:input-p       if
      afnix:sio:output-p      of
      afnix:sio:input-file-p  if
      afnix:sio:output-file-p of
      </example>
    </subsect>

    <!-- reading and writing -->
    <subsect>
      <title>Reading and writing</title>

      <p>
      The <code>read</code> method reads a byte on an input
      stream. The <code>write</code> method writes one or more literal
      arguments on the output stream. The <code>writeln</code> method
      writes one or more literal arguments followed by a newline
      byte on the output stream. The <code>newline</code> method
      write a newline byte on the output stream. The
      <code>eof-p</code> predicate returns true for an input stream,
      if the stream is at the end. The <code>valid-p</code> predicate
      returns true if an input stream is in a valid state. With these
      methods, copying a file is a simple operation.
      </p>

      <example>
      # load the module and open the files
      interp:library "afnix-sio"
      const if (afnix:sio:InputFile "orig.txt")
      const of (afnix:sio:OutputFile "copy.txt")

      # loop in the input file and write
      while (if:valid-p) (of:write (if:read))
      </example>

      <p>
      The use of the <code>readln</code> method can be more
      effective. The example below is a simple cat program which take
      the file name an argument.
      </p>

      <example>
      # cat a file on the output terminal
      # usage: axi 0601.als file
 
      # get the io module
      interp:library "afnix-sio"
 
      # cat a file
      const cat (name) {
        const f (afnix:sio:InputFile name)
	while (f:valid-p) (println (f:readln))
	f:close
      }
 
      # get the file
      if (== 0 (interp:argv:length)) {
        errorln "usage: axi 0601.als file"
      } {
        cat (interp:argv:get 0)
      }
      </example>
    </subsect>
  </section>

  <!-- multiplexing -->
  <section>
    <title>Multiplexing</title>

    <p>
    I/O multiplexing is the ability to manipulate several streams at
    the same time and process one at a time. Although the use of
    threads reduce the needs for i/o multiplexing, there is still
    situations where they are needed. In other words, I/O multiplexing
    is identical to the <code>valid-p</code> predicate, except that it
    works with several stream objects.
    </p>

    <!-- selector object -->
    <subsect>
      <title>Selector object</title>

      <p>
      I/O multiplexing is accomplished with the <code>Selector</code>
      class. The constructor takes 0 or several stream arguments. The
      class manages automatically to differentiate between
      <code>Input</code> stream and <code>Output</code> streams. Once
      the class is constructed, it is possible to get the first stream
      ready for reading or writing or all of them. We assume in the
      following example that <code>is</code> and <code>os</code> are
      respectively an input and an output stream.
      </p>

      <example>
      # create a selector
      const slt (afnix:sio:Selector is)

      # at this stage the selector has one stream
      # the add method can add more streams
      slt:add os
      </example>

      <p>
      The <code>add</code> method adds a new stream to the
      selector. The stream must be either an <code>Input</code> and
      <code>Output</code> stream or an exception is raised. The
      <code>input-length</code> method returns the number of input
      streams in this selector. The <code>output-length</code> method
      returns the number of output streams in this selector. The
      <code>input-get</code> method returns the selector input stream
      by index. The <code>output-get</code> method returns the
      selector output stream by index.
      </p>
    </subsect>

    <!-- waiting for i/o event -->
    <subsect>
      <title>Waiting for i/o event</title>

      <p>
      The <code>wait</code> and <code>wait-all</code> methods can be
      used to detect a status change in the selector. Without argument
      both methods will block indefinitely until one stream
      change. With one integer argument, both method blocks until one
      stream change or the integer argument timeout expires. The
      timeout is expressed in milliseconds. Note that 0 indicates an
      immediate return. The <code>wait</code> method returns the first
      stream which is ready either for reading or writing depending
      whether it is an input or output stream. The
      <code>wait-all</code> method returns a vector with all streams
      that have changed their status. The <code>wait</code> method
      returns <code>nil</code> if the no stream have changed. 
      Similarly, the <code>wait-all</code> method returns an empty
      vector.
      </p>

      <example>
      # wait for a status change
      const is (slt:wait)
      # is is ready for reading - make sure it is an input one
      if (afnix:sio:input-p is) (is:read)
      </example>
      
      <p>
      A call to the <code>wait</code> method will always returns the
      first input stream.
      </p>
    </subsect>

    <!-- multiplexing policy -->
    <subsect>
      <title>Multiplexing policy</title>

      <p>
      When used with several input streams in a multi-threaded
      context, the selector behavior can becomes quite
      complicated. Either <code>wait</code> and <code>wait-all</code>
      methods check first the input streams push-back buffer. If one or
      several buffers are not empty, the method returns with these
      streams. During this operation, the input streams are locked, so
      no other thread can push-back a byte. The selector then
      checks for status change and unlock the streams. Note that the
      output streams are not locked. Note also that a thread which
      rely on the input stream 	push-back method to release a selector
      will result in a dead lock.
      </p>
    </subsect>
  </section>

  <!-- terminal streams -->
  <section>
    <title>Terminal streams</title>

    <p>
    Terminal streams are another kind of streams available in the
    standard i/o module. The <code>InputTerm</code>,
    <code>OutputTerm</code> and  <code>ErrorTerm</code> classes are
    low level classes used to read or write from or to the standard
    streams. The basic methods to read or write are the same as the
    file streams. Reading from the input terminal is not a good idea,
    since the class does not provide any formatting capability. One may
    prefer to use the <code>Terminal</code> class. The use of the
    output terminal or error terminal streams is convenient when the
    interpreter standard streams have been changed but one still need
    to print to the terminal. 
    </p>

    <!-- terminal class -->
    <subsect>
      <title>Terminal class</title>
      
      <p>
      The <code>Terminal</code> class combines an input stream and an
      output stream with some line editing capabilities. When the
      class is created, the constructed attempts to detect if the
      input and output streams are bounded to a terminal (i.e tty). If
      the line editing capabilities can be loaded (i.e non canonical
      mode), the terminal is initialized for line editing. Arrows,
      backspace, delete and other control sequences are available when
      using the <code>read-line</code> method. The standard methods
      like <code>read</code> or <code>readln</code> do not use the
      line editing features. When using a terminal, the prompt can be
      set to whatever the user wishes with the methods
      <code>set-primary-prompt</code> or
      <code>set-secondary-prompt</code>. A secondary prompt is
      displayed when the <code>read-line</code> method is called with
      the boolean argument false.
      </p>

      <example>
      const term (Terminal)
      term:set-primary-prompt "demo:"
      const line (term:read-line)
      errorln line
      </example>
    </subsect>

    <!-- error terminal -->
    <subsect>
      <title>Using the error terminal</title>

      <p>
      The <code>ErrorTerm</code> class is the most frequently used
      class for printing data on the standard error stream. <afnix/>
      provides the reserved keyword <code>error</code> or
      <code>errorln</code> to write on the interpreter error
      stream. If the interpreter error stream has been changed, the
      use of the <code>ErrorTerm</code> will provide the facility
      required to print directly on the terminal. The <code>cat</code>
      program can be rewritten to do exactly this.
      </p>

      <example>
      # cat a file on the error terminal
 
      # get the io module
      interp:library "afnix-sio"
 
      # cat a file
      const cat (name es) {
        const f (afnix:sio:InputFile name)
	while (f:valid-p) (es:writeln (f:readln))
	f:close
      }
      </example>
    </subsect>
  </section>
</chapter>
