176 lines
6.0 KiB
C
176 lines
6.0 KiB
C
// file_playdate.c - Cell integration for Playdate File API
|
|
// Wraps pd_api_file.h functions for JavaScript access
|
|
// Note: fd_playdate.c already provides the main file operations.
|
|
// This module provides additional raw file API access.
|
|
|
|
#include "cell.h"
|
|
#include "common.h"
|
|
#include <string.h>
|
|
|
|
// --- Helpers ---
|
|
static SDFile* js2sdfile(JSContext *js, JSValueConst val) {
|
|
int64_t ptr;
|
|
if (JS_ToInt64(js, &ptr, val) < 0) return NULL;
|
|
return (SDFile*)(intptr_t)ptr;
|
|
}
|
|
|
|
// --- File Functions ---
|
|
|
|
JSC_CCALL(file_geterr,
|
|
if (!pd_file) return JS_ThrowInternalError(js, "file not initialized");
|
|
const char *err = pd_file->geterr();
|
|
return err ? JS_NewString(js, err) : JS_NULL;
|
|
)
|
|
|
|
JSC_SCALL(file_stat,
|
|
if (!pd_file) return JS_ThrowInternalError(js, "file not initialized");
|
|
FileStat st;
|
|
if (pd_file->stat(str, &st) != 0) {
|
|
ret = JS_NULL;
|
|
} else {
|
|
JSValue obj = JS_NewObject(js);
|
|
JS_SetPropertyStr(js, obj, "isdir", JS_NewBool(js, st.isdir));
|
|
JS_SetPropertyStr(js, obj, "size", JS_NewInt64(js, st.size));
|
|
JS_SetPropertyStr(js, obj, "year", JS_NewInt32(js, st.m_year));
|
|
JS_SetPropertyStr(js, obj, "month", JS_NewInt32(js, st.m_month));
|
|
JS_SetPropertyStr(js, obj, "day", JS_NewInt32(js, st.m_day));
|
|
JS_SetPropertyStr(js, obj, "hour", JS_NewInt32(js, st.m_hour));
|
|
JS_SetPropertyStr(js, obj, "minute", JS_NewInt32(js, st.m_minute));
|
|
JS_SetPropertyStr(js, obj, "second", JS_NewInt32(js, st.m_second));
|
|
ret = obj;
|
|
}
|
|
)
|
|
|
|
JSC_SCALL(file_mkdir,
|
|
if (!pd_file) return JS_ThrowInternalError(js, "file not initialized");
|
|
ret = JS_NewBool(js, pd_file->mkdir(str) == 0);
|
|
)
|
|
|
|
JSC_SCALL(file_unlink,
|
|
if (!pd_file) return JS_ThrowInternalError(js, "file not initialized");
|
|
int recursive = argc > 1 ? JS_ToBool(js, argv[1]) : 0;
|
|
ret = JS_NewBool(js, pd_file->unlink(str, recursive) == 0);
|
|
)
|
|
|
|
JSC_SCALL(file_rename,
|
|
if (!pd_file) return JS_ThrowInternalError(js, "file not initialized");
|
|
const char *to = JS_ToCString(js, argv[1]);
|
|
int result = pd_file->rename(str, to);
|
|
JS_FreeCString(js, to);
|
|
ret = JS_NewBool(js, result == 0);
|
|
)
|
|
|
|
JSC_SCALL(file_open,
|
|
if (!pd_file) return JS_ThrowInternalError(js, "file not initialized");
|
|
FileOptions mode = kFileRead;
|
|
if (argc > 1) mode = (FileOptions)(int)js2number(js, argv[1]);
|
|
SDFile *f = pd_file->open(str, mode);
|
|
ret = f ? JS_NewInt64(js, (int64_t)(intptr_t)f) : JS_NULL;
|
|
)
|
|
|
|
JSC_CCALL(file_close,
|
|
if (!pd_file) return JS_ThrowInternalError(js, "file not initialized");
|
|
SDFile *f = js2sdfile(js, argv[0]);
|
|
return JS_NewBool(js, pd_file->close(f) == 0);
|
|
)
|
|
|
|
JSC_CCALL(file_read,
|
|
if (!pd_file) return JS_ThrowInternalError(js, "file not initialized");
|
|
SDFile *f = js2sdfile(js, argv[0]);
|
|
unsigned int len = (unsigned int)js2number(js, argv[1]);
|
|
void *buf = malloc(len);
|
|
if (!buf) return JS_ThrowInternalError(js, "malloc failed");
|
|
int read = pd_file->read(f, buf, len);
|
|
if (read < 0) {
|
|
free(buf);
|
|
return JS_NULL;
|
|
}
|
|
JSValue blob = js_new_blob_stoned_copy(js, buf, read);
|
|
free(buf);
|
|
return blob;
|
|
)
|
|
|
|
JSC_CCALL(file_write,
|
|
if (!pd_file) return JS_ThrowInternalError(js, "file not initialized");
|
|
SDFile *f = js2sdfile(js, argv[0]);
|
|
size_t len;
|
|
const void *data = js_get_blob_data(js, &len, argv[1]);
|
|
if (data == (void*)-1) return JS_EXCEPTION;
|
|
int written = pd_file->write(f, data, (unsigned int)len);
|
|
return JS_NewInt32(js, written);
|
|
)
|
|
|
|
JSC_CCALL(file_flush,
|
|
if (!pd_file) return JS_ThrowInternalError(js, "file not initialized");
|
|
SDFile *f = js2sdfile(js, argv[0]);
|
|
return JS_NewBool(js, pd_file->flush(f) == 0);
|
|
)
|
|
|
|
JSC_CCALL(file_tell,
|
|
if (!pd_file) return JS_ThrowInternalError(js, "file not initialized");
|
|
SDFile *f = js2sdfile(js, argv[0]);
|
|
return JS_NewInt32(js, pd_file->tell(f));
|
|
)
|
|
|
|
JSC_CCALL(file_seek,
|
|
if (!pd_file) return JS_ThrowInternalError(js, "file not initialized");
|
|
SDFile *f = js2sdfile(js, argv[0]);
|
|
int pos = (int)js2number(js, argv[1]);
|
|
int whence = argc > 2 ? (int)js2number(js, argv[2]) : SEEK_SET;
|
|
return JS_NewBool(js, pd_file->seek(f, pos, whence) == 0);
|
|
)
|
|
|
|
struct listfiles_ctx {
|
|
JSContext *js;
|
|
JSValue array;
|
|
int index;
|
|
};
|
|
|
|
static void listfiles_cb(const char *path, void *userdata) {
|
|
struct listfiles_ctx *ctx = (struct listfiles_ctx*)userdata;
|
|
JS_SetPropertyUint32(ctx->js, ctx->array, ctx->index++, JS_NewString(ctx->js, path));
|
|
}
|
|
|
|
JSC_SCALL(file_listfiles,
|
|
if (!pd_file) return JS_ThrowInternalError(js, "file not initialized");
|
|
int showhidden = argc > 1 ? JS_ToBool(js, argv[1]) : 0;
|
|
JSValue arr = JS_NewArray(js);
|
|
struct listfiles_ctx ctx = { js, arr, 0 };
|
|
if (pd_file->listfiles(str, listfiles_cb, &ctx, showhidden) != 0) {
|
|
JS_FreeValue(js, arr);
|
|
ret = JS_NULL;
|
|
} else {
|
|
ret = arr;
|
|
}
|
|
)
|
|
|
|
static const JSCFunctionListEntry js_file_funcs[] = {
|
|
MIST_FUNC_DEF(file, geterr, 0),
|
|
MIST_FUNC_DEF(file, stat, 1),
|
|
MIST_FUNC_DEF(file, mkdir, 1),
|
|
MIST_FUNC_DEF(file, unlink, 2),
|
|
MIST_FUNC_DEF(file, rename, 2),
|
|
MIST_FUNC_DEF(file, open, 2),
|
|
MIST_FUNC_DEF(file, close, 1),
|
|
MIST_FUNC_DEF(file, read, 2),
|
|
MIST_FUNC_DEF(file, write, 2),
|
|
MIST_FUNC_DEF(file, flush, 1),
|
|
MIST_FUNC_DEF(file, tell, 1),
|
|
MIST_FUNC_DEF(file, seek, 3),
|
|
MIST_FUNC_DEF(file, listfiles, 2),
|
|
};
|
|
|
|
JSValue js_file_use(JSContext *js) {
|
|
JSValue mod = JS_NewObject(js);
|
|
JS_SetPropertyFunctionList(js, mod, js_file_funcs, countof(js_file_funcs));
|
|
// Export constants
|
|
JS_SetPropertyStr(js, mod, "READ", JS_NewInt32(js, kFileRead));
|
|
JS_SetPropertyStr(js, mod, "READ_DATA", JS_NewInt32(js, kFileReadData));
|
|
JS_SetPropertyStr(js, mod, "WRITE", JS_NewInt32(js, kFileWrite));
|
|
JS_SetPropertyStr(js, mod, "APPEND", JS_NewInt32(js, kFileAppend));
|
|
JS_SetPropertyStr(js, mod, "SEEK_SET", JS_NewInt32(js, SEEK_SET));
|
|
JS_SetPropertyStr(js, mod, "SEEK_CUR", JS_NewInt32(js, SEEK_CUR));
|
|
JS_SetPropertyStr(js, mod, "SEEK_END", JS_NewInt32(js, SEEK_END));
|
|
return mod;
|
|
}
|