]> granicus.if.org Git - jq/commitdiff
Add $ENV builtin variable to access environment
authorNicolas Williams <nico@cryptonector.com>
Sun, 26 Feb 2017 06:28:12 +0000 (00:28 -0600)
committerNicolas Williams <nico@cryptonector.com>
Sun, 26 Feb 2017 06:39:24 +0000 (00:39 -0600)
docs/content/3.manual/manual.yml
jq.1.prebuilt
src/compile.c

index a0d713e74502e790083245eb7fc014386d58996a..84675182f6e2afbde4f6bf0a5783e24d42cf8337 100644 (file)
@@ -1666,12 +1666,22 @@ sections:
             output:
               - '[{"a":{"b":2}}]'
 
-      - title: "`env`"
+      - title: "`$ENV`, `env`"
         body: |
 
-          Outputs an object representing jq's environment.
+          `$ENV` is an object representing the environment variables as
+          set when the jq program started.
+
+          `env` outputs an object representing jq's current environment.
+
+          At the moment there is no builtin for setting environment
+          variables.
 
         examples:
+          - program: '$ENV.PAGER'
+            input: 'null'
+            output: ['"less"']
+
           - program: 'env.PAGER'
             input: 'null'
             output: ['"less"']
index c4d25ea7317d637782eeee4909b0973da10b64ac..04b90715a85a7c516d514083810b95230582decf 100644 (file)
@@ -1830,13 +1830,23 @@ jq \'walk( if type == "object" then with_entries( \.key |= sub( "^_+"; "") ) els
 .
 .IP "" 0
 .
-.SS "env"
-Outputs an object representing jq\'s environment\.
+.SS "$ENV, env"
+\fB$ENV\fR is an object representing the environment variables as set when the jq program started\.
+.
+.P
+\fBenv\fR outputs an object representing jq\'s current environment\.
+.
+.P
+At the moment there is no builtin for setting environment variables\.
 .
 .IP "" 4
 .
 .nf
 
+jq \'$ENV\.PAGER\'
+   null
+=> "less"
+
 jq \'env\.PAGER\'
    null
 => "less"
index 5b408e0d842409f653544b1ce7d93fa05601c7ac..8e2d09f27ec4b74d4957e10cc317d70a92b2c4fe 100644 (file)
@@ -5,6 +5,7 @@
 #include <math.h>
 #include <string.h>
 #include <stdlib.h>
+#include <unistd.h>
 #include "compile.h"
 #include "bytecode.h"
 #include "locfile.h"
@@ -997,6 +998,37 @@ static int count_cfunctions(block b) {
   return n;
 }
 
+#ifdef WIN32
+extern const char **environ;
+#endif
+
+static jv env = {JV_KIND_INVALID, 0, 0, 0, {0}};
+
+static void
+free_env(void)
+{
+  jv_free(env);
+}
+
+static jv
+make_env(void)
+{
+  if (jv_is_valid(env))
+    return jv_copy(env);
+  jv r = jv_object();
+  if (environ == NULL)
+    return r;
+  for (size_t i = 0; environ[i] != NULL; i++) {
+    const char *eq;
+
+    if ((eq = strchr(environ[i], '=')) == NULL)
+      r = jv_object_delete(r, jv_string(environ[i]));
+    else
+      r = jv_object_set(r, jv_string_sized(environ[i], eq - environ[i]), jv_string(eq + 1));
+  }
+  atexit(free_env);
+  return (env = jv_copy(r));
+}
 
 // Expands call instructions into a calling sequence
 static int expand_call_arglist(block* b) {
@@ -1004,7 +1036,10 @@ static int expand_call_arglist(block* b) {
   block ret = gen_noop();
   for (inst* curr; (curr = block_take(b));) {
     if (opcode_describe(curr->op)->flags & OP_HAS_BINDING) {
-      if (!curr->bound_by) {
+      if (!curr->bound_by && curr->op == LOADV && strcmp(curr->symbol, "ENV") == 0) {
+        curr->op = LOADK;
+        curr->imm.constant = make_env();
+      } else if (!curr->bound_by) {
         if (curr->symbol[0] == '*' && curr->symbol[1] >= '1' && curr->symbol[1] <= '3' && curr->symbol[2] == '\0')
           locfile_locate(curr->locfile, curr->source, "jq: error: break used outside labeled control structure");
         else if (curr->op == LOADV)