summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNicolas Williams <nico@cryptonector.com>2017-02-26 00:28:12 -0600
committerNicolas Williams <nico@cryptonector.com>2017-02-26 00:39:24 -0600
commit3504bd9a2a9e9cb1e4864b69821b446d15fab85d (patch)
treece8e9d14641eb1791a7b623275178451f1e454cb
parent1a8a0ae0f55858a8f0a5e8c73f71e1e609b820f4 (diff)
Add $ENV builtin variable to access environment
-rw-r--r--docs/content/3.manual/manual.yml14
-rw-r--r--jq.1.prebuilt14
-rw-r--r--src/compile.c37
3 files changed, 60 insertions, 5 deletions
diff --git a/docs/content/3.manual/manual.yml b/docs/content/3.manual/manual.yml
index a0d713e7..84675182 100644
--- a/docs/content/3.manual/manual.yml
+++ b/docs/content/3.manual/manual.yml
@@ -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"']
diff --git a/jq.1.prebuilt b/jq.1.prebuilt
index c4d25ea7..04b90715 100644
--- a/jq.1.prebuilt
+++ b/jq.1.prebuilt
@@ -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"
diff --git a/src/compile.c b/src/compile.c
index 5b408e0d..8e2d09f2 100644
--- a/src/compile.c
+++ b/src/compile.c
@@ -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)