2020-09-06 16:53:08 +00:00
|
|
|
/*
|
|
|
|
* QuickJS C library
|
|
|
|
*
|
2021-03-27 10:17:31 +00:00
|
|
|
* Copyright (c) 2017-2021 Fabrice Bellard
|
|
|
|
* Copyright (c) 2017-2021 Charlie Gordon
|
2020-09-06 16:53:08 +00:00
|
|
|
*
|
|
|
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
|
|
* of this software and associated documentation files (the "Software"), to deal
|
|
|
|
* in the Software without restriction, including without limitation the rights
|
|
|
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
|
|
* copies of the Software, and to permit persons to whom the Software is
|
|
|
|
* furnished to do so, subject to the following conditions:
|
|
|
|
*
|
|
|
|
* The above copyright notice and this permission notice shall be included in
|
|
|
|
* all copies or substantial portions of the Software.
|
|
|
|
*
|
|
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
|
|
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
|
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
|
|
* THE SOFTWARE.
|
|
|
|
*/
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdarg.h>
|
|
|
|
#include <inttypes.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <assert.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <errno.h>
|
|
|
|
#include <fcntl.h>
|
|
|
|
#include <sys/time.h>
|
|
|
|
#include <time.h>
|
|
|
|
#include <signal.h>
|
|
|
|
#include <limits.h>
|
|
|
|
#include <sys/stat.h>
|
|
|
|
#include <dirent.h>
|
|
|
|
#if defined(_WIN32)
|
|
|
|
#include <windows.h>
|
|
|
|
#include <conio.h>
|
2020-09-06 17:07:30 +00:00
|
|
|
#include <utime.h>
|
2020-09-06 16:53:08 +00:00
|
|
|
#else
|
|
|
|
#include <dlfcn.h>
|
|
|
|
#include <termios.h>
|
|
|
|
#include <sys/ioctl.h>
|
|
|
|
#include <sys/wait.h>
|
2020-09-06 17:07:30 +00:00
|
|
|
|
2020-09-06 16:53:08 +00:00
|
|
|
#if defined(__APPLE__)
|
|
|
|
typedef sig_t sighandler_t;
|
2020-09-06 17:07:30 +00:00
|
|
|
#if !defined(environ)
|
|
|
|
#include <crt_externs.h>
|
|
|
|
#define environ (*_NSGetEnviron())
|
|
|
|
#endif
|
|
|
|
#endif /* __APPLE__ */
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#if !defined(_WIN32)
|
|
|
|
/* enable the os.Worker API. IT relies on POSIX threads */
|
|
|
|
#define USE_WORKER
|
2020-09-06 16:53:08 +00:00
|
|
|
#endif
|
2020-09-06 17:07:30 +00:00
|
|
|
|
|
|
|
#ifdef USE_WORKER
|
|
|
|
#include <pthread.h>
|
|
|
|
#include <stdatomic.h>
|
2020-09-06 16:53:08 +00:00
|
|
|
#endif
|
|
|
|
|
|
|
|
#include "cutils.h"
|
|
|
|
#include "list.h"
|
|
|
|
#include "quickjs-libc.h"
|
|
|
|
|
|
|
|
/* TODO:
|
|
|
|
- add socket calls
|
|
|
|
*/
|
|
|
|
|
|
|
|
typedef struct {
|
|
|
|
struct list_head link;
|
|
|
|
int fd;
|
|
|
|
JSValue rw_func[2];
|
|
|
|
} JSOSRWHandler;
|
|
|
|
|
|
|
|
typedef struct {
|
|
|
|
struct list_head link;
|
|
|
|
int sig_num;
|
|
|
|
JSValue func;
|
|
|
|
} JSOSSignalHandler;
|
|
|
|
|
|
|
|
typedef struct {
|
|
|
|
struct list_head link;
|
|
|
|
BOOL has_object;
|
|
|
|
int64_t timeout;
|
|
|
|
JSValue func;
|
|
|
|
} JSOSTimer;
|
|
|
|
|
2020-09-06 17:07:30 +00:00
|
|
|
typedef struct {
|
|
|
|
struct list_head link;
|
|
|
|
uint8_t *data;
|
|
|
|
size_t data_len;
|
|
|
|
/* list of SharedArrayBuffers, necessary to free the message */
|
|
|
|
uint8_t **sab_tab;
|
|
|
|
size_t sab_tab_len;
|
|
|
|
} JSWorkerMessage;
|
|
|
|
|
|
|
|
typedef struct {
|
|
|
|
int ref_count;
|
|
|
|
#ifdef USE_WORKER
|
|
|
|
pthread_mutex_t mutex;
|
|
|
|
#endif
|
|
|
|
struct list_head msg_queue; /* list of JSWorkerMessage.link */
|
|
|
|
int read_fd;
|
|
|
|
int write_fd;
|
|
|
|
} JSWorkerMessagePipe;
|
|
|
|
|
|
|
|
typedef struct {
|
|
|
|
struct list_head link;
|
|
|
|
JSWorkerMessagePipe *recv_pipe;
|
|
|
|
JSValue on_message_func;
|
|
|
|
} JSWorkerMessageHandler;
|
|
|
|
|
|
|
|
typedef struct JSThreadState {
|
|
|
|
struct list_head os_rw_handlers; /* list of JSOSRWHandler.link */
|
|
|
|
struct list_head os_signal_handlers; /* list JSOSSignalHandler.link */
|
|
|
|
struct list_head os_timers; /* list of JSOSTimer.link */
|
|
|
|
struct list_head port_list; /* list of JSWorkerMessageHandler.link */
|
|
|
|
int eval_script_recurse; /* only used in the main thread */
|
|
|
|
/* not used in the main thread */
|
|
|
|
JSWorkerMessagePipe *recv_pipe, *send_pipe;
|
|
|
|
} JSThreadState;
|
|
|
|
|
2020-09-06 16:53:08 +00:00
|
|
|
static uint64_t os_pending_signals;
|
|
|
|
static int (*os_poll_func)(JSContext *ctx);
|
|
|
|
|
2020-09-06 17:07:30 +00:00
|
|
|
static void js_std_dbuf_init(JSContext *ctx, DynBuf *s)
|
|
|
|
{
|
|
|
|
dbuf_init2(s, JS_GetRuntime(ctx), (DynBufReallocFunc *)js_realloc_rt);
|
|
|
|
}
|
|
|
|
|
|
|
|
static BOOL my_isdigit(int c)
|
|
|
|
{
|
|
|
|
return (c >= '0' && c <= '9');
|
|
|
|
}
|
|
|
|
|
2020-09-06 16:53:08 +00:00
|
|
|
static JSValue js_printf_internal(JSContext *ctx,
|
|
|
|
int argc, JSValueConst *argv, FILE *fp)
|
|
|
|
{
|
|
|
|
char fmtbuf[32];
|
|
|
|
uint8_t cbuf[UTF8_CHAR_LEN_MAX+1];
|
|
|
|
JSValue res;
|
|
|
|
DynBuf dbuf;
|
|
|
|
const char *fmt_str;
|
|
|
|
const uint8_t *fmt, *fmt_end;
|
|
|
|
const uint8_t *p;
|
|
|
|
char *q;
|
2020-09-06 17:07:30 +00:00
|
|
|
int i, c, len, mod;
|
2020-09-06 16:53:08 +00:00
|
|
|
size_t fmt_len;
|
|
|
|
int32_t int32_arg;
|
|
|
|
int64_t int64_arg;
|
|
|
|
double double_arg;
|
|
|
|
const char *string_arg;
|
|
|
|
/* Use indirect call to dbuf_printf to prevent gcc warning */
|
|
|
|
int (*dbuf_printf_fun)(DynBuf *s, const char *fmt, ...) = (void*)dbuf_printf;
|
|
|
|
|
|
|
|
js_std_dbuf_init(ctx, &dbuf);
|
|
|
|
|
|
|
|
if (argc > 0) {
|
|
|
|
fmt_str = JS_ToCStringLen(ctx, &fmt_len, argv[0]);
|
|
|
|
if (!fmt_str)
|
|
|
|
goto fail;
|
|
|
|
|
|
|
|
i = 1;
|
|
|
|
fmt = (const uint8_t *)fmt_str;
|
|
|
|
fmt_end = fmt + fmt_len;
|
|
|
|
while (fmt < fmt_end) {
|
|
|
|
for (p = fmt; fmt < fmt_end && *fmt != '%'; fmt++)
|
|
|
|
continue;
|
|
|
|
dbuf_put(&dbuf, p, fmt - p);
|
|
|
|
if (fmt >= fmt_end)
|
|
|
|
break;
|
|
|
|
q = fmtbuf;
|
|
|
|
*q++ = *fmt++; /* copy '%' */
|
2020-09-06 17:07:30 +00:00
|
|
|
|
|
|
|
/* flags */
|
|
|
|
for(;;) {
|
|
|
|
c = *fmt;
|
|
|
|
if (c == '0' || c == '#' || c == '+' || c == '-' || c == ' ' ||
|
|
|
|
c == '\'') {
|
|
|
|
if (q >= fmtbuf + sizeof(fmtbuf) - 1)
|
2020-09-06 16:53:08 +00:00
|
|
|
goto invalid;
|
2020-09-06 17:07:30 +00:00
|
|
|
*q++ = c;
|
|
|
|
fmt++;
|
|
|
|
} else {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/* width */
|
|
|
|
if (*fmt == '*') {
|
|
|
|
if (i >= argc)
|
|
|
|
goto missing;
|
|
|
|
if (JS_ToInt32(ctx, &int32_arg, argv[i++]))
|
|
|
|
goto fail;
|
|
|
|
q += snprintf(q, fmtbuf + sizeof(fmtbuf) - q, "%d", int32_arg);
|
|
|
|
fmt++;
|
|
|
|
} else {
|
|
|
|
while (my_isdigit(*fmt)) {
|
|
|
|
if (q >= fmtbuf + sizeof(fmtbuf) - 1)
|
2020-09-06 16:53:08 +00:00
|
|
|
goto invalid;
|
2020-09-06 17:07:30 +00:00
|
|
|
*q++ = *fmt++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (*fmt == '.') {
|
|
|
|
if (q >= fmtbuf + sizeof(fmtbuf) - 1)
|
|
|
|
goto invalid;
|
|
|
|
*q++ = *fmt++;
|
|
|
|
if (*fmt == '*') {
|
2020-09-06 16:53:08 +00:00
|
|
|
if (i >= argc)
|
|
|
|
goto missing;
|
|
|
|
if (JS_ToInt32(ctx, &int32_arg, argv[i++]))
|
|
|
|
goto fail;
|
|
|
|
q += snprintf(q, fmtbuf + sizeof(fmtbuf) - q, "%d", int32_arg);
|
2020-09-06 17:07:30 +00:00
|
|
|
fmt++;
|
|
|
|
} else {
|
|
|
|
while (my_isdigit(*fmt)) {
|
|
|
|
if (q >= fmtbuf + sizeof(fmtbuf) - 1)
|
|
|
|
goto invalid;
|
|
|
|
*q++ = *fmt++;
|
2020-09-06 16:53:08 +00:00
|
|
|
}
|
2020-09-06 17:07:30 +00:00
|
|
|
}
|
|
|
|
}
|
2020-09-06 16:53:08 +00:00
|
|
|
|
2020-09-06 17:07:30 +00:00
|
|
|
/* we only support the "l" modifier for 64 bit numbers */
|
|
|
|
mod = ' ';
|
|
|
|
if (*fmt == 'l') {
|
|
|
|
mod = *fmt++;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* type */
|
|
|
|
c = *fmt++;
|
|
|
|
if (q >= fmtbuf + sizeof(fmtbuf) - 1)
|
|
|
|
goto invalid;
|
|
|
|
*q++ = c;
|
|
|
|
*q = '\0';
|
|
|
|
|
|
|
|
switch (c) {
|
|
|
|
case 'c':
|
|
|
|
if (i >= argc)
|
|
|
|
goto missing;
|
|
|
|
if (JS_IsString(argv[i])) {
|
2020-09-06 16:53:08 +00:00
|
|
|
string_arg = JS_ToCString(ctx, argv[i++]);
|
|
|
|
if (!string_arg)
|
|
|
|
goto fail;
|
2020-09-06 17:07:30 +00:00
|
|
|
int32_arg = unicode_from_utf8((uint8_t *)string_arg, UTF8_CHAR_LEN_MAX, &p);
|
2020-09-06 16:53:08 +00:00
|
|
|
JS_FreeCString(ctx, string_arg);
|
2020-09-06 17:07:30 +00:00
|
|
|
} else {
|
|
|
|
if (JS_ToInt32(ctx, &int32_arg, argv[i++]))
|
2020-09-06 16:53:08 +00:00
|
|
|
goto fail;
|
2020-09-06 17:07:30 +00:00
|
|
|
}
|
|
|
|
/* handle utf-8 encoding explicitly */
|
|
|
|
if ((unsigned)int32_arg > 0x10FFFF)
|
|
|
|
int32_arg = 0xFFFD;
|
|
|
|
/* ignore conversion flags, width and precision */
|
|
|
|
len = unicode_to_utf8(cbuf, int32_arg);
|
|
|
|
dbuf_put(&dbuf, cbuf, len);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 'd':
|
|
|
|
case 'i':
|
|
|
|
case 'o':
|
|
|
|
case 'u':
|
|
|
|
case 'x':
|
|
|
|
case 'X':
|
|
|
|
if (i >= argc)
|
|
|
|
goto missing;
|
|
|
|
if (JS_ToInt64Ext(ctx, &int64_arg, argv[i++]))
|
|
|
|
goto fail;
|
|
|
|
if (mod == 'l') {
|
|
|
|
/* 64 bit number */
|
|
|
|
#if defined(_WIN32)
|
|
|
|
if (q >= fmtbuf + sizeof(fmtbuf) - 3)
|
|
|
|
goto invalid;
|
|
|
|
q[2] = q[-1];
|
|
|
|
q[-1] = 'I';
|
|
|
|
q[0] = '6';
|
|
|
|
q[1] = '4';
|
|
|
|
q[3] = '\0';
|
|
|
|
dbuf_printf_fun(&dbuf, fmtbuf, (int64_t)int64_arg);
|
|
|
|
#else
|
|
|
|
if (q >= fmtbuf + sizeof(fmtbuf) - 2)
|
|
|
|
goto invalid;
|
|
|
|
q[1] = q[-1];
|
|
|
|
q[-1] = q[0] = 'l';
|
|
|
|
q[2] = '\0';
|
|
|
|
dbuf_printf_fun(&dbuf, fmtbuf, (long long)int64_arg);
|
|
|
|
#endif
|
|
|
|
} else {
|
|
|
|
dbuf_printf_fun(&dbuf, fmtbuf, (int)int64_arg);
|
|
|
|
}
|
|
|
|
break;
|
2020-09-06 16:53:08 +00:00
|
|
|
|
2020-09-06 17:07:30 +00:00
|
|
|
case 's':
|
|
|
|
if (i >= argc)
|
|
|
|
goto missing;
|
|
|
|
/* XXX: handle strings containing null characters */
|
|
|
|
string_arg = JS_ToCString(ctx, argv[i++]);
|
|
|
|
if (!string_arg)
|
2020-09-06 16:53:08 +00:00
|
|
|
goto fail;
|
2020-09-06 17:07:30 +00:00
|
|
|
dbuf_printf_fun(&dbuf, fmtbuf, string_arg);
|
|
|
|
JS_FreeCString(ctx, string_arg);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 'e':
|
|
|
|
case 'f':
|
|
|
|
case 'g':
|
|
|
|
case 'a':
|
|
|
|
case 'E':
|
|
|
|
case 'F':
|
|
|
|
case 'G':
|
|
|
|
case 'A':
|
|
|
|
if (i >= argc)
|
|
|
|
goto missing;
|
|
|
|
if (JS_ToFloat64(ctx, &double_arg, argv[i++]))
|
2020-09-06 16:53:08 +00:00
|
|
|
goto fail;
|
2020-09-06 17:07:30 +00:00
|
|
|
dbuf_printf_fun(&dbuf, fmtbuf, double_arg);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case '%':
|
|
|
|
dbuf_putc(&dbuf, '%');
|
2020-09-06 16:53:08 +00:00
|
|
|
break;
|
2020-09-06 17:07:30 +00:00
|
|
|
|
|
|
|
default:
|
|
|
|
/* XXX: should support an extension mechanism */
|
|
|
|
invalid:
|
|
|
|
JS_ThrowTypeError(ctx, "invalid conversion specifier in format string");
|
|
|
|
goto fail;
|
|
|
|
missing:
|
|
|
|
JS_ThrowReferenceError(ctx, "missing argument for conversion specifier");
|
|
|
|
goto fail;
|
2020-09-06 16:53:08 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
JS_FreeCString(ctx, fmt_str);
|
|
|
|
}
|
|
|
|
if (dbuf.error) {
|
|
|
|
res = JS_ThrowOutOfMemory(ctx);
|
|
|
|
} else {
|
|
|
|
if (fp) {
|
|
|
|
len = fwrite(dbuf.buf, 1, dbuf.size, fp);
|
|
|
|
res = JS_NewInt32(ctx, len);
|
|
|
|
} else {
|
|
|
|
res = JS_NewStringLen(ctx, (char *)dbuf.buf, dbuf.size);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
dbuf_free(&dbuf);
|
|
|
|
return res;
|
|
|
|
|
|
|
|
fail:
|
|
|
|
dbuf_free(&dbuf);
|
|
|
|
return JS_EXCEPTION;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint8_t *js_load_file(JSContext *ctx, size_t *pbuf_len, const char *filename)
|
|
|
|
{
|
|
|
|
FILE *f;
|
|
|
|
uint8_t *buf;
|
|
|
|
size_t buf_len;
|
|
|
|
long lret;
|
|
|
|
|
|
|
|
f = fopen(filename, "rb");
|
|
|
|
if (!f)
|
|
|
|
return NULL;
|
|
|
|
if (fseek(f, 0, SEEK_END) < 0)
|
|
|
|
goto fail;
|
|
|
|
lret = ftell(f);
|
|
|
|
if (lret < 0)
|
|
|
|
goto fail;
|
|
|
|
/* XXX: on Linux, ftell() return LONG_MAX for directories */
|
|
|
|
if (lret == LONG_MAX) {
|
|
|
|
errno = EISDIR;
|
|
|
|
goto fail;
|
|
|
|
}
|
|
|
|
buf_len = lret;
|
|
|
|
if (fseek(f, 0, SEEK_SET) < 0)
|
|
|
|
goto fail;
|
|
|
|
if (ctx)
|
|
|
|
buf = js_malloc(ctx, buf_len + 1);
|
|
|
|
else
|
|
|
|
buf = malloc(buf_len + 1);
|
|
|
|
if (!buf)
|
|
|
|
goto fail;
|
|
|
|
if (fread(buf, 1, buf_len, f) != buf_len) {
|
|
|
|
errno = EIO;
|
|
|
|
if (ctx)
|
|
|
|
js_free(ctx, buf);
|
|
|
|
else
|
|
|
|
free(buf);
|
|
|
|
fail:
|
|
|
|
fclose(f);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
buf[buf_len] = '\0';
|
|
|
|
fclose(f);
|
|
|
|
*pbuf_len = buf_len;
|
|
|
|
return buf;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* load and evaluate a file */
|
|
|
|
static JSValue js_loadScript(JSContext *ctx, JSValueConst this_val,
|
|
|
|
int argc, JSValueConst *argv)
|
|
|
|
{
|
|
|
|
uint8_t *buf;
|
|
|
|
const char *filename;
|
|
|
|
JSValue ret;
|
|
|
|
size_t buf_len;
|
|
|
|
|
|
|
|
filename = JS_ToCString(ctx, argv[0]);
|
|
|
|
if (!filename)
|
|
|
|
return JS_EXCEPTION;
|
|
|
|
buf = js_load_file(ctx, &buf_len, filename);
|
|
|
|
if (!buf) {
|
|
|
|
JS_ThrowReferenceError(ctx, "could not load '%s'", filename);
|
|
|
|
JS_FreeCString(ctx, filename);
|
|
|
|
return JS_EXCEPTION;
|
|
|
|
}
|
|
|
|
ret = JS_Eval(ctx, (char *)buf, buf_len, filename,
|
|
|
|
JS_EVAL_TYPE_GLOBAL);
|
|
|
|
js_free(ctx, buf);
|
|
|
|
JS_FreeCString(ctx, filename);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2020-09-06 17:02:03 +00:00
|
|
|
/* load a file as a UTF-8 encoded string */
|
|
|
|
static JSValue js_std_loadFile(JSContext *ctx, JSValueConst this_val,
|
|
|
|
int argc, JSValueConst *argv)
|
|
|
|
{
|
|
|
|
uint8_t *buf;
|
|
|
|
const char *filename;
|
|
|
|
JSValue ret;
|
|
|
|
size_t buf_len;
|
|
|
|
|
|
|
|
filename = JS_ToCString(ctx, argv[0]);
|
|
|
|
if (!filename)
|
|
|
|
return JS_EXCEPTION;
|
|
|
|
buf = js_load_file(ctx, &buf_len, filename);
|
|
|
|
JS_FreeCString(ctx, filename);
|
|
|
|
if (!buf)
|
|
|
|
return JS_NULL;
|
|
|
|
ret = JS_NewStringLen(ctx, (char *)buf, buf_len);
|
|
|
|
js_free(ctx, buf);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2020-09-06 16:53:08 +00:00
|
|
|
typedef JSModuleDef *(JSInitModuleFunc)(JSContext *ctx,
|
|
|
|
const char *module_name);
|
|
|
|
|
|
|
|
|
|
|
|
#if defined(_WIN32)
|
|
|
|
static JSModuleDef *js_module_loader_so(JSContext *ctx,
|
|
|
|
const char *module_name)
|
|
|
|
{
|
|
|
|
JS_ThrowReferenceError(ctx, "shared library modules are not supported yet");
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
static JSModuleDef *js_module_loader_so(JSContext *ctx,
|
|
|
|
const char *module_name)
|
|
|
|
{
|
|
|
|
JSModuleDef *m;
|
|
|
|
void *hd;
|
|
|
|
JSInitModuleFunc *init;
|
|
|
|
char *filename;
|
|
|
|
|
|
|
|
if (!strchr(module_name, '/')) {
|
|
|
|
/* must add a '/' so that the DLL is not searched in the
|
|
|
|
system library paths */
|
|
|
|
filename = js_malloc(ctx, strlen(module_name) + 2 + 1);
|
|
|
|
if (!filename)
|
|
|
|
return NULL;
|
|
|
|
strcpy(filename, "./");
|
|
|
|
strcpy(filename + 2, module_name);
|
|
|
|
} else {
|
|
|
|
filename = (char *)module_name;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* C module */
|
|
|
|
hd = dlopen(filename, RTLD_NOW | RTLD_LOCAL);
|
|
|
|
if (filename != module_name)
|
|
|
|
js_free(ctx, filename);
|
|
|
|
if (!hd) {
|
|
|
|
JS_ThrowReferenceError(ctx, "could not load module filename '%s' as shared library",
|
|
|
|
module_name);
|
|
|
|
goto fail;
|
|
|
|
}
|
|
|
|
|
|
|
|
init = dlsym(hd, "js_init_module");
|
|
|
|
if (!init) {
|
|
|
|
JS_ThrowReferenceError(ctx, "could not load module filename '%s': js_init_module not found",
|
|
|
|
module_name);
|
|
|
|
goto fail;
|
|
|
|
}
|
|
|
|
|
|
|
|
m = init(ctx, module_name);
|
|
|
|
if (!m) {
|
|
|
|
JS_ThrowReferenceError(ctx, "could not load module filename '%s': initialization error",
|
|
|
|
module_name);
|
|
|
|
fail:
|
|
|
|
if (hd)
|
|
|
|
dlclose(hd);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
return m;
|
|
|
|
}
|
|
|
|
#endif /* !_WIN32 */
|
|
|
|
|
|
|
|
int js_module_set_import_meta(JSContext *ctx, JSValueConst func_val,
|
|
|
|
JS_BOOL use_realpath, JS_BOOL is_main)
|
|
|
|
{
|
|
|
|
JSModuleDef *m;
|
|
|
|
char buf[PATH_MAX + 16];
|
|
|
|
JSValue meta_obj;
|
|
|
|
JSAtom module_name_atom;
|
|
|
|
const char *module_name;
|
|
|
|
|
|
|
|
assert(JS_VALUE_GET_TAG(func_val) == JS_TAG_MODULE);
|
|
|
|
m = JS_VALUE_GET_PTR(func_val);
|
|
|
|
|
|
|
|
module_name_atom = JS_GetModuleName(ctx, m);
|
|
|
|
module_name = JS_AtomToCString(ctx, module_name_atom);
|
|
|
|
JS_FreeAtom(ctx, module_name_atom);
|
|
|
|
if (!module_name)
|
|
|
|
return -1;
|
|
|
|
if (!strchr(module_name, ':')) {
|
|
|
|
strcpy(buf, "file://");
|
|
|
|
#if !defined(_WIN32)
|
|
|
|
/* realpath() cannot be used with modules compiled with qjsc
|
|
|
|
because the corresponding module source code is not
|
|
|
|
necessarily present */
|
|
|
|
if (use_realpath) {
|
|
|
|
char *res = realpath(module_name, buf + strlen(buf));
|
|
|
|
if (!res) {
|
|
|
|
JS_ThrowTypeError(ctx, "realpath failure");
|
|
|
|
JS_FreeCString(ctx, module_name);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
} else
|
|
|
|
#endif
|
|
|
|
{
|
|
|
|
pstrcat(buf, sizeof(buf), module_name);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
pstrcpy(buf, sizeof(buf), module_name);
|
|
|
|
}
|
|
|
|
JS_FreeCString(ctx, module_name);
|
|
|
|
|
|
|
|
meta_obj = JS_GetImportMeta(ctx, m);
|
|
|
|
if (JS_IsException(meta_obj))
|
|
|
|
return -1;
|
|
|
|
JS_DefinePropertyValueStr(ctx, meta_obj, "url",
|
|
|
|
JS_NewString(ctx, buf),
|
|
|
|
JS_PROP_C_W_E);
|
|
|
|
JS_DefinePropertyValueStr(ctx, meta_obj, "main",
|
|
|
|
JS_NewBool(ctx, is_main),
|
|
|
|
JS_PROP_C_W_E);
|
|
|
|
JS_FreeValue(ctx, meta_obj);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
JSModuleDef *js_module_loader(JSContext *ctx,
|
|
|
|
const char *module_name, void *opaque)
|
|
|
|
{
|
|
|
|
JSModuleDef *m;
|
|
|
|
|
|
|
|
if (has_suffix(module_name, ".so")) {
|
|
|
|
m = js_module_loader_so(ctx, module_name);
|
|
|
|
} else {
|
|
|
|
size_t buf_len;
|
|
|
|
uint8_t *buf;
|
|
|
|
JSValue func_val;
|
|
|
|
|
|
|
|
buf = js_load_file(ctx, &buf_len, module_name);
|
|
|
|
if (!buf) {
|
|
|
|
JS_ThrowReferenceError(ctx, "could not load module filename '%s'",
|
|
|
|
module_name);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* compile the module */
|
|
|
|
func_val = JS_Eval(ctx, (char *)buf, buf_len, module_name,
|
|
|
|
JS_EVAL_TYPE_MODULE | JS_EVAL_FLAG_COMPILE_ONLY);
|
|
|
|
js_free(ctx, buf);
|
|
|
|
if (JS_IsException(func_val))
|
|
|
|
return NULL;
|
|
|
|
/* XXX: could propagate the exception */
|
|
|
|
js_module_set_import_meta(ctx, func_val, TRUE, FALSE);
|
|
|
|
/* the module is already referenced, so we must free it */
|
|
|
|
m = JS_VALUE_GET_PTR(func_val);
|
|
|
|
JS_FreeValue(ctx, func_val);
|
|
|
|
}
|
|
|
|
return m;
|
|
|
|
}
|
|
|
|
|
|
|
|
static JSValue js_std_exit(JSContext *ctx, JSValueConst this_val,
|
|
|
|
int argc, JSValueConst *argv)
|
|
|
|
{
|
|
|
|
int status;
|
|
|
|
if (JS_ToInt32(ctx, &status, argv[0]))
|
|
|
|
status = -1;
|
|
|
|
exit(status);
|
|
|
|
return JS_UNDEFINED;
|
|
|
|
}
|
|
|
|
|
|
|
|
static JSValue js_std_getenv(JSContext *ctx, JSValueConst this_val,
|
|
|
|
int argc, JSValueConst *argv)
|
|
|
|
{
|
|
|
|
const char *name, *str;
|
|
|
|
name = JS_ToCString(ctx, argv[0]);
|
|
|
|
if (!name)
|
|
|
|
return JS_EXCEPTION;
|
|
|
|
str = getenv(name);
|
|
|
|
JS_FreeCString(ctx, name);
|
|
|
|
if (!str)
|
|
|
|
return JS_UNDEFINED;
|
|
|
|
else
|
|
|
|
return JS_NewString(ctx, str);
|
|
|
|
}
|
|
|
|
|
2020-11-08 13:30:56 +00:00
|
|
|
#if defined(_WIN32)
|
|
|
|
static void setenv(const char *name, const char *value, int overwrite)
|
|
|
|
{
|
|
|
|
char *str;
|
|
|
|
size_t name_len, value_len;
|
|
|
|
name_len = strlen(name);
|
|
|
|
value_len = strlen(value);
|
|
|
|
str = malloc(name_len + 1 + value_len + 1);
|
|
|
|
memcpy(str, name, name_len);
|
|
|
|
str[name_len] = '=';
|
|
|
|
memcpy(str + name_len + 1, value, value_len);
|
|
|
|
str[name_len + 1 + value_len] = '\0';
|
|
|
|
_putenv(str);
|
|
|
|
free(str);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void unsetenv(const char *name)
|
|
|
|
{
|
|
|
|
setenv(name, "", TRUE);
|
|
|
|
}
|
|
|
|
#endif /* _WIN32 */
|
|
|
|
|
|
|
|
static JSValue js_std_setenv(JSContext *ctx, JSValueConst this_val,
|
|
|
|
int argc, JSValueConst *argv)
|
|
|
|
{
|
|
|
|
const char *name, *value;
|
|
|
|
name = JS_ToCString(ctx, argv[0]);
|
|
|
|
if (!name)
|
|
|
|
return JS_EXCEPTION;
|
|
|
|
value = JS_ToCString(ctx, argv[1]);
|
|
|
|
if (!value) {
|
|
|
|
JS_FreeCString(ctx, name);
|
|
|
|
return JS_EXCEPTION;
|
|
|
|
}
|
|
|
|
setenv(name, value, TRUE);
|
|
|
|
JS_FreeCString(ctx, name);
|
|
|
|
JS_FreeCString(ctx, value);
|
|
|
|
return JS_UNDEFINED;
|
|
|
|
}
|
|
|
|
|
|
|
|
static JSValue js_std_unsetenv(JSContext *ctx, JSValueConst this_val,
|
|
|
|
int argc, JSValueConst *argv)
|
|
|
|
{
|
|
|
|
const char *name;
|
|
|
|
name = JS_ToCString(ctx, argv[0]);
|
|
|
|
if (!name)
|
|
|
|
return JS_EXCEPTION;
|
|
|
|
unsetenv(name);
|
|
|
|
JS_FreeCString(ctx, name);
|
|
|
|
return JS_UNDEFINED;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* return an object containing the list of the available environment
|
|
|
|
variables. */
|
|
|
|
static JSValue js_std_getenviron(JSContext *ctx, JSValueConst this_val,
|
|
|
|
int argc, JSValueConst *argv)
|
|
|
|
{
|
|
|
|
char **envp;
|
|
|
|
const char *name, *p, *value;
|
|
|
|
JSValue obj;
|
|
|
|
uint32_t idx;
|
|
|
|
size_t name_len;
|
|
|
|
JSAtom atom;
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
obj = JS_NewObject(ctx);
|
|
|
|
if (JS_IsException(obj))
|
|
|
|
return JS_EXCEPTION;
|
|
|
|
envp = environ;
|
|
|
|
for(idx = 0; envp[idx] != NULL; idx++) {
|
|
|
|
name = envp[idx];
|
|
|
|
p = strchr(name, '=');
|
|
|
|
name_len = p - name;
|
|
|
|
if (!p)
|
|
|
|
continue;
|
|
|
|
value = p + 1;
|
|
|
|
atom = JS_NewAtomLen(ctx, name, name_len);
|
|
|
|
if (atom == JS_ATOM_NULL)
|
|
|
|
goto fail;
|
|
|
|
ret = JS_DefinePropertyValue(ctx, obj, atom, JS_NewString(ctx, value),
|
|
|
|
JS_PROP_C_W_E);
|
|
|
|
JS_FreeAtom(ctx, atom);
|
|
|
|
if (ret < 0)
|
|
|
|
goto fail;
|
|
|
|
}
|
|
|
|
return obj;
|
|
|
|
fail:
|
|
|
|
JS_FreeValue(ctx, obj);
|
|
|
|
return JS_EXCEPTION;
|
|
|
|
}
|
|
|
|
|
2020-09-06 16:53:08 +00:00
|
|
|
static JSValue js_std_gc(JSContext *ctx, JSValueConst this_val,
|
|
|
|
int argc, JSValueConst *argv)
|
|
|
|
{
|
|
|
|
JS_RunGC(JS_GetRuntime(ctx));
|
|
|
|
return JS_UNDEFINED;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int interrupt_handler(JSRuntime *rt, void *opaque)
|
|
|
|
{
|
|
|
|
return (os_pending_signals >> SIGINT) & 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int get_bool_option(JSContext *ctx, BOOL *pbool,
|
|
|
|
JSValueConst obj,
|
|
|
|
const char *option)
|
|
|
|
{
|
|
|
|
JSValue val;
|
|
|
|
val = JS_GetPropertyStr(ctx, obj, option);
|
|
|
|
if (JS_IsException(val))
|
|
|
|
return -1;
|
|
|
|
if (!JS_IsUndefined(val)) {
|
|
|
|
*pbool = JS_ToBool(ctx, val);
|
|
|
|
}
|
|
|
|
JS_FreeValue(ctx, val);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static JSValue js_evalScript(JSContext *ctx, JSValueConst this_val,
|
|
|
|
int argc, JSValueConst *argv)
|
|
|
|
{
|
2020-09-06 17:07:30 +00:00
|
|
|
JSRuntime *rt = JS_GetRuntime(ctx);
|
|
|
|
JSThreadState *ts = JS_GetRuntimeOpaque(rt);
|
2020-09-06 16:53:08 +00:00
|
|
|
const char *str;
|
|
|
|
size_t len;
|
|
|
|
JSValue ret;
|
|
|
|
JSValueConst options_obj;
|
|
|
|
BOOL backtrace_barrier = FALSE;
|
|
|
|
int flags;
|
|
|
|
|
|
|
|
if (argc >= 2) {
|
|
|
|
options_obj = argv[1];
|
|
|
|
if (get_bool_option(ctx, &backtrace_barrier, options_obj,
|
|
|
|
"backtrace_barrier"))
|
|
|
|
return JS_EXCEPTION;
|
|
|
|
}
|
|
|
|
|
|
|
|
str = JS_ToCStringLen(ctx, &len, argv[0]);
|
|
|
|
if (!str)
|
|
|
|
return JS_EXCEPTION;
|
2020-09-06 17:07:30 +00:00
|
|
|
if (!ts->recv_pipe && ++ts->eval_script_recurse == 1) {
|
2020-09-06 16:53:08 +00:00
|
|
|
/* install the interrupt handler */
|
|
|
|
JS_SetInterruptHandler(JS_GetRuntime(ctx), interrupt_handler, NULL);
|
|
|
|
}
|
|
|
|
flags = JS_EVAL_TYPE_GLOBAL;
|
|
|
|
if (backtrace_barrier)
|
|
|
|
flags |= JS_EVAL_FLAG_BACKTRACE_BARRIER;
|
|
|
|
ret = JS_Eval(ctx, str, len, "<evalScript>", flags);
|
|
|
|
JS_FreeCString(ctx, str);
|
2020-09-06 17:07:30 +00:00
|
|
|
if (!ts->recv_pipe && --ts->eval_script_recurse == 0) {
|
2020-09-06 16:53:08 +00:00
|
|
|
/* remove the interrupt handler */
|
|
|
|
JS_SetInterruptHandler(JS_GetRuntime(ctx), NULL, NULL);
|
|
|
|
os_pending_signals &= ~((uint64_t)1 << SIGINT);
|
|
|
|
/* convert the uncatchable "interrupted" error into a normal error
|
|
|
|
so that it can be caught by the REPL */
|
|
|
|
if (JS_IsException(ret))
|
|
|
|
JS_ResetUncatchableError(ctx);
|
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
static JSClassID js_std_file_class_id;
|
|
|
|
|
|
|
|
typedef struct {
|
|
|
|
FILE *f;
|
|
|
|
BOOL close_in_finalizer;
|
|
|
|
BOOL is_popen;
|
|
|
|
} JSSTDFile;
|
|
|
|
|
|
|
|
static void js_std_file_finalizer(JSRuntime *rt, JSValue val)
|
|
|
|
{
|
|
|
|
JSSTDFile *s = JS_GetOpaque(val, js_std_file_class_id);
|
|
|
|
if (s) {
|
|
|
|
if (s->f && s->close_in_finalizer) {
|
|
|
|
if (s->is_popen)
|
|
|
|
pclose(s->f);
|
|
|
|
else
|
|
|
|
fclose(s->f);
|
|
|
|
}
|
|
|
|
js_free_rt(rt, s);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-09-06 17:02:03 +00:00
|
|
|
static ssize_t js_get_errno(ssize_t ret)
|
2020-09-06 16:53:08 +00:00
|
|
|
{
|
2020-09-06 17:02:03 +00:00
|
|
|
if (ret == -1)
|
|
|
|
ret = -errno;
|
|
|
|
return ret;
|
2020-09-06 16:53:08 +00:00
|
|
|
}
|
|
|
|
|
2020-09-06 17:02:03 +00:00
|
|
|
static JSValue js_std_strerror(JSContext *ctx, JSValueConst this_val,
|
2020-09-06 16:53:08 +00:00
|
|
|
int argc, JSValueConst *argv)
|
|
|
|
{
|
|
|
|
int err;
|
|
|
|
if (JS_ToInt32(ctx, &err, argv[0]))
|
|
|
|
return JS_EXCEPTION;
|
|
|
|
return JS_NewString(ctx, strerror(err));
|
|
|
|
}
|
|
|
|
|
2020-09-06 17:07:30 +00:00
|
|
|
static JSValue js_std_parseExtJSON(JSContext *ctx, JSValueConst this_val,
|
|
|
|
int argc, JSValueConst *argv)
|
|
|
|
{
|
|
|
|
JSValue obj;
|
|
|
|
const char *str;
|
|
|
|
size_t len;
|
|
|
|
|
|
|
|
str = JS_ToCStringLen(ctx, &len, argv[0]);
|
|
|
|
if (!str)
|
|
|
|
return JS_EXCEPTION;
|
|
|
|
obj = JS_ParseJSON2(ctx, str, len, "<input>", JS_PARSE_JSON_EXT);
|
|
|
|
JS_FreeCString(ctx, str);
|
|
|
|
return obj;
|
|
|
|
}
|
|
|
|
|
2020-09-06 16:53:08 +00:00
|
|
|
static JSValue js_new_std_file(JSContext *ctx, FILE *f,
|
|
|
|
BOOL close_in_finalizer,
|
|
|
|
BOOL is_popen)
|
|
|
|
{
|
|
|
|
JSSTDFile *s;
|
|
|
|
JSValue obj;
|
|
|
|
obj = JS_NewObjectClass(ctx, js_std_file_class_id);
|
|
|
|
if (JS_IsException(obj))
|
|
|
|
return obj;
|
|
|
|
s = js_mallocz(ctx, sizeof(*s));
|
|
|
|
if (!s) {
|
|
|
|
JS_FreeValue(ctx, obj);
|
|
|
|
return JS_EXCEPTION;
|
|
|
|
}
|
|
|
|
s->close_in_finalizer = close_in_finalizer;
|
|
|
|
s->is_popen = is_popen;
|
|
|
|
s->f = f;
|
|
|
|
JS_SetOpaque(obj, s);
|
|
|
|
return obj;
|
|
|
|
}
|
|
|
|
|
2020-09-06 17:02:03 +00:00
|
|
|
static void js_set_error_object(JSContext *ctx, JSValue obj, int err)
|
|
|
|
{
|
|
|
|
if (!JS_IsUndefined(obj)) {
|
|
|
|
JS_SetPropertyStr(ctx, obj, "errno", JS_NewInt32(ctx, err));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-09-06 16:53:08 +00:00
|
|
|
static JSValue js_std_open(JSContext *ctx, JSValueConst this_val,
|
|
|
|
int argc, JSValueConst *argv)
|
|
|
|
{
|
|
|
|
const char *filename, *mode = NULL;
|
|
|
|
FILE *f;
|
2020-09-06 17:02:03 +00:00
|
|
|
int err;
|
|
|
|
|
2020-09-06 16:53:08 +00:00
|
|
|
filename = JS_ToCString(ctx, argv[0]);
|
|
|
|
if (!filename)
|
|
|
|
goto fail;
|
|
|
|
mode = JS_ToCString(ctx, argv[1]);
|
|
|
|
if (!mode)
|
|
|
|
goto fail;
|
|
|
|
if (mode[strspn(mode, "rwa+b")] != '\0') {
|
2020-09-06 17:02:03 +00:00
|
|
|
JS_ThrowTypeError(ctx, "invalid file mode");
|
2020-09-06 16:53:08 +00:00
|
|
|
goto fail;
|
|
|
|
}
|
|
|
|
|
|
|
|
f = fopen(filename, mode);
|
2020-09-06 17:02:03 +00:00
|
|
|
if (!f)
|
|
|
|
err = errno;
|
|
|
|
else
|
|
|
|
err = 0;
|
|
|
|
if (argc >= 3)
|
|
|
|
js_set_error_object(ctx, argv[2], err);
|
2020-09-06 16:53:08 +00:00
|
|
|
JS_FreeCString(ctx, filename);
|
|
|
|
JS_FreeCString(ctx, mode);
|
|
|
|
if (!f)
|
2020-09-06 17:02:03 +00:00
|
|
|
return JS_NULL;
|
2020-09-06 16:53:08 +00:00
|
|
|
return js_new_std_file(ctx, f, TRUE, FALSE);
|
|
|
|
fail:
|
|
|
|
JS_FreeCString(ctx, filename);
|
|
|
|
JS_FreeCString(ctx, mode);
|
|
|
|
return JS_EXCEPTION;
|
|
|
|
}
|
|
|
|
|
|
|
|
static JSValue js_std_popen(JSContext *ctx, JSValueConst this_val,
|
|
|
|
int argc, JSValueConst *argv)
|
|
|
|
{
|
|
|
|
const char *filename, *mode = NULL;
|
|
|
|
FILE *f;
|
2020-09-06 17:02:03 +00:00
|
|
|
int err;
|
|
|
|
|
2020-09-06 16:53:08 +00:00
|
|
|
filename = JS_ToCString(ctx, argv[0]);
|
|
|
|
if (!filename)
|
|
|
|
goto fail;
|
|
|
|
mode = JS_ToCString(ctx, argv[1]);
|
|
|
|
if (!mode)
|
|
|
|
goto fail;
|
|
|
|
if (mode[strspn(mode, "rw")] != '\0') {
|
2020-09-06 17:02:03 +00:00
|
|
|
JS_ThrowTypeError(ctx, "invalid file mode");
|
2020-09-06 16:53:08 +00:00
|
|
|
goto fail;
|
|
|
|
}
|
|
|
|
|
|
|
|
f = popen(filename, mode);
|
2020-09-06 17:02:03 +00:00
|
|
|
if (!f)
|
|
|
|
err = errno;
|
|
|
|
else
|
|
|
|
err = 0;
|
|
|
|
if (argc >= 3)
|
|
|
|
js_set_error_object(ctx, argv[2], err);
|
2020-09-06 16:53:08 +00:00
|
|
|
JS_FreeCString(ctx, filename);
|
|
|
|
JS_FreeCString(ctx, mode);
|
|
|
|
if (!f)
|
2020-09-06 17:02:03 +00:00
|
|
|
return JS_NULL;
|
2020-09-06 16:53:08 +00:00
|
|
|
return js_new_std_file(ctx, f, TRUE, TRUE);
|
|
|
|
fail:
|
|
|
|
JS_FreeCString(ctx, filename);
|
|
|
|
JS_FreeCString(ctx, mode);
|
|
|
|
return JS_EXCEPTION;
|
|
|
|
}
|
|
|
|
|
|
|
|
static JSValue js_std_fdopen(JSContext *ctx, JSValueConst this_val,
|
|
|
|
int argc, JSValueConst *argv)
|
|
|
|
{
|
|
|
|
const char *mode;
|
|
|
|
FILE *f;
|
2020-09-06 17:02:03 +00:00
|
|
|
int fd, err;
|
2020-09-06 16:53:08 +00:00
|
|
|
|
|
|
|
if (JS_ToInt32(ctx, &fd, argv[0]))
|
|
|
|
return JS_EXCEPTION;
|
|
|
|
mode = JS_ToCString(ctx, argv[1]);
|
|
|
|
if (!mode)
|
|
|
|
goto fail;
|
|
|
|
if (mode[strspn(mode, "rwa+")] != '\0') {
|
2020-09-06 17:02:03 +00:00
|
|
|
JS_ThrowTypeError(ctx, "invalid file mode");
|
2020-09-06 16:53:08 +00:00
|
|
|
goto fail;
|
|
|
|
}
|
|
|
|
|
|
|
|
f = fdopen(fd, mode);
|
2020-09-06 17:02:03 +00:00
|
|
|
if (!f)
|
|
|
|
err = errno;
|
|
|
|
else
|
|
|
|
err = 0;
|
|
|
|
if (argc >= 3)
|
|
|
|
js_set_error_object(ctx, argv[2], err);
|
2020-09-06 16:53:08 +00:00
|
|
|
JS_FreeCString(ctx, mode);
|
|
|
|
if (!f)
|
2020-09-06 17:02:03 +00:00
|
|
|
return JS_NULL;
|
2020-09-06 16:53:08 +00:00
|
|
|
return js_new_std_file(ctx, f, TRUE, FALSE);
|
|
|
|
fail:
|
|
|
|
JS_FreeCString(ctx, mode);
|
|
|
|
return JS_EXCEPTION;
|
|
|
|
}
|
|
|
|
|
|
|
|
static JSValue js_std_tmpfile(JSContext *ctx, JSValueConst this_val,
|
|
|
|
int argc, JSValueConst *argv)
|
|
|
|
{
|
|
|
|
FILE *f;
|
|
|
|
f = tmpfile();
|
2020-09-06 17:02:03 +00:00
|
|
|
if (argc >= 1)
|
|
|
|
js_set_error_object(ctx, argv[0], f ? 0 : errno);
|
2020-09-06 16:53:08 +00:00
|
|
|
if (!f)
|
2020-09-06 17:02:03 +00:00
|
|
|
return JS_NULL;
|
2020-09-06 16:53:08 +00:00
|
|
|
return js_new_std_file(ctx, f, TRUE, FALSE);
|
|
|
|
}
|
|
|
|
|
|
|
|
static JSValue js_std_sprintf(JSContext *ctx, JSValueConst this_val,
|
|
|
|
int argc, JSValueConst *argv)
|
|
|
|
{
|
|
|
|
return js_printf_internal(ctx, argc, argv, NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
static JSValue js_std_printf(JSContext *ctx, JSValueConst this_val,
|
|
|
|
int argc, JSValueConst *argv)
|
|
|
|
{
|
|
|
|
return js_printf_internal(ctx, argc, argv, stdout);
|
|
|
|
}
|
|
|
|
|
|
|
|
static FILE *js_std_file_get(JSContext *ctx, JSValueConst obj)
|
|
|
|
{
|
|
|
|
JSSTDFile *s = JS_GetOpaque2(ctx, obj, js_std_file_class_id);
|
|
|
|
if (!s)
|
|
|
|
return NULL;
|
|
|
|
if (!s->f) {
|
2020-09-06 17:02:03 +00:00
|
|
|
JS_ThrowTypeError(ctx, "invalid file handle");
|
2020-09-06 16:53:08 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
return s->f;
|
|
|
|
}
|
|
|
|
|
|
|
|
static JSValue js_std_file_puts(JSContext *ctx, JSValueConst this_val,
|
|
|
|
int argc, JSValueConst *argv, int magic)
|
|
|
|
{
|
|
|
|
FILE *f;
|
|
|
|
int i;
|
|
|
|
const char *str;
|
2020-09-06 17:04:20 +00:00
|
|
|
size_t len;
|
2020-09-06 16:53:08 +00:00
|
|
|
|
|
|
|
if (magic == 0) {
|
|
|
|
f = stdout;
|
|
|
|
} else {
|
|
|
|
f = js_std_file_get(ctx, this_val);
|
|
|
|
if (!f)
|
|
|
|
return JS_EXCEPTION;
|
|
|
|
}
|
|
|
|
|
|
|
|
for(i = 0; i < argc; i++) {
|
2020-09-06 17:04:20 +00:00
|
|
|
str = JS_ToCStringLen(ctx, &len, argv[i]);
|
2020-09-06 16:53:08 +00:00
|
|
|
if (!str)
|
|
|
|
return JS_EXCEPTION;
|
2020-09-06 17:04:20 +00:00
|
|
|
fwrite(str, 1, len, f);
|
2020-09-06 16:53:08 +00:00
|
|
|
JS_FreeCString(ctx, str);
|
|
|
|
}
|
|
|
|
return JS_UNDEFINED;
|
|
|
|
}
|
|
|
|
|
|
|
|
static JSValue js_std_file_close(JSContext *ctx, JSValueConst this_val,
|
|
|
|
int argc, JSValueConst *argv)
|
|
|
|
{
|
|
|
|
JSSTDFile *s = JS_GetOpaque2(ctx, this_val, js_std_file_class_id);
|
2020-09-06 17:02:03 +00:00
|
|
|
int err;
|
2020-09-06 16:53:08 +00:00
|
|
|
if (!s)
|
|
|
|
return JS_EXCEPTION;
|
|
|
|
if (!s->f)
|
2020-09-06 17:02:03 +00:00
|
|
|
return JS_ThrowTypeError(ctx, "invalid file handle");
|
2020-09-06 16:53:08 +00:00
|
|
|
if (s->is_popen)
|
2020-09-06 17:02:03 +00:00
|
|
|
err = js_get_errno(pclose(s->f));
|
2020-09-06 16:53:08 +00:00
|
|
|
else
|
2020-09-06 17:02:03 +00:00
|
|
|
err = js_get_errno(fclose(s->f));
|
2020-09-06 16:53:08 +00:00
|
|
|
s->f = NULL;
|
2020-09-06 17:02:03 +00:00
|
|
|
return JS_NewInt32(ctx, err);
|
2020-09-06 16:53:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static JSValue js_std_file_printf(JSContext *ctx, JSValueConst this_val,
|
|
|
|
int argc, JSValueConst *argv)
|
|
|
|
{
|
|
|
|
FILE *f = js_std_file_get(ctx, this_val);
|
|
|
|
if (!f)
|
|
|
|
return JS_EXCEPTION;
|
|
|
|
return js_printf_internal(ctx, argc, argv, f);
|
|
|
|
}
|
|
|
|
|
|
|
|
static JSValue js_std_file_flush(JSContext *ctx, JSValueConst this_val,
|
|