]> granicus.if.org Git - jq/commitdiff
Add a --arg option to allow variables to be passed from the cmdline.
authorStephen Dolan <mu@netsoc.tcd.ie>
Mon, 6 May 2013 13:21:00 +0000 (14:21 +0100)
committerStephen Dolan <mu@netsoc.tcd.ie>
Mon, 6 May 2013 13:21:00 +0000 (14:21 +0100)
Closes #107

compile.c
compile.h
docs/content/3.manual/manual.yml
execute.c
execute.h
main.c
parser.y

index 69044626fa2492dcf165fc2523ccf23659efad15..77dfd904d9d4b61919be2b675ba7d14b85638074 100644 (file)
--- a/compile.c
+++ b/compile.c
@@ -371,6 +371,12 @@ block gen_or(block a, block b) {
                                                    gen_const(jv_false())))));
 }
 
+block gen_var_binding(block var, const char* name, block body) {
+  return BLOCK(gen_op_simple(DUP), var,
+               block_bind(gen_op_var_unbound(STOREV, name),
+                          body, OP_HAS_VARIABLE));
+}
+
 block gen_cond(block cond, block iftrue, block iffalse) {
   return BLOCK(gen_op_simple(DUP), cond, 
                gen_condbranch(BLOCK(gen_op_simple(POP), iftrue),
index f982e3bf11a9f95de18868683e4bfbaef4c676b8..00a863c6b9a538c29be74e9075a48f589ea2f7a9 100644 (file)
--- a/compile.h
+++ b/compile.h
@@ -40,6 +40,8 @@ block gen_condbranch(block iftrue, block iffalse);
 block gen_and(block a, block b);
 block gen_or(block a, block b);
 
+block gen_var_binding(block var, const char* name, block body);
+
 block gen_cond(block cond, block iftrue, block iffalse);
 
 block gen_cbinding(const struct cfunction* functions, int nfunctions, block b);
index 7b490659954d7e93de8335c4b76aa66d7c096b98..c85fcd575639154aa35d213a8d3d63160c888520 100644 (file)
@@ -121,6 +121,12 @@ sections:
         formatted as a JSON string with quotes. This can be useful for
         making jq filters talk to non-JSON-based systems.
 
+      * `--arg name value`:
+
+        This option passes a value to the jq program as a predefined
+        variable. If you run jq with `--arg foo bar`, then `$foo` is
+        available in the program and has the value `"bar"`.
+
   - title: Basic filters
     entries:
       - title: "`.`"
index 22ffadbbe7e7f3dc924703459ac414cbeb0cbb41..5651dcf51d35cc214ac2907b27a55d2e91240857 100644 (file)
--- a/execute.c
+++ b/execute.c
@@ -506,13 +506,22 @@ void jq_teardown(jq_state **jq) {
   jv_mem_free(old_jq);
 }
 
-struct bytecode* jq_compile(const char* str) {
+struct bytecode* jq_compile_args(const char* str, jv args) {
+  assert(jv_get_kind(args) == JV_KIND_ARRAY);
   struct locfile locations;
   locfile_init(&locations, str, strlen(str));
   block program;
   struct bytecode* bc = 0;
   int nerrors = jq_parse(&locations, &program);
   if (nerrors == 0) {
+    for (int i=0; i<jv_array_length(jv_copy(args)); i++) {
+      jv arg = jv_array_get(jv_copy(args), i);
+      jv name = jv_object_get(jv_copy(arg), jv_string("name"));
+      jv value = jv_object_get(arg, jv_string("value"));
+      program = gen_var_binding(gen_const(value), jv_string_value(name), program);
+      jv_free(name);
+    }
+    jv_free(args);
     program = builtins_bind(program);
     nerrors = block_compile(program, &locations, &bc);
   }
@@ -522,3 +531,7 @@ struct bytecode* jq_compile(const char* str) {
   locfile_free(&locations);
   return bc;
 }
+
+struct bytecode* jq_compile(const char* str) {
+  return jq_compile_args(str, jv_array());
+}
index 1cf14df78e5feeaf3aceba630f078078d135ad93..004b66ba0270aa0afb9b2c7b24415df0190edee5 100644 (file)
--- a/execute.h
+++ b/execute.h
@@ -3,8 +3,12 @@
 #include "bytecode.h"
 
 
+
 struct bytecode* jq_compile(const char* str);
 
+/* args must be an array of the form [{name:"foo", value:"thing"}, {name:"bar",value:3}] */
+struct bytecode* jq_compile_args(const char* str, jv args);
+
 typedef struct jq_state jq_state;
 enum {JQ_DEBUG_TRACE = 1};
 
diff --git a/main.c b/main.c
index d2c553c03942ad61511e5375020b91af63b64419..afdff189e63e2c125e7d7e6fe17e8148047f03be 100644 (file)
--- a/main.c
+++ b/main.c
@@ -154,6 +154,7 @@ int main(int argc, char* argv[]) {
   ninput_files = 0;
   int further_args_are_files = 0;
   int jq_flags = 0;
+  jv program_arguments = jv_array();
   for (int i=1; i<argc; i++) {
     if (further_args_are_files) {
       input_filenames[ninput_files++] = argv[i];
@@ -184,6 +185,16 @@ int main(int argc, char* argv[]) {
       options |= PROVIDE_NULL;
     } else if (isoption(argv[i], 'f', "from-file")) {
       options |= FROM_FILE;
+    } else if (isoption(argv[i], 0, "arg")) {
+      if (i >= argc - 2) {
+        fprintf(stderr, "%s: --arg takes two parameters (e.g. -a varname value)\n", progname);
+        die();
+      }
+      jv arg = jv_object();
+      arg = jv_object_set(arg, jv_string("name"), jv_string(argv[i+1]));
+      arg = jv_object_set(arg, jv_string("value"), jv_string(argv[i+2]));
+      program_arguments = jv_array_append(program_arguments, arg);
+      i += 2; // skip the next two arguments
     } else if (isoption(argv[i],  0,  "debug-dump-disasm")) {
       options |= DUMP_DISASM;
     } else if (isoption(argv[i],  0,  "debug-trace")) {
@@ -214,10 +225,10 @@ int main(int argc, char* argv[]) {
       jv_free(data);
       return 1;
     }
-    bc = jq_compile(jv_string_value(data));
+    bc = jq_compile_args(jv_string_value(data), program_arguments);
     jv_free(data);
   } else {
-    bc = jq_compile(program);
+    bc = jq_compile_args(program, program_arguments);
   }
   if (!bc) return 1;
 
index 92cd9db8840fe9e89a976260592d92ab34a47b6b..8c663b9b0fb1708d43ab00f552b6ad3e11ac36f2 100644 (file)
--- a/parser.y
+++ b/parser.y
@@ -201,9 +201,7 @@ FuncDef Exp %prec ';' {
 } |
 
 Term "as" '$' IDENT '|' Exp {
-  $$ = BLOCK(gen_op_simple(DUP), $1, 
-             block_bind(gen_op_var_unbound(STOREV, jv_string_value($4)), 
-                        $6, OP_HAS_VARIABLE));
+  $$ = gen_var_binding($1, jv_string_value($4), $6);
   jv_free($4);
 } |