Add $ARGS, --args and --jsonargs (fix #1345)
This commit is contained in:
1 parent
e8abc0a2f6
commit
66fb962a66
1 file changed
+78
-36
+78
-36
@@ -41,7 +41,7 @@ static const char* progname;
|
|||||||
* For a longer help message we could use a better option parsing
|
* For a longer help message we could use a better option parsing
|
||||||
* strategy, one that lets stack options.
|
* strategy, one that lets stack options.
|
||||||
*/
|
*/
|
||||||
static void usage(int code) {
|
static void usage(int code, int keep_it_short) {
|
||||||
FILE *f = stderr;
|
FILE *f = stderr;
|
||||||
|
|
||||||
if (code == 0)
|
if (code == 0)
|
||||||
@@ -49,7 +49,9 @@ static void usage(int code) {
|
|||||||
|
|
||||||
int ret = fprintf(f,
|
int ret = fprintf(f,
|
||||||
"jq - commandline JSON processor [version %s]\n"
|
"jq - commandline JSON processor [version %s]\n"
|
||||||
"\nUsage:\n\n\t%s [options] <jq filter> [file...]\n\n"
|
"\nUsage:\t%s [options] <jq filter> [file...]\n"
|
||||||
|
"\t%s [options] --args <jq filter> [strings...]\n"
|
||||||
|
"\t%s [options] --jsonargs <jq filter> [JSON_TEXTS...]\n\n"
|
||||||
"jq is a tool for processing JSON inputs, applying the given filter to\n"
|
"jq is a tool for processing JSON inputs, applying the given filter to\n"
|
||||||
"its JSON text inputs and producing the filter's results as JSON on\n"
|
"its JSON text inputs and producing the filter's results as JSON on\n"
|
||||||
"standard output.\n\n"
|
"standard output.\n\n"
|
||||||
@@ -59,7 +61,14 @@ static void usage(int code) {
|
|||||||
"For more advanced filters see the jq(1) manpage (\"man jq\")\n"
|
"For more advanced filters see the jq(1) manpage (\"man jq\")\n"
|
||||||
"and/or https://stedolan.github.io/jq\n\n"
|
"and/or https://stedolan.github.io/jq\n\n"
|
||||||
"Example:\n\n\t$ echo '{\"foo\": 0}' | jq .\n"
|
"Example:\n\n\t$ echo '{\"foo\": 0}' | jq .\n"
|
||||||
"\t{\n\t\t\"foo\": 0\n\t}\n\n"
|
"\t{\n\t\t\"foo\": 0\n\t}\n\n",
|
||||||
|
JQ_VERSION, progname, progname, progname);
|
||||||
|
if (keep_it_short) {
|
||||||
|
fprintf(f,
|
||||||
|
"For a listing of options, use %s --help.\n",
|
||||||
|
progname);
|
||||||
|
} else {
|
||||||
|
(void) fprintf(f,
|
||||||
"Some of the options include:\n"
|
"Some of the options include:\n"
|
||||||
" -c compact instead of pretty-printed output;\n"
|
" -c compact instead of pretty-printed output;\n"
|
||||||
" -n use `null` as the single input value;\n"
|
" -n use `null` as the single input value;\n"
|
||||||
@@ -74,7 +83,13 @@ static void usage(int code) {
|
|||||||
" --arg a v set variable $a to value <v>;\n"
|
" --arg a v set variable $a to value <v>;\n"
|
||||||
" --argjson a v set variable $a to JSON value <v>;\n"
|
" --argjson a v set variable $a to JSON value <v>;\n"
|
||||||
" --slurpfile a f set variable $a to an array of JSON texts read from <f>;\n"
|
" --slurpfile a f set variable $a to an array of JSON texts read from <f>;\n"
|
||||||
"\nSee the manpage for more options.\n", JQ_VERSION, progname);
|
" --args remaining arguments are string arguments, not files;\n"
|
||||||
|
" --jsonargs remaining arguments are JSON arguments, not files;\n"
|
||||||
|
" -- terminates argument processing;\n\n"
|
||||||
|
"Named arguments are also available as $ARGS.named[], while\n"
|
||||||
|
"positional arguments are available as $ARGS.positional[].\n"
|
||||||
|
"\nSee the manpage for more options.\n");
|
||||||
|
}
|
||||||
exit((ret < 0 && code == 0) ? 2 : code);
|
exit((ret < 0 && code == 0) ? 2 : code);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -200,7 +215,8 @@ int main(int argc, char* argv[]) {
|
|||||||
int parser_flags = 0;
|
int parser_flags = 0;
|
||||||
int nfiles = 0;
|
int nfiles = 0;
|
||||||
int badwrite;
|
int badwrite;
|
||||||
jv program_arguments = jv_array();
|
jv ARGS = jv_array(); /* positional arguments */
|
||||||
|
jv program_arguments = jv_object(); /* named arguments */
|
||||||
|
|
||||||
#ifdef WIN32
|
#ifdef WIN32
|
||||||
fflush(stdout);
|
fflush(stdout);
|
||||||
@@ -234,21 +250,35 @@ int main(int argc, char* argv[]) {
|
|||||||
|
|
||||||
jq_util_input_state *input_state = jq_util_input_init(NULL, NULL); // XXX add err_cb
|
jq_util_input_state *input_state = jq_util_input_init(NULL, NULL); // XXX add err_cb
|
||||||
|
|
||||||
int further_args_are_files = 0;
|
int further_args_are_strings = 0;
|
||||||
|
int further_args_are_json = 0;
|
||||||
|
int args_done = 0;
|
||||||
int jq_flags = 0;
|
int jq_flags = 0;
|
||||||
size_t short_opts = 0;
|
size_t short_opts = 0;
|
||||||
jv lib_search_paths = jv_null();
|
jv lib_search_paths = jv_null();
|
||||||
for (int i=1; i<argc; i++, short_opts = 0) {
|
for (int i=1; i<argc; i++, short_opts = 0) {
|
||||||
if (further_args_are_files) {
|
if (args_done) {
|
||||||
|
if (further_args_are_strings) {
|
||||||
|
ARGS = jv_array_append(ARGS, jv_string(argv[i]));
|
||||||
|
} else if (further_args_are_json) {
|
||||||
|
ARGS = jv_array_append(ARGS, jv_parse(argv[i]));
|
||||||
|
} else {
|
||||||
jq_util_input_add_input(input_state, argv[i]);
|
jq_util_input_add_input(input_state, argv[i]);
|
||||||
nfiles++;
|
nfiles++;
|
||||||
|
}
|
||||||
} else if (!strcmp(argv[i], "--")) {
|
} else if (!strcmp(argv[i], "--")) {
|
||||||
if (!program) usage(2);
|
if (!program) usage(2, 1);
|
||||||
further_args_are_files = 1;
|
args_done = 1;
|
||||||
} else if (!isoptish(argv[i])) {
|
} else if (!isoptish(argv[i])) {
|
||||||
if (program) {
|
if (program) {
|
||||||
|
if (further_args_are_strings) {
|
||||||
|
ARGS = jv_array_append(ARGS, jv_string(argv[i]));
|
||||||
|
} else if (further_args_are_json) {
|
||||||
|
ARGS = jv_array_append(ARGS, jv_parse(argv[i]));
|
||||||
|
} else {
|
||||||
jq_util_input_add_input(input_state, argv[i]);
|
jq_util_input_add_input(input_state, argv[i]);
|
||||||
nfiles++;
|
nfiles++;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
program = argv[i];
|
program = argv[i];
|
||||||
}
|
}
|
||||||
@@ -294,7 +324,7 @@ int main(int argc, char* argv[]) {
|
|||||||
}
|
}
|
||||||
if (isoption(argv[i], 0, "unbuffered", &short_opts)) {
|
if (isoption(argv[i], 0, "unbuffered", &short_opts)) {
|
||||||
options |= UNBUFFERED_OUTPUT;
|
options |= UNBUFFERED_OUTPUT;
|
||||||
if (!short_opts) continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (isoption(argv[i], 'S', "sort-keys", &short_opts)) {
|
if (isoption(argv[i], 'S', "sort-keys", &short_opts)) {
|
||||||
options |= SORTED_OUTPUT;
|
options |= SORTED_OUTPUT;
|
||||||
@@ -319,7 +349,7 @@ int main(int argc, char* argv[]) {
|
|||||||
if (isoption(argv[i], 0, "tab", &short_opts)) {
|
if (isoption(argv[i], 0, "tab", &short_opts)) {
|
||||||
dumpopts &= ~JV_PRINT_INDENT_FLAGS(7);
|
dumpopts &= ~JV_PRINT_INDENT_FLAGS(7);
|
||||||
dumpopts |= JV_PRINT_TAB | JV_PRINT_PRETTY;
|
dumpopts |= JV_PRINT_TAB | JV_PRINT_PRETTY;
|
||||||
if (!short_opts) continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (isoption(argv[i], 0, "indent", &short_opts)) {
|
if (isoption(argv[i], 0, "indent", &short_opts)) {
|
||||||
if (i >= argc - 1) {
|
if (i >= argc - 1) {
|
||||||
@@ -334,53 +364,60 @@ int main(int argc, char* argv[]) {
|
|||||||
}
|
}
|
||||||
dumpopts |= JV_PRINT_INDENT_FLAGS(indent);
|
dumpopts |= JV_PRINT_INDENT_FLAGS(indent);
|
||||||
i++;
|
i++;
|
||||||
if (!short_opts) continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (isoption(argv[i], 0, "seq", &short_opts)) {
|
if (isoption(argv[i], 0, "seq", &short_opts)) {
|
||||||
options |= SEQ;
|
options |= SEQ;
|
||||||
if (!short_opts) continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (isoption(argv[i], 0, "stream", &short_opts)) {
|
if (isoption(argv[i], 0, "stream", &short_opts)) {
|
||||||
parser_flags |= JV_PARSE_STREAMING;
|
parser_flags |= JV_PARSE_STREAMING;
|
||||||
if (!short_opts) continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (isoption(argv[i], 0, "stream-errors", &short_opts)) {
|
if (isoption(argv[i], 0, "stream-errors", &short_opts)) {
|
||||||
parser_flags |= JV_PARSE_STREAM_ERRORS;
|
parser_flags |= JV_PARSE_STREAM_ERRORS;
|
||||||
if (!short_opts) continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (isoption(argv[i], 'e', "exit-status", &short_opts)) {
|
if (isoption(argv[i], 'e', "exit-status", &short_opts)) {
|
||||||
options |= EXIT_STATUS;
|
options |= EXIT_STATUS;
|
||||||
if (!short_opts) continue;
|
if (!short_opts) continue;
|
||||||
}
|
}
|
||||||
// FIXME: For --arg* we should check that the varname is acceptable
|
// FIXME: For --arg* we should check that the varname is acceptable
|
||||||
|
if (isoption(argv[i], 0, "args", &short_opts)) {
|
||||||
|
further_args_are_strings = 1;
|
||||||
|
further_args_are_json = 0;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (isoption(argv[i], 0, "jsonargs", &short_opts)) {
|
||||||
|
further_args_are_strings = 0;
|
||||||
|
further_args_are_json = 1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
if (isoption(argv[i], 0, "arg", &short_opts)) {
|
if (isoption(argv[i], 0, "arg", &short_opts)) {
|
||||||
if (i >= argc - 2) {
|
if (i >= argc - 2) {
|
||||||
fprintf(stderr, "%s: --arg takes two parameters (e.g. --arg varname value)\n", progname);
|
fprintf(stderr, "%s: --arg takes two parameters (e.g. --arg varname value)\n", progname);
|
||||||
die();
|
die();
|
||||||
}
|
}
|
||||||
jv arg = jv_object();
|
if (!jv_object_has(jv_copy(program_arguments), jv_string(argv[i+1])))
|
||||||
arg = jv_object_set(arg, jv_string("name"), jv_string(argv[i+1]));
|
program_arguments = jv_object_set(program_arguments, jv_string(argv[i+1]), jv_string(argv[i+2]));
|
||||||
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
|
i += 2; // skip the next two arguments
|
||||||
if (!short_opts) continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (isoption(argv[i], 0, "argjson", &short_opts)) {
|
if (isoption(argv[i], 0, "argjson", &short_opts)) {
|
||||||
if (i >= argc - 2) {
|
if (i >= argc - 2) {
|
||||||
fprintf(stderr, "%s: --argjson takes two parameters (e.g. --argjson varname text)\n", progname);
|
fprintf(stderr, "%s: --argjson takes two parameters (e.g. --argjson varname text)\n", progname);
|
||||||
die();
|
die();
|
||||||
}
|
}
|
||||||
|
if (!jv_object_has(jv_copy(program_arguments), jv_string(argv[i+1]))) {
|
||||||
jv v = jv_parse(argv[i+2]);
|
jv v = jv_parse(argv[i+2]);
|
||||||
if (!jv_is_valid(v)) {
|
if (!jv_is_valid(v)) {
|
||||||
fprintf(stderr, "%s: invalid JSON text passed to --argjson\n", progname);
|
fprintf(stderr, "%s: invalid JSON text passed to --argjson\n", progname);
|
||||||
die();
|
die();
|
||||||
}
|
}
|
||||||
jv arg = jv_object();
|
program_arguments = jv_object_set(program_arguments, jv_string(argv[i+1]), v);
|
||||||
arg = jv_object_set(arg, jv_string("name"), jv_string(argv[i+1]));
|
}
|
||||||
arg = jv_object_set(arg, jv_string("value"), v);
|
|
||||||
program_arguments = jv_array_append(program_arguments, arg);
|
|
||||||
i += 2; // skip the next two arguments
|
i += 2; // skip the next two arguments
|
||||||
if (!short_opts) continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (isoption(argv[i], 0, "argfile", &short_opts) ||
|
if (isoption(argv[i], 0, "argfile", &short_opts) ||
|
||||||
isoption(argv[i], 0, "slurpfile", &short_opts)) {
|
isoption(argv[i], 0, "slurpfile", &short_opts)) {
|
||||||
@@ -393,36 +430,34 @@ int main(int argc, char* argv[]) {
|
|||||||
fprintf(stderr, "%s: --%s takes two parameters (e.g. --%s varname filename)\n", progname, which, which);
|
fprintf(stderr, "%s: --%s takes two parameters (e.g. --%s varname filename)\n", progname, which, which);
|
||||||
die();
|
die();
|
||||||
}
|
}
|
||||||
jv arg = jv_object();
|
if (!jv_object_has(jv_copy(program_arguments), jv_string(argv[i+1]))) {
|
||||||
arg = jv_object_set(arg, jv_string("name"), jv_string(argv[i+1]));
|
|
||||||
jv data = jv_load_file(argv[i+2], 0);
|
jv data = jv_load_file(argv[i+2], 0);
|
||||||
if (!jv_is_valid(data)) {
|
if (!jv_is_valid(data)) {
|
||||||
data = jv_invalid_get_msg(data);
|
data = jv_invalid_get_msg(data);
|
||||||
fprintf(stderr, "%s: Bad JSON in --%s %s %s: %s\n", progname, which,
|
fprintf(stderr, "%s: Bad JSON in --%s %s %s: %s\n", progname, which,
|
||||||
argv[i+1], argv[i+2], jv_string_value(data));
|
argv[i+1], argv[i+2], jv_string_value(data));
|
||||||
jv_free(data);
|
jv_free(data);
|
||||||
jv_free(arg);
|
|
||||||
ret = 2;
|
ret = 2;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
if (isoption(argv[i], 0, "argfile", &short_opts) &&
|
if (strcmp(which, "argfile") == 0 &&
|
||||||
jv_get_kind(data) == JV_KIND_ARRAY && jv_array_length(jv_copy(data)) == 1)
|
jv_get_kind(data) == JV_KIND_ARRAY && jv_array_length(jv_copy(data)) == 1)
|
||||||
data = jv_array_get(data, 0);
|
data = jv_array_get(data, 0);
|
||||||
arg = jv_object_set(arg, jv_string("value"), data);
|
program_arguments = jv_object_set(program_arguments, jv_string(argv[i+1]), data);
|
||||||
program_arguments = jv_array_append(program_arguments, arg);
|
}
|
||||||
i += 2; // skip the next two arguments
|
i += 2; // skip the next two arguments
|
||||||
if (!short_opts) continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (isoption(argv[i], 0, "debug-dump-disasm", &short_opts)) {
|
if (isoption(argv[i], 0, "debug-dump-disasm", &short_opts)) {
|
||||||
options |= DUMP_DISASM;
|
options |= DUMP_DISASM;
|
||||||
if (!short_opts) continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (isoption(argv[i], 0, "debug-trace", &short_opts)) {
|
if (isoption(argv[i], 0, "debug-trace", &short_opts)) {
|
||||||
jq_flags |= JQ_DEBUG_TRACE;
|
jq_flags |= JQ_DEBUG_TRACE;
|
||||||
if (!short_opts) continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (isoption(argv[i], 'h', "help", &short_opts)) {
|
if (isoption(argv[i], 'h', "help", &short_opts)) {
|
||||||
usage(0);
|
usage(0, 0);
|
||||||
if (!short_opts) continue;
|
if (!short_opts) continue;
|
||||||
}
|
}
|
||||||
if (isoption(argv[i], 'V', "version", &short_opts)) {
|
if (isoption(argv[i], 'V', "version", &short_opts)) {
|
||||||
@@ -489,7 +524,7 @@ int main(int argc, char* argv[]) {
|
|||||||
program = ".";
|
program = ".";
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (!program) usage(2);
|
if (!program) usage(2, 1);
|
||||||
|
|
||||||
if (options & FROM_FILE) {
|
if (options & FROM_FILE) {
|
||||||
char *program_origin = strdup(program);
|
char *program_origin = strdup(program);
|
||||||
@@ -507,11 +542,17 @@ int main(int argc, char* argv[]) {
|
|||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
jq_set_attr(jq, jv_string("PROGRAM_ORIGIN"), jq_realpath(jv_string(dirname(program_origin))));
|
jq_set_attr(jq, jv_string("PROGRAM_ORIGIN"), jq_realpath(jv_string(dirname(program_origin))));
|
||||||
|
ARGS = JV_OBJECT(jv_string("positional"), ARGS,
|
||||||
|
jv_string("named"), jv_copy(program_arguments));
|
||||||
|
program_arguments = jv_object_set(program_arguments, jv_string("ARGS"), jv_copy(ARGS));
|
||||||
compiled = jq_compile_args(jq, skip_shebang(jv_string_value(data)), jv_copy(program_arguments));
|
compiled = jq_compile_args(jq, skip_shebang(jv_string_value(data)), jv_copy(program_arguments));
|
||||||
free(program_origin);
|
free(program_origin);
|
||||||
jv_free(data);
|
jv_free(data);
|
||||||
} else {
|
} else {
|
||||||
jq_set_attr(jq, jv_string("PROGRAM_ORIGIN"), jq_realpath(jv_string("."))); // XXX is this good?
|
jq_set_attr(jq, jv_string("PROGRAM_ORIGIN"), jq_realpath(jv_string("."))); // XXX is this good?
|
||||||
|
ARGS = JV_OBJECT(jv_string("positional"), ARGS,
|
||||||
|
jv_string("named"), jv_copy(program_arguments));
|
||||||
|
program_arguments = jv_object_set(program_arguments, jv_string("ARGS"), jv_copy(ARGS));
|
||||||
compiled = jq_compile_args(jq, program, jv_copy(program_arguments));
|
compiled = jq_compile_args(jq, program, jv_copy(program_arguments));
|
||||||
}
|
}
|
||||||
if (!compiled){
|
if (!compiled){
|
||||||
@@ -576,6 +617,7 @@ out:
|
|||||||
ret = 2;
|
ret = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
jv_free(ARGS);
|
||||||
jv_free(program_arguments);
|
jv_free(program_arguments);
|
||||||
jq_util_input_free(&input_state);
|
jq_util_input_free(&input_state);
|
||||||
jq_teardown(&jq);
|
jq_teardown(&jq);
|
||||||
|
|||||||
Reference in new issue
Block a user