From 292f2d3208ab9a75e6f788c46e0b7e59cc087b3a Mon Sep 17 00:00:00 2001 From: Nicolas Williams Date: Thu, 18 Jun 2015 21:24:41 -0500 Subject: [PATCH] argv[] may not be UTF-8 (fix #811) --- docs/content/3.manual/manual.yml | 3 +- jq.h | 11 +++++-- main.c | 6 ++-- util.c | 51 ++++++++++++++++++-------------- 4 files changed, 42 insertions(+), 29 deletions(-) diff --git a/docs/content/3.manual/manual.yml b/docs/content/3.manual/manual.yml index aaf5c637..05e1733f 100644 --- a/docs/content/3.manual/manual.yml +++ b/docs/content/3.manual/manual.yml @@ -2477,7 +2477,8 @@ sections: body: | Returns the name of the file whose input is currently being - filtered. + filtered. Note that this will not work well unless jq is + running in a UTF-8 locale. - title: "`input_line_number`" body: | diff --git a/jq.h b/jq.h index 2c5ef168..0e47d628 100644 --- a/jq.h +++ b/jq.h @@ -37,12 +37,19 @@ jv jq_get_lib_dirs(jq_state *); void jq_set_attr(jq_state *, jv, jv); jv jq_get_attr(jq_state *, jv); +/* + * We use char * instead of jf for filenames here because filenames + * should be in the process' locale's codeset, which may not be UTF-8, + * whereas jv string values must be in UTF-8. This way the caller + * doesn't have to perform any codeset conversions. + */ typedef struct jq_util_input_state *jq_util_input_state; +typedef void (*jq_util_msg_cb)(void *, const char *); -jq_util_input_state jq_util_input_init(jq_msg_cb, void *); +jq_util_input_state jq_util_input_init(jq_util_msg_cb, void *); void jq_util_input_set_parser(jq_util_input_state, jv_parser *, int); void jq_util_input_free(jq_util_input_state *); -void jq_util_input_add_input(jq_util_input_state, jv); +void jq_util_input_add_input(jq_util_input_state, const char *); int jq_util_input_errors(jq_util_input_state); jv jq_util_input_next_input(jq_util_input_state); jv jq_util_input_next_input_cb(jq_state *, void *); diff --git a/main.c b/main.c index 246b2dfd..ceb2360a 100644 --- a/main.c +++ b/main.c @@ -185,14 +185,14 @@ int main(int argc, char* argv[]) { jv lib_search_paths = jv_null(); for (int i=1; i RAW -jq_util_input_state jq_util_input_init(jq_msg_cb err_cb, void *err_cb_data) { +jq_util_input_state jq_util_input_init(jq_util_msg_cb err_cb, void *err_cb_data) { if (err_cb == NULL) { err_cb = fprinter; err_cb_data = stderr; @@ -192,7 +193,9 @@ jq_util_input_state jq_util_input_init(jq_msg_cb err_cb, void *err_cb_data) { new_state->err_cb_data = err_cb_data; new_state->parser = NULL; new_state->current_input = NULL; - new_state->files = jv_array(); + new_state->files = NULL; + new_state->nfiles = 0; + new_state->curr_file = 0; new_state->slurped = jv_invalid(); new_state->buf[0] = 0; new_state->buf_valid_len = 0; @@ -222,25 +225,27 @@ void jq_util_input_free(jq_util_input_state *state) { if (old_state->parser != NULL) jv_parser_free(old_state->parser); - jv_free(old_state->files); + for (int i = 0; i < old_state->nfiles; i++) + free(old_state->files[i]); + free(old_state->files); jv_free(old_state->slurped); jv_free(old_state->current_filename); jv_mem_free(old_state); } -void jq_util_input_add_input(jq_util_input_state state, jv fname) { - state->files = jv_array_append(state->files, fname); +void jq_util_input_add_input(jq_util_input_state state, const char *fname) { + state->files = jv_mem_realloc(state->files, (state->nfiles + 1) * sizeof(state->files[0])); + state->files[state->nfiles++] = jv_mem_strdup(fname); } int jq_util_input_errors(jq_util_input_state state) { return state->failures; } -static jv next_file(jq_util_input_state state) { - jv next = jv_array_get(jv_copy(state->files), 0); - if (jv_array_length(jv_copy(state->files)) > 0) - state->files = jv_array_slice(state->files, 1, jv_array_length(jv_copy(state->files))); - return next; +static const char *next_file(jq_util_input_state state) { + if (state->curr_file < state->nfiles) + return state->files[state->curr_file++]; + return NULL; } static int jq_util_input_read_more(jq_util_input_state state) { @@ -262,21 +267,20 @@ static int jq_util_input_read_more(jq_util_input_state state) { state->current_filename = jv_invalid(); state->current_line = 0 ; } - jv f = next_file(state); - if (jv_is_valid(f)) { - if (!strcmp(jv_string_value(f), "-")) { + const char *f = next_file(state); + if (f != NULL) { + if (!strcmp(f, "-")) { state->current_input = stdin; state->current_filename = jv_string(""); } else { - state->current_input = fopen(jv_string_value(f), "r"); - state->current_filename = jv_copy(f); + state->current_input = fopen(f, "r"); + state->current_filename = jv_string(f); if (!state->current_input) { - state->err_cb(state->err_cb_data, jv_copy(f)); + state->err_cb(state->err_cb_data, f); state->failures++; } } state->current_line = 0; - jv_free(f); } } @@ -330,7 +334,8 @@ static int jq_util_input_read_more(jq_util_input_state state) { } } } - return jv_array_length(jv_copy(state->files)) == 0 && (!state->current_input || feof(state->current_input)); + return state->curr_file == state->nfiles && + (!state->current_input || feof(state->current_input) || ferror(state->current_input)); } jv jq_util_input_next_input_cb(jq_state *jq, void *data) {