1
0
mirror of https://github.com/stedolan/jq.git synced 2024-05-11 05:55:39 +00:00

argv[] may not be UTF-8 (fix #811)

This commit is contained in:
Nicolas Williams
2015-06-18 21:24:41 -05:00
parent 3cbefde376
commit 292f2d3208
4 changed files with 42 additions and 29 deletions

View File

@@ -2477,7 +2477,8 @@ sections:
body: | body: |
Returns the name of the file whose input is currently being 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`" - title: "`input_line_number`"
body: | body: |

11
jq.h
View File

@@ -37,12 +37,19 @@ jv jq_get_lib_dirs(jq_state *);
void jq_set_attr(jq_state *, jv, jv); void jq_set_attr(jq_state *, jv, jv);
jv jq_get_attr(jq_state *, 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 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_set_parser(jq_util_input_state, jv_parser *, int);
void jq_util_input_free(jq_util_input_state *); 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); 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(jq_util_input_state);
jv jq_util_input_next_input_cb(jq_state *, void *); jv jq_util_input_next_input_cb(jq_state *, void *);

6
main.c
View File

@@ -185,14 +185,14 @@ int main(int argc, char* argv[]) {
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 (further_args_are_files) {
jq_util_input_add_input(input_state, jv_string(argv[i])); jq_util_input_add_input(input_state, argv[i]);
nfiles++; nfiles++;
} else if (!strcmp(argv[i], "--")) { } else if (!strcmp(argv[i], "--")) {
if (!program) usage(2); if (!program) usage(2);
further_args_are_files = 1; further_args_are_files = 1;
} else if (!isoptish(argv[i])) { } else if (!isoptish(argv[i])) {
if (program) { if (program) {
jq_util_input_add_input(input_state, jv_string(argv[i])); jq_util_input_add_input(input_state, argv[i]);
nfiles++; nfiles++;
} else { } else {
program = argv[i]; program = argv[i];
@@ -484,7 +484,7 @@ int main(int argc, char* argv[]) {
jq_set_debug_cb(jq, debug_cb, &dumpopts); jq_set_debug_cb(jq, debug_cb, &dumpopts);
if (nfiles == 0) if (nfiles == 0)
jq_util_input_add_input(input_state, jv_string("-")); jq_util_input_add_input(input_state, "-");
if (options & PROVIDE_NULL) { if (options & PROVIDE_NULL) {
ret = process(jq, jv_null(), jq_flags, dumpopts); ret = process(jq, jv_null(), jq_flags, dumpopts);

51
util.c
View File

@@ -162,11 +162,13 @@ not_this:
} }
struct jq_util_input_state { struct jq_util_input_state {
jq_msg_cb err_cb; jq_util_msg_cb err_cb;
void *err_cb_data; void *err_cb_data;
jv_parser *parser; jv_parser *parser;
FILE* current_input; FILE* current_input;
jv files; char **files;
int nfiles;
int curr_file;
int failures; int failures;
jv slurped; jv slurped;
char buf[4096]; char buf[4096];
@@ -175,13 +177,12 @@ struct jq_util_input_state {
size_t current_line; size_t current_line;
}; };
static void fprinter(void *data, jv fname) { static void fprinter(void *data, const char *fname) {
fprintf((FILE *)data, "jq: error: Could not open file %s: %s\n", jv_string_value(fname), strerror(errno)); fprintf((FILE *)data, "jq: error: Could not open file %s: %s\n", fname, strerror(errno));
jv_free(fname);
} }
// If parser == NULL -> RAW // If parser == NULL -> 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) { if (err_cb == NULL) {
err_cb = fprinter; err_cb = fprinter;
err_cb_data = stderr; 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->err_cb_data = err_cb_data;
new_state->parser = NULL; new_state->parser = NULL;
new_state->current_input = 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->slurped = jv_invalid();
new_state->buf[0] = 0; new_state->buf[0] = 0;
new_state->buf_valid_len = 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) if (old_state->parser != NULL)
jv_parser_free(old_state->parser); 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->slurped);
jv_free(old_state->current_filename); jv_free(old_state->current_filename);
jv_mem_free(old_state); jv_mem_free(old_state);
} }
void jq_util_input_add_input(jq_util_input_state state, jv fname) { void jq_util_input_add_input(jq_util_input_state state, const char *fname) {
state->files = jv_array_append(state->files, 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) { int jq_util_input_errors(jq_util_input_state state) {
return state->failures; return state->failures;
} }
static jv next_file(jq_util_input_state state) { static const char *next_file(jq_util_input_state state) {
jv next = jv_array_get(jv_copy(state->files), 0); if (state->curr_file < state->nfiles)
if (jv_array_length(jv_copy(state->files)) > 0) return state->files[state->curr_file++];
state->files = jv_array_slice(state->files, 1, jv_array_length(jv_copy(state->files))); return NULL;
return next;
} }
static int jq_util_input_read_more(jq_util_input_state state) { 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_filename = jv_invalid();
state->current_line = 0 ; state->current_line = 0 ;
} }
jv f = next_file(state); const char *f = next_file(state);
if (jv_is_valid(f)) { if (f != NULL) {
if (!strcmp(jv_string_value(f), "-")) { if (!strcmp(f, "-")) {
state->current_input = stdin; state->current_input = stdin;
state->current_filename = jv_string("<stdin>"); state->current_filename = jv_string("<stdin>");
} else { } else {
state->current_input = fopen(jv_string_value(f), "r"); state->current_input = fopen(f, "r");
state->current_filename = jv_copy(f); state->current_filename = jv_string(f);
if (!state->current_input) { 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->failures++;
} }
} }
state->current_line = 0; 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) { jv jq_util_input_next_input_cb(jq_state *jq, void *data) {