Skip to content

Commit 9c0dca7

Browse files
committed
Add std.writeFile
std.loadFile already exists and is convenient. std.writeFile replaces the more onerous std.open + std.write + std.close idiom.
1 parent 9d6e372 commit 9c0dca7

File tree

3 files changed

+82
-6
lines changed

3 files changed

+82
-6
lines changed

docs/docs/stdlib.md

+12
Original file line numberDiff line numberDiff line change
@@ -355,6 +355,18 @@ encoding. Return `null` in case of I/O error.
355355

356356
If `options.binary` is set to `true` a `Uint8Array` is returned instead.
357357

358+
### `writeFile(filename, data)`
359+
360+
Create the file `filename` and write `data` into it.
361+
362+
`data` can be a string, a typed array or an `ArrayBuffer`. `undefined` is
363+
treated as the empty string.
364+
365+
When `data` is a string, the file is opened in text mode; otherwise it is
366+
opened in binary mode. (This distinction is only relevant on Windows.)
367+
368+
Throws an exception if the file cannot be created or written to.
369+
358370
### `open(filename, flags, errorObj = undefined)`
359371

360372
Open a file (wrapper to the libc `fopen()`). Return the FILE

quickjs-libc.c

+63
Original file line numberDiff line numberDiff line change
@@ -536,6 +536,68 @@ static JSValue js_std_loadFile(JSContext *ctx, JSValue this_val,
536536
return ret;
537537
}
538538

539+
static JSValue js_std_writeFile(JSContext *ctx, JSValue this_val,
540+
int argc, JSValue *argv)
541+
{
542+
const char *filename;
543+
const char *mode;
544+
const void *buf;
545+
size_t len, n;
546+
JSValue data, val, ret;
547+
bool release, unref;
548+
FILE *fp;
549+
550+
ret = JS_EXCEPTION;
551+
len = 0;
552+
buf = "";
553+
mode = "w";
554+
data = argv[1];
555+
unref = false;
556+
release = false;
557+
filename = JS_ToCString(ctx, argv[0]);
558+
if (!filename)
559+
return JS_EXCEPTION;
560+
if (JS_IsObject(data)) {
561+
val = JS_GetPropertyStr(ctx, data, "buffer");
562+
if (JS_IsException(val))
563+
goto exception;
564+
if (JS_IsArrayBuffer(val)) {
565+
data = val;
566+
unref = true;
567+
} else {
568+
JS_FreeValue(ctx, val);
569+
}
570+
}
571+
if (JS_IsArrayBuffer(data)) {
572+
buf = JS_GetArrayBuffer(ctx, &len, data);
573+
mode = "wb";
574+
} else if (!JS_IsUndefined(data)) {
575+
buf = JS_ToCStringLen(ctx, &len, data);
576+
release = true;
577+
}
578+
if (!buf)
579+
goto exception;
580+
fp = fopen(filename, mode);
581+
if (!fp) {
582+
JS_ThrowPlainError(ctx, "error opening %s for writing", filename);
583+
goto exception;
584+
}
585+
n = fwrite(buf, len, 1, fp);
586+
fclose(fp);
587+
if (n != 1) {
588+
JS_ThrowPlainError(ctx, "error writing to %s", filename);
589+
goto exception;
590+
}
591+
ret = JS_UNDEFINED;
592+
exception:
593+
JS_FreeCString(ctx, filename);
594+
if (release)
595+
JS_FreeCString(ctx, buf);
596+
if (unref)
597+
JS_FreeValue(ctx, data);
598+
return ret;
599+
}
600+
539601
typedef JSModuleDef *(JSInitModuleFunc)(JSContext *ctx,
540602
const char *module_name);
541603

@@ -1674,6 +1736,7 @@ static const JSCFunctionListEntry js_std_funcs[] = {
16741736
JS_CFUNC_DEF("urlGet", 1, js_std_urlGet ),
16751737
#endif
16761738
JS_CFUNC_DEF("loadFile", 1, js_std_loadFile ),
1739+
JS_CFUNC_DEF("writeFile", 2, js_std_writeFile ),
16771740
JS_CFUNC_DEF("strerror", 1, js_std_strerror ),
16781741

16791742
/* FILE I/O */

tests/test_std.js

+7-6
Original file line numberDiff line numberDiff line change
@@ -93,14 +93,15 @@ function test_getline()
9393
function test_popen()
9494
{
9595
var str, f, fname = "tmp_file.txt";
96-
var content = "hello world";
96+
var ta, content = "hello world";
9797
var cmd = isWin ? "type" : "cat";
9898

99-
f = std.open(fname, "w");
100-
f.puts(content);
101-
f.close();
102-
103-
/* test loadFile */
99+
ta = new Uint8Array([...content].map(c => c.charCodeAt(0)));
100+
std.writeFile(fname, ta);
101+
assert(std.loadFile(fname), content);
102+
std.writeFile(fname, ta.buffer);
103+
assert(std.loadFile(fname), content);
104+
std.writeFile(fname, content);
104105
assert(std.loadFile(fname), content);
105106

106107
/* execute shell command */

0 commit comments

Comments
 (0)