summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/builtin.c6
-rw-r--r--src/execute.c15
-rw-r--r--src/jq.h3
-rw-r--r--src/main.c15
-rwxr-xr-xtests/shtest10
5 files changed, 47 insertions, 2 deletions
diff --git a/src/builtin.c b/src/builtin.c
index c71272f8..fb7513ce 100644
--- a/src/builtin.c
+++ b/src/builtin.c
@@ -1245,7 +1245,11 @@ static jv f_debug(jq_state *jq, jv input) {
}
static jv f_stderr(jq_state *jq, jv input) {
- jv_dumpf(jv_copy(input), stderr, 0);
+ jq_msg_cb cb;
+ void *data;
+ jq_get_stderr_cb(jq, &cb, &data);
+ if (cb != NULL)
+ cb(data, jv_copy(input));
return input;
}
diff --git a/src/execute.c b/src/execute.c
index adf37737..34bb63dc 100644
--- a/src/execute.c
+++ b/src/execute.c
@@ -49,6 +49,8 @@ struct jq_state {
void *input_cb_data;
jq_msg_cb debug_cb;
void *debug_cb_data;
+ jq_msg_cb stderr_cb;
+ void *stderr_cb_data;
};
struct closure {
@@ -1018,6 +1020,9 @@ jq_state *jq_init(void) {
jq->debug_cb = NULL;
jq->debug_cb_data = NULL;
+ jq->stderr_cb = NULL;
+ jq->stderr_cb_data = NULL;
+
jq->err_cb = default_err_cb;
jq->err_cb_data = stderr;
@@ -1249,6 +1254,16 @@ void jq_get_debug_cb(jq_state *jq, jq_msg_cb *cb, void **data) {
*data = jq->debug_cb_data;
}
+void jq_set_stderr_cb(jq_state *jq, jq_msg_cb cb, void *data) {
+ jq->stderr_cb = cb;
+ jq->stderr_cb_data = data;
+}
+
+void jq_get_stderr_cb(jq_state *jq, jq_msg_cb *cb, void **data) {
+ *cb = jq->stderr_cb;
+ *data = jq->stderr_cb_data;
+}
+
void
jq_halt(jq_state *jq, jv exit_code, jv error_message)
{
diff --git a/src/jq.h b/src/jq.h
index 5269de3f..b44a6a55 100644
--- a/src/jq.h
+++ b/src/jq.h
@@ -34,9 +34,10 @@ jv jq_get_error_message(jq_state *);
typedef jv (*jq_input_cb)(jq_state *, void *);
void jq_set_input_cb(jq_state *, jq_input_cb, void *);
void jq_get_input_cb(jq_state *, jq_input_cb *, void **);
-
void jq_set_debug_cb(jq_state *, jq_msg_cb, void *);
void jq_get_debug_cb(jq_state *, jq_msg_cb *, void **);
+void jq_set_stderr_cb(jq_state *, jq_msg_cb, void *);
+void jq_get_stderr_cb(jq_state *, jq_msg_cb *, void **);
void jq_set_attrs(jq_state *, jv);
jv jq_get_attrs(jq_state *);
diff --git a/src/main.c b/src/main.c
index 99857c21..ff2a9660 100644
--- a/src/main.c
+++ b/src/main.c
@@ -263,6 +263,18 @@ static void debug_cb(void *data, jv input) {
fprintf(stderr, "\n");
}
+static void stderr_cb(void *data, jv input) {
+ if (jv_get_kind(input) == JV_KIND_STRING) {
+ int dumpopts = *(int *)data;
+ priv_fwrite(jv_string_value(input), jv_string_length_bytes(jv_copy(input)),
+ stderr, dumpopts & JV_PRINT_ISATTY);
+ } else {
+ input = jv_dump_string(input, 0);
+ fprintf(stderr, "%s", jv_string_value(input));
+ }
+ jv_free(input);
+}
+
#ifdef WIN32
int umain(int argc, char* argv[]);
@@ -694,6 +706,9 @@ int main(int argc, char* argv[]) {
// Let jq program call `debug` builtin and have that go somewhere
jq_set_debug_cb(jq, debug_cb, &dumpopts);
+ // Let jq program call `stderr` builtin and have that go somewhere
+ jq_set_stderr_cb(jq, stderr_cb, &dumpopts);
+
if (nfiles == 0)
jq_util_input_add_input(input_state, "-");
diff --git a/tests/shtest b/tests/shtest
index 1ee84d3a..6cc428ca 100755
--- a/tests/shtest
+++ b/tests/shtest
@@ -237,6 +237,16 @@ grep "Expected string key after '{', not '\\['" $d/err > /dev/null
echo '{"x":"y",["a","b"]}' | $JQ --stream > /dev/null 2> $d/err || true
grep "Expected string key after ',' in object, not '\\['" $d/err > /dev/null
+# debug, stderr
+$VALGRIND $Q $JQ -n '"test", {} | debug, stderr' >/dev/null
+$JQ -n -c -j '"hello\nworld", null, [false, 0], {"foo":["bar"]}, "\n" | stderr' >$d/out 2>$d/err
+cat > $d/expected <<'EOF'
+hello
+worldnull[false,0]{"foo":["bar"]}
+EOF
+cmp $d/out $d/expected
+cmp $d/err $d/expected
+
# --arg, --argjson, $ARGS.named
$VALGRIND $JQ -n -c --arg foo 1 --argjson bar 2 '{$foo, $bar} | ., . == $ARGS.named' > $d/out
printf '{"foo":"1","bar":2}\ntrue\n' > $d/expected