# 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).

## Managing multiple walk contexts

In a naked [fs/core], there can only be one walking context at once, ever. It's
ok for finding and opening files as well as creating and removing them, but for
copying and moving around, it's insufficient: we need to have two concurrent
walking contexts.

This unit provides them. We call them "source" and "destination" walking
contexts. They are opaque buffers big enough to store everything one needs to
remember where we were walking at, that is:

* curfs
* walkcontext
* walkpath
* walkname
* walksize
* walkdir?

What happens is that you copy from/to those context using "walksrc" and
"walkdst". What this does is that it saves the current walking context in the
"other" buffer and then restores the specified buffer in the walk context.

For instance, "walksrc" saves current context in the "dst" buffer and then
restores the "src" buffer.

If a restored buffer is empty (used for the first time), the initial "restore"
is a noop.

Additionally, there is also "walk>r" and "r>walk", which store current context
in RS. This is useful for recursion.

## Words operating on source and destination

The "big" words in this unit operate on both a source and destination. Words
like "copyfile", "copydir" etc. These word don't take paths as parameters, they
expect the "src" and "dst" contexts to be set. For example, this is how you
call "copyfile":

  walksrc p"foo/bar.fs"
  walkdst p"foo/baz.fs"
  copyfile

Same thing for directories. When we say "copyall", we mean to copy children of
the source walking context to the destination walking context, both of which
must exist. If you want to create destinations on the fly, use pf" and pd":

  walksrc p"path/to/srcdir"
  walkdst pd"a:maybenew"
  copyall

## API

### Words

walksrc ( -- )
  Save current walking context to "dst" buffer and restore "src" context.

  When the "src" buffer is uninitialized, the "restore" part is a noop.

walkdst ( -- )
  Save current walking context to "src" buffer and restore "dst" context.

  When the "dst" buffer is uninitialized, the "restore" part is a noop.

p"..." ( -- ) *I*
  Lookup string using "lookup#".

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

pf"..." ( -- id fs ) *I*
  Like p"...", but with "ensurefile".

pd"..." ( -- id fs ) *I*
  Like pf"...", but with "ensuredir".

.walkpath ( -- )
  Print the absolute path, including FS mapped letter, corresponding to the
  target of the current walk context.

ensurepath ( dir? str -- )
  Tries to look up "str" relatively (like "lookuprel"). If not found, ensure
  that directories leading to the final element of that path are created, then
  create the last element as a file or directory depending on the "dir?" flag.

  If "path" already exists and is of a different file/dir kind as the one
  requested, abort with error.

ensurefile ( str -- )
  Shortcut for ensurepath with dir?=0, but *not* for a relative path. The lookup
  being done here, unlike in "ensurepath", is absolute.

ensuredir ( str -- )
  Like "ensurefile", for with dir?=1.

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

  Abort if source or dest is not a file.

copyall ( -- )
  Recursively copy all elements in source to destination.

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

  Abort if source or dest is not a directory.

copydirs ( -- )
  Like "copyall", but ignore files in current directory. When doing recursion,
  it becomes exactly like "copyall".

copyfiles ( -- )
  Like "copyall", but only copy files. This implies that there is no recursion.

copylist ( stringlist -- )
  Lookup each path in "stringlist" and copy them to [fs/sh] destination,
  recreating the same paths there.

  When the path in the stringlist is a directory, use "copydir". Otherwise,
  "copyfile".

listdir ( -- )
  Ensure that source path is a directory, 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.

listtree ( -- )
  Does a recursive "listdir", that is, whenever it lists a directory, list that
  directory's content underneath with a 1 space indent.
