diff --git a/.gitignore b/.gitignore index d1ffac3838..dbcd31fcb7 100644 --- a/.gitignore +++ b/.gitignore @@ -16,6 +16,9 @@ jq !tests/modules/lib/jq/ jq.1 +# Generator programs +src/gen_jq_builtins + # Generated source src/builtin.inc src/config_opts.inc diff --git a/Makefile.am b/Makefile.am index 437363b557..7f67753c8d 100644 --- a/Makefile.am +++ b/Makefile.am @@ -19,7 +19,9 @@ LIBJQ_SRC = src/builtin.c src/bytecode.c src/compile.c src/execute.c \ ### C build options -AM_CFLAGS = -Wextra -Wall -Wno-unused-parameter -Wno-unused-function +AM_CFLAGS = -Wextra -Wall -Woverlength-strings + +AM_CFLAGS += -Wno-unused-parameter -Wno-unused-function if WIN32 AM_CFLAGS += -municode @@ -117,12 +119,17 @@ src/config_opts.inc: fi | sed -e 's/\\/\\\\/g' -e 's/"/\\"/g' -e 's/^/"/' -e 's/$$/"/' -e 's/^/#define JQ_CONFIG /' > $@ src/main.c: src/version.h src/config_opts.inc -src/builtin.inc: $(srcdir)/src/builtin.jq - mkdir -p src - $(AM_V_GEN) sed -e 's/\\/\\\\/g' -e 's/"/\\"/g' -e 's/^/"/' -e 's/$$/\\n"/' $(srcdir)/src/builtin.jq > $@ +src/gen_jq_builtins: $(srcdir)/src/gen_jq_builtins.c + @mkdir -p src + $(AM_V_CCLD)$(COMPILE) -o $@ $< + file -- $@ +src/builtin.inc: src/gen_jq_builtins $(srcdir)/src/builtin.jq + @mkdir -p src + $(AM_V_GEN)src/gen_jq_builtins $(srcdir)/src/builtin.jq > $@ src/builtin.o: src/builtin.inc -CLEANFILES = src/version.h .remake-version-h src/builtin.inc src/config_opts.inc +CLEANFILES = src/version.h .remake-version-h src/config_opts.inc \ + src/gen_jq_builtins src/builtin.inc bin_PROGRAMS = jq jq_SOURCES = src/main.c src/version.h @@ -228,7 +235,8 @@ EXTRA_DIST = $(DOC_FILES) $(man_MANS) $(TESTS) $(TEST_LOG_COMPILER) \ tests/optional.test tests/man.test tests/manonig.test \ tests/jq.test tests/onig.test tests/base64.test \ tests/utf8-truncate.jq tests/jq-f-test.sh \ - tests/no-main-program.jq tests/yes-main-program.jq + tests/no-main-program.jq tests/yes-main-program.jq \ + src/gen_jq_builtins.c AM_DISTCHECK_CONFIGURE_FLAGS=--with-oniguruma=builtin diff --git a/src/builtin.c b/src/builtin.c index 2630fbd1d2..49da351cd7 100644 --- a/src/builtin.c +++ b/src/builtin.c @@ -1798,33 +1798,8 @@ static block bind_bytecoded_builtins(block b) { static const char jq_builtins[] = /* Include jq-coded builtins */ #include "src/builtin.inc" - -/* Include unsupported math functions next */ -#define LIBM_DD(name) -#define LIBM_DDD(name) -#define LIBM_DDDD(name) -#define LIBM_DD_NO(name) "def " #name ": \"Error: " #name "/0 not found at build time\"|error;" -#define LIBM_DDD_NO(name) "def " #name "(a;b): \"Error: " #name "/2 not found at build time\"|error;" -#define LIBM_DDDD_NO(name) "def " #name "(a;b;c): \"Error: " #name "/3 not found at build time\"|error;" -#include "libm.h" -#ifndef HAVE_FREXP - "def frexp: \"Error: frexp/0 not found at build time\"|error;" -#endif -#ifndef HAVE_MODF - "def modf: \"Error: modf/0 not found at build time\"|error;" -#endif -#ifndef HAVE_LGAMMA_R - "def lgamma_r: \"Error: lgamma_r/0 not found at build time\"|error;" -#endif ; -#undef LIBM_DDDD_NO -#undef LIBM_DDD_NO -#undef LIBM_DD_NO -#undef LIBM_DDDD -#undef LIBM_DDD -#undef LIBM_DD - static block gen_builtin_list(block builtins) { jv list = jv_array_append(block_list_funcs(builtins, 1), jv_string("builtins/0")); return BLOCK(builtins, gen_function("builtins", gen_noop(), gen_const(list))); diff --git a/src/gen_jq_builtins.c b/src/gen_jq_builtins.c new file mode 100644 index 0000000000..05788f717b --- /dev/null +++ b/src/gen_jq_builtins.c @@ -0,0 +1,132 @@ +#include +#include +#include +#include + +#include "main-win32.h" +#include "math-macos.h" + +static uint_least8_t index = 0; + +static bool indentation(void) { + if (index == 0 && fputs(" ", stdout) == EOF) { + perror("fputs"); + return false; + } + return true; +} + +static bool separator(void) { + if (putchar(index < 10 ? ' ' : '\n') == EOF) { + perror("putchar"); + return false; + } + index = (index + 1) % 11; + return true; +} + +static bool gen_char(char const ch) { + if (!indentation()) + return false; + if (printf("%.4o,", (unsigned)ch) == EOF) + return false; + return separator(); +} + +static bool gen_string(char const *const string) +{ + for (char const *ch = string; *ch; ++ch) { + if (!gen_char(*ch)) + return false; + } + return true; +} + +static bool gen_file(FILE *const fp) { + for (int ch; (ch = getc(fp)) != EOF;) { + if (!gen_char(ch)) + return false; + } + if (ferror(fp)) { + perror("getc"); + return false; + } + return true; +} + +DEFINE_MAIN(int argc, char *const argv[]) { + /* argv[1] must be the path to "src/builtin.jq" */ + if (argc != 2) { + static char const err[] = + "gen_builtin_inc: Wrong number of arguments.\n"; + if (fputs(err, stderr) == EOF) + perror("fputs"); + return EXIT_FAILURE; + } + + if (puts("{") == EOF) { + perror("puts"); + return EXIT_FAILURE; + } + + FILE *const builtin_jq = fopen(argv[1], "r"); + if (!builtin_jq) { + perror("fopen"); + return EXIT_FAILURE; + } + if (!gen_file(builtin_jq)) + return EXIT_FAILURE; + +#define GEN_STRING(string) \ + do { \ + if (!gen_string(string)) \ + return EXIT_FAILURE; \ + } while (0) + + /* Unsupported math functions */ +#define LIBM_DD(name) +#define LIBM_DDD(name) +#define LIBM_DDDD(name) +#define LIBM_DD_NO(name) \ + gen_string( \ + "def " #name ":" \ + "\"Error: " #name "/0 not found at build time\"|error;"); +#define LIBM_DDD_NO(name) \ + gen_string( \ + "def " #name "(a;b):" \ + "\"Error: " #name "/2 not found at build time\"|error;"); +#define LIBM_DDDD_NO(name) \ + gen_string("def " #name "(a;b;c):" \ + "\"Error: " #name "/3 not found at build time\"|error;"); +#include "libm.h" +#undef LIBM_DD +#undef LIBM_DDD +#undef LIBM_DDDD +#undef LIBM_DD_NO +#undef LIBM_DDD_NO +#undef LIBM_DDDD_NO + +#ifndef HAVE_FREXP + GEN_STRING( + "def frexp:" + "\"Error: frexp/0 not found at build time\"|error;"); +#endif +#ifndef HAVE_MODF + GEN_STRING( + "def modf:" + "\"Error: modf/0 not found at build time\"|error;"); +#endif +#ifndef HAVE_LGAMMA_R + GEN_STRING( + "def lgamma_r:" + "\"Error: lgamma_r/0 not found at build time\"|error;"); +#endif + +#undef GEN_STRING + + if (puts("'\\0',\n}") == EOF) { + perror("puts"); + return EXIT_FAILURE; + } + return EXIT_SUCCESS; +}