diff --git a/docs/docs/stdlib.md b/docs/docs/stdlib.md index 511663f67..828a20e28 100644 --- a/docs/docs/stdlib.md +++ b/docs/docs/stdlib.md @@ -566,15 +566,15 @@ Return true if there was an error. Clear the error indication. -#### `read(buffer, position, length)` +#### `read(buffer, position = 0, length = buffer.length)` Read `length` bytes from the file to the ArrayBuffer `buffer` at byte -position `position` (wrapper to the libc `fread`). +position `position`. Wrapper to the libc function `fread`. -#### `write(buffer, position, length)` +#### `write(buffer, position = 0, length = buffer.length)` -Write `length` bytes to the file from the ArrayBuffer `buffer` at byte -position `position` (wrapper to the libc `fwrite`). +Write `length` bytes to the file from the ArrayBuffer or string `buffer` +at byte position `position`. Wrapper to the libc function `fwrite`. #### `getline()` diff --git a/quickjs-libc.c b/quickjs-libc.c index a7cbc3033..926c184ef 100644 --- a/quickjs-libc.c +++ b/quickjs-libc.c @@ -1519,25 +1519,41 @@ static JSValue js_std_file_read_write(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv, int magic) { FILE *f = js_std_file_get(ctx, this_val); + bool is_write = (magic != 0); uint64_t pos, len; size_t size, ret; + const char *str; uint8_t *buf; if (!f) return JS_EXCEPTION; - if (JS_ToIndex(ctx, &pos, argv[1])) + pos = 0; + if (argc > 1 && JS_ToIndex(ctx, &pos, argv[1])) return JS_EXCEPTION; - if (JS_ToIndex(ctx, &len, argv[2])) + len = 0; + if (argc > 2 && JS_ToIndex(ctx, &len, argv[2])) return JS_EXCEPTION; - buf = JS_GetArrayBuffer(ctx, &size, argv[0]); + if (is_write && JS_IsString(argv[0])) { + str = JS_ToCStringLen(ctx, &size, argv[0]); + buf = (void *)str; + } else { + str = NULL; + buf = JS_GetArrayBuffer(ctx, &size, argv[0]); + } if (!buf) return JS_EXCEPTION; + if (pos > size) + pos = size; + if (argc < 3) + len = size - pos; if (pos + len > size) - return JS_ThrowRangeError(ctx, "read/write array buffer overflow"); - if (magic) + len = size - pos; + if (is_write) { ret = fwrite(buf + pos, 1, len, f); - else + } else { ret = fread(buf + pos, 1, len, f); + } + JS_FreeCString(ctx, str); return JS_NewInt64(ctx, ret); } @@ -1909,8 +1925,8 @@ static const JSCFunctionListEntry js_std_file_proto_funcs[] = { JS_CFUNC_DEF("fileno", 0, js_std_file_fileno ), JS_CFUNC_DEF("error", 0, js_std_file_error ), JS_CFUNC_DEF("clearerr", 0, js_std_file_clearerr ), - JS_CFUNC_MAGIC_DEF("read", 3, js_std_file_read_write, 0 ), - JS_CFUNC_MAGIC_DEF("write", 3, js_std_file_read_write, 1 ), + JS_CFUNC_MAGIC_DEF("read", 1, js_std_file_read_write, 0 ), + JS_CFUNC_MAGIC_DEF("write", 1, js_std_file_read_write, 1 ), JS_CFUNC_DEF("getline", 0, js_std_file_getline ), JS_CFUNC_MAGIC_DEF("readAsArrayBuffer", 0, js_std_file_readAs, 0 ), JS_CFUNC_MAGIC_DEF("readAsString", 0, js_std_file_readAs, 1 ), diff --git a/tests/test_std.js b/tests/test_std.js index b1d398360..443b6990d 100644 --- a/tests/test_std.js +++ b/tests/test_std.js @@ -223,7 +223,18 @@ function test_os() [fpath, fd] = os.mkstemp(`${fdir}/XXXXXX`); assert(fdir.startsWith(`${fdir}`)); assert(fd >= 0); - os.close(fd); + + const f = std.fdopen(fd, "w+"); + f.write("xyzzy"); + f.flush(); + const b = new Uint8Array(5); + f.seek(0, std.SEEK_SET); + assert(5, f.read(b.buffer)); + const s = [...b].map(c => String.fromCharCode(c)).join(""); + assert(s, "xyzzy"); + f.seek(0, std.SEEK_SET); + assert(0, f.read(b.buffer, 5, 42)); + f.close(); assert(os.remove(fpath), 0); assert(os.remove(fdir), 0);