More methods

This commit is contained in:
Bruce Hill 2024-09-09 01:48:37 -04:00
parent 11c560ebcc
commit 6752c60f32
3 changed files with 51 additions and 1 deletions

View File

@ -1,4 +1,5 @@
// A lang for filesystem paths
#include <dirent.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>
@ -6,6 +7,7 @@
#include <stdint.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistr.h>
#include "array.h"
@ -59,12 +61,16 @@ public Text_t Path$relative(Path_t path, Path_t relative_to)
public bool Path$exists(Path_t path)
{
if (Text$matches(path, Pattern("~/{..}")))
path = Paths(Text$format("%s", getenv("HOME")), Text$slice(path, I(2), I(-1)));
struct stat sb;
return (stat(Text$as_c_string(path), &sb) == 0);
}
public bool Path$is_file(Path_t path, bool follow_symlinks)
{
if (Text$matches(path, Pattern("~/{..}")))
path = Paths(Text$format("%s", getenv("HOME")), Text$slice(path, I(2), I(-1)));
struct stat sb;
const char *path_str = Text$as_c_string(path);
int status = follow_symlinks ? stat(path_str, &sb) : lstat(path_str, &sb);
@ -74,6 +80,8 @@ public bool Path$is_file(Path_t path, bool follow_symlinks)
public bool Path$is_directory(Path_t path, bool follow_symlinks)
{
if (Text$matches(path, Pattern("~/{..}")))
path = Paths(Text$format("%s", getenv("HOME")), Text$slice(path, I(2), I(-1)));
struct stat sb;
const char *path_str = Text$as_c_string(path);
int status = follow_symlinks ? stat(path_str, &sb) : lstat(path_str, &sb);
@ -83,6 +91,8 @@ public bool Path$is_directory(Path_t path, bool follow_symlinks)
public bool Path$is_pipe(Path_t path, bool follow_symlinks)
{
if (Text$matches(path, Pattern("~/{..}")))
path = Paths(Text$format("%s", getenv("HOME")), Text$slice(path, I(2), I(-1)));
struct stat sb;
const char *path_str = Text$as_c_string(path);
int status = follow_symlinks ? stat(path_str, &sb) : lstat(path_str, &sb);
@ -92,6 +102,8 @@ public bool Path$is_pipe(Path_t path, bool follow_symlinks)
public bool Path$is_socket(Path_t path, bool follow_symlinks)
{
if (Text$matches(path, Pattern("~/{..}")))
path = Paths(Text$format("%s", getenv("HOME")), Text$slice(path, I(2), I(-1)));
struct stat sb;
const char *path_str = Text$as_c_string(path);
int status = follow_symlinks ? stat(path_str, &sb) : lstat(path_str, &sb);
@ -101,6 +113,8 @@ public bool Path$is_socket(Path_t path, bool follow_symlinks)
public bool Path$is_symlink(Path_t path)
{
if (Text$matches(path, Pattern("~/{..}")))
path = Paths(Text$format("%s", getenv("HOME")), Text$slice(path, I(2), I(-1)));
struct stat sb;
const char *path_str = Text$as_c_string(path);
int status = stat(path_str, &sb);
@ -110,6 +124,8 @@ public bool Path$is_symlink(Path_t path)
static void _write(Path_t path, Text_t text, int mode, int permissions)
{
if (Text$matches(path, Pattern("~/{..}")))
path = Paths(Text$format("%s", getenv("HOME")), Text$slice(path, I(2), I(-1)));
const char *path_str = Text$as_c_string(path);
int fd = open(path_str, mode, permissions);
if (fd == -1)
@ -134,6 +150,8 @@ public void Path$append(Path_t path, Text_t text, int permissions)
public Text_t Path$read(Path_t path)
{
if (Text$matches(path, Pattern("~/{..}")))
path = Paths(Text$format("%s", getenv("HOME")), Text$slice(path, I(2), I(-1)));
int fd = open(Text$as_c_string(path), O_RDONLY);
if (fd == -1)
fail("Could not read file: %k (%s)", &path, strerror(errno));
@ -174,6 +192,8 @@ public Text_t Path$read(Path_t path)
public void Path$remove(Path_t path, bool ignore_missing)
{
if (Text$matches(path, Pattern("~/{..}")))
path = Paths(Text$format("%s", getenv("HOME")), Text$slice(path, I(2), I(-1)));
const char *path_str = Text$as_c_string(path);
struct stat sb;
if (lstat(path_str, &sb) != 0) {
@ -194,10 +214,39 @@ public void Path$remove(Path_t path, bool ignore_missing)
public void Path$create_directory(Path_t path, int permissions)
{
if (Text$matches(path, Pattern("~/{..}")))
path = Paths(Text$format("%s", getenv("HOME")), Text$slice(path, I(2), I(-1)));
if (mkdir(Text$as_c_string(path), (mode_t)permissions) != 0)
fail("Could not create directory: %k (%s)", &path, strerror(errno));
}
public Array_t Path$children(Path_t path, bool include_hidden)
{
if (Text$matches(path, Pattern("~/{..}")))
path = Paths(Text$format("%s", getenv("HOME")), Text$slice(path, I(2), I(-1)));
struct dirent *dir;
Array_t children = {};
const char *path_str = Text$as_c_string(path);
size_t path_len = strlen(path_str);
DIR *d = opendir(path_str);
if (!d)
fail("Could not open directory: %k (%s)", &path, strerror(errno));
if (path_str[path_len-1] == '/')
--path_len;
while ((dir = readdir(d)) != NULL) {
if (!include_hidden && dir->d_name[0] == '.')
continue;
if (streq(dir->d_name, ".") || streq(dir->d_name, ".."))
continue;
Path_t child = Text$format("%.*s/%s", path_len, path_str, dir->d_name);
Array$insert(&children, &child, I(0), sizeof(Path_t));
}
closedir(d);
return children;
}
public const TypeInfo Path$info = {
.size=sizeof(Path_t),
.align=__alignof__(Path_t),

View File

@ -22,12 +22,12 @@ bool Path$is_directory(Path_t path, bool follow_symlinks);
bool Path$is_pipe(Path_t path, bool follow_symlinks);
bool Path$is_socket(Path_t path, bool follow_symlinks);
bool Path$is_symlink(Path_t path);
void Path$write(Path_t path, Text_t text, int permissions);
void Path$append(Path_t path, Text_t text, int permissions);
Text_t Path$read(Path_t path);
void Path$remove(Path_t path, bool ignore_missing);
void Path$create_directory(Path_t path, int permissions);
Array_t Path$children(Path_t path, bool include_hidden);
extern const TypeInfo Path$info;

View File

@ -250,6 +250,7 @@ env_t *new_compilation_unit(CORD *libname)
)},
{"Path", Type(TextType, .lang="Path", .env=namespace_env(env, "Path")), "Text_t", "Text$info", TypedArray(ns_entry_t,
{"append", "Path$append", "func(path:Path, text:Text, permissions=0o644_i32)"},
{"children", "Path$children", "func(path:Path, include_hidden=no)->[Path]"},
{"create_directory", "Path$create_directory", "func(path:Path, permissions=0o644_i32)"},
{"escape_text", "Path$escape_text", "func(text:Text)->Path"},
{"exists", "Path$exists", "func(path:Path)->Bool"},