From 5df20f4954a5d3c2b2b1086bf758c1c9e7f3a61d Mon Sep 17 00:00:00 2001 From: Nicolas Williams Date: Sat, 27 Dec 2014 17:15:56 -0600 Subject: [PATCH] Add `debug` builtin And refactor setup of jv dump flags. --- builtin.c | 9 +++++++ docs/content/3.manual/manual.yml | 14 +++++++++++ execute.c | 12 +++++++++ jq.h | 4 +++ main.c | 43 +++++++++++++++++++------------- 5 files changed, 65 insertions(+), 17 deletions(-) diff --git a/builtin.c b/builtin.c index 0bf7b9f0..105290ca 100644 --- a/builtin.c +++ b/builtin.c @@ -875,6 +875,14 @@ static jv f_input(jq_state *jq, jv input) { return jv_invalid_with_msg(jv_string("break")); } +static jv f_debug(jq_state *jq, jv input) { + jq_debug_cb cb; + void *data; + jq_get_debug_cb(jq, &cb, &data); + if (cb != NULL) + cb(jq, data, jv_copy(input)); + return input; +} #define LIBM_DD(name) \ @@ -927,6 +935,7 @@ static const struct cfunction function_list[] = { {(cfunction_ptr)f_match, "_match_impl", 4}, {(cfunction_ptr)f_modulemeta, "modulemeta", 1}, {(cfunction_ptr)f_input, "_input", 1}, + {(cfunction_ptr)f_debug, "debug", 1}, }; #undef LIBM_DD diff --git a/docs/content/3.manual/manual.yml b/docs/content/3.manual/manual.yml index 862f261b..5e4467c4 100644 --- a/docs/content/3.manual/manual.yml +++ b/docs/content/3.manual/manual.yml @@ -2226,6 +2226,12 @@ sections: jq itself. These two builtins, and jq's own reading actions, can be interleaved with each other. + One builtin provides minimal output capabilities, `debug`. + (Recall that a jq program's output values are always output as + JSON texts on `stdout`.) The `debug` builtin can have + application-specific behavior, such as for executables that use + the libjq C API but aren't the jq executable itself. + - title: "`input`" body: | @@ -2239,6 +2245,14 @@ sections: This is primarily useful for reductions over a program's inputs. + - title: "`debug`" + body: | + + Causes a debug message based on the input value to be + produced. The jq executable wraps the input value with + `["DEBUG:", ]` and prints that and a newline on + stderr, compactly. This may change in the future. + - title: Assignment body: | diff --git a/execute.c b/execute.c index 556b65db..91c426e3 100644 --- a/execute.c +++ b/execute.c @@ -41,6 +41,8 @@ struct jq_state { jv attrs; jq_input_cb input_cb; void *input_cb_data; + jq_debug_cb debug_cb; + void *debug_cb_data; }; struct closure { @@ -1049,3 +1051,13 @@ void jq_get_input_cb(jq_state *jq, jq_input_cb *cb, void **data) { *cb = jq->input_cb; *data = jq->input_cb_data; } + +void jq_set_debug_cb(jq_state *jq, jq_debug_cb cb, void *data) { + jq->debug_cb = cb; + jq->debug_cb_data = data; +} + +void jq_get_debug_cb(jq_state *jq, jq_debug_cb *cb, void **data) { + *cb = jq->debug_cb; + *data = jq->debug_cb_data; +} diff --git a/jq.h b/jq.h index e410fdde..2252fa84 100644 --- a/jq.h +++ b/jq.h @@ -26,6 +26,10 @@ 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 **); +typedef void (*jq_debug_cb)(jq_state *, void *, jv); +void jq_set_debug_cb(jq_state *, jq_debug_cb, void *); +void jq_get_debug_cb(jq_state *, jq_debug_cb *, void **); + void jq_set_attrs(jq_state *, jv); jv jq_get_attrs(jq_state *); jv jq_get_jq_origin(jq_state *); diff --git a/main.c b/main.c index 09c834a0..5b12f48a 100644 --- a/main.c +++ b/main.c @@ -98,7 +98,7 @@ enum { }; static int options = 0; -static int process(jq_state *jq, jv value, int flags) { +static int process(jq_state *jq, jv value, int flags, int dumpopts) { int ret = 14; // No valid results && -e -> exit(4) jq_start(jq, value, flags); jv result; @@ -108,19 +108,6 @@ static int process(jq_state *jq, jv value, int flags) { ret = 0; jv_free(result); } else { - int dumpopts; - /* Disable colour by default on Windows builds as Windows - terminals tend not to display it correctly */ -#ifdef WIN32 - dumpopts = 0; -#else - dumpopts = isatty(fileno(stdout)) ? JV_PRINT_COLOUR : 0; -#endif - if (options & SORTED_OUTPUT) dumpopts |= JV_PRINT_SORTED; - if (!(options & COMPACT_OUTPUT)) dumpopts |= JV_PRINT_PRETTY; - if (options & ASCII_OUTPUT) dumpopts |= JV_PRINT_ASCII; - if (options & COLOUR_OUTPUT) dumpopts |= JV_PRINT_COLOUR; - if (options & NO_COLOUR_OUTPUT) dumpopts &= ~JV_PRINT_COLOUR; if (jv_get_kind(result) == JV_KIND_FALSE || jv_get_kind(result) == JV_KIND_NULL) ret = 11; else @@ -234,6 +221,12 @@ static jv next_input(jq_state *jq, void *data) { return value; } +static void debug_cb(jq_state *jq, void *data, jv input) { + int dumpopts = *(int *)data; + jv_dumpf(JV_ARRAY(jv_string("DEBUG:"), input), stderr, dumpopts & ~(JV_PRINT_PRETTY)); + fprintf(stderr, "\n"); +} + int main(int argc, char* argv[]) { jq_state *jq = NULL; int ret = 0; @@ -436,6 +429,20 @@ int main(int argc, char* argv[]) { } } + int dumpopts; + /* Disable colour by default on Windows builds as Windows + terminals tend not to display it correctly */ +#ifdef WIN32 + dumpopts = 0; +#else + dumpopts = isatty(fileno(stdout)) ? JV_PRINT_COLOUR : 0; +#endif + if (options & SORTED_OUTPUT) dumpopts |= JV_PRINT_SORTED; + if (!(options & COMPACT_OUTPUT)) dumpopts |= JV_PRINT_PRETTY; + if (options & ASCII_OUTPUT) dumpopts |= JV_PRINT_ASCII; + if (options & COLOUR_OUTPUT) dumpopts |= JV_PRINT_COLOUR; + if (options & NO_COLOUR_OUTPUT) dumpopts &= ~JV_PRINT_COLOUR; + char *penv = getenv("JQ_LIBRARY_PATH"); if (penv && jv_get_kind(lib_search_paths) == JV_KIND_NULL) { // Use $JQ_LIBRARY_PATH @@ -554,13 +561,15 @@ int main(int argc, char* argv[]) { // Let jq program read from inputs jq_set_input_cb(jq, next_input, &input_state); + jq_set_debug_cb(jq, debug_cb, &dumpopts); + if (options & PROVIDE_NULL) { - ret = process(jq, jv_null(), jq_flags); + ret = process(jq, jv_null(), jq_flags, dumpopts); } else { jv value; while (jv_is_valid((value = next_input(jq, &input_state))) || jv_invalid_has_msg(jv_copy(value))) { if (jv_is_valid(value)) { - ret = process(jq, value, jq_flags); + ret = process(jq, value, jq_flags, dumpopts); continue; } @@ -577,7 +586,7 @@ int main(int argc, char* argv[]) { jv_free(msg); } if (options & SLURP) { - ret = process(jq, input_state.slurped, jq_flags); + ret = process(jq, input_state.slurped, jq_flags, dumpopts); input_state.slurped = jv_invalid(); } }