main.c (jq-1.5) | : | main.c (jq-1.6) | ||
---|---|---|---|---|
skipping to change at line 20 | skipping to change at line 20 | |||
#ifdef WIN32 | #ifdef WIN32 | |||
#include <windows.h> | #include <windows.h> | |||
#include <io.h> | #include <io.h> | |||
#include <fcntl.h> | #include <fcntl.h> | |||
#include <processenv.h> | #include <processenv.h> | |||
#include <shellapi.h> | #include <shellapi.h> | |||
#include <wchar.h> | #include <wchar.h> | |||
#include <wtypes.h> | #include <wtypes.h> | |||
#endif | #endif | |||
#if !defined(HAVE_ISATTY) && defined(HAVE__ISATTY) | ||||
#undef isatty | ||||
#define isatty _isatty | ||||
#endif | ||||
#if defined(HAVE_ISATTY) || defined(HAVE__ISATTY) | ||||
#define USE_ISATTY | ||||
#endif | ||||
#include "compile.h" | #include "compile.h" | |||
#include "jv.h" | #include "jv.h" | |||
#include "jq.h" | #include "jq.h" | |||
#include "jv_alloc.h" | #include "jv_alloc.h" | |||
#include "util.h" | #include "util.h" | |||
#include "version.h" | #include "src/version.h" | |||
int jq_testsuite(jv lib_dirs, int verbose, int argc, char* argv[]); | int jq_testsuite(jv lib_dirs, int verbose, int argc, char* argv[]); | |||
static const char* progname; | 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) | |||
f = stdout; | f = stdout; | |||
int ret = fprintf(f, | int ret = fprintf(f, | |||
"jq - commandline JSON processor [version %s]\n" | "jq - commandline JSON processor [version %s]\n" | |||
"Usage: %s [options] <jq filter> [file...]\n\n" | "\nUsage:\t%s [options] <jq filter> [file...]\n" | |||
"\tjq is a tool for processing JSON inputs, applying the\n" | "\t%s [options] --args <jq filter> [strings...]\n" | |||
"\tgiven filter to its JSON text inputs and producing the\n" | "\t%s [options] --jsonargs <jq filter> [JSON_TEXTS...]\n\n" | |||
"\tfilter's results as JSON on standard output.\n" | "jq is a tool for processing JSON inputs, applying the given filter to\n" | |||
"\tThe simplest filter is ., which is the identity filter,\n" | "its JSON text inputs and producing the filter's results as JSON on\n" | |||
"\tcopying jq's input to its output unmodified (except for\n" | "standard output.\n\n" | |||
"\tformatting).\n" | "The simplest filter is ., which copies jq's input to its output\n" | |||
"\tFor more advanced filters see the jq(1) manpage (\"man jq\")\n" | "unmodified (except for formatting, but note that IEEE754 is used\n" | |||
"\tand/or https://stedolan.github.io/jq\n\n" | "for number representation internally, with all that that implies).\n\n" | |||
"\tSome of the options include:\n" | "For more advanced filters see the jq(1) manpage (\"man jq\")\n" | |||
"\t -c\t\tcompact instead of pretty-printed output;\n" | "and/or https://stedolan.github.io/jq\n\n" | |||
"\t -n\t\tuse `null` as the single input value;\n" | "Example:\n\n\t$ echo '{\"foo\": 0}' | jq .\n" | |||
"\t -e\t\tset the exit status code based on the output;\n" | "\t{\n\t\t\"foo\": 0\n\t}\n\n", | |||
"\t -s\t\tread (slurp) all inputs into an array; apply filter to it;\n" | JQ_VERSION, progname, progname, progname); | |||
"\t -r\t\toutput raw strings, not JSON texts;\n" | if (keep_it_short) { | |||
"\t -R\t\tread raw strings, not JSON texts;\n" | fprintf(f, | |||
"\t -C\t\tcolorize JSON;\n" | "For a listing of options, use %s --help.\n", | |||
"\t -M\t\tmonochrome (don't colorize JSON);\n" | progname); | |||
"\t -S\t\tsort keys of objects on output;\n" | } else { | |||
"\t --tab\tuse tabs for indentation;\n" | (void) fprintf(f, | |||
"\t --arg a v\tset variable $a to value <v>;\n" | "Some of the options include:\n" | |||
"\t --argjson a v\tset variable $a to JSON value <v>;\n" | " -c compact instead of pretty-printed output;\n" | |||
"\t --slurpfile a f\tset variable $a to an array of JSON texts read from <f> | " -n use `null` as the single input value;\n" | |||
;\n" | " -e set the exit status code based on the output;\n" | |||
"\tSee the manpage for more options.\n", JQ_VERSION, progname); | " -s read (slurp) all inputs into an array; apply filter to | |||
it;\n" | ||||
" -r output raw strings, not JSON texts;\n" | ||||
" -R read raw strings, not JSON texts;\n" | ||||
" -C colorize JSON;\n" | ||||
" -M monochrome (don't colorize JSON);\n" | ||||
" -S sort keys of objects on output;\n" | ||||
" --tab use tabs for indentation;\n" | ||||
" --arg a v set variable $a to 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" | ||||
" --rawfile a f set variable $a to a string consisting of the contents | ||||
of <f>;\n" | ||||
" --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); | |||
} | } | |||
static void die() { | static void die() { | |||
fprintf(stderr, "Use %s --help for help with command-line options,\n", prognam e); | fprintf(stderr, "Use %s --help for help with command-line options,\n", prognam e); | |||
fprintf(stderr, "or see the jq manpage, or online docs at https://stedolan.gi thub.io/jq\n"); | fprintf(stderr, "or see the jq manpage, or online docs at https://stedolan.gi thub.io/jq\n"); | |||
exit(2); | exit(2); | |||
} | } | |||
static int isoptish(const char* text) { | static int isoptish(const char* text) { | |||
skipping to change at line 104 | skipping to change at line 131 | |||
} | } | |||
return 0; | return 0; | |||
} | } | |||
enum { | enum { | |||
SLURP = 1, | SLURP = 1, | |||
RAW_INPUT = 2, | RAW_INPUT = 2, | |||
PROVIDE_NULL = 4, | PROVIDE_NULL = 4, | |||
RAW_OUTPUT = 8, | RAW_OUTPUT = 8, | |||
ASCII_OUTPUT = 32, | ASCII_OUTPUT = 32, | |||
COLOUR_OUTPUT = 64, | COLOR_OUTPUT = 64, | |||
NO_COLOUR_OUTPUT = 128, | NO_COLOR_OUTPUT = 128, | |||
SORTED_OUTPUT = 256, | SORTED_OUTPUT = 256, | |||
FROM_FILE = 512, | FROM_FILE = 512, | |||
RAW_NO_LF = 1024, | RAW_NO_LF = 1024, | |||
UNBUFFERED_OUTPUT = 2048, | UNBUFFERED_OUTPUT = 2048, | |||
EXIT_STATUS = 4096, | EXIT_STATUS = 4096, | |||
SEQ = 8192, | EXIT_STATUS_EXACT = 8192, | |||
RUN_TESTS = 16384, | SEQ = 16384, | |||
RUN_TESTS = 32768, | ||||
/* debugging only */ | /* debugging only */ | |||
DUMP_DISASM = 32768, | DUMP_DISASM = 65536, | |||
}; | }; | |||
static int options = 0; | static int options = 0; | |||
static const char *skip_shebang(const char *p) { | ||||
if (strncmp(p, "#!", sizeof("#!") - 1) != 0) | ||||
return p; | ||||
const char *n = strchr(p, '\n'); | ||||
if (n == NULL || n[1] != '#') | ||||
return p; | ||||
n = strchr(n + 1, '\n'); | ||||
if (n == NULL || n[1] == '#' || n[1] == '\0' || n[-1] != '\\' || n[-2] == '\\' | ||||
) | ||||
return p; | ||||
n = strchr(n + 1, '\n'); | ||||
if (n == NULL) | ||||
return p; | ||||
return n+1; | ||||
} | ||||
static int process(jq_state *jq, jv value, int flags, int dumpopts) { | static int process(jq_state *jq, jv value, int flags, int dumpopts) { | |||
int ret = 14; // No valid results && -e -> exit(4) | int ret = 14; // No valid results && -e -> exit(4) | |||
jq_start(jq, value, flags); | jq_start(jq, value, flags); | |||
jv result; | jv result; | |||
while (jv_is_valid(result = jq_next(jq))) { | while (jv_is_valid(result = jq_next(jq))) { | |||
if ((options & RAW_OUTPUT) && jv_get_kind(result) == JV_KIND_STRING) { | if ((options & RAW_OUTPUT) && jv_get_kind(result) == JV_KIND_STRING) { | |||
fwrite(jv_string_value(result), 1, jv_string_length_bytes(jv_copy(result)) | if (options & ASCII_OUTPUT) { | |||
, stdout); | jv_dumpf(result, stdout, JV_PRINT_ASCII); | |||
} else { | ||||
fwrite(jv_string_value(result), 1, jv_string_length_bytes(jv_copy(result | ||||
)), stdout); | ||||
} | ||||
ret = 0; | ret = 0; | |||
jv_free(result); | jv_free(result); | |||
} else { | } else { | |||
if (jv_get_kind(result) == JV_KIND_FALSE || jv_get_kind(result) == JV_KIND _NULL) | if (jv_get_kind(result) == JV_KIND_FALSE || jv_get_kind(result) == JV_KIND _NULL) | |||
ret = 11; | ret = 11; | |||
else | else | |||
ret = 0; | ret = 0; | |||
if (options & SEQ) | if (options & SEQ) | |||
priv_fwrite("\036", 1, stdout, dumpopts & JV_PRINT_ISATTY); | priv_fwrite("\036", 1, stdout, dumpopts & JV_PRINT_ISATTY); | |||
jv_dump(result, dumpopts); | jv_dump(result, dumpopts); | |||
} | } | |||
if (!(options & RAW_NO_LF)) | if (!(options & RAW_NO_LF)) | |||
priv_fwrite("\n", 1, stdout, dumpopts & JV_PRINT_ISATTY); | priv_fwrite("\n", 1, stdout, dumpopts & JV_PRINT_ISATTY); | |||
if (options & UNBUFFERED_OUTPUT) | if (options & UNBUFFERED_OUTPUT) | |||
fflush(stdout); | fflush(stdout); | |||
} | } | |||
if (jv_invalid_has_msg(jv_copy(result))) { | if (jq_halted(jq)) { | |||
// jq program invoked `halt` or `halt_error` | ||||
options |= EXIT_STATUS_EXACT; | ||||
jv exit_code = jq_get_exit_code(jq); | ||||
if (!jv_is_valid(exit_code)) | ||||
ret = 0; | ||||
else if (jv_get_kind(exit_code) == JV_KIND_NUMBER) | ||||
ret = jv_number_value(exit_code); | ||||
else | ||||
ret = 5; | ||||
jv_free(exit_code); | ||||
jv error_message = jq_get_error_message(jq); | ||||
if (jv_get_kind(error_message) == JV_KIND_STRING) { | ||||
fprintf(stderr, "%s", jv_string_value(error_message)); | ||||
} else if (jv_get_kind(error_message) == JV_KIND_NULL) { | ||||
// Halt with no output | ||||
} else if (jv_is_valid(error_message)) { | ||||
error_message = jv_dump_string(jv_copy(error_message), 0); | ||||
fprintf(stderr, "%s\n", jv_string_value(error_message)); | ||||
} // else no message on stderr; use --debug-trace to see a message | ||||
fflush(stderr); | ||||
jv_free(error_message); | ||||
} else if (jv_invalid_has_msg(jv_copy(result))) { | ||||
// Uncaught jq exception | // Uncaught jq exception | |||
jv msg = jv_invalid_get_msg(jv_copy(result)); | jv msg = jv_invalid_get_msg(jv_copy(result)); | |||
jv input_pos = jq_util_input_get_position(jq); | jv input_pos = jq_util_input_get_position(jq); | |||
if (jv_get_kind(msg) == JV_KIND_STRING) { | if (jv_get_kind(msg) == JV_KIND_STRING) { | |||
fprintf(stderr, "jq: error (at %s): %s\n", | fprintf(stderr, "jq: error (at %s): %s\n", | |||
jv_string_value(input_pos), jv_string_value(msg)); | jv_string_value(input_pos), jv_string_value(msg)); | |||
} else { | } else { | |||
msg = jv_dump_string(msg, 0); | msg = jv_dump_string(msg, 0); | |||
fprintf(stderr, "jq: error (at %s) (not a string): %s\n", | fprintf(stderr, "jq: error (at %s) (not a string): %s\n", | |||
jv_string_value(input_pos), jv_string_value(msg)); | jv_string_value(input_pos), jv_string_value(msg)); | |||
skipping to change at line 174 | skipping to change at line 243 | |||
fprintf(stderr, "\n"); | fprintf(stderr, "\n"); | |||
} | } | |||
int main(int argc, char* argv[]) { | int main(int argc, char* argv[]) { | |||
jq_state *jq = NULL; | jq_state *jq = NULL; | |||
int ret = 0; | int ret = 0; | |||
int compiled = 0; | int compiled = 0; | |||
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 | |||
SetConsoleOutputCP(CP_UTF8); | ||||
fflush(stdout); | fflush(stdout); | |||
fflush(stderr); | fflush(stderr); | |||
_setmode(fileno(stdout), _O_TEXT | _O_U8TEXT); | _setmode(fileno(stdout), _O_TEXT | _O_U8TEXT); | |||
_setmode(fileno(stderr), _O_TEXT | _O_U8TEXT); | _setmode(fileno(stderr), _O_TEXT | _O_U8TEXT); | |||
int wargc; | int wargc; | |||
wchar_t **wargv = CommandLineToArgvW(GetCommandLineW(), &wargc); | wchar_t **wargv = CommandLineToArgvW(GetCommandLineW(), &wargc); | |||
assert(wargc == argc); | assert(wargc == argc); | |||
size_t arg_sz; | size_t arg_sz; | |||
for (int i = 0; i < argc; i++) { | for (int i = 0; i < argc; i++) { | |||
argv[i] = alloca((arg_sz = WideCharToMultiByte(CP_UTF8, | argv[i] = alloca((arg_sz = WideCharToMultiByte(CP_UTF8, | |||
skipping to change at line 209 | skipping to change at line 278 | |||
perror("malloc"); | perror("malloc"); | |||
ret = 2; | ret = 2; | |||
goto out; | goto out; | |||
} | } | |||
int dumpopts = JV_PRINT_INDENT_FLAGS(2); | int dumpopts = JV_PRINT_INDENT_FLAGS(2); | |||
const char* program = 0; | const char* program = 0; | |||
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) { | |||
jq_util_input_add_input(input_state, argv[i]); | if (further_args_are_strings) { | |||
nfiles++; | 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]); | ||||
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) { | |||
jq_util_input_add_input(input_state, argv[i]); | if (further_args_are_strings) { | |||
nfiles++; | 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]); | ||||
nfiles++; | ||||
} | ||||
} else { | } else { | |||
program = argv[i]; | program = argv[i]; | |||
} | } | |||
} else { | } else { | |||
if (argv[i][1] == 'L') { | if (argv[i][1] == 'L') { | |||
if (jv_get_kind(lib_search_paths) == JV_KIND_NULL) | if (jv_get_kind(lib_search_paths) == JV_KIND_NULL) | |||
lib_search_paths = jv_array(); | lib_search_paths = jv_array(); | |||
if (argv[i][2] != 0) { // -Lname (faster check than strlen) | if (argv[i][2] != 0) { // -Lname (faster check than strlen) | |||
lib_search_paths = jv_array_append(lib_search_paths, jq_realpath(jv_ string(argv[i]+2))); | lib_search_paths = jv_array_append(lib_search_paths, jq_realpath(jv_ string(argv[i]+2))); | |||
} else if (i >= argc - 1) { | } else if (i >= argc - 1) { | |||
skipping to change at line 256 | skipping to change at line 339 | |||
} | } | |||
if (isoption(argv[i], 'r', "raw-output", &short_opts)) { | if (isoption(argv[i], 'r', "raw-output", &short_opts)) { | |||
options |= RAW_OUTPUT; | options |= RAW_OUTPUT; | |||
if (!short_opts) continue; | if (!short_opts) continue; | |||
} | } | |||
if (isoption(argv[i], 'c', "compact-output", &short_opts)) { | if (isoption(argv[i], 'c', "compact-output", &short_opts)) { | |||
dumpopts &= ~(JV_PRINT_TAB | JV_PRINT_INDENT_FLAGS(7)); | dumpopts &= ~(JV_PRINT_TAB | JV_PRINT_INDENT_FLAGS(7)); | |||
if (!short_opts) continue; | if (!short_opts) continue; | |||
} | } | |||
if (isoption(argv[i], 'C', "color-output", &short_opts)) { | if (isoption(argv[i], 'C', "color-output", &short_opts)) { | |||
options |= COLOUR_OUTPUT; | options |= COLOR_OUTPUT; | |||
if (!short_opts) continue; | if (!short_opts) continue; | |||
} | } | |||
if (isoption(argv[i], 'M', "monochrome-output", &short_opts)) { | if (isoption(argv[i], 'M', "monochrome-output", &short_opts)) { | |||
options |= NO_COLOUR_OUTPUT; | options |= NO_COLOR_OUTPUT; | |||
if (!short_opts) continue; | if (!short_opts) continue; | |||
} | } | |||
if (isoption(argv[i], 'a', "ascii-output", &short_opts)) { | if (isoption(argv[i], 'a', "ascii-output", &short_opts)) { | |||
options |= ASCII_OUTPUT; | options |= ASCII_OUTPUT; | |||
if (!short_opts) continue; | if (!short_opts) continue; | |||
} | } | |||
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; | |||
if (!short_opts) continue; | if (!short_opts) continue; | |||
} | } | |||
if (isoption(argv[i], 'R', "raw-input", &short_opts)) { | if (isoption(argv[i], 'R', "raw-input", &short_opts)) { | |||
options |= RAW_INPUT; | options |= RAW_INPUT; | |||
if (!short_opts) continue; | if (!short_opts) continue; | |||
} | } | |||
if (isoption(argv[i], 'n', "null-input", &short_opts)) { | if (isoption(argv[i], 'n', "null-input", &short_opts)) { | |||
skipping to change at line 294 | skipping to change at line 377 | |||
options |= FROM_FILE; | options |= FROM_FILE; | |||
if (!short_opts) continue; | if (!short_opts) continue; | |||
} | } | |||
if (isoption(argv[i], 'j', "join-output", &short_opts)) { | if (isoption(argv[i], 'j', "join-output", &short_opts)) { | |||
options |= RAW_OUTPUT | RAW_NO_LF; | options |= RAW_OUTPUT | RAW_NO_LF; | |||
if (!short_opts) continue; | if (!short_opts) continue; | |||
} | } | |||
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) { | |||
fprintf(stderr, "%s: --indent takes one parameter\n", progname); | fprintf(stderr, "%s: --indent takes one parameter\n", progname); | |||
die(); | die(); | |||
} | } | |||
dumpopts &= ~(JV_PRINT_TAB | JV_PRINT_INDENT_FLAGS(7)); | dumpopts &= ~(JV_PRINT_TAB | JV_PRINT_INDENT_FLAGS(7)); | |||
int indent = atoi(argv[i+1]); | int indent = atoi(argv[i+1]); | |||
if (indent < -1 || indent > 7) { | if (indent < -1 || indent > 7) { | |||
fprintf(stderr, "%s: --indent takes a number between -1 and 7\n", prog name); | fprintf(stderr, "%s: --indent takes a number between -1 and 7\n", prog name); | |||
die(); | die(); | |||
} | } | |||
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 va lue)\n", progname); | fprintf(stderr, "%s: --arg takes two parameters (e.g. --arg varname va lue)\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+ | |||
arg = jv_object_set(arg, jv_string("value"), jv_string(argv[i+2])); | 1]), 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 va rname text)\n", progname); | fprintf(stderr, "%s: --argjson takes two parameters (e.g. --argjson va rname text)\n", progname); | |||
die(); | die(); | |||
} | } | |||
jv v = jv_parse(argv[i+2]); | if (!jv_object_has(jv_copy(program_arguments), jv_string(argv[i+1]))) { | |||
if (!jv_is_valid(v)) { | jv v = jv_parse(argv[i+2]); | |||
fprintf(stderr, "%s: invalid JSON text passed to --argjson\n", prognam | if (!jv_is_valid(v)) { | |||
e); | fprintf(stderr, "%s: invalid JSON text passed to --argjson\n", progn | |||
die(); | ame); | |||
die(); | ||||
} | ||||
program_arguments = jv_object_set(program_arguments, jv_string(argv[i+ | ||||
1]), v); | ||||
} | } | |||
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"), 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, "rawfile", &short_opts) || | ||||
isoption(argv[i], 0, "slurpfile", &short_opts)) { | isoption(argv[i], 0, "slurpfile", &short_opts)) { | |||
int raw = isoption(argv[i], 0, "rawfile", &short_opts); | ||||
const char *which; | const char *which; | |||
if (isoption(argv[i], 0, "argfile", &short_opts)) | if (isoption(argv[i], 0, "argfile", &short_opts)) | |||
which = "argfile"; | which = "argfile"; | |||
else if (raw) | ||||
which = "rawfile"; | ||||
else | else | |||
which = "slurpfile"; | which = "slurpfile"; | |||
if (i >= argc - 2) { | if (i >= argc - 2) { | |||
fprintf(stderr, "%s: --%s takes two parameters (e.g. --%s varname file name)\n", progname, which, which); | fprintf(stderr, "%s: --%s takes two parameters (e.g. --%s varname file name)\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], raw); | |||
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); | ret = 2; | |||
jv_free(arg); | goto out; | |||
ret = 2; | } | |||
goto out; | if (strcmp(which, "argfile") == 0 && | |||
jv_get_kind(data) == JV_KIND_ARRAY && jv_array_length(jv_copy(data | ||||
)) == 1) | ||||
data = jv_array_get(data, 0); | ||||
program_arguments = jv_object_set(program_arguments, jv_string(argv[i+ | ||||
1]), data); | ||||
} | } | |||
if (isoption(argv[i], 0, "argfile", &short_opts) && | ||||
jv_get_kind(data) == JV_KIND_ARRAY && jv_array_length(jv_copy(data)) | ||||
== 1) | ||||
data = jv_array_get(data, 0); | ||||
arg = jv_object_set(arg, jv_string("value"), 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; | |||
continue; | ||||
} | ||||
if (isoption(argv[i], 0, "debug-trace=all", &short_opts)) { | ||||
jq_flags |= JQ_DEBUG_TRACE_ALL; | ||||
if (!short_opts) continue; | if (!short_opts) 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)) { | |||
printf("jq-%s\n", JQ_VERSION); | printf("jq-%s\n", JQ_VERSION); | |||
ret = 0; | ret = 0; | |||
goto out; | goto out; | |||
} | } | |||
if (isoption(argv[i], 0, "run-tests", &short_opts)) { | if (isoption(argv[i], 0, "run-tests", &short_opts)) { | |||
i++; | i++; | |||
// XXX Pass program_arguments, even a whole jq_state *, through; | // XXX Pass program_arguments, even a whole jq_state *, through; | |||
skipping to change at line 423 | skipping to change at line 519 | |||
} | } | |||
// check for unknown options... if this argument was a short option | // check for unknown options... if this argument was a short option | |||
if (strlen(argv[i]) != short_opts + 1) { | if (strlen(argv[i]) != short_opts + 1) { | |||
fprintf(stderr, "%s: Unknown option %s\n", progname, argv[i]); | fprintf(stderr, "%s: Unknown option %s\n", progname, argv[i]); | |||
die(); | die(); | |||
} | } | |||
} | } | |||
} | } | |||
if (isatty(fileno(stdout))) { | #ifdef USE_ISATTY | |||
if (isatty(STDOUT_FILENO)) { | ||||
dumpopts |= JV_PRINT_ISATTY; | dumpopts |= JV_PRINT_ISATTY; | |||
#ifndef WIN32 | #ifndef WIN32 | |||
/* Disable colour by default on Windows builds as Windows | /* Disable color by default on Windows builds as Windows | |||
terminals tend not to display it correctly */ | terminals tend not to display it correctly */ | |||
dumpopts |= JV_PRINT_COLOUR; | dumpopts |= JV_PRINT_COLOR; | |||
#endif | #endif | |||
} | } | |||
#endif | ||||
if (options & SORTED_OUTPUT) dumpopts |= JV_PRINT_SORTED; | if (options & SORTED_OUTPUT) dumpopts |= JV_PRINT_SORTED; | |||
if (options & ASCII_OUTPUT) dumpopts |= JV_PRINT_ASCII; | if (options & ASCII_OUTPUT) dumpopts |= JV_PRINT_ASCII; | |||
if (options & COLOUR_OUTPUT) dumpopts |= JV_PRINT_COLOUR; | if (options & COLOR_OUTPUT) dumpopts |= JV_PRINT_COLOR; | |||
if (options & NO_COLOUR_OUTPUT) dumpopts &= ~JV_PRINT_COLOUR; | if (options & NO_COLOR_OUTPUT) dumpopts &= ~JV_PRINT_COLOR; | |||
if (getenv("JQ_COLORS") != NULL && !jq_set_colors(getenv("JQ_COLORS"))) | ||||
fprintf(stderr, "Failed to set $JQ_COLORS\n"); | ||||
if (jv_get_kind(lib_search_paths) == JV_KIND_NULL) { | if (jv_get_kind(lib_search_paths) == JV_KIND_NULL) { | |||
// Default search path list | // Default search path list | |||
lib_search_paths = JV_ARRAY(jv_string("~/.jq"), | lib_search_paths = JV_ARRAY(jv_string("~/.jq"), | |||
jv_string("$ORIGIN/../lib/jq"), | jv_string("$ORIGIN/../lib/jq"), | |||
jv_string("$ORIGIN/lib")); | jv_string("$ORIGIN/lib")); | |||
} | } | |||
jq_set_attr(jq, jv_string("JQ_LIBRARY_PATH"), lib_search_paths); | jq_set_attr(jq, jv_string("JQ_LIBRARY_PATH"), lib_search_paths); | |||
char *origin = strdup(argv[0]); | char *origin = strdup(argv[0]); | |||
skipping to change at line 457 | skipping to change at line 558 | |||
exit(1); | exit(1); | |||
} | } | |||
jq_set_attr(jq, jv_string("JQ_ORIGIN"), jv_string(dirname(origin))); | jq_set_attr(jq, jv_string("JQ_ORIGIN"), jv_string(dirname(origin))); | |||
free(origin); | free(origin); | |||
if (strchr(JQ_VERSION, '-') == NULL) | if (strchr(JQ_VERSION, '-') == NULL) | |||
jq_set_attr(jq, jv_string("VERSION_DIR"), jv_string(JQ_VERSION)); | jq_set_attr(jq, jv_string("VERSION_DIR"), jv_string(JQ_VERSION)); | |||
else | else | |||
jq_set_attr(jq, jv_string("VERSION_DIR"), jv_string_fmt("%.*s-master", (int) (strchr(JQ_VERSION, '-') - JQ_VERSION), JQ_VERSION)); | jq_set_attr(jq, jv_string("VERSION_DIR"), jv_string_fmt("%.*s-master", (int) (strchr(JQ_VERSION, '-') - JQ_VERSION), JQ_VERSION)); | |||
#if (!defined(WIN32) && defined(HAVE_ISATTY)) || defined(HAVE__ISATTY) | #ifdef USE_ISATTY | |||
if (!program && (!isatty(STDOUT_FILENO) || !isatty(STDIN_FILENO))) | ||||
#if defined(HAVE__ISATTY) && defined(isatty) | ||||
#undef isatty | ||||
#define isatty _isatty | ||||
#endif | ||||
if (!program && isatty(STDOUT_FILENO) && !isatty(STDIN_FILENO)) | ||||
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); | |||
if (program_origin == NULL) { | if (program_origin == NULL) { | |||
perror("malloc"); | perror("malloc"); | |||
exit(2); | exit(2); | |||
} | } | |||
jv data = jv_load_file(program, 1); | jv data = jv_load_file(program, 1); | |||
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: %s\n", progname, jv_string_value(data)); | fprintf(stderr, "%s: %s\n", progname, jv_string_value(data)); | |||
jv_free(data); | jv_free(data); | |||
ret = 2; | ret = 2; | |||
goto out; | goto out; | |||
} | } | |||
jq_set_attr(jq, jv_string("PROGRAM_ORIGIN"), jq_realpath(jv_string(dirname(p rogram_origin)))); | jq_set_attr(jq, jv_string("PROGRAM_ORIGIN"), jq_realpath(jv_string(dirname(p rogram_origin)))); | |||
compiled = jq_compile_args(jq, jv_string_value(data), jv_copy(program_argume | ARGS = JV_OBJECT(jv_string("positional"), ARGS, | |||
nts)); | jv_string("named"), jv_copy(program_arguments)); | |||
program_arguments = jv_object_set(program_arguments, jv_string("ARGS"), jv_c | ||||
opy(ARGS)); | ||||
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_c | ||||
opy(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){ | |||
ret = 3; | ret = 3; | |||
goto out; | goto out; | |||
} | } | |||
if (options & DUMP_DISASM) { | if (options & DUMP_DISASM) { | |||
jq_dump_disassembly(jq, 0); | jq_dump_disassembly(jq, 0); | |||
printf("\n"); | printf("\n"); | |||
skipping to change at line 555 | skipping to change at line 656 | |||
if (jq_util_input_errors(input_state) != 0) | if (jq_util_input_errors(input_state) != 0) | |||
ret = 2; | ret = 2; | |||
out: | out: | |||
badwrite = ferror(stdout); | badwrite = ferror(stdout); | |||
if (fclose(stdout)!=0 || badwrite) { | if (fclose(stdout)!=0 || badwrite) { | |||
fprintf(stderr,"Error: writing output failed: %s\n", strerror(errno)); | fprintf(stderr,"Error: writing output failed: %s\n", strerror(errno)); | |||
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); | |||
if (ret >= 10 && (options & EXIT_STATUS)) | if (ret >= 10 && (options & EXIT_STATUS)) | |||
return ret - 10; | return ret - 10; | |||
if (ret >= 10) | if (ret >= 10 && !(options & EXIT_STATUS_EXACT)) | |||
return 0; | return 0; | |||
return ret; | return ret; | |||
} | } | |||
End of changes. 50 change blocks. | ||||
105 lines changed or deleted | 216 lines changed or added |