Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

new memstream filehandle type #129

Merged
merged 1 commit into from
Nov 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions docs/generated/builtins.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,15 @@ Support for declaring builtins

```mermaid
flowchart TD
BuiltInMemBufHash --entries--> entries
BuiltIn --name--> HashSymbol
BuiltIn --result--> TcType
BuiltIn --args--> BuiltInArgs
BuiltIn --implementation--> void_ptr
BuiltInImplementation --implementation--> void_ptr
BuiltInImplementation --nargs--> int
BuiltInMemBuf --buffer--> string
BuiltInMemBuf --size--> size
BuiltInArgs["BuiltInArgs[]"] --entries--> TcType
BuiltIns["BuiltIns[]"] --entries--> BuiltIn
```
Expand Down
24 changes: 24 additions & 0 deletions fn/ioutils.fn
Original file line number Diff line number Diff line change
Expand Up @@ -29,3 +29,27 @@ fn with_input_from(filename, handler) {
}
}
}

fn with_buffer(handler) {
switch (openmem()) {
(success(filehandle)) {
let data = some(handler(filehandle));
in
close(filehandle);
data;
}
(failure(errmsg)) {
print(errmsg);
nothing;
}
}
}

fn to_string(data) {
unsafe switch (with_buffer(fn (buf) {
fputv(buf, data);
fgets(buf);
})) {
(some(result)) { result }
}
}
86 changes: 77 additions & 9 deletions src/builtin_io.c
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ static void registerGets(BuiltIns *registry);
static void registerFGets(BuiltIns *registry);

static void registerOpen(BuiltIns *registry);
static void registerOpenMemstream(BuiltIns *registry);
static void registerClose(BuiltIns *registry);

static void registerOpenDir(BuiltIns *registry);
Expand All @@ -62,6 +63,21 @@ static void registerCloseDir(BuiltIns *registry);

static void registerFType(BuiltIns *registry);

static BuiltInMemBufHash *memBufs = NULL;

void markMemBufs() {
if (memBufs != NULL) {
markHashTable((HashTable *) memBufs);
}
}

static BuiltInMemBufHash *getMemBufs(void) {
if (memBufs == NULL) {
memBufs = newBuiltInMemBufHash();
}
return memBufs;
}

void registerIO(BuiltIns *registry) {
registerPutc(registry);
registerFPutc(registry);
Expand All @@ -76,6 +92,7 @@ void registerIO(BuiltIns *registry) {
registerGets(registry);
registerFGets(registry);
registerOpen(registry);
registerOpenMemstream(registry);
registerClose(registry);
registerOpenDir(registry);
registerReadDir(registry);
Expand Down Expand Up @@ -157,12 +174,25 @@ static Value builtin_puts(Vec *args) {
#define IO_MODE_WRITE 1
#define IO_MODE_APPEND 2

static HashSymbol *fileHandleToKey(FILE *file) {
static char buf[128];
sprintf(buf, "%p", file);
return newSymbol(buf);
}

static void opaque_io_close(Opaque *data) {
if (data == NULL) return;
if (data->data == NULL) return;
DEBUG("closing io %p", data->data);
fclose(data->data);
HashSymbol *key = fileHandleToKey(data->data);
BuiltInMemBuf *memBuf = NULL;
if (getBuiltInMemBufHash(getMemBufs(), key, &memBuf)) {
if (memBuf->buffer != NULL) {
free(memBuf->buffer);
memBuf->buffer = NULL;
}
}
data->data = NULL;
}

Expand Down Expand Up @@ -204,6 +234,21 @@ static Value builtin_open(Vec *args) {
return result;
}

static Value builtin_open_memstream(Vec *args __attribute__((unused))) {
BuiltInMemBuf *memBuf = newBuiltInMemBuf();
int save = PROTECT(memBuf);
FILE *file = open_memstream(&memBuf->buffer, &memBuf->size);
BuiltInMemBufHash *memBufs = getMemBufs();
HashSymbol *key = fileHandleToKey(file);
setBuiltInMemBufHash(memBufs, key, memBuf);
Opaque *wrapper = newOpaque(file, opaque_io_close, NULL);
Value opaque = value_Opaque(wrapper);
protectValue(opaque);
Value result = makeTryResult(1, opaque);
UNPROTECT(save);
return result;
}

static Value builtin_opendir(Vec *args) {
char *dirname = listToUtf8(args->entries[0]);
DIR *dir = opendir(dirname);
Expand Down Expand Up @@ -364,7 +409,7 @@ void fputValue(FILE *fh, Value x) {
fputVec(fh, x.val.vec);
break;
default:
cant_happen("unrecognised value type in fputValue");
cant_happen("unrecognised value type %s", valueTypeName(x.type));
}
}

Expand All @@ -390,13 +435,24 @@ void putVec(Vec *x) {
static Value private_fgets(FILE *fh) {
ByteArray *bytes = newByteArray();
int save = PROTECT(bytes);
int c;
while ((c = fgetc(fh)) != EOF) {
if (c == '\n') break;
if (c == 0) break;
pushByteArray(bytes, (Byte) c);
HashSymbol *key = fileHandleToKey(fh);
BuiltInMemBuf *buf = NULL;
if (getBuiltInMemBufHash(getMemBufs(), key, &buf)) {
fflush(fh);
if (buf->buffer == NULL) {
cant_happen("fgets on null memstream");
}
char *b = buf->buffer;
do { pushByteArray(bytes, (Byte) *b); } while (*(b++));
} else {
int c;
while ((c = fgetc(fh)) != EOF) {
if (c == '\n') break;
if (c == 0) break;
pushByteArray(bytes, (Byte) c);
}
pushByteArray(bytes, 0);
}
pushByteArray(bytes, 0);
Value string = utf8ToList((char *) bytes->entries);
UNPROTECT(save);
return string;
Expand Down Expand Up @@ -441,8 +497,8 @@ static Value builtin_fputv(Vec *args) {
if (data == NULL || data->data == NULL) {
cant_happen("fput on closed file handle");
}
fputValue((FILE *) data->data, args->entries[0]);
return args->entries[0];
fputValue((FILE *) data->data, args->entries[1]);
return args->entries[1];
}

static TcType *pushFileArg(BuiltInArgs *args) {
Expand Down Expand Up @@ -572,6 +628,18 @@ static void registerOpen(BuiltIns *registry) {
UNPROTECT(save);
}

// try(string, opaque(file))
static void registerOpenMemstream(BuiltIns *registry) {
BuiltInArgs *args = newBuiltInArgs();
int save = PROTECT(args);
TcType *stringType = makeStringType();
PROTECT(stringType);
TcType *tryFileType = makeTryFileType(stringType);
PROTECT(tryFileType);
pushNewBuiltIn(registry, "openmem", tryFileType, args, (void *)builtin_open_memstream);
UNPROTECT(save);
}

// string -> try(string, opaque(dir))
static void registerOpenDir(BuiltIns *registry) {
BuiltInArgs *args = newBuiltInArgs();
Expand Down
1 change: 1 addition & 0 deletions src/builtin_io.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
# include <stdio.h>
# include "builtins.h"

void markMemBufs(void);
void registerIO(BuiltIns *registry);
void putValue(Value x);
void fputValue(FILE *fh, Value x);
Expand Down
8 changes: 8 additions & 0 deletions src/builtins.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,14 @@ structs:
implementation: void_ptr
nargs: int

BuiltInMemBuf:
buffer: string=NULL
size: size=0

hashes:
BuiltInMemBufHash:
entries: BuiltInMemBuf

arrays:
BuiltInArgs:
dimension: 1
Expand Down
2 changes: 2 additions & 0 deletions src/memory.c
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
#include "symbol.h"
#include "arithmetic.h"
#include "opaque.h"
#include "builtin_io.h"

static int bytesAllocated = 0;
static int nextGC = 0;
Expand Down Expand Up @@ -381,6 +382,7 @@ static void mark() {
markProtected();
markArithmetic();
markNamespaces();
markMemBufs();
#ifdef DEBUG_LOG_GC
eprintf("starting markVarTable\n");
#endif
Expand Down
4 changes: 4 additions & 0 deletions src/primitives.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -120,3 +120,7 @@ file:
printf: "%p"
valued: true

size:
cname: size_t
printf: "%zu"
valued: true
14 changes: 0 additions & 14 deletions tests/fn/test_hygiene.fn

This file was deleted.

4 changes: 4 additions & 0 deletions tests/fn/test_tostring.fn
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
let
link "ioutils.fn" as io;
in
assert(io.to_string(1234 + 5i) == "(1234+5i)")
Loading