(********************************************************************)
(*                                                                  *)
(*  dir.s7i       Implementation type to read directories as files  *)
(*  Copyright (C) 1994, 2005  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 "null_file.s7i";
include "osfiles.s7i";


(**
 *  [[file|File]] to read the contents of a directory.
 *)
const type: dirFile is sub null_file struct
    var string: path is "";
    var array string: dirArray is 0 times "";
    var integer: currLine is 0;
    var integer: currColumn is 0;
  end struct;


(**
 *  Open a ''dirFile''.
 *  @return the ''dirFile'' opened, or [[null_file#STD_NULL|STD_NULL]]
 *          if it could not be opened.
 *  @exception MEMORY_ERROR Not enough memory to convert the path
 *             to the system path type.
 *  @exception RANGE_ERROR 'path' does not use the standard path
 *             representation or it cannot be converted to the system
 *             path type.
 *)
const func file: openDir (in string: directoryPath) is func
  result
    var file: newFile is STD_NULL;
  local
    var dirFile: new_file is dirFile.value;
  begin
    new_file.path := "";
    new_file.currLine := 1;
    new_file.currColumn := 1;
    block
      new_file.dirArray := readDir(directoryPath);
      newFile := toInterface(new_file);
    exception
      catch FILE_ERROR:
        newFile := STD_NULL;
    end block;
  end func;


const func file: openDirPath (in string: directoryPath) is func
  result
    var file: newFile is STD_NULL;
  local
    var dirFile: new_file is dirFile.value;
  begin
    if directoryPath[length(directoryPath)] <> '/' then
      new_file.path := directoryPath & "/";
    else
      new_file.path := directoryPath;
    end if;
    new_file.currLine := 1;
    new_file.currColumn := 1;
    block
      new_file.dirArray := readDir(directoryPath);
      newFile := toInterface(new_file);
    exception
      catch FILE_ERROR:
        newFile := STD_NULL;
    end block;
  end func;


(**
 *  Read a file name from a ''dirFile''.
 *  When the function is left dirFile.bufferChar contains '\n' or
 *  [[char#EOF|EOF]].
 *  @return the file name.
 *)
const func string: getln (inout dirFile: aFile) is func
  result
    var string: stri is "";
  begin
    if aFile.currLine <= length(aFile.dirArray) then
      stri := aFile.path &
          aFile.dirArray[aFile.currLine][aFile.currColumn .. ];
      incr(aFile.currLine);
      aFile.currColumn := 1;
      aFile.bufferChar := '\n';
    else
      aFile.bufferChar := EOF;
    end if;
  end func;


(**
 *  Read a file name from a ''dirFile''.
 *  When the function is left dirFile.bufferChar contains '\n' or
 *  [[char#EOF|EOF]].
 *  @return the file name.
 *)
const func string: getwd (inout dirFile: aFile) is func
  result
    var string: stri is "";
  begin
    if aFile.currLine <= length(aFile.dirArray) then
      stri := aFile.path &
          aFile.dirArray[aFile.currLine][aFile.currColumn .. ];
      incr(aFile.currLine);
      aFile.currColumn := 1;
      aFile.bufferChar := '\n';
    else
      aFile.bufferChar := EOF;
    end if;
  end func;


const func string: gets (in dirFile: aFile, in integer: maxLength) is func
  result
    var string: stri is "";
  begin
    stri := "";
  end func;


(**
 *  Determine the end-of-file indicator.
 *  @return TRUE if the end-of-file indicator is set, FALSE otherwise.
 *)
const func boolean: eof (in dirFile: aFile) is
  return aFile.currLine > length(aFile.dirArray);


(**
 *  Determine if another filename can be read successfully.
 *  This function allows a file to be handled like an iterator.
 *  @return FALSE if 'getln' would return "", TRUE otherwise.
 *)
const func boolean: hasNext (in dirFile: aFile) is
  return aFile.currLine <= length(aFile.dirArray);