Remove example module for files
This commit is contained in:
parent
dad567bfc8
commit
43c595cafe
@ -2,7 +2,6 @@
|
||||
|
||||
- [coroutine.tm](coroutine.tm): A library for coroutines similar to Lua's
|
||||
(using [libaco](https://libaco.org)).
|
||||
- [file.tm](file.tm): A file handling module.
|
||||
- [game/](game/): An example game using raylib.
|
||||
- [ini.tm](ini.tm): An INI configuration file reader tool.
|
||||
- [vectors.tm](vectors.tm): A math vector library.
|
||||
|
244
examples/file.tm
244
examples/file.tm
@ -1,244 +0,0 @@
|
||||
# A module for interacting with files
|
||||
extern builtin_last_err:func()->Text
|
||||
|
||||
use <fcntl.h>
|
||||
use <stdio.h>
|
||||
use <sys/mman.h>
|
||||
use <sys/stat.h>
|
||||
use <unistd.h>
|
||||
use <unistr.h>
|
||||
use libunistring.so
|
||||
|
||||
enum FileReadResult(Success(text:Text), Failure(reason:Text))
|
||||
|
||||
func _wrap_with_finalizer(obj:@Memory, finalizer:func(obj:@Memory))->@Memory:
|
||||
return inline C (
|
||||
({
|
||||
FILE **wrapper = GC_MALLOC(sizeof(FILE*));
|
||||
*wrapper = $obj;
|
||||
GC_register_finalizer(wrapper, (void*)$finalizer.fn, wrapper, NULL, NULL);
|
||||
wrapper;
|
||||
})
|
||||
):@Memory
|
||||
|
||||
func _close_file(fp:@Memory):
|
||||
inline C {
|
||||
if (*(FILE**)$fp)
|
||||
fclose(*(FILE**)$fp);
|
||||
*(FILE**)$fp = NULL;
|
||||
}
|
||||
|
||||
func read(path:Text)->FileReadResult:
|
||||
inline C {
|
||||
int fd = open(Text$as_c_string($path), O_RDONLY);
|
||||
if (fd != -1) {
|
||||
struct stat sb;
|
||||
if (fstat(fd, &sb) == -1) {
|
||||
const char *mem = mmap(NULL, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
|
||||
char *gc_mem = GC_MALLOC_ATOMIC(sb.st_size+1);
|
||||
memcpy(gc_mem, mem, sb.st_size);
|
||||
gc_mem[sb.st_size] = '\0';
|
||||
close(fd);
|
||||
return file$FileReadResult$tagged$Success(Text$from_strn(gc_mem, sb.st_size));
|
||||
} else {
|
||||
const int chunk_size = 256;
|
||||
char *buf = GC_MALLOC_ATOMIC(chunk_size);
|
||||
Text_t contents = Text("");
|
||||
size_t just_read;
|
||||
do {
|
||||
just_read = read(fd, buf, chunk_size);
|
||||
if (just_read > 0) {
|
||||
if (u8_check(buf, just_read) != NULL)
|
||||
break;
|
||||
contents = Texts(contents, Text$from_strn(buf, just_read));
|
||||
buf = GC_MALLOC_ATOMIC(chunk_size);
|
||||
}
|
||||
} while (just_read > 0);
|
||||
close(fd);
|
||||
return file$FileReadResult$tagged$Success(contents);
|
||||
}
|
||||
}
|
||||
}
|
||||
return Failure(builtin_last_err())
|
||||
|
||||
func resolve_path(path:Text, relative_to=".")->Text:
|
||||
path_c_str := path:as_c_string()
|
||||
relative_to_c_str := relative_to:as_c_string()
|
||||
inline C {
|
||||
extern char *resolve_path(char*, char*, char*);
|
||||
}
|
||||
resolved := inline C (
|
||||
resolve_path($path_c_str, $relative_to_c_str, $relative_to_c_str)
|
||||
): CString
|
||||
return Text.from_c_string(resolved)
|
||||
|
||||
func relative_path(path:Text, relative_to=".")->Text:
|
||||
path = resolve_path(path, relative_to)
|
||||
|
||||
relative_to = resolve_path(relative_to)
|
||||
if path:matches($/{start}$relative_to$"/"{..}/):
|
||||
return path:slice(relative_to.length + 2, -1)
|
||||
|
||||
return path
|
||||
|
||||
struct WriteHandle(_file:@Memory):
|
||||
func write(h:WriteHandle, text:Text, flush=yes):
|
||||
inline C {
|
||||
fputs(Text$as_c_string($text), *(FILE**)$h.$_file);
|
||||
if ($flush)
|
||||
fflush(*(FILE**)$h.$_file);
|
||||
}
|
||||
|
||||
func close(h:WriteHandle):
|
||||
_close_file(h._file)
|
||||
|
||||
enum FileWriteResult(Open(h:WriteHandle), Failure(reason:Text))
|
||||
func writing(path:Text)->FileWriteResult:
|
||||
maybe_f := inline C (
|
||||
fopen(Text$as_c_string($path), "w")
|
||||
):@Memory?
|
||||
when maybe_f is @f:
|
||||
obj := _wrap_with_finalizer(f, _close_file)
|
||||
return Open(WriteHandle(obj))
|
||||
else:
|
||||
return Failure(builtin_last_err())
|
||||
|
||||
func appending(path:Text)->FileWriteResult:
|
||||
maybe_f := inline C (
|
||||
fopen(Text$as_c_string($path), "a")
|
||||
):@Memory?
|
||||
when maybe_f is @f:
|
||||
return Open(WriteHandle(f))
|
||||
else:
|
||||
return Failure(builtin_last_err())
|
||||
|
||||
struct LineReader(_file:@Memory):
|
||||
func stdin()->LineReader:
|
||||
f := inline C (
|
||||
stdin
|
||||
):@Memory
|
||||
return LineReader(_wrap_with_finalizer(f, _close_file))
|
||||
|
||||
func is_finished(r:LineReader)->Bool:
|
||||
return inline C (
|
||||
feof(*(FILE**)$r.$_file) != 0;
|
||||
):Bool
|
||||
|
||||
func next_line(r:LineReader)->FileReadResult:
|
||||
line := inline C (
|
||||
({
|
||||
if (*(FILE**)$r.$_file == NULL) fail("File has already been closed!");
|
||||
char *buf = NULL;
|
||||
size_t space = 0;
|
||||
ssize_t len = getline(&buf, &space, *(FILE**)$r.$_file);
|
||||
if (len < 0) {
|
||||
file$_close_file($r.$_file);
|
||||
return (file$FileReadResult_t){1, .$Failure={Text("End of file")}};
|
||||
}
|
||||
if (len > 0 && buf[len-1] == '\n') --len;
|
||||
char *line = GC_MALLOC_ATOMIC(len + 1);
|
||||
memcpy(line, buf, len);
|
||||
line[len] = '\0';
|
||||
if (buf) free(buf);
|
||||
u8_check(line, len) ? Text("") : Text$from_strn(line, len);
|
||||
})
|
||||
):Text
|
||||
return Success(line)
|
||||
|
||||
func from_file(path:Text)->FileLineReaderResult:
|
||||
maybe_f := inline C (
|
||||
fopen(Text$as_c_string($path), "r")
|
||||
):@Memory?
|
||||
when maybe_f is @f:
|
||||
obj := _wrap_with_finalizer(f, _close_file)
|
||||
return Open(LineReader(obj))
|
||||
else:
|
||||
return Failure(builtin_last_err())
|
||||
|
||||
func from_command(cmd:Text)->FileLineReaderResult:
|
||||
maybe_f := inline C (
|
||||
popen(Text$as_c_string($cmd), "r")
|
||||
):@Memory?
|
||||
when maybe_f is @f:
|
||||
obj := _wrap_with_finalizer(f, _close_file)
|
||||
return Open(LineReader(obj))
|
||||
else:
|
||||
return Failure(builtin_last_err())
|
||||
|
||||
func close(r:LineReader):
|
||||
_close_file(r._file)
|
||||
|
||||
enum FileLineReaderResult(Open(reader:LineReader), Failure(reason:Text))
|
||||
|
||||
func command(cmd:Text)->FileReadResult:
|
||||
maybe_f := inline C (
|
||||
popen(Text$as_c_string($cmd), "r")
|
||||
):@Memory?
|
||||
|
||||
when maybe_f is @f:
|
||||
text := inline C (
|
||||
({
|
||||
const int chunk_size = 256;
|
||||
char *buf = GC_MALLOC_ATOMIC(chunk_size);
|
||||
Text_t contents = Text("");
|
||||
size_t just_read;
|
||||
do {
|
||||
just_read = fread(buf, sizeof(char), chunk_size, $f);
|
||||
if (just_read > 0) {
|
||||
contents = Texts(contents, Text$from_strn(buf, just_read));
|
||||
buf = GC_MALLOC_ATOMIC(chunk_size);
|
||||
}
|
||||
} while (just_read > 0);
|
||||
pclose($f);
|
||||
contents;
|
||||
})
|
||||
):Text
|
||||
text = text:replace($/$(\n){end}/, "")
|
||||
return Success(text)
|
||||
else:
|
||||
return Failure(builtin_last_err())
|
||||
|
||||
func main(path:Text, relative_to="."):
|
||||
>> resolve_path(path, relative_to)
|
||||
>> relative_path(resolve_path(path, relative_to))
|
||||
# word := ""
|
||||
# when command("shuf -n 1 /usr/share/dict/words") is Success(w):
|
||||
# >> word = w
|
||||
# is Failure(msg):
|
||||
# fail(msg)
|
||||
|
||||
# when writing("test.txt") is Open(f):
|
||||
# say("Writing {word} to test.txt")
|
||||
# f:write("Hello {word}!{\n}")
|
||||
# is Failure(msg):
|
||||
# fail(msg)
|
||||
|
||||
# when read("test.txt") is Success(text):
|
||||
# say("Roundtrip: {text}")
|
||||
# is Failure(msg):
|
||||
# fail(msg)
|
||||
|
||||
# say("Reading stdin:")
|
||||
# reader := LineReader.stdin()
|
||||
# while yes:
|
||||
# when reader:next_line() is Success(line):
|
||||
# >> line
|
||||
# else: stop
|
||||
|
||||
# say("Reading cmd:")
|
||||
# when LineReader.from_command("ping google.com") is Open(reader):
|
||||
# while yes:
|
||||
# when reader:next_line() is Success(line):
|
||||
# >> line
|
||||
# else: stop
|
||||
# is Failure(msg):
|
||||
# fail("{msg}")
|
||||
|
||||
# say("Reading /dev/stdin:")
|
||||
# when LineReader.from_file("/dev/stdin") is Open(reader):
|
||||
# while yes:
|
||||
# when reader:next_line() is Success(line):
|
||||
# >> line
|
||||
# else: stop
|
||||
# is Failure(msg):
|
||||
# fail("{msg}")
|
Loading…
Reference in New Issue
Block a user