summaryrefslogtreecommitdiffstats
path: root/main.c
diff options
context:
space:
mode:
authorNicolas Williams <nico@cryptonector.com>2014-12-27 17:58:47 -0600
committerNicolas Williams <nico@cryptonector.com>2015-02-13 15:55:31 -0600
commit91fb3df4954ead7914255a093d55192d0420b962 (patch)
treedd685ba5043614c2c94063f194d3f01ac0638a86 /main.c
parent373ef71febac87ae48368e3b8c0f3bc4012d9b13 (diff)
Refactor handling of inputs in main() (fix #667)
Much of this could be in libjq. Eventually all of the work of reading from files and looping over `jq_next()` should move into libjq, with `main()` mostly doing all the command-line option processing.
Diffstat (limited to 'main.c')
-rw-r--r--main.c158
1 files changed, 101 insertions, 57 deletions
diff --git a/main.c b/main.c
index 7a91f038..6321cabe 100644
--- a/main.c
+++ b/main.c
@@ -140,56 +140,98 @@ static int process(jq_state *jq, jv value, int flags, int dumpopts) {
return ret;
}
-// XXX Move all this into the next_input_state struct
-FILE* current_input;
-const char** input_filenames = NULL;
-int ninput_files;
-int next_input_idx;
-static int read_more(char* buf, size_t size) {
- if (!current_input || feof(current_input)) {
- if (current_input) {
- if (current_input == stdin) {
+// XXX Move this and related functions into libjq (with a better name), into util.[ch] say
+struct next_input_state {
+ FILE* current_input;
+ const char** input_filenames;
+ int alloced;
+ int ninput_files;
+ int next_input_idx;
+ int open_failures;
+ struct jv_parser *parser;
+ jv slurped;
+ char buf[4096];
+};
+typedef struct next_input_state *next_input_state;
+
+static void input_state_free(next_input_state *state) {
+ next_input_state old_state = *state;
+ *state = NULL;
+ if (old_state == NULL)
+ return;
+ if (old_state->parser != NULL)
+ jv_parser_free(old_state->parser);
+ jv_mem_free(old_state->input_filenames);
+ jv_free(old_state->slurped);
+ jv_mem_free(old_state);
+}
+
+static int input_state_init(next_input_state *state, int max_inputs) {
+ next_input_state new_state = jv_mem_alloc(sizeof(*new_state));
+ new_state->next_input_idx = 0;
+ new_state->open_failures = 0;
+ new_state->ninput_files = 0;
+ new_state->current_input = NULL;
+ new_state->parser = NULL; // initialized when we know the flags
+ new_state->slurped = jv_invalid();
+ new_state->buf[0] = 0;
+
+ // XXX a jv_mem_calloc() would be nice
+ assert(max_inputs > 0 && (uintmax_t)max_inputs * sizeof(const char*) < SIZE_MAX);
+ new_state->input_filenames = jv_mem_alloc(sizeof(const char*) * max_inputs);
+ new_state->alloced = max_inputs;
+ for (; max_inputs > 0; max_inputs--)
+ new_state->input_filenames[max_inputs - 1] = NULL;
+ *state = new_state;
+ return 0;
+}
+
+static void input_state_add_input(next_input_state state, const char *input) {
+ assert(state->ninput_files < state->alloced);
+ state->input_filenames[state->ninput_files++] = input;
+}
+
+static int input_state_read_more(next_input_state state) {
+ if (!state->current_input || feof(state->current_input)) {
+ if (state->current_input) {
+ if (state->current_input == stdin) {
clearerr(stdin); // perhaps we can read again; anyways, we don't fclose(stdin)
} else {
- fclose(current_input);
+ fclose(state->current_input);
}
- current_input = 0;
+ state->current_input = NULL;
}
- if (next_input_idx < ninput_files) {
- if (!strcmp(input_filenames[next_input_idx], "-")) {
- current_input = stdin;
+ if (state->next_input_idx < state->ninput_files) {
+ if (!strcmp(state->input_filenames[state->next_input_idx], "-")) {
+ state->current_input = stdin;
} else {
- current_input = fopen(input_filenames[next_input_idx], "r");
- if (!current_input)
- fprintf(stderr, "%s: %s: %s\n", progname, input_filenames[next_input_idx], strerror(errno));
+ state->current_input = fopen(state->input_filenames[state->next_input_idx], "r");
+ if (!state->current_input) {
+ fprintf(stderr, "%s: Error: could not open %s: %s\n", progname, state->input_filenames[state->next_input_idx], strerror(errno));
+ state->open_failures++;
+ }
}
- next_input_idx++;
+ state->next_input_idx++;
}
}
- buf[0] = 0;
- if (current_input) {
- if (!fgets(buf, size, current_input))
- buf[0] = 0;
+ state->buf[0] = 0;
+ if (state->current_input) {
+ if (!fgets(state->buf, sizeof(state->buf), state->current_input))
+ state->buf[0] = 0;
}
- return next_input_idx == ninput_files && (!current_input || feof(current_input));
+ return state->next_input_idx == state->ninput_files && (!state->current_input || feof(state->current_input));
}
-struct next_input_state {
- struct jv_parser *parser;
- jv slurped;
- char buf[4096];
-};
-
// Blocks to read one more input from stdin and/or given files
// When slurping, it returns just one value
-static jv next_input(jq_state *jq, void *data) {
- struct next_input_state *state = data;
+static jv input_state_next_input(jq_state *jq, void *data) {
+ next_input_state state = data;
int is_last = 0;
jv value = jv_invalid(); // need more input
do {
if (options & RAW_INPUT) {
- is_last = read_more(state->buf, sizeof(state->buf));
+ is_last = input_state_read_more(state);
if (state->buf[0] == '\0')
continue;
int len = strlen(state->buf); // Raw input doesn't support NULs
@@ -210,7 +252,7 @@ static jv next_input(jq_state *jq, void *data) {
}
} else {
if (jv_parser_remaining(state->parser) == 0) {
- is_last = read_more(state->buf, sizeof(state->buf));
+ is_last = input_state_read_more(state);
jv_parser_set_buf(state->parser, state->buf, strlen(state->buf), !is_last); // NULs also not supported here
}
value = jv_parser_next(state->parser);
@@ -227,6 +269,7 @@ static jv next_input(jq_state *jq, void *data) {
} while (!is_last);
return value;
}
+// XXX End of stuff to move into utils
static void debug_cb(jq_state *jq, void *data, jv input) {
int dumpopts = *(int *)data;
@@ -251,8 +294,10 @@ int main(int argc, char* argv[]) {
}
const char* program = 0;
- input_filenames = jv_mem_alloc(sizeof(const char*) * argc);
- ninput_files = 0;
+
+ next_input_state input_state;
+ input_state_init(&input_state, argc);
+
int further_args_are_files = 0;
int jq_flags = 0;
size_t short_opts = 0;
@@ -260,13 +305,13 @@ int main(int argc, char* argv[]) {
jv lib_search_paths = jv_null();
for (int i=1; i<argc; i++, short_opts = 0) {
if (further_args_are_files) {
- input_filenames[ninput_files++] = argv[i];
+ input_state_add_input(input_state, argv[i]);
} else if (!strcmp(argv[i], "--")) {
if (!program) usage(2);
further_args_are_files = 1;
} else if (!isoptish(argv[i])) {
if (program) {
- input_filenames[ninput_files++] = argv[i];
+ input_state_add_input(input_state, argv[i]);
} else {
program = argv[i];
}
@@ -489,11 +534,11 @@ int main(int argc, char* argv[]) {
if (!program) usage(2);
if ((options & IN_PLACE)) {
- if (ninput_files == 0) usage(2);
- if (strcmp(input_filenames[0], "-") == 0) usage(2);
- size_t tlen = strlen(input_filenames[0]) + 7;
+ if (input_state->ninput_files == 0) usage(2);
+ if (strcmp(input_state->input_filenames[0], "-") == 0) usage(2);
+ size_t tlen = strlen(input_state->input_filenames[0]) + 7;
t = jv_mem_alloc(tlen);
- int n = snprintf(t, tlen,"%sXXXXXX", input_filenames[0]);
+ int n = snprintf(t, tlen,"%sXXXXXX", input_state->input_filenames[0]);
assert(n > 0 && (size_t)n < tlen);
if (mkstemp(t) == -1) {
fprintf(stderr, "Error: %s creating temporary file", strerror(errno));
@@ -504,7 +549,6 @@ int main(int argc, char* argv[]) {
exit(3);
}
}
- if (ninput_files == 0) current_input = stdin;
if ((options & PROVIDE_NULL) && (options & (RAW_INPUT | SLURP))) {
fprintf(stderr, "%s: --null-input cannot be used with --raw-input or --slurp\n", progname);
@@ -544,22 +588,20 @@ int main(int argc, char* argv[]) {
printf("\n");
}
- // XXX Refactor this and input_filenames[] and related setup into a
- // function to setup struct next_input_state.
if ((options & SEQ))
parser_flags |= JV_PARSE_SEQ;
- struct next_input_state input_state;
- input_state.parser = jv_parser_new(parser_flags);
+ if (input_state->ninput_files == 0) input_state->current_input = stdin;
+ input_state->parser = jv_parser_new(parser_flags);
if ((options & RAW_INPUT) && (options & SLURP))
- input_state.slurped = jv_string("");
+ input_state->slurped = jv_string("");
else if ((options & SLURP))
- input_state.slurped = jv_array();
+ input_state->slurped = jv_array();
else
- input_state.slurped = jv_invalid();
+ input_state->slurped = jv_invalid();
// Let jq program read from inputs
- jq_set_input_cb(jq, next_input, &input_state);
+ jq_set_input_cb(jq, input_state_next_input, input_state);
jq_set_debug_cb(jq, debug_cb, &dumpopts);
@@ -567,7 +609,8 @@ int main(int argc, char* argv[]) {
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))) {
+ while (input_state->open_failures == 0 &&
+ (jv_is_valid((value = input_state_next_input(jq, input_state))) || jv_invalid_has_msg(jv_copy(value)))) {
if (jv_is_valid(value)) {
ret = process(jq, value, jq_flags, dumpopts);
continue;
@@ -586,13 +629,13 @@ int main(int argc, char* argv[]) {
jv_free(msg);
}
if (options & SLURP) {
- ret = process(jq, input_state.slurped, jq_flags, dumpopts);
- input_state.slurped = jv_invalid();
+ ret = process(jq, input_state->slurped, jq_flags, dumpopts);
+ input_state->slurped = jv_invalid();
}
}
- jv_free(input_state.slurped);
- jv_parser_free(input_state.parser);
+ if (ret == 0 && input_state->open_failures != 0)
+ ret = 2;
if (ret != 0)
goto out;
@@ -608,14 +651,15 @@ int main(int argc, char* argv[]) {
fprintf(stderr, "Error: %s opening /dev/null\n", strerror(errno));
exit(3);
}
- if (rename(t, input_filenames[0]) == -1) {
+ assert(input_state->ninput_files > 0 && !strcmp(input_state->input_filenames[0], "-"));
+ if (rename(t, input_state->input_filenames[0]) == -1) {
fprintf(stderr, "Error: %s renaming temporary file\n", strerror(errno));
exit(3);
}
jv_mem_free(t);
}
out:
- jv_mem_free(input_filenames);
+ input_state_free(&input_state);
jq_teardown(&jq);
if (ret >= 10 && (options & EXIT_STATUS))
return ret - 10;