/*
 *  filesystem.sli
 *
 *  This file is part of NEST.
 *
 *  Copyright (C) 2004 The NEST Initiative
 *
 *  NEST is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  NEST 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 General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with NEST.  If not, see <http://www.gnu.org/licenses/>.
 *
 */

/filesystem /SLI ($Revision: 9979 $) provide-component
/filesystem /C++ (7610) require-component


/FileNames_s
{
  regcomp
  FileNames_r
} def

/FileNames_r
{
  << >> begin
    /Mask Set
    Directory
    FileNames_
    :sort
    /FilesList [] def
    {
      dup Mask exch regex_find
      {FilesList exch append  /FilesList Set}
      {pop} ifelse
    } forall
    FilesList
  end
} def

/* BeginDocumentation
 Name: FileNames - return contents of current working directory
 Synopsis: string FileNames -> array
           regex  FileNames -> array
 Description: FileNames reads contents of current working directory
    via POSIX commands. Only files matching the regular expression
    mask set in string/regex are used.
 Parameters: string : a mask converted to the regex
             regex  : the regular expression used to filter files
             array  : an array of strings containing matched files
 Examples: (.*) FileNames -> all files of current directory
           Remember that POSIX regex and those used by ls are not
           necessarily the same !
 Bugs: see remarks
 Author: Hehl
 FirstVersion: Oct 12th 1999
 Remarks: Sorting of files done by :sort, a dummy UNIX sorter which
    is far from protable!
 SeeAlso: SetDirectory, Directory, ls, cd
*/ 

/FileNames trie
  [/stringtype] /FileNames_s load addtotrie
  [/regextype] /FileNames_r load addtotrie
def

/* BeginDocumentation
 Name: ls - print contents of current working directory
 Synopsis: ls -> -
 Description: Prints the contents of the working directory on stdout.
    Don't mess it up with UNIX ls, this is POSIX. No parameters can 
    be set like -l, -a !
    Any files starting with a . are NOT shown by default.
    Use FileNames if you need them.
 Parameters: -
 Examples: There's only one usage: 
           ls -> see contents of current working directory
 Bugs: 
 Author: Hehl
 FirstVersion: Oct 12th 1999
 Remarks: This is in fact not much more than a wrapper to FileNames,
          in addition using a regex to filter out ".anything" files.
 SeeAlso: FileNames, SetDirectory, Directory, MakeDirectory, RemoveDirectory, cd
*/ 

/ls  {(^[^\\.]) FileNames {=} forall} def

/* BeginDocumentation
 Name: SetDirectory - Change working directory
 Synopsis: string SetDirectory -> boolean
 Description: Changes the working directory to the given argument,
    e.g. the value of '.' in the UNIX world.
 Parameters: string : The new working directory.
             boolean: A flag if operation succeded.
 Examples: (/home/MyName) SetDirectory -> Commands like ofstream, 
                                          FileNames etc. take
                                          /home/MyName as a default.
           (..) SetDirectory           -> Flip to parent directory.
 Bugs: -
 Author: Hehl
 FirstVersion: Oct 12th 1999
 Remarks: 
 SeeAlso: FileNames, Directory, MakeDirectory, RemoveDirectory, cd, ls
*/ 

/SetDirectory trie
  [/stringtype] /SetDirectory_ load addtotrie
def

/* BeginDocumentation
 Name: cd - Change working directory
 Synopsis: string cd -> -
 Description: Changes the working directory to the given argument,
              e.g. the value of '.' in the UNIX world.
 Parameters: string : The new working directory.
             boolean: A flag if operation succeded.
 Examples: (..) cd  -> Flip to parent directory.
 Diagnostics: Raises /UnknownDirectory, if SetDirectory fails. 
 Bugs: -
 Author: Hehl
 FirstVersion: Oct 12th 1999
 Remarks: This is a wrapper to SetDirectory
 SeeAlso: FileNames, Directory, SetDirectory, MakeDirectory, RemoveDirectory, ls
*/ 

/cd {dup SetDirectory not {/cd /UnknownDirectory raiseerror} if pop} def

/* BeginDocumentation
 Name: pwd - Print working directory
 Synopsis: pwd -> -
 Description: Prints the working directory.
	      For UNIX compatibility.
 Parameters: -
 Bugs: -
 Author: Schrader
 Remarks: This is a wrapper to Directory
 SeeAlso: Directory, SetDirectory, MakeDirectory, RemoveDirectory, ls
*/ 

/pwd {Directory =} def

/* BeginDocumentation
 Name: MoveFile - Rename a file
 Synopsis: string1 string2 MoveFile -> boolean
 Description: Rename a file, e.g. link the file to the new name
     and unlink the old filename. If this unlink was the only link
     to the file, the old file is effectively deleted.
     Note that this is only guaranteed to work if new and old filename
     refer to the same directory. Renaming over different directories
     might work, but that's not POSIX and thus not portable.
 Parameters: string1 : Old File
             string2 : NewFile
             boolean : A flag if operation succeded.
 Examples: (Simulation1) (obsolete) MoveFile -> The File Simulation1
                                                is now called obsolete
 Bugs: -
 Author: Hehl
 FirstVersion: Oct 12th 1999
 Remarks: Since POSIX rename() did not work for some obscur reasons,
     MoveFile indeed works by linking the new filename and unlinking
     the old one!
     But that's exactly what rename() is supposed to do, no damage done...
 SeeAlso: CopyFile, ofstream, ifstream, DeleteFile, FileNames, MakeDirectory, RemoveDirectory
*/ 

/MoveFile trie
  [/stringtype /stringtype] /MoveFile_ load addtotrie
def








/* BeginDocumentation
 Name: CopyFile - Copy a file
 Synopsis: (sourcefilename) (targetfilename) CopyFile -> -
 Description: Copy a file.
 Examples: (Simulation1) (Sim1Backup) CopyFile
 Author: R Kupper
 FirstVersion: 06 aug 2008
 Diagnostics: Issues informative message and
   raises /BadIO if file cannot be copied for any reason.
 SeeAlso: MoveFile, ofstream, ifstream, DeleteFile, FileNames, MakeDirectory, RemoveDirectory
*/ 

/CopyFile trie
  [/stringtype /stringtype] /CopyFile_ load addtotrie
def


/* BeginDocumentation
 Name: DeleteFile - Delete a file
 Synopsis: string DeleteFile -> boolean
 Description: Delete a file defined by it's filename. To be exact, it
    is unlinked, so if it link to another file, only the link and not
    the file is removed. (This is at least what is supposed to happen 
    if your POSIX is really POSIX ...)
    Mind that regex arguments like (*) DeleteFile are NOT supported.
    This was done for safety reasons because the regex flavour of 
    POSIX is not exactly like what one might be used to from UNIX, 
    which could easily end in a disaster.
 Parameters: string : Filename of file to be deleted.
             boolean : A flag if operation succeded.
 Examples: (DontNeedYou) DeleteFile -> True, and DontNeedYou is removed
                                       from your working directory
                                       if this file existed,
                                       otherwise False.
 Bugs: -
 Author: Hehl
 FirstVersion: Oct 12th 1999
 Remarks: -
 SeeAlso: CopyFile, ofstream, ifstream, MoveFile, FileNames, MakeDirectory, RemoveDirectory
*/ 

/DeleteFile trie
  [/stringtype] /DeleteFile_ load addtotrie
def

/* BeginDocumentation
 Name: MakeDirectory - Create a new directory
 Synopsis: string MakeDirectory -> boolean
 Description: MakeDirectory creates the named subdirectory of your
    current working directory. 
 Parameters: string : Name of new subdirectory
             boolean : A flag if operation succeded.
 Examples: (NewSubDir) MakeDirectory -> ./NewSubDir created
 Bugs: -
 Author: Hehl
 FirstVersion: Oct 12th 1999
 Remarks: -
 SeeAlso: FileNames, MoveDirectory, RemoveDirectory
*/ 

/MakeDirectory trie
  [/stringtype] /MakeDirectory_ load addtotrie
def

/* BeginDocumentation
 Name: RemoveDirectory - Delete a directory
 Synopsis: string RemoveDirectory -> boolean
 Description: RemoveDirectory deletes the named subdirectory of your
    current working directory, provided it is empty.
 Parameters: string : Name of subdirectory to be deleted.
             boolean : A flag if operation succeded.
 Examples: (RemoveMeDir) RemoveDirectory -> True, and
            ./RemoveMeDir does not longer exist, provided it ever did
            and was empty.
 Bugs: -
 Author: Hehl
 FirstVersion: Oct 12th 1999
 Remarks: -
 SeeAlso: FileNames, MoveDirectory, RemoveDirectory
*/ 

/RemoveDirectory trie
  [/stringtype] /RemoveDirectory_ load addtotrie
def

/* BeginDocumentation
 Name: MoveDirectory - Rename a directory
 Synopsis: string1 string2 MoveDirectory -> boolean
 Description: MoveDirectory unlinks old directory name and links to
      the new name. This is only possible if this directory is empty.
 Parameters: string1 : Name of old directory
             string2 : Name of new directory
             boolean : A flag if operation succeded.
 Examples: (NewSubDir) (Other) MoveDirectory -> True, and ./NewSubDir
            is now called ./Other, provided it exists and is empty.
 Bugs: -
 Author: Hehl
 FirstVersion: Oct 12th 1999
 Remarks: This operator in fact only sequentially calls
          RemoveDirectory, MoveDirectory
          POSIX statet this would be the same operator like renaming
          a file, but that did not work.
 SeeAlso: FileNames, MoveDirectory, RemoveDirectory, MoveFile
*/ 

/MoveDirectory trie
  [/stringtype /stringtype] {MakeDirectory pop RemoveDirectory pop} addtotrie
def

/CompareFiles trie
  [/stringtype /stringtype] /CompareFiles_s_s load addtotrie
def


/* BeginDocumentation
  Name: dirname - strip last component from file name
  Synopsis: string dirname -> string
  Description: Print NAME with its trailing /component removed;
      if NAME contains no /'s, output `.' (meaning the current directory).
  Parameters: string: Name of the directory
  Examples: (./../test/dir/foo.sli) dirname -> (./../test/dir)
  FirstVersion: November 2012
  Author: Yury V. Zaytsev and Jochen M. Eppler
*/

/dirname {

  /pth exch def

  mark

    % Special cases of leading directory separators
    pth (/) eq
      pth (//) eq or
      pth (///) eq or
        { (/) } case

    % Special cases of lacking directory separators
    pth (/) searchif not
      pth () eq or
      pth (.) eq or
      pth (..) eq or
        { (.) } case

    {
      % General case
      (/{1,3}[^/]+/{0,3}$) regexdict/REG_EXTENDED :: regcomp () pth regex_replace

      % Special case of non-empty path plus leading directory separator
      dup () eq { pop (/) } if
    }

  switchdefault

} def