(********************************************************************)
(*                                                                  *)
(*  enable_io.s7i Templates to enable file I/O for a given type     *)
(*  Copyright (C) 1989 - 2018  Thomas Mertes                        *)
(*                                                                  *)
(*  This file is part of the Seed7 Runtime Library.                 *)
(*                                                                  *)
(*  The Seed7 Runtime Library is free software; you can             *)
(*  redistribute it and/or modify it under the terms of the GNU     *)
(*  Lesser General Public License as published by the Free Software *)
(*  Foundation; either version 2.1 of the License, or (at your      *)
(*  option) any later version.                                      *)
(*                                                                  *)
(*  The Seed7 Runtime Library 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.  See the GNU Lesser General Public License for more    *)
(*  details.                                                        *)
(*                                                                  *)
(*  You should have received a copy of the GNU Lesser General       *)
(*  Public License along with this program; if not, write to the    *)
(*  Free Software Foundation, Inc., 51 Franklin Street,             *)
(*  Fifth Floor, Boston, MA  02110-1301, USA.                       *)
(*                                                                  *)
(********************************************************************)


include "file.s7i";


var file: IN is forward;
var file: OUT is forward;


(**
 *  Template function to define input functions for ''aType''.
 *  It defines the functions [[#read(inout_aType)|read]] and
 *  [[#readln(inout_aType)|readln]]. The functions read a
 *  whitespace terminated word respectively a line as
 *  [[string]]. Afterwards the ''parse'' operator is used to
 *  convert the ''string'' to an ''aType'' value. The functions
 *  [[#read(inout_file,inout_aType)|read]] and
 *  [[#readln(inout_file,inout_aType)|readln]] are defined with
 *  [[file]] argument and without [[file]] argument. The
 *  functions without [[file]] argument use the standard
 *  input file [[stdio#IN|IN]].
 *   const type: myType is ...
 *   const func myType is (attr myType) parse (in string: stri) is ...
 *   enable_input(myType);
 *  Afterwards it is possible to read ''myType'' values from a file.
 *)
const proc: enable_input (in type: aType) is func
  begin

    (**
     *  Read ''aVar'' from a word read from ''inFile''.
     *  Before reading the word it skips spaces and tabs. The function
     *  accepts words ending with " ", "\t", end-of-line or [[char#EOF|EOF]].
     *  The conversion to the type ''aType'' is done with the ''parse''
     *  operator. When the function is left inFile.bufferChar contains the
     *  word ending character (' ', '\t', '\n' or [[char#EOF|EOF]]).
     *  @exception RANGE_ERROR If the ''parse'' operator cannot convert
     *             the word to the type ''aType''.
     *)
    const proc: read (inout file: inFile, inout aType: aVar) is func
      begin
         aVar := aType parse getwd(inFile);
      end func;

   (**
     *  Read ''aVar'' from a word read from ''inFile'' or use ''defaultValue''.
     *  Before reading the word it skips spaces and tabs. The function
     *  accepts words ending with " ", "\t", end-of-line or [[char#EOF|EOF]].
     *  If the word is empty ''defaultValue'' is assigned to ''aVar''.
     *  The conversion to the type ''aType'' is done with the ''parse''
     *  operator. When the function is left inFile.bufferChar contains the
     *  word ending character (' ', '\t', '\n' or [[char#EOF|EOF]]).
     *  @exception RANGE_ERROR If the ''parse'' operator cannot convert
     *             the word to the type ''aType''.
     *)
    const proc: read (inout file: inFile, inout aType: aVar,
        in aType: defaultValue) is func
      local
        var string: stri is "";
      begin
        stri := getwd(inFile);
        if stri = "" then
          aVar := defaultValue;
        else
          aVar := aType parse stri;
        end if;
      end func;

    (**
     *  Read ''aVar'' from a line read from ''inFile''.
     *  The function reads a string up to end-of-line or [[char#EOF|EOF]].
     *  The conversion to the type ''aType'' is done with the ''parse''
     *  operator. When the function is left inFile.bufferChar contains the
     *  line ending character ('\n' or [[char#EOF|EOF]]).
     *  @exception RANGE_ERROR If the ''parse'' operator cannot convert
     *             the line to the type ''aType''.
     *)
    const proc: readln (inout file: inFile, inout aType: aVar) is func
      begin
        aVar := aType parse trimValue(aType, getln(inFile));
      end func;

    (**
     *  Read ''aVar'' from a line read from ''inFile'' or use ''defaultValue''.
     *  The function reads a string up to end-of-line or [[char#EOF|EOF]].
     *  If the line is empty ''defaultValue'' is assigned to ''aVar''.
     *  The conversion to the type ''aType'' is done with the ''parse''
     *  operator. When the function is left inFile.bufferChar contains the
     *  line ending character ('\n' or [[char#EOF|EOF]]).
     *  @exception RANGE_ERROR If the ''parse'' operator cannot convert
     *             the line to the type ''aType''.
     *)
    const proc: readln (inout file: inFile, inout aType: aVar,
        in aType: defaultValue) is func
      local
        var string: stri is "";
      begin
        stri := getln(inFile);
        if stri = "" then
          aVar := defaultValue;
        else
          aVar := aType parse trimValue(aType, stri);
        end if;
      end func;

    (**
     *  Read ''aVar'' from a word read from the standard input file [[stdio#IN|IN]].
     *  Before reading the word it skips spaces and tabs. The function
     *  accepts words ending with " ", "\t", end-of-line or [[char#EOF|EOF]].
     *  The conversion to the type ''aType'' is done with the ''parse''
     *  operator. When the function is left [[stdio#IN|IN]].bufferChar contains the
     *  word ending character (' ', '\t', '\n' or [[char#EOF|EOF]]).
     *  @exception RANGE_ERROR If the ''parse'' operator cannot convert
     *             the word to the type ''aType''.
     *)
    const proc: read (inout aType: aVar) is func
      begin
        read(IN, aVar);
      end func;

    (**
     *  Read ''aVar'' from a word read from standard input ([[stdio#IN|IN]]) or use ''defaultValue''.
     *  Before reading the word it skips spaces and tabs. The function
     *  accepts words ending with " ", "\t", end-of-line or [[char#EOF|EOF]].
     *  If the word is empty ''defaultValue'' is assigned to ''aVar''.
     *  The conversion to the type ''aType'' is done with the ''parse''
     *  operator. When the function is left [[stdio#IN|IN]].bufferChar contains the
     *  word ending character (' ', '\t', '\n' or [[char#EOF|EOF]]).
     *  @exception RANGE_ERROR If the ''parse'' operator cannot convert
     *             the word to the type ''aType''.
     *)
    const proc: read (inout aType: aVar, in aType: defaultValue) is func
      begin
        read(IN, aVar, defaultValue);
      end func;

    (**
     *  Read ''aVar'' from a line read from the standard input file [[stdio#IN|IN]].
     *  The function reads a string up to end-of-line or [[char#EOF|EOF]].
     *  The conversion to the type ''aType'' is done with the ''parse''
     *  operator. When the function is left [[stdio#IN|IN]].bufferChar contains the
     *  line ending character ('\n' or [[char#EOF|EOF]]).
     *  @exception RANGE_ERROR If the ''parse'' operator cannot convert
     *             the line to the type ''aType''.
     *)
    const proc: readln (inout aType: aVar) is func
      begin
        readln(IN, aVar);
      end func;

    (**
     *  Read ''aVar'' from a line read from standard input ([[stdio#IN|IN]]) or use ''defaultValue''.
     *  The function reads a string up to end-of-line or [[char#EOF|EOF]].
     *  If the line is empty ''defaultValue'' is assigned to ''aVar''.
     *  The conversion to the type ''aType'' is done with the ''parse''
     *  operator. When the function is left [[stdio#IN|IN]].bufferChar contains the
     *  line ending character ('\n' or [[char#EOF|EOF]]).
     *  @exception RANGE_ERROR If the ''parse'' operator cannot convert
     *             the line to the type ''aType''.
     *)
    const proc: readln (inout aType: aVar, in aType: defaultValue) is func
      begin
        readln(IN, aVar, defaultValue);
      end func;

  end func;


(**
 *  Template function to define output functions for ''aType''.
 *  It defines the functions [[#write(in_aType)|write]]
 *  and [[#writeln(in_aType)|writeln]] and the operators
 *  [[#(in_aType)lpad(in_integer)|lpad]], [[#(in_aType)rpad(in_integer)|rpad]]
 *  and [[#(in_string)<&(in_aType)|<&]]. The functions and operators use
 *  the ''str'' function to convert the ''aType'' value to a [[string]].
 *  Afterwards they call the corresponding function respectively operator
 *  for [[string]] values. The functions [[#write(inout_file,in_aType)|write]]
 *  and [[#writeln(inout_file,in_aType)|writeln]] are defined with [[file]]
 *  argument and without [[file]] argument. The functions without [[file]]
 *  argument write to the standard output file [[stdio#OUT|OUT]].
 *   const type: myType is ...
 *   const func string: str (in myType: myTypeValue) is ...
 *   enable_output(myType);
 *  Afterwards it is possible to write ''myType'' values to a file.
 *)
const proc: enable_output (in type: aType) is func
  begin

    (**
     *  Write ''aValue'' to the [[file]] ''outFile''.
     *)
    const proc: write (inout file: outFile, in aType: aValue) is func
      begin
        write(outFile, str(aValue));
      end func;

    (**
     *  Write ''aValue'' followed by end-of-line to the [[file]] ''outFile''.
     *)
    const proc: writeln (inout file: outFile, in aType: aValue) is func
      begin
        writeln(outFile, str(aValue));
      end func;

    (**
     *  Write ''aValue'' to the standard output file [[stdio#OUT|OUT]].
     *)
    const proc: write (in aType: aValue) is func
      begin
        write(OUT, aValue);
      end func;

    (**
     *  Write ''aValue'' followed by end-of-line to the standard output file [[stdio#OUT|OUT]].
     *)
    const proc: writeln (in aType: aValue) is func
      begin
        writeln(OUT, aValue);
      end func;

    (**
     *  Convert ''aValue'' to [[string]] and pad it with spaces at the left side.
     *  The [[string]] is padded up to a given length.
     *  @return ''aValue'' converted to string and left padded with spaces.
     *)
    const func string: (in aType: aValue) lpad (in integer: leng) is
      return str(aValue) lpad leng;

    (**
     *  Convert ''aValue'' to [[string]] and pad it with spaces at the right side.
     *  The [[string]] is padded up to a given length.
     *  @return ''aValue'' converted to string and right padded with spaces.
     *)
    const func string: (in aType: aValue) rpad (in integer: leng) is
      return str(aValue) rpad leng;

    (**
     *  Convert ''aValue'' to [[string]] and append it to ''stri''.
     *  This operator is intended for write statements.
     *  @return the result of the concatenation.
     *)
    const func string: (in string: stri) <& (in aType: aValue) is
      return stri & str(aValue);

    (**
     *  Convert ''aValue'' to [[string]] and append ''stri'' to it.
     *  This operator is intended for write statements.
     *  @return the result of the concatenation.
     *)
    const func string: (in aType: aValue) <& (in string: stri) is
      return str(aValue) & stri;

  end func;


(**
 *  Template function to define I/O functions for ''aType''.
 *  It defines the functions [[#read(inout_aType)|read]],
 *  [[#readln(inout_aType)|readln]], [[#write(in_aType)|write]]
 *  and [[#writeln(in_aType)|writeln]] and the
 *  operators [[#(in_aType)lpad(in_integer)|lpad]],
 *  [[#(in_aType)rpad(in_integer)|rpad]]
 *  and [[#(in_string)<&(in_aType)|<&]]. To do this it
 *  calls the templates [[#enable_input(in_type)|enable_input]] and
 *  [[#enable_output(in_type)|enable_output]].
 *   const type: myType is ...
 *   const func myType is (attr myType) parse (in string: stri) is ...
 *   const func string: str (in myType: myTypeValue) is ...
 *   enable_io(myType);
 *  Afterwards it is possible to read and write ''myType'' values.
 *)
const proc: enable_io (in type: aType) is func
  begin
    enable_input(aType);
    enable_output(aType);
  end func;


enable_io(char);
enable_io(integer);
enable_io(boolean);
enable_io(bitset);
enable_output(void);
# enable_output(type);
# enable_output(ACTION);