#include <JavaScriptCore/JavaScript.h>
#include <uv.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
static JSGlobalContextRef globalCtx = NULL;
typedef struct {
char* filepath;
char* content;
size_t size;
JSObjectRef resolve;
JSObjectRef reject;
JSContextRef ctx;
} ReadFileData;
static JSValueRef jsprint(JSContextRef ctx,
JSObjectRef function,
JSObjectRef thisObject,
size_t argumentCount,
const JSValueRef arguments[],
JSValueRef* exception) {
for (size_t i = 0; i < argumentCount; i++) {
if (i > 0) printf(" ");
JSStringRef strRef = JSValueToStringCopy(ctx, arguments[i], exception);
size_t bufferSize = JSStringGetMaximumUTF8CStringSize(strRef);
char* str = (char*)malloc(bufferSize);
JSStringGetUTF8CString(strRef, str, bufferSize);
printf("%s", str);
free(str);
JSStringRelease(strRef);
}
printf("\n");
return JSValueMakeUndefined(ctx);
}
static void on_read(uv_fs_t* req) {
ReadFileData* data = (ReadFileData*)req->data;
if (req->result < 0) {
JSStringRef errorMsg = JSStringCreateWithUTF8CString(uv_strerror(req->result));
JSValueRef error = JSValueMakeString(data->ctx, errorMsg);
JSValueRef args[] = { error };
JSObjectCallAsFunction(data->ctx, data->reject, NULL, 1, args, NULL);
JSStringRelease(errorMsg);
} else {
JSStringRef content = JSStringCreateWithUTF8CString(data->content);
JSValueRef result = JSValueMakeString(data->ctx, content);
JSValueRef args[] = { result };
JSObjectCallAsFunction(data->ctx, data->resolve, NULL, 1, args, NULL);
JSStringRelease(content);
}
free(data->content);
free(data->filepath);
free(data);
uv_fs_req_cleanup(req);
free(req);
}
static void on_open(uv_fs_t* req) {
if (req->result < 0) {
ReadFileData* data = (ReadFileData*)req->data;
JSStringRef errorMsg = JSStringCreateWithUTF8CString(uv_strerror(req->result));
JSValueRef error = JSValueMakeString(data->ctx, errorMsg);
JSValueRef args[] = { error };
JSObjectCallAsFunction(data->ctx, data->reject, NULL, 1, args, NULL);
JSStringRelease(errorMsg);
free(data->filepath);
free(data);
uv_fs_req_cleanup(req);
free(req);
return;
}
ReadFileData* data = (ReadFileData*)req->data;
uv_fs_t* read_req = (uv_fs_t*)malloc(sizeof(uv_fs_t));
read_req->data = data;
uv_fs_t stat_req;
uv_fs_fstat(uv_default_loop(), &stat_req, req->result, NULL);
data->size = stat_req.statbuf.st_size;
data->content = (char*)malloc(data->size + 1);
data->content[data->size] = '\0';
uv_buf_t buf = uv_buf_init(data->content, data->size);
uv_fs_read(uv_default_loop(), read_req, req->result, &buf, 1, 0, on_read);
uv_fs_req_cleanup(&stat_req);
uv_fs_req_cleanup(req);
free(req);
}
static JSValueRef readFile(JSContextRef ctx,
JSObjectRef function,
JSObjectRef thisObject,
size_t argumentCount,
const JSValueRef arguments[],
JSValueRef* exception) {
if (argumentCount < 1) {
JSStringRef errorMsg = JSStringCreateWithUTF8CString("File path required");
*exception = JSValueMakeString(ctx, errorMsg);
JSStringRelease(errorMsg);
return JSValueMakeUndefined(ctx);
}
JSStringRef pathStr = JSValueToStringCopy(ctx, arguments[0], exception);
size_t bufferSize = JSStringGetMaximumUTF8CStringSize(pathStr);
char* filepath = (char*)malloc(bufferSize);
JSStringGetUTF8CString(pathStr, filepath, bufferSize);
JSStringRelease(pathStr);
JSObjectRef resolve, reject;
JSObjectRef promise = JSObjectMakeDeferredPromise(ctx, &resolve, &reject, exception);
if (*exception) {
free(filepath);
return JSValueMakeUndefined(ctx);
}
ReadFileData* data = (ReadFileData*)malloc(sizeof(ReadFileData));
data->filepath = filepath;
data->content = NULL;
data->ctx = ctx;
data->resolve = resolve;
data->reject = reject;
uv_fs_t* open_req = (uv_fs_t*)malloc(sizeof(uv_fs_t));
open_req->data = data;
uv_fs_open(uv_default_loop(), open_req, filepath, O_RDONLY, 0, on_open);
return promise;
}
static void setupGlobalFunctions(JSContextRef ctx, JSObjectRef globalObject) {
JSStringRef printName = JSStringCreateWithUTF8CString("jsprint");
JSObjectRef printFunc = JSObjectMakeFunctionWithCallback(ctx, printName, jsprint);
JSObjectSetProperty(ctx, globalObject, printName, printFunc,
kJSPropertyAttributeNone, NULL);
JSStringRelease(printName);
JSStringRef readFileName = JSStringCreateWithUTF8CString("readFile");
JSObjectRef readFileFunc = JSObjectMakeFunctionWithCallback(ctx, readFileName, readFile);
JSObjectSetProperty(ctx, globalObject, readFileName, readFileFunc,
kJSPropertyAttributeNone, NULL);
JSStringRelease(readFileName);
}
int main() {
JSContextGroupRef group = JSContextGroupCreate();
globalCtx = JSGlobalContextCreateInGroup(group, NULL);
JSObjectRef globalObject = JSContextGetGlobalObject(globalCtx);
setupGlobalFunctions(globalCtx, globalObject);
const char* script =
"jsprint(typeof readFile('1.txt'));\n"
"async function test() {\n"
" try {\n"
" jsprint('Reading file...');\n"
" const content = await readFile('test.txt');\n"
" jsprint('File content:', content);\n"
" } catch (err) {\n"
" jsprint('Error:', err);\n"
" }\n"
"}\n"
"test();\n";
JSStringRef scriptJS = JSStringCreateWithUTF8CString(script);
JSValueRef exception = NULL;
JSEvaluateScript(globalCtx, scriptJS, NULL, NULL, 1, &exception);
if (exception) {
JSStringRef exceptionStr = JSValueToStringCopy(globalCtx, exception, NULL);
size_t bufferSize = JSStringGetMaximumUTF8CStringSize(exceptionStr);
char* str = (char*)malloc(bufferSize);
JSStringGetUTF8CString(exceptionStr, str, bufferSize);
printf("Exception: %s\n", str);
free(str);
JSStringRelease(exceptionStr);
}
uv_run(uv_default_loop(), UV_RUN_DEFAULT);
JSStringRelease(scriptJS);
JSGlobalContextRelease(globalCtx);
JSContextGroupRelease(group);
uv_loop_close(uv_default_loop());
return 0;
}