std1.0.0-beta-7 SafeC docs
// SafeC Standard Library — Directories and file system entries (hosted)
//
// Listing, creating, copying and removing directories, and querying what a
// path names. Backends: dir_posix.sc (Linux, macOS, BSD) and dir_win32.sc
// (Windows); the tree operations (create_all, walk, copy, remove_all) are
// shared, in dir.sc. Paths are '/'-separated (Windows accepts '/' too);
// see std/path.h for joining and normalizing them.
//
//   ?&Dir d = Dir::open("docs");
//   match (d) {
//       case some(dir): {
//           struct DirEntry e = DirEntry::new();
//           while (dir.next(&e)) { println(e.name.as_ptr()); }
//           e.free();
//           dir.close();
//       }
//       case null: { eprintln("cannot open docs/"); }
//   }
//
//   struct Vec<struct String> files = Vec::new();
//   dir_walk("docs", &files);            // every file below docs/, sorted
//   dir_copy_tree("public", "dist");     // cp -R public/. dist/
//
// All int-returning operations return 1 on success and 0 on failure.
#pragma once
#include <std/collections/string.h>
#include <std/collections/vec.h>

// What a path or directory entry names.
#define DIR_NONE  0   // nothing there (file_stat failed)
#define DIR_FILE  1   // a regular file
#define DIR_DIR   2   // a directory
#define DIR_LINK  3   // a symbolic link (not followed) / Windows reparse point
#define DIR_OTHER 4   // device, pipe, socket, ...

namespace std {

struct DirEntry {
    struct String name;   // the entry's own name (no directory part)
    int kind;             // DIR_FILE / DIR_DIR / DIR_LINK / DIR_OTHER

    static struct DirEntry new();
    void drop();
    void free() consume;   // = drop()
};

// An open directory listing.
struct Dir {
    int opaque_;   // never constructed by SafeC code; only referenced

    // Opens 'path' for listing; null if it isn't a readable directory.
    static ?&Dir open(const &char path);

    // Reads the next entry into 'out' (its name is replaced). "." and ".."
    // are skipped. Order is whatever the OS returns. 1 if an entry was
    // read, 0 at the end of the listing.
    int  next(&DirEntry out);

    // Closes the listing (the handle is invalid afterwards).
    void drop();
    void close() consume;   // = drop()
};

// What file_stat reports.
struct FileStat {
    int       kind;      // DIR_NONE .. DIR_OTHER (a link itself, not its target)
    long long size;      // bytes (regular files)
    long long mtime_ns;  // last modification, ns since the Unix epoch
                         // (0 where the platform backend can't tell: see dir_posix.sc)
};

// Fills 'out' for 'path' (symbolic links are not followed). 0, with
// out.kind = DIR_NONE, if nothing is there.
int file_stat(const &char path, &FileStat out);

// The kind of 'path' (DIR_NONE when nothing is there).
int path_kind(const &char path);

// 1 if something exists at 'path'.
int path_exists(const &char path);

// Creates one directory (its parent must exist). 1 also when it already
// exists as a directory.
int dir_create(const &char path);

// Creates 'path' and every missing parent (mkdir -p).
int dir_create_all(const &char path);

// Removes an empty directory.
int dir_remove(const &char path);

// Removes 'path' and everything below it (rm -rf); links are removed, not
// followed. 1 also when nothing was there.
int dir_remove_all(const &char path);

// Deletes a file (or a link).
int file_remove(const &char path);

// Copies the file 'from' to 'to' (created or truncated).
int file_copy(const &char from, const &char to);

// Appends the path of every file below 'root', relative to it and
// '/'-separated ("guide/intro.md"), to 'out', sorted. Directories are
// descended into (links to them are not); hidden entries are included.
int dir_walk(const &char root, &Vec<struct String> out);

// Copies everything inside 'from' into 'to' (cp -R from/. to/), creating
// 'to' and subdirectories as needed; existing files are overwritten.
int dir_copy_tree(const &char from, const &char to);

} // namespace std