diff --git a/compile.c b/compile.c index 69044626..77dfd904 100644 --- 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), diff --git a/compile.h b/compile.h index f982e3bf..00a863c6 100644 --- 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); diff --git a/docs/content/3.manual/manual.yml b/docs/content/3.manual/manual.yml index 7b490659..c85fcd57 100644 --- a/docs/content/3.manual/manual.yml +++ b/docs/content/3.manual/manual.yml @@ -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: "`.`" diff --git a/execute.c b/execute.c index 22ffadbb..5651dcf5 100644 --- 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()); +} diff --git a/execute.h b/execute.h index 1cf14df7..004b66ba 100644 --- 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 d2c553c0..afdff189 100644 --- 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; diff --git a/parser.y b/parser.y index 92cd9db8..8c663b9b 100644 --- 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); } |