]> git.kaiwu.me - njs.git/commitdiff
Added process global object.
authorDmitry Volyntsev <xeioex@nginx.com>
Tue, 18 Jun 2019 14:57:38 +0000 (17:57 +0300)
committerDmitry Volyntsev <xeioex@nginx.com>
Tue, 18 Jun 2019 14:57:38 +0000 (17:57 +0300)
process object properties:
    argv - an array containing the command line arguments
    env - an object containing the user environment
    pid - process PID
    ppid - process parent PID

This closes #84 issue on Github.

12 files changed:
nginx/ngx_http_js_module.c
nginx/ngx_stream_js_module.c
njs/njs.h
njs/njs_builtin.c
njs/njs_generator.c
njs/njs_lexer.h
njs/njs_lexer_keyword.c
njs/njs_object_hash.h
njs/njs_parser_terminal.c
njs/njs_shell.c
njs/njs_vm.h
njs/test/njs_expect_test.exp

index cd8a8f958a53a49747786a215ece152426665492..787098a027d28b497a68f3dd77dc0650af3d8367 100644 (file)
@@ -2283,6 +2283,8 @@ ngx_http_js_include(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
 
     options.backtrace = 1;
     options.ops = &ngx_http_js_ops;
+    options.argv = ngx_argv;
+    options.argc = ngx_argc;
 
     file = value[1];
     options.file.start = file.data;
index 4375ae1aa1e8550addbfab4106070f133b8bd565..5471f6bdfe6aefdd5732f015aef134aa55f886a4 100644 (file)
@@ -1473,6 +1473,8 @@ ngx_stream_js_include(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
 
     options.backtrace = 1;
     options.ops = &ngx_stream_js_ops;
+    options.argv = ngx_argv;
+    options.argc = ngx_argc;
 
     file = value[1];
     options.file.start = file.data;
index a6adc2b05babb5a4391cd1a0fddbd8609faa5851..d3863cf67fbc9f25ca8214d78d18052eea320af2 100644 (file)
--- a/njs/njs.h
+++ b/njs/njs.h
@@ -143,6 +143,9 @@ typedef struct {
     njs_vm_ops_t                    *ops;
     nxt_str_t                       file;
 
+    char                            **argv;
+    nxt_uint_t                      argc;
+
     uint8_t                         trailer;         /* 1 bit */
     uint8_t                         init;            /* 1 bit */
     uint8_t                         accumulative;    /* 1 bit */
index 27587b0173fb70b6060fffcb0cd1ac622a32aa56..012c0caf25136d275de89d97eef2b82a7a2a4758 100644 (file)
@@ -28,17 +28,21 @@ static njs_ret_t njs_prototype_function(njs_vm_t *vm, njs_value_t *args,
 static nxt_array_t *njs_vm_expression_completions(njs_vm_t *vm,
     nxt_str_t *expression);
 static nxt_array_t *njs_object_completions(njs_vm_t *vm, njs_object_t *object);
+static nxt_int_t njs_env_hash_init(njs_vm_t *vm, nxt_lvlhsh_t *hash,
+    char **environment);
 
 
-const njs_object_init_t  njs_njs_object_init;
 const njs_object_init_t  njs_global_this_init;
+const njs_object_init_t  njs_njs_object_init;
+const njs_object_init_t  njs_process_object_init;
 
 
 const njs_object_init_t  *njs_object_init[] = {
-    &njs_global_this_init,        /* global this        */
-    &njs_njs_object_init,         /* global njs object  */
-    &njs_math_object_init,        /* Math               */
-    &njs_json_object_init,        /* JSON               */
+    &njs_global_this_init,
+    &njs_njs_object_init,
+    &njs_process_object_init,
+    &njs_math_object_init,
+    &njs_json_object_init,
     NULL
 };
 
@@ -214,6 +218,9 @@ const njs_object_prototype_t  njs_prototype_values[] = {
 };
 
 
+extern char  **environ;
+
+
 nxt_inline nxt_int_t
 njs_object_hash_init(njs_vm_t *vm, nxt_lvlhsh_t *hash,
     const njs_object_init_t *init)
@@ -229,8 +236,8 @@ njs_builtin_objects_create(njs_vm_t *vm)
     njs_module_t               *module;
     njs_object_t               *object, *string_object;
     njs_function_t             *func;
-    nxt_lvlhsh_query_t         lhq;
     njs_vm_shared_t            *shared;
+    nxt_lvlhsh_query_t         lhq;
     njs_object_prototype_t     *prototype;
     const njs_object_init_t    *obj, **p;
     const njs_function_init_t  *f;
@@ -285,6 +292,11 @@ njs_builtin_objects_create(njs_vm_t *vm)
         object++;
     }
 
+    ret = njs_env_hash_init(vm, &shared->env_hash, environ);
+    if (nxt_slow_path(ret != NXT_OK)) {
+        return NXT_ERROR;
+    }
+
     lhq.replace = 0;
     lhq.pool = vm->mem_pool;
 
@@ -1075,6 +1087,35 @@ njs_dump_value(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs,
 }
 
 
+static const njs_object_prop_t  njs_global_this_object_properties[] =
+{
+    {
+        .type = NJS_PROPERTY,
+        .name = njs_string("NaN"),
+        .value = njs_value(NJS_NUMBER, 0, NAN),
+    },
+
+    {
+        .type = NJS_PROPERTY,
+        .name = njs_string("Infinity"),
+        .value = njs_value(NJS_NUMBER, 0, INFINITY),
+    },
+
+    {
+        .type = NJS_PROPERTY,
+        .name = njs_string("undefined"),
+        .value = njs_value(NJS_UNDEFINED, 0, NAN),
+    },
+};
+
+
+const njs_object_init_t  njs_global_this_init = {
+    nxt_string("this"),
+    njs_global_this_object_properties,
+    nxt_nitems(njs_global_this_object_properties)
+};
+
+
 static const njs_object_prop_t  njs_njs_object_properties[] =
 {
     {
@@ -1102,30 +1143,223 @@ const njs_object_init_t  njs_njs_object_init = {
 };
 
 
-static const njs_object_prop_t  njs_global_this_object_properties[] =
+static njs_ret_t
+njs_process_object_argv(njs_vm_t *vm, njs_value_t *process,
+    njs_value_t *unused, njs_value_t *retval)
+{
+    char                **arg;
+    nxt_int_t           ret;
+    nxt_uint_t          i;
+    njs_array_t         *argv;
+    njs_object_prop_t   *prop;
+    nxt_lvlhsh_query_t  lhq;
+
+    static const njs_value_t  argv_string = njs_string("argv");
+
+    if (nxt_slow_path(vm->options.argv == NULL)) {
+        njs_internal_error(vm, "argv was not provided by host environment");
+        return NXT_ERROR;
+    }
+
+    argv = njs_array_alloc(vm, vm->options.argc, 0);
+    if (nxt_slow_path(argv == NULL)) {
+        return NXT_ERROR;
+    }
+
+    i = 0;
+
+    for (arg = vm->options.argv; i < vm->options.argc; arg++) {
+        njs_string_set(vm, &argv->start[i++], (u_char *) *arg,
+                       nxt_strlen(*arg));
+    }
+
+    prop = njs_object_prop_alloc(vm, &argv_string, &njs_value_undefined, 1);
+    if (nxt_slow_path(prop == NULL)) {
+        return NJS_ERROR;
+    }
+
+    prop->value.data.u.array = argv;
+    prop->value.type = NJS_ARRAY;
+    prop->value.data.truth = 1;
+
+    lhq.value = prop;
+    lhq.key_hash = NJS_ARGV_HASH;
+    lhq.key = nxt_string_value("argv");
+    lhq.replace = 0;
+    lhq.pool = vm->mem_pool;
+    lhq.proto = &njs_object_hash_proto;
+
+    ret = nxt_lvlhsh_insert(&process->data.u.object->hash, &lhq);
+
+    if (nxt_fast_path(ret == NXT_OK)) {
+        *retval = prop->value;
+        return NXT_OK;
+    }
+
+    njs_internal_error(vm, "lvlhsh insert failed");
+
+    return NXT_ERROR;
+}
+
+
+static nxt_int_t
+njs_env_hash_init(njs_vm_t *vm, nxt_lvlhsh_t *hash, char **environment)
+{
+    char                **ep;
+    u_char              *val, *entry;
+    nxt_int_t           ret;
+    njs_object_prop_t   *prop;
+    nxt_lvlhsh_query_t  lhq;
+
+    lhq.replace = 0;
+    lhq.pool = vm->mem_pool;
+    lhq.proto = &njs_object_hash_proto;
+
+    ep = environment;
+
+    while (*ep != NULL) {
+        prop = njs_object_prop_alloc(vm, &njs_value_undefined,
+                                     &njs_value_undefined, 1);
+        if (nxt_slow_path(prop == NULL)) {
+            return NXT_ERROR;
+        }
+
+        entry = (u_char *) *ep++;
+
+        val = nxt_strchr(entry, '=');
+        if (nxt_slow_path(val == NULL)) {
+            continue;
+        }
+
+        ret = njs_string_set(vm, &prop->name, entry, val - entry);
+        if (nxt_slow_path(ret != NXT_OK)) {
+            return NXT_ERROR;
+        }
+
+        val++;
+
+        ret = njs_string_set(vm, &prop->value, val, nxt_strlen(val));
+        if (nxt_slow_path(ret != NXT_OK)) {
+            return NXT_ERROR;
+        }
+
+        lhq.value = prop;
+        njs_string_get(&prop->name, &lhq.key);
+        lhq.key_hash = nxt_djb_hash(lhq.key.start, lhq.key.length);
+
+        ret = nxt_lvlhsh_insert(hash, &lhq);
+        if (nxt_slow_path(ret != NXT_OK)) {
+            njs_internal_error(vm, "lvlhsh insert failed");
+            return NXT_ERROR;
+        }
+    }
+
+    return NXT_OK;
+}
+
+
+static njs_ret_t
+njs_process_object_env(njs_vm_t *vm, njs_value_t *process,
+    njs_value_t *unused, njs_value_t *retval)
+{
+    nxt_int_t           ret;
+    njs_object_t        *env;
+    njs_object_prop_t   *prop;
+    nxt_lvlhsh_query_t  lhq;
+
+    static const njs_value_t  env_string = njs_string("env");
+
+    env = njs_object_alloc(vm);
+    if (nxt_slow_path(env == NULL)) {
+        return NXT_ERROR;
+    }
+
+    env->shared_hash = vm->shared->env_hash;
+
+    prop = njs_object_prop_alloc(vm, &env_string, &njs_value_undefined, 1);
+    if (nxt_slow_path(prop == NULL)) {
+        return NXT_ERROR;
+    }
+
+    prop->value.data.u.object = env;
+    prop->value.type = NJS_OBJECT;
+    prop->value.data.truth = 1;
+
+    lhq.replace = 0;
+    lhq.pool = vm->mem_pool;
+    lhq.proto = &njs_object_hash_proto;
+    lhq.value = prop;
+    lhq.key = nxt_string_value("env");
+    lhq.key_hash = NJS_ENV_HASH;
+
+    ret = nxt_lvlhsh_insert(&process->data.u.object->hash, &lhq);
+
+    if (nxt_fast_path(ret == NXT_OK)) {
+        *retval = prop->value;
+        return NXT_OK;
+    }
+
+    njs_internal_error(vm, "lvlhsh insert failed");
+
+    return NXT_ERROR;
+}
+
+
+static njs_ret_t
+njs_process_object_pid(njs_vm_t *vm, njs_value_t *unused,
+    njs_value_t *unused2, njs_value_t *retval)
+{
+    retval->data.u.number = getpid();
+    retval->type = NJS_NUMBER;
+    retval->data.truth = njs_is_number_true(retval->data.u.number);
+
+    return NJS_OK;
+}
+
+
+static njs_ret_t
+njs_process_object_ppid(njs_vm_t *vm, njs_value_t *unused,
+    njs_value_t *unused2, njs_value_t *retval)
+{
+    retval->data.u.number = getppid();
+    retval->type = NJS_NUMBER;
+    retval->data.truth = njs_is_number_true(retval->data.u.number);
+
+    return NJS_OK;
+}
+
+
+static const njs_object_prop_t  njs_process_object_properties[] =
 {
     {
-        .type = NJS_PROPERTY,
-        .name = njs_string("NaN"),
-        .value = njs_value(NJS_NUMBER, 0, NAN),
+        .type = NJS_PROPERTY_HANDLER,
+        .name = njs_string("argv"),
+        .value = njs_prop_handler(njs_process_object_argv),
     },
 
     {
-        .type = NJS_PROPERTY,
-        .name = njs_string("Infinity"),
-        .value = njs_value(NJS_NUMBER, 0, INFINITY),
+        .type = NJS_PROPERTY_HANDLER,
+        .name = njs_string("env"),
+        .value = njs_prop_handler(njs_process_object_env),
     },
 
     {
-        .type = NJS_PROPERTY,
-        .name = njs_string("undefined"),
-        .value = njs_value(NJS_UNDEFINED, 0, NAN),
+        .type = NJS_PROPERTY_HANDLER,
+        .name = njs_string("pid"),
+        .value = njs_prop_handler(njs_process_object_pid),
+    },
+
+    {
+        .type = NJS_PROPERTY_HANDLER,
+        .name = njs_string("ppid"),
+        .value = njs_prop_handler(njs_process_object_ppid),
     },
+
 };
 
 
-const njs_object_init_t  njs_global_this_init = {
-    nxt_string("this"),
-    njs_global_this_object_properties,
-    nxt_nitems(njs_global_this_object_properties)
+const njs_object_init_t  njs_process_object_init = {
+    nxt_string("process"),
+    njs_process_object_properties,
+    nxt_nitems(njs_process_object_properties),
 };
index 58615f4e35dea548c631c503aa6a8a9babf3bf17..c1ea3e4949a7a1f32ff06781e2b7d7ad92e6d1d6 100644 (file)
@@ -451,6 +451,7 @@ njs_generator(njs_vm_t *vm, njs_generator_t *generator, njs_parser_node_t *node)
         /* Fall through. */
 
     case NJS_TOKEN_NJS:
+    case NJS_TOKEN_PROCESS:
     case NJS_TOKEN_MATH:
     case NJS_TOKEN_JSON:
     case NJS_TOKEN_EVAL:
index bc7ec764acf05807061bd60891eecd0dd6ddffdf..159952af38ef8225702629c8b85ee2b3fe2b14e9 100644 (file)
@@ -171,6 +171,7 @@ typedef enum {
 
     NJS_TOKEN_GLOBAL_THIS,
     NJS_TOKEN_NJS,
+    NJS_TOKEN_PROCESS,
     NJS_TOKEN_MATH,
     NJS_TOKEN_JSON,
 
index f1d6d0716b8f684fa3715b63eb7a57edee0729c5..0a827574e25940fef8e56008f50028fc0edda9bc 100644 (file)
@@ -55,6 +55,7 @@ static const njs_keyword_t  njs_keywords[] = {
     { nxt_string("this"),          NJS_TOKEN_THIS, 0 },
     { nxt_string("arguments"),     NJS_TOKEN_ARGUMENTS, 0 },
     { nxt_string("njs"),           NJS_TOKEN_NJS, 0 },
+    { nxt_string("process"),       NJS_TOKEN_PROCESS, 0 },
     { nxt_string("Math"),          NJS_TOKEN_MATH, 0 },
     { nxt_string("JSON"),          NJS_TOKEN_JSON, 0 },
 
index f567240198cd97fe635e33925d1fce9775cc375e..4c028bce6c4426d7e257974b8b3d4ae86108f202 100644 (file)
@@ -8,6 +8,14 @@
 #define _NJS_OBJECT_HASH_H_INCLUDED_
 
 
+#define NJS_ARGV_HASH                                                         \
+    nxt_djb_hash_add(                                                         \
+    nxt_djb_hash_add(                                                         \
+    nxt_djb_hash_add(                                                         \
+    nxt_djb_hash_add(NXT_DJB_HASH_INIT,                                       \
+        'a'), 'r'), 'g'), 'v')
+
+
 #define NJS_CONFIGURABLE_HASH                                                 \
     nxt_djb_hash_add(                                                         \
     nxt_djb_hash_add(                                                         \
         'e'), 'n'), 'c'), 'o'), 'd'), 'i'), 'n'), 'g')
 
 
+#define NJS_ENV_HASH                                                          \
+    nxt_djb_hash_add(                                                         \
+    nxt_djb_hash_add(                                                         \
+    nxt_djb_hash_add(NXT_DJB_HASH_INIT,                                       \
+        'e'), 'n'), 'v')
+
+
 #define NJS_FLAG_HASH                                                         \
     nxt_djb_hash_add(                                                         \
     nxt_djb_hash_add(                                                         \
index 3c85ccdac26acc62ceee5775a331bb8f81206942..c5ef19127392dc09b543078552fdfe4688a71679 100644 (file)
@@ -270,6 +270,7 @@ njs_parser_reference(njs_vm_t *vm, njs_parser_t *parser, njs_token_t token,
         /* Fall through. */
 
     case NJS_TOKEN_NJS:
+    case NJS_TOKEN_PROCESS:
     case NJS_TOKEN_MATH:
     case NJS_TOKEN_JSON:
         ret = njs_parser_builtin(vm, parser, node, NJS_OBJECT, name, hash);
index 706c4111717d80301b219bdfe4c72ef8236f7f4e..9fcd1534ae65e75a63c56ab3b3ded1f2a8345ae2 100644 (file)
@@ -265,6 +265,8 @@ main(int argc, char **argv)
 
     vm_options.ops = &njs_console_ops;
     vm_options.external = &njs_console;
+    vm_options.argv = argv;
+    vm_options.argc = argc;
 
     if (opts.interactive) {
         ret = njs_interactive_shell(&opts, &vm_options);
index 52f914e9494b99c05713e694cdda855fbdf29404..b4c168c3bfa89d7d512e9880d4519e973d648b55 100644 (file)
@@ -1154,6 +1154,8 @@ struct njs_vm_shared_s {
     nxt_lvlhsh_t             arrow_instance_hash;
     nxt_lvlhsh_t             arguments_object_instance_hash;
 
+    nxt_lvlhsh_t             env_hash;
+
     njs_object_t             string_object;
     njs_object_t             objects[NJS_OBJECT_MAX];
     njs_function_t           functions[NJS_FUNCTION_MAX];
index 351981a270b939870bf98ab0e2ffdfa8c12a0b46..9ff3fb5adf03b65e2c47d10f1a329e63d4b39afa 100644 (file)
@@ -658,6 +658,20 @@ njs_run {"-c" "console.log(\"a b c\")"} "a b c"
 njs_run {"-c" "console.log("} "SyntaxError: Unexpected end of input in string:1"
 
 
+# process
+
+njs_run {"-c" "console.log(typeof process.argv)"} "object"
+njs_run {"-c" "console.log(process.argv[3])" "AAA"} "AAA"
+
+njs_run {"-c" "console.log(typeof process.env)"} "object"
+njs_run {"-c" "console.log(process.env.HOME != undefined)"} "true"
+njs_run {"-c" "console.log(process.env.___UNDECLARED != undefined)"} "false"
+
+njs_run {"-c" "console.log(process.pid)"} "\\d+"
+
+njs_run {"-c" "console.log(process.ppid)"} "\\d+"
+
+
 # disassemble
 
 njs_test {