3926 lines · 108.6 KB · C
RawDownload
/* * QuickJS C library *  * Copyright (c) 2017-2020 Fabrice Bellard * Copyright (c) 2017-2020 Charlie Gordon * * 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>#include <utime.h>#else#include <dlfcn.h>#include <termios.h>#include <sys/ioctl.h>#include <sys/wait.h> #if defined(__APPLE__)typedef sig_t sighandler_t;#if !defined(environ)#include <crt_externs.h>#define environ (*_NSGetEnviron())#endif#endif /* __APPLE__ */ #endif #if !defined(_WIN32) && !defined(__plan9__)/* enable the os.Worker API. IT relies on POSIX threads */#define USE_WORKER#endif #ifdef USE_WORKER#include <pthread.h>#include <stdatomic.h>#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; 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; static uint64_t os_pending_signals;static int (*os_poll_func)(JSContext *ctx); 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');} 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;    int i, c, len, mod;    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 '%' */                        /* flags */            for(;;) {                c = *fmt;                if (c == '0' || c == '#' || c == '+' || c == '-' || c == ' ' ||                    c == '\'') {                    if (q >= fmtbuf + sizeof(fmtbuf) - 1)                        goto invalid;                    *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)                        goto invalid;                    *q++ = *fmt++;                }            }            if (*fmt == '.') {                if (q >= fmtbuf + sizeof(fmtbuf) - 1)                    goto invalid;                *q++ = *fmt++;                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)                            goto invalid;                        *q++ = *fmt++;                    }                }            }             /* 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])) {                    string_arg = JS_ToCString(ctx, argv[i++]);                    if (!string_arg)                        goto fail;                    int32_arg = unicode_from_utf8((uint8_t *)string_arg, UTF8_CHAR_LEN_MAX, &p);                    JS_FreeCString(ctx, string_arg);                } else {                    if (JS_ToInt32(ctx, &int32_arg, argv[i++]))                        goto fail;                }                /* 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;             case 's':                if (i >= argc)                    goto missing;                /* XXX: handle strings containing null characters */                string_arg = JS_ToCString(ctx, argv[i++]);                if (!string_arg)                    goto fail;                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++]))                    goto fail;                dbuf_printf_fun(&dbuf, fmtbuf, double_arg);                break;                            case '%':                dbuf_putc(&dbuf, '%');                break;                            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;            }        }        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;} /* 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;} typedef JSModuleDef *(JSInitModuleFunc)(JSContext *ctx,                                        const char *module_name);  #if defined(_WIN32) || defined(__plan9__)static JSModuleDef *js_module_loader_so(JSContext *ctx,                                        const char *module_name){    JS_ThrowReferenceError(ctx, "shared library modules are not supported yet");    return NULL;}#elsestatic 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;    } 

Lines 1–500 of 3926.

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t