void jq_teardown(jq_state **jq) { jq_state *old_jq = *jq; if (old_jq == NULL) return; *jq = NULL; jq_reset(old_jq); bytecode_free(old_jq->bc); old_jq->bc = 0; jv_mem_free(old_jq); }
void bytecode_free(struct bytecode* bc) { if (!bc) return; jv_mem_free(bc->code); jv_free(bc->constants); for (int i=0; i<bc->nsubfunctions; i++) bytecode_free(bc->subfunctions[i]); if (!bc->parent) symbol_table_free(bc->globals); jv_mem_free(bc->subfunctions); jv_free(bc->debuginfo); jv_mem_free(bc); }
int block_compile(block b, struct locfile* locations, struct bytecode** out) { struct bytecode* bc = jv_mem_alloc(sizeof(struct bytecode)); bc->parent = 0; bc->nclosures = 0; bc->globals = jv_mem_alloc(sizeof(struct symbol_table)); int ncfunc = count_cfunctions(b); bc->globals->ncfunctions = 0; bc->globals->cfunctions = jv_mem_alloc(sizeof(struct cfunction) * ncfunc); bc->globals->cfunc_names = jv_array(); bc->debuginfo = jv_object_set(jv_object(), jv_string("name"), jv_null()); int nerrors = compile(locations, bc, b); assert(bc->globals->ncfunctions == ncfunc); if (nerrors > 0) { bytecode_free(bc); *out = 0; } else { *out = bc; } return nerrors; }
int jq_compile_args(jq_state *jq, const char* str, jv args) { jv_nomem_handler(jq->nomem_handler, jq->nomem_handler_data); assert(jv_get_kind(args) == JV_KIND_ARRAY); struct locfile locations; locfile_init(&locations, jq, str, strlen(str)); block program; jq_reset(jq); if (jq->bc) { bytecode_free(jq->bc); jq->bc = 0; } int nerrors = jq_parse(&locations, &program); if (nerrors == 0) { int i; for (i=0; i<jv_array_length(jv_copy(args)); i++) { jv arg = jv_array_get(jv_copy(args), i); jv name = jv_object_get(jv_copy(arg), jv_string("name")); jv value = jv_object_get(arg, jv_string("value")); program = gen_var_binding(gen_const(value), jv_string_value(name), program); jv_free(name); } nerrors = builtins_bind(jq, &program); if (nerrors == 0) { nerrors = block_compile(program, &locations, &jq->bc); } } jv_free(args); if (nerrors) { jv s = jv_string_fmt("%d compile %s", nerrors, nerrors > 1 ? "errors" : "error"); if (jq->err_cb != NULL) jq->err_cb(jq->err_cb_data, s); else if (!jv_is_valid(s)) fprintf(stderr, "Error formatting jq compilation errors: %s\n", strerror(errno)); else fprintf(stderr, "%s\n", jv_string_value(s)); jv_free(s); } locfile_free(&locations); return jq->bc != NULL; }
static void run_jq_tests(FILE *testdata) { char buf[4096]; int tests = 0, passed = 0, invalid = 0; jq_state *jq = NULL; while (1) { if (!fgets(buf, sizeof(buf), testdata)) break; if (skipline(buf)) continue; if (buf[strlen(buf)-1] == '\n') buf[strlen(buf)-1] = 0; printf("Testing %s\n", buf); int pass = 1; tests++; struct bytecode* bc = jq_compile(buf); if (!bc) {invalid++; continue;} printf("Disassembly:\n"); dump_disassembly(2, bc); printf("\n"); fgets(buf, sizeof(buf), testdata); jv input = jv_parse(buf); if (!jv_is_valid(input)){ invalid++; continue; } jq_init(bc, input, &jq, JQ_DEBUG_TRACE); while (fgets(buf, sizeof(buf), testdata)) { if (skipline(buf)) break; jv expected = jv_parse(buf); if (!jv_is_valid(expected)){ invalid++; continue; } jv actual = jq_next(jq); if (!jv_is_valid(actual)) { jv_free(actual); printf("*** Insufficient results\n"); pass = 0; break; } else if (!jv_equal(jv_copy(expected), jv_copy(actual))) { printf("*** Expected "); jv_dump(jv_copy(expected), 0); printf(", but got "); jv_dump(jv_copy(actual), 0); printf("\n"); pass = 0; } jv as_string = jv_dump_string(jv_copy(expected), rand() & ~JV_PRINT_COLOUR); jv reparsed = jv_parse_sized(jv_string_value(as_string), jv_string_length_bytes(jv_copy(as_string))); assert(jv_equal(jv_copy(expected), jv_copy(reparsed))); jv_free(as_string); jv_free(reparsed); jv_free(expected); jv_free(actual); } if (pass) { jv extra = jq_next(jq); if (jv_is_valid(extra)) { printf("*** Superfluous result: "); jv_dump(extra, 0); printf("\n"); pass = 0; } else { jv_free(extra); } } jq_teardown(&jq); bytecode_free(bc); passed+=pass; } printf("%d of %d tests passed (%d malformed)\n", passed,tests,invalid); if (passed != tests) exit(1); }
int main(int argc, char* argv[]) { if (argc) progname = argv[0]; const char* program = 0; for (int i=1; i<argc; i++) { if (!isoptish(argv[i])) { if (program) usage(); program = argv[i]; } else if (isoption(argv[i], 's', "slurp")) { options |= SLURP; } else if (isoption(argv[i], 'r', "raw-output")) { options |= RAW_OUTPUT; } else if (isoption(argv[i], 'c', "compact-output")) { options |= COMPACT_OUTPUT; } else if (isoption(argv[i], 'a', "ascii-output")) { options |= ASCII_OUTPUT; } else if (isoption(argv[i], 'R', "raw-input")) { options |= RAW_INPUT; } else if (isoption(argv[i], 'n', "null-input")) { options |= PROVIDE_NULL; } else if (isoption(argv[i], 'h', "help")) { usage(); } else { fprintf(stderr, "%s: Unknown option %s\n", progname, argv[i]); die(); } } if (!program) usage(); if ((options & PROVIDE_NULL) && (options & (RAW_INPUT | SLURP))) { fprintf(stderr, "%s: --null-input cannot be used with --raw-input or --slurp\n", program); die(); } bc = jq_compile(program); if (!bc) return 1; #if JQ_DEBUG dump_disassembly(0, bc); printf("\n"); #endif if (options & PROVIDE_NULL) { process(jv_null()); } else { jv slurped; if (options & SLURP) slurped = jv_invalid(); int first = 1; struct jv_parser parser; jv_parser_init(&parser); while (!feof(stdin)) { char buf[4096]; if (!fgets(buf, sizeof(buf), stdin)) buf[0] = 0; if (options & RAW_INPUT) { int len = strlen(buf); if (len > 0) { if (options & SLURP) { if (first) slurped = jv_string(buf); else slurped = jv_string_concat(slurped, jv_string(buf)); } else { if (buf[len-1] == '\n') buf[len-1] = 0; process(jv_string(buf)); } } } else { jv_parser_set_buf(&parser, buf, strlen(buf), !feof(stdin)); jv value; while (jv_is_valid((value = jv_parser_next(&parser)))) { if (options & SLURP) { if (first) slurped = jv_array(); slurped = jv_array_append(slurped, value); } else { process(value); } } if (jv_invalid_has_msg(jv_copy(value))) { jv msg = jv_invalid_get_msg(value); fprintf(stderr, "parse error: %s\n", jv_string_value(msg)); jv_free(msg); break; } else { jv_free(value); } } first = 0; } jv_parser_free(&parser); if (options & SLURP) { if (jv_is_valid(slurped)) { process(slurped); } else { jv_free(slurped); } } } bytecode_free(bc); return 0; }
int main(int argc, char* argv[]) { int ret = 0; if (argc) progname = argv[0]; if (argc > 1 && !strcmp(argv[1], "--run-tests")) { return jq_testsuite(argc - 1, argv + 1); } const char* program = 0; input_filenames = jv_mem_alloc(sizeof(const char*) * argc); ninput_files = 0; int further_args_are_files = 0; int jq_flags = 0; jv program_arguments = jv_array(); for (int i=1; i<argc; i++) { if (further_args_are_files) { input_filenames[ninput_files++] = argv[i]; } else if (!strcmp(argv[i], "--")) { if (!program) usage(); further_args_are_files = 1; } else if (!isoptish(argv[i])) { if (program) { input_filenames[ninput_files++] = argv[i]; } else { program = argv[i]; } } else if (isoption(argv[i], 's', "slurp")) { options |= SLURP; } else if (isoption(argv[i], 'r', "raw-output")) { options |= RAW_OUTPUT; } else if (isoption(argv[i], 'c', "compact-output")) { options |= COMPACT_OUTPUT; } else if (isoption(argv[i], 'C', "color-output")) { options |= COLOUR_OUTPUT; } else if (isoption(argv[i], 'M', "monochrome-output")) { options |= NO_COLOUR_OUTPUT; } else if (isoption(argv[i], 'a', "ascii-output")) { options |= ASCII_OUTPUT; } else if (isoption(argv[i], 'R', "raw-input")) { options |= RAW_INPUT; } else if (isoption(argv[i], 'n', "null-input")) { options |= PROVIDE_NULL; } else if (isoption(argv[i], 'f', "from-file")) { options |= FROM_FILE; } else if (isoption(argv[i], 0, "arg")) { if (i >= argc - 2) { fprintf(stderr, "%s: --arg takes two parameters (e.g. -a varname value)\n", progname); die(); } jv arg = jv_object(); arg = jv_object_set(arg, jv_string("name"), jv_string(argv[i+1])); arg = jv_object_set(arg, jv_string("value"), jv_string(argv[i+2])); program_arguments = jv_array_append(program_arguments, arg); i += 2; // skip the next two arguments } else if (isoption(argv[i], 0, "debug-dump-disasm")) { options |= DUMP_DISASM; } else if (isoption(argv[i], 0, "debug-trace")) { jq_flags |= JQ_DEBUG_TRACE; } else if (isoption(argv[i], 'h', "help")) { usage(); } else if (isoption(argv[i], 'V', "version")) { fprintf(stderr, "jq version %s\n", PACKAGE_VERSION); return 0; } else { fprintf(stderr, "%s: Unknown option %s\n", progname, argv[i]); die(); } } if (!program) usage(); 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); die(); } if (options & FROM_FILE) { jv data = slurp_file(program); if (!jv_is_valid(data)) { data = jv_invalid_get_msg(data); fprintf(stderr, "%s: %s\n", progname, jv_string_value(data)); jv_free(data); return 1; } bc = jq_compile_args(jv_string_value(data), program_arguments); jv_free(data); } else { bc = jq_compile_args(program, program_arguments); } if (!bc) return 1; if (options & DUMP_DISASM) { dump_disassembly(0, bc); printf("\n"); } if (options & PROVIDE_NULL) { process(jv_null(), jq_flags); } else { jv slurped; if (options & SLURP) { if (options & RAW_INPUT) { slurped = jv_string(""); } else { slurped = jv_array(); } } struct jv_parser parser; jv_parser_init(&parser); char buf[4096]; while (read_more(buf, sizeof(buf))) { if (options & RAW_INPUT) { int len = strlen(buf); if (len > 0) { if (options & SLURP) { slurped = jv_string_concat(slurped, jv_string(buf)); } else { if (buf[len-1] == '\n') buf[len-1] = 0; process(jv_string(buf), jq_flags); } } } else { jv_parser_set_buf(&parser, buf, strlen(buf), !feof(stdin)); jv value; while (jv_is_valid((value = jv_parser_next(&parser)))) { if (options & SLURP) { slurped = jv_array_append(slurped, value); } else { process(value, jq_flags); } } if (jv_invalid_has_msg(jv_copy(value))) { jv msg = jv_invalid_get_msg(value); fprintf(stderr, "parse error: %s\n", jv_string_value(msg)); jv_free(msg); ret = 1; break; } else { jv_free(value); } } } jv_parser_free(&parser); if (ret != 0) goto out; if (options & SLURP) { process(slurped, jq_flags); } } out: jv_mem_free(input_filenames); bytecode_free(bc); return ret; }