# Filesystem "shell" utilities

Words in this unit are a diverse collection of useful FS-related tools that
are generally used directly by the operator (rather than as a library). In
other words, it's a collection of tools too fancy for [fs/core].

## Path literals

There are two words for path/file shortcuts: p" and f". These literals work both
in runtime and compile time mode. In compile time mode, it's not the FS ID that
is compiled, but the path string. In other words, path finding isn't done at
compile time but at runtime.

p"foo" is a shortcut for:

  "foo" lookup#

f"foo" is a shortcut for:

  p"foo" open

then, on top of that is pf"..." and pd"..." which are like p"..." except that
they "ensure" their path (create it if it doesn't exist).

## Global source and destination

Some words operate on both source and destination paths, and because those are
FSID/FS pairs, this can make the calling semantics quite hairy in some cases.

This is why this unit has global values for this, which you set with "src!" and
"dst!" which both have the signature ( id fs -- ). Then, you can call the
appropriate operation word with a lighted calling semantic. Example:

  p"foo/bar.fs" src! p"foo/baz.fs" dst! copyfile

This implies that all operation words on this unit operate on a source and
destination that already exist.

## API

src! ( id fs -- )
  Set global source path.

dst! ( id fs -- )
  Set global destination path.

p"..." ( -- id fs ) *I*
  Lookup string and yield the corresponding FSID/FS pair. Aborts if path doesn't
  exist.

f"..." ( -- file ) *I*
  Shortcut for p"..." open.

pf"..." ( -- id fs ) *I*
  Like p"...", but if path doesn't exist, create as a file.

pd"..." ( -- id fs ) *I*
  Like pf"...", but for directories.

path ( id fs -- str )
  Yield the string path corresponding to specified FSID.

ensurepath ( str dirid fs -- id f )
  Run a "lookuprel". If found, "id" is the result of "lookup" and f=1. If not,
  f=0 and "id" is the ID of the directory where such a path would live. If
  "path" has non-leaf (the last component of the path) elements that don't
  exist, a new directory is created for each of them.

  For example, "path/to/name" bootfs ensurepath would, on a bootfs that doesn't
  contain a "path" directory, create a "path" directory, then a "to" in it, then
  yield f=0 with "id" being the FSID of the "to" directory freshly created.

ensurepathrel ( dir? str dirid fs -- id fs )
  Calls "ensurepath" and, if it doesn't already exist, create a file or
  directory (depending on the "dir?" flag) at that path.
  Then, yield its "id fs" pair.

  If ensurepath yields f=1 but that the resulting id is of a different file/dir
  kind as the one requested, abort with error.

ensurefile ( str -- id fs )
  Shortcut for ensurepathrel with dir?=0 and pathfs lookup.

ensuredir ( str -- id fs )
  Shortcut for ensurepathrel with dir?=1 and pathfs lookup.

?child ( name dirid fs -- id 1 OR name dirid fs 0 )
  Call "child" and possibly yield the resulting ID. If not found, PS is kept
  intact. This makes it convenient to subsequently call "newfile" or "newdir".

copyfile ( -- )
  Copy source file to destination file.

copydir ( -- )
  Recursively copy source directory to destination.

  While running recursion, it ensures that the destination path exists before
  copying.

listdir ( path -- )
  Lookup specified path, then print all children of that path, one per line,
  with that path as a prefix (so, we print full absolute paths).

  For each line, either the size of the file or "[DIR]" is printed text to it.

  Children can be files and/or subdirectories.

filesonly ( ... n -- ... n )
  Given a PS list of FSIDs residing on source FS, keep only those who represent
  files.

dirsonly ( ... n -- ... n )
  Given a PS list of FSIDs residing on source FS, keep only those who represent
  directories.

ncopy ( ... n -- )
  Copy files in the supplied PS list of FSIDs, living in source FS, to
  destination. Destination paths are recreated using "ensurepathrel" [fs/core].
  Files are copied using "copyfile", directories are copied using "copydir".

  Example usage:

  p"a:" dst! p"" 2dup src! children dirsonly ncopy

  Limitation: for now, only full paths can be recreated in destination. For
  example, if you use 'p"foo" children' as a source, the "foo" directory will
  be recreated in your destination. Eventually, the API will change to allow for
  the avoidance of this.
