difftastic/vendored_parsers/tree-sitter-hare/example/fs.ha

178 lines
4.7 KiB
Plaintext

use errors;
use io;
use path;
// Closes a filesystem. The fs cannot be used after this function is called.
export fn close(fs: *fs) void = {
match (fs.close) {
null => void,
f: *closefunc => f(fs),
};
};
// Opens a file. If no flags are provided, the default read/write mode is
// RDONLY.
export fn open(fs: *fs, path: str, flags: flags...) (*io::stream | error) = {
return match (fs.open) {
null => errors::unsupported,
f: *openfunc => f(fs, path, flags...),
};
};
// Creates a new file and opens it for writing. If no flags are provided, the
// default read/write mode is WRONLY.
//
// Only the permission bits of the mode are used. If other bits are set, they
// are discarded.
export fn create(
fs: *fs,
path: str,
mode: mode,
flags: flags...
) (*io::stream | error) = {
mode = mode & 0o777;
return match (fs.create) {
null => errors::unsupported,
f: *createfunc => f(fs, path, mode, flags...),
};
};
// Removes a file.
export fn remove(fs: *fs, path: str) (void | error) = {
return match (fs.remove) {
null => errors::unsupported,
f: *removefunc => f(fs, path),
};
};
// Returns an iterator for a path, which yields the contents of a directory.
// Pass empty string to yield from the root. The order in which entries are
// returned is undefined.
export fn iter(fs: *fs, path: str) (*iterator | error) = {
return match (fs.iter) {
null => errors::unsupported,
f: *iterfunc => f(fs, path),
};
};
// Obtains information about a file or directory. If the target is a symlink,
// information is returned about the link, not its target.
export fn stat(fs: *fs, path: str) (filestat | error) = {
return match (fs.stat) {
null => errors::unsupported,
f: *statfunc => f(fs, path),
};
};
// Opens a new filesystem for a subdirectory. The subdirectory must be closed
// separately from the parent filesystem, and its lifetime can outlive that of
// its parent.
export fn subdir(fs: *fs, path: str) (*fs | error) = {
return match (fs.subdir) {
null => errors::unsupported,
f: *subdirfunc => f(fs, path),
};
};
// Creates a directory.
export fn mkdir(fs: *fs, path: str) (void | error) = {
return match (fs.mkdir) {
null => errors::unsupported,
f: *mkdirfunc => f(fs, path),
};
};
// Makes a directory, and all non-extant directories in its path.
export fn mkdirs(fs: *fs, path: str) (void | error) = {
let parent = path::dirname(path);
if (path != parent) {
match (mkdirs(fs, parent)) {
errors::exists => void,
err: error => return err,
void => void,
};
};
return mkdir(fs, path);
};
// Removes a directory. The target directory must be empty; see [rmdirall] to
// remove its contents as well.
export fn rmdir(fs: *fs, path: str) (void | error) = {
if (path == "") {
return errors::invalid;
};
return match (fs.rmdir) {
null => errors::unsupported,
f: *rmdirfunc => f(fs, path),
};
};
// Removes a directory, and anything in it.
export fn rmdirall(fs: *fs, path: str) (void | error) = {
let it = iter(fs, path)?;
for (true) match (next(it)) {
ent: dirent => {
if (ent.name == "." || ent.name == "..") {
continue;
};
let p = path::join(path, ent.name);
defer free(p);
switch (ent.ftype) {
mode::DIR => rmdirall(fs, p)?,
* => remove(fs, p)?,
};
},
void => break,
};
if (path != "") {
return rmdir(fs, path);
};
};
// Creates a directory and returns a subdir for it. Some filesystems support
// doing this operation atomically, but if not, a fallback is used.
export fn mksubdir(fs: *fs, path: str) (*fs | error) = {
return match (fs.mksubdir) {
null => {
mkdir(fs, path)?;
subdir(fs, path);
},
f: *mksubdirfunc => f(fs, path),
};
};
// Changes mode flags on a file or directory. Type bits are discared.
export fn chmod(fs: *fs, path: str, mode: mode) (void | error) = {
mode &= 0o755;
return match (fs.chmod) {
f: *chmodfunc => f(fs, path, mode),
null => abort(),
};
};
// Changes ownership of a file.
export fn chown(fs: *fs, path: str, uid: uint, gid: uint) (void | error) = {
return match (fs.chown) {
f: *chownfunc => f(fs, path, uid, gid),
null => abort(),
};
};
// Resolves a path to its absolute, normalized value. This consoldates ./ and
// ../ sequences, roots the path, and returns a new path. The caller must free
// the return value.
export fn resolve(fs: *fs, path: str) str = {
match (fs.resolve) {
f: *resolvefunc => return f(fs, path),
null => void,
};
abort(); // TODO
};
// Returns the next directory entry from an interator, or void if none remain.
// It is a programming error to call this again after it has returned void. The
// file stat returned may only have the type bits set on the file mode; callers
// should call [fs::stat] to obtain the detailed file mode.
export fn next(iter: *iterator) (dirent | void) = iter.next(iter);