* Set default error code to -4 in main(), Fixes #1142 * fix --exit-code with more than one object in input, Fixes #1139 - Return code 1 or 4 based on last output, not last input.
This commit is contained in:
1 parent
712330940b
commit
6d3d2750ec
2 files changed
+65
-23
No files matched your search
+42
-21
@@ -146,6 +146,17 @@ enum {
|
|||||||
};
|
};
|
||||||
static int options = 0;
|
static int options = 0;
|
||||||
|
|
||||||
|
enum {
|
||||||
|
JQ_OK = 0,
|
||||||
|
JQ_OK_NULL_KIND = -1, /* exit 0 if --exit-status is not set*/
|
||||||
|
JQ_ERROR_SYSTEM = 2,
|
||||||
|
JQ_ERROR_COMPILE = 3,
|
||||||
|
JQ_OK_NO_OUTPUT = -4, /* exit 0 if --exit-status is not set*/
|
||||||
|
JQ_ERROR_UNKNOWN = 5,
|
||||||
|
};
|
||||||
|
#define jq_exit_with_status(r) exit(abs(r))
|
||||||
|
#define jq_exit(r) exit( r > 0 ? r : 0 )
|
||||||
|
|
||||||
static const char *skip_shebang(const char *p) {
|
static const char *skip_shebang(const char *p) {
|
||||||
if (strncmp(p, "#!", sizeof("#!") - 1) != 0)
|
if (strncmp(p, "#!", sizeof("#!") - 1) != 0)
|
||||||
return p;
|
return p;
|
||||||
@@ -162,7 +173,7 @@ static const char *skip_shebang(const char *p) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
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 = JQ_OK_NO_OUTPUT; // 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))) {
|
||||||
@@ -172,13 +183,13 @@ static int process(jq_state *jq, jv value, int flags, int dumpopts) {
|
|||||||
} else {
|
} else {
|
||||||
fwrite(jv_string_value(result), 1, jv_string_length_bytes(jv_copy(result)), stdout);
|
fwrite(jv_string_value(result), 1, jv_string_length_bytes(jv_copy(result)), stdout);
|
||||||
}
|
}
|
||||||
ret = 0;
|
ret = JQ_OK;
|
||||||
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 = JQ_OK_NULL_KIND;
|
||||||
else
|
else
|
||||||
ret = 0;
|
ret = JQ_OK;
|
||||||
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);
|
||||||
@@ -193,11 +204,11 @@ static int process(jq_state *jq, jv value, int flags, int dumpopts) {
|
|||||||
options |= EXIT_STATUS_EXACT;
|
options |= EXIT_STATUS_EXACT;
|
||||||
jv exit_code = jq_get_exit_code(jq);
|
jv exit_code = jq_get_exit_code(jq);
|
||||||
if (!jv_is_valid(exit_code))
|
if (!jv_is_valid(exit_code))
|
||||||
ret = 0;
|
ret = JQ_OK;
|
||||||
else if (jv_get_kind(exit_code) == JV_KIND_NUMBER)
|
else if (jv_get_kind(exit_code) == JV_KIND_NUMBER)
|
||||||
ret = jv_number_value(exit_code);
|
ret = jv_number_value(exit_code);
|
||||||
else
|
else
|
||||||
ret = 5;
|
ret = JQ_ERROR_UNKNOWN;
|
||||||
jv_free(exit_code);
|
jv_free(exit_code);
|
||||||
jv error_message = jq_get_error_message(jq);
|
jv error_message = jq_get_error_message(jq);
|
||||||
if (jv_get_kind(error_message) == JV_KIND_STRING) {
|
if (jv_get_kind(error_message) == JV_KIND_STRING) {
|
||||||
@@ -222,7 +233,7 @@ static int process(jq_state *jq, jv value, int flags, int dumpopts) {
|
|||||||
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));
|
||||||
}
|
}
|
||||||
ret = 5;
|
ret = JQ_ERROR_UNKNOWN;
|
||||||
jv_free(input_pos);
|
jv_free(input_pos);
|
||||||
jv_free(msg);
|
jv_free(msg);
|
||||||
}
|
}
|
||||||
@@ -238,10 +249,11 @@ static void debug_cb(void *data, jv input) {
|
|||||||
|
|
||||||
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 = JQ_OK_NO_OUTPUT;
|
||||||
int compiled = 0;
|
int compiled = 0;
|
||||||
int parser_flags = 0;
|
int parser_flags = 0;
|
||||||
int nfiles = 0;
|
int nfiles = 0;
|
||||||
|
int last_result = -1; /* -1 = no result, 0=null or false, 1=true */
|
||||||
int badwrite;
|
int badwrite;
|
||||||
jv ARGS = jv_array(); /* positional arguments */
|
jv ARGS = jv_array(); /* positional arguments */
|
||||||
jv program_arguments = jv_object(); /* named arguments */
|
jv program_arguments = jv_object(); /* named arguments */
|
||||||
@@ -269,7 +281,7 @@ int main(int argc, char* argv[]) {
|
|||||||
jq = jq_init();
|
jq = jq_init();
|
||||||
if (jq == NULL) {
|
if (jq == NULL) {
|
||||||
perror("malloc");
|
perror("malloc");
|
||||||
ret = 2;
|
ret = JQ_ERROR_SYSTEM;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -469,7 +481,7 @@ int main(int argc, char* argv[]) {
|
|||||||
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;
|
ret = JQ_ERROR_SYSTEM;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
if (strcmp(which, "argfile") == 0 &&
|
if (strcmp(which, "argfile") == 0 &&
|
||||||
@@ -498,7 +510,7 @@ int main(int argc, char* argv[]) {
|
|||||||
}
|
}
|
||||||
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 = JQ_OK;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
if (isoption(argv[i], 0, "run-tests", &short_opts)) {
|
if (isoption(argv[i], 0, "run-tests", &short_opts)) {
|
||||||
@@ -577,7 +589,7 @@ int main(int argc, char* argv[]) {
|
|||||||
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 = JQ_ERROR_SYSTEM;
|
||||||
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))));
|
||||||
@@ -595,7 +607,7 @@ int main(int argc, char* argv[]) {
|
|||||||
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 = JQ_ERROR_COMPILE;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -629,6 +641,8 @@ int main(int argc, char* argv[]) {
|
|||||||
(jv_is_valid((value = jq_util_input_next_input(input_state))) || jv_invalid_has_msg(jv_copy(value)))) {
|
(jv_is_valid((value = jq_util_input_next_input(input_state))) || jv_invalid_has_msg(jv_copy(value)))) {
|
||||||
if (jv_is_valid(value)) {
|
if (jv_is_valid(value)) {
|
||||||
ret = process(jq, value, jq_flags, dumpopts);
|
ret = process(jq, value, jq_flags, dumpopts);
|
||||||
|
if (ret <= 0 && ret != JQ_OK_NO_OUTPUT)
|
||||||
|
last_result = (ret != JQ_OK_NULL_KIND);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -636,7 +650,7 @@ int main(int argc, char* argv[]) {
|
|||||||
jv msg = jv_invalid_get_msg(value);
|
jv msg = jv_invalid_get_msg(value);
|
||||||
if (!(options & SEQ)) {
|
if (!(options & SEQ)) {
|
||||||
// --seq -> errors are not fatal
|
// --seq -> errors are not fatal
|
||||||
ret = 4;
|
ret = JQ_OK_NO_OUTPUT;
|
||||||
fprintf(stderr, "parse error: %s\n", jv_string_value(msg));
|
fprintf(stderr, "parse error: %s\n", jv_string_value(msg));
|
||||||
jv_free(msg);
|
jv_free(msg);
|
||||||
break;
|
break;
|
||||||
@@ -647,22 +661,29 @@ int main(int argc, char* argv[]) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (jq_util_input_errors(input_state) != 0)
|
if (jq_util_input_errors(input_state) != 0)
|
||||||
ret = 2;
|
ret = JQ_ERROR_SYSTEM;
|
||||||
|
|
||||||
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 = JQ_ERROR_SYSTEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
jv_free(ARGS);
|
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))
|
|
||||||
return ret - 10;
|
if (options & (EXIT_STATUS|EXIT_STATUS_EXACT)) {
|
||||||
if (ret >= 10 && !(options & EXIT_STATUS_EXACT))
|
if (ret != JQ_OK_NO_OUTPUT)
|
||||||
return 0;
|
jq_exit_with_status(ret);
|
||||||
return ret;
|
else
|
||||||
|
switch (last_result) {
|
||||||
|
case -1: jq_exit_with_status(JQ_OK_NO_OUTPUT);
|
||||||
|
case 0: jq_exit_with_status(JQ_OK_NULL_KIND);
|
||||||
|
default: jq_exit_with_status(JQ_OK);
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
jq_exit(ret);
|
||||||
}
|
}
|
||||||
+23
-2
@@ -96,14 +96,20 @@ cmp $d/out $d/expected
|
|||||||
cat > $d/expected <<EOF
|
cat > $d/expected <<EOF
|
||||||
ignoring parse error: Unfinished abandoned text at EOF at line 1, column 4
|
ignoring parse error: Unfinished abandoned text at EOF at line 1, column 4
|
||||||
EOF
|
EOF
|
||||||
printf '"foo' | $JQ -ce --seq . > $d/out 2>&1
|
printf '"foo' | $JQ -c --seq . > $d/out 2>&1
|
||||||
|
cmp $d/out $d/expected
|
||||||
|
|
||||||
|
# with -e option should give 4 here as there's no valid output after
|
||||||
|
# ignoring parse errors with --seq.
|
||||||
|
printf '"foo' | $JQ -ce --seq . > $d/out 2>&1 || ret=$?
|
||||||
|
[ $ret -eq 4 ]
|
||||||
cmp $d/out $d/expected
|
cmp $d/out $d/expected
|
||||||
|
|
||||||
# Numeric values truncated by EOF are ignored
|
# Numeric values truncated by EOF are ignored
|
||||||
cat > $d/expected <<EOF
|
cat > $d/expected <<EOF
|
||||||
ignoring parse error: Unfinished abandoned text at EOF at line 1, column 1
|
ignoring parse error: Unfinished abandoned text at EOF at line 1, column 1
|
||||||
EOF
|
EOF
|
||||||
printf '1' | $JQ -ce --seq . > $d/out 2>&1
|
printf '1' | $JQ -c --seq . > $d/out 2>&1
|
||||||
cmp $d/out $d/expected
|
cmp $d/out $d/expected
|
||||||
|
|
||||||
cat > $d/expected <<EOF
|
cat > $d/expected <<EOF
|
||||||
@@ -115,6 +121,21 @@ if printf '1\n' | $JQ -cen --seq '[inputs] == []' >/dev/null 2> $d/out; then
|
|||||||
fi
|
fi
|
||||||
cmp $d/out $d/expected
|
cmp $d/out $d/expected
|
||||||
|
|
||||||
|
|
||||||
|
## Test --exit-status
|
||||||
|
data='{"i": 1}\n{"i": 2}\n{"i": 3}\n'
|
||||||
|
echo "$data" | $JQ --exit-status 'select(.i==1)' > /dev/null 2>&1
|
||||||
|
echo "$data" | $JQ --exit-status 'select(.i==2)' > /dev/null 2>&1
|
||||||
|
echo "$data" | $JQ --exit-status 'select(.i==3)' > /dev/null 2>&1
|
||||||
|
ret=0
|
||||||
|
echo "$data" | $JQ --exit-status 'select(.i==4)' > /dev/null 2>&1 || ret=$?
|
||||||
|
[ $ret -eq 4 ]
|
||||||
|
ret=0
|
||||||
|
echo "$data" | $JQ --exit-status 'select(.i==2) | false' > /dev/null 2>&1 || ret=$?
|
||||||
|
[ $ret -eq 1 ]
|
||||||
|
echo "$data" | $JQ --exit-status 'select(.i==2) | true' > /dev/null 2>&1
|
||||||
|
|
||||||
|
|
||||||
# Regression test for #951
|
# Regression test for #951
|
||||||
printf '"a\n' > $d/input
|
printf '"a\n' > $d/input
|
||||||
if $VALGRIND $Q $JQ -e . $d/input; then
|
if $VALGRIND $Q $JQ -e . $d/input; then
|
||||||
|
|||||||
Reference in new issue
Block a user