diff options
author | EuAndreh <eu@euandre.org> | 2024-02-20 11:26:48 -0300 |
---|---|---|
committer | EuAndreh <eu@euandre.org> | 2024-02-21 05:44:16 -0300 |
commit | 613398385703b6e99c8137a1b89454d977ccf2c8 (patch) | |
tree | 40c53155336296951b3475a3a0798a59f63edc14 /src | |
parent | Makefile: Include SQL migration files as installable artifacts (diff) | |
download | papod-613398385703b6e99c8137a1b89454d977ccf2c8.tar.gz papod-613398385703b6e99c8137a1b89454d977ccf2c8.tar.xz |
Remove C code and cleanup repository
Diffstat (limited to 'src')
-rw-r--r-- | src/catalog.c | 501 | ||||
-rw-r--r-- | src/catalog.h | 33 | ||||
-rw-r--r-- | src/config.h.in | 31 | ||||
-rw-r--r-- | src/i18n.c | 69 | ||||
-rw-r--r-- | src/i18n.h | 56 | ||||
-rw-r--r-- | src/logerr.c | 301 | ||||
-rw-r--r-- | src/logerr.h | 23 | ||||
-rw-r--r-- | src/napi-sqlite.c | 932 | ||||
-rw-r--r-- | src/papo.en.msg | 72 |
9 files changed, 0 insertions, 2018 deletions
diff --git a/src/catalog.c b/src/catalog.c deleted file mode 100644 index c3ec9b2..0000000 --- a/src/catalog.c +++ /dev/null @@ -1,501 +0,0 @@ -#include "catalog.h" -#include "logerr.h" - -#include <assert.h> -#include <errno.h> -#include <nl_types.h> -#include <stdlib.h> -#include <string.h> - -#ifdef TEST -#include "../tests/tests-lib.h" -#include "../tests/slurp.h" - -static const char *const -FNAME = __FILE__ ".txt"; - -enum TEST_MSGCATALOG_ID { - MSG_X_FIRST = 1, - MSG_X_1, - MSG_X_2, - MSG_X_LAST, - MSG_STANDALONE, -}; - -static const char *const -TEST_MSGS[] = { - "", - [MSG_X_FIRST]="First line\n", - [MSG_X_1]="a second\n", - [MSG_X_2]="a third\n", - [MSG_X_LAST]="and the last one\n", - [MSG_STANDALONE]="single line message\n", - NULL -}; -#endif - - - -static const char *const -CATALOG_NAME = NAME_MACRO_STRING; - -static nl_catd -catalog_descriptor = NULL; - -static const char *const -NLSPATH = LOCALEDIR_MACRO_STRING "/%l_%t/LC_MESSAGES/%N.cat" ":" - LOCALEDIR_MACRO_STRING "/%l/LC_MESSAGES/%N.cat"; - -static const char *const -NLSPATH_KEY = "NLSPATH"; - - -int -i18n_init(void) { - int rc = 0; - - static const int should_overwrite = 0; - if (setenv(NLSPATH_KEY, NLSPATH, should_overwrite)) { - logerr("setenv(\"%s\", \"%s\", 0): %s\n", NLSPATH_KEY, - NLSPATH, strerror(errno)); - rc = -1; - goto out; - } - - catalog_descriptor = catopen(CATALOG_NAME, 0); - if (catalog_descriptor && catalog_descriptor == (nl_catd)-1) { - logerr("catopen(\"%s\", 0): %s\n", CATALOG_NAME, strerror(errno)); - catalog_descriptor = NULL; - rc = -1; - goto out; - } - -out: - return rc; -} - -#ifdef TEST -static int -test_i18n_init(void) { - int rc = 0; - - test_start("i18n_init()"); - - { - testing("simple call without touching the environment"); - - static const int should_overwrite = 1; - if (setenv(NLSPATH_KEY, "src/%N.en.cat", should_overwrite)) { - logerr("setenv(\"%s\", \"src/%%N.en.cat\", 1): %s\n", - NLSPATH_KEY, strerror(errno)); - rc = -1; - goto out; - } - - if (i18n_init()) { - logerr("i18n_init()\n"); - rc = -1; - goto out; - } - - test_ok(); - } - -out: - if (i18n_destroy()) { - logerr("i18n_destroy()\n"); - rc = -1; - } - return rc; -} -#endif - - -int -i18n_destroy(void) { - int rc = 0; - - if (catalog_descriptor) { - if (catclose(catalog_descriptor)) { - logerr("catclose(...): %s\n", strerror(errno)); - rc = -1; - goto out; - } - } - -out: - if (catalog_descriptor) { - catalog_descriptor = NULL; - } - return rc; -} - -#ifdef TEST -static int -test_i18n_destroy(void) { - int rc = 0; - - test_start("i18n_destroy()"); - - { - testing("simple call without init first"); - - if (i18n_destroy()) { - logerr("i18n_destroy()\n"); - rc = -1; - goto out; - } - - test_ok(); - } - -out: - return rc; -} -#endif - - -/** - * Infallible: always returns a valid string, no matter what. - */ -const char * -s(const char* const MSGS[], const int msg_id) { - assert(msg_id > 0); - // FIXME: assert within bounds! - // printf("sizeof(MSGS): %ld\n", sizeof(MSGS)); - if (!catalog_descriptor) { - return MSGS[msg_id]; - } - - errno = 0; - const char *const ret = - catgets(catalog_descriptor, NL_SETD, msg_id, MSGS[msg_id]); - if (errno) { - logerr("catgets(%d): %s\n", msg_id, strerror(errno)); - } - - return ret; -} - -#ifdef TEST -static int -test_s(void) { - int rc = 0; - - test_start("_()"); - FILE *file = NULL; - char *str = NULL; - - { - testing("empty string"); - - file = fopen(FNAME, "w"); - if (!file) { - perror("fopen(FNAME, \"w\")"); - rc = -1; - goto out; - } - - // FIXME: implement correct test - - - - test_ok(); - } - -out: - if (str) { - free(str); - } - if (file) { - if (fclose(file)) { - logerr("fclose(file): %s\n", strerror(errno)); - rc = -1; - } - } - return rc; -} -#endif - - -int -s_print_msgs( - const char *const MSGS[], - FILE *restrict stream, - const int msg_begin, - const int msg_end -) { - int rc = 0; - - for (int i = msg_begin; i <= msg_end; i++) { - if (fprintf(stream, "%s", s(MSGS, i)) < 0) { - logerr("fprintf(stream, \"%%s\", _(%d)): %s\n", i, - strerror(errno)); - rc = -1; - goto out; - } - } - -out: - return rc; -} - -#ifdef TEST -static int -test_s_print_msgs(void) { - int rc = 0; - - test_start("s_print_msgs()"); - FILE *file = NULL; - char *str = NULL; - - { - testing("message in range"); - - file = fopen(FNAME, "w"); - if (!file) { - perror("fopen(FNAME, \"w\")"); - rc = -1; - goto out; - } - - if (s_print_msgs(TEST_MSGS, file, MSG_X_FIRST, MSG_X_LAST)) { - logerr("print_msgs(TEST_MSGS, file, MSG_X_FIRST, MSG_X_LAST)\n"); - rc = -1; - goto out; - } - - const int ret = fclose(file); - file = NULL; - if (ret) { - logerr("fclose(file): %s\n", strerror(errno)); - rc = -1; - goto out; - } - - if (slurp_for_tests(FNAME, &str)) { - logerr("slurp_for_tests(FNAME, &str)\n"); - rc = -1; - goto out; - } - - const char *const expected = - "First line\n" - "a second\n" - "a third\n" - "and the last one\n" - ; - - assert(strcmp(expected, str) == 0); - - free(str); - str = NULL; - - test_ok(); - } - { - testing("range begin and end is the same"); - - file = fopen(FNAME, "w"); - if (!file) { - logerr("fopen(FNAME, \"w\"): %s\n", strerror(errno)); - rc = -1; - goto out; - } - - if (s_print_msgs(TEST_MSGS, file, MSG_X_FIRST, MSG_X_FIRST)) { - logerr("s_print_msgs(TEST_MSGS, file, MSG_X_FIRST, MSG_X_FIRST)\n"); - rc = -1; - goto out; - } - - const int ret = fclose(file); - file = NULL; - if (ret) { - logerr("fclose(file): %s\n", strerror(errno)); - rc = -1; - goto out; - } - - if (slurp_for_tests(FNAME, &str)) { - logerr("slurp_for_tests(FNAME, &str)\n"); - rc = -1; - goto out; - } - - const char *const expected = - "First line\n"; - - assert(strcmp(expected, str) == 0); - - free(str); - str = NULL; - - test_ok(); - } - -out: - if (str) { - free(str); - } - if (file) { - if (fclose(file)) { - logerr("fclose(file): %s\n", strerror(errno)); - rc = -1; - } - } - return rc; -} -#endif - - -int -s_print_msg(const char *const MSGS[], FILE *const fd, const int msg_id) { - return s_print_msgs(MSGS, fd, msg_id, msg_id); -} - -#ifdef TEST -static int -test_s_print_msg(void) { - int rc = 0; - - test_start("s_print_msg()"); - FILE *file = NULL; - char *str = NULL; - - { - testing("simple individual message"); - - file = fopen(FNAME, "w"); - if (!file) { - logerr("fopen(FNAME, \"w\"): %s\n"); - rc = -1; - goto out; - } - - if (s_print_msg(TEST_MSGS, file, MSG_STANDALONE)) { - logerr("s_print_msg(TEST_MSGS, file, MSG_STANDALONE)\n"); - rc = -1; - goto out; - } - - const int ret = fclose(file); - file = NULL; - if (ret) { - logerr("fopen(file): %s\n", strerror(errno)); - rc = -1; - goto out; - } - - if (slurp_for_tests(FNAME, &str)) { - logerr("slurp_for_tests(FNAME, &str)\n"); - rc = -1; - goto out; - } - - const char *const expected = - "single line message\n"; - - assert(strcmp(expected, str) == 0); - - free(str); - str = NULL; - - test_ok(); - } - -out: - if (str) { - free(str); - } - if (file) { - if (fclose(file)) { - logerr("fclose(file): %s\n", strerror(errno)); - rc = -1; - } - } - return rc; -} -#endif - - -int -dump_translatable_strings(const char *const MSGS[]) { - int rc = 0; - - for (size_t i = 1; MSGS[i]; i++) { - if (printf("%ld ", i) < 0) { - logerr("printf(\"%%ld\", %d): %s\n", i); - rc = -1; - goto out; - } - - for (size_t j = 0; MSGS[i][j]; j++) { - if (MSGS[i][j] == '\n') { - if (printf("\\n") < 0) { - logerr("printf(\"\\\\n\"): %s\n", - strerror(errno)); - rc = -1; - goto out; - } - } else { - if (printf("%c", MSGS[i][j]) < 0) { - logerr("printf(\"%%c\", " - "MSGS[%ld][%ld]): %s\n", - i, j, strerror(errno)); - rc = -1; - goto out; - } - } - } - - if (printf("\n\n") < 0) { - logerr("printf(\"\\n\\n\"): %s\n", strerror(errno)); - rc = -1; - goto out; - } - } - -out: - return rc; -} - -#ifdef TEST -int -main(void) { - int rc = 0; - - if (test_i18n_init()) { - logerr("test_i18n_init()\n"); - rc = -1; - goto out; - } - - if (test_i18n_destroy()) { - logerr("test_i18n_destroy()\n"); - rc = -1; - goto out; - } - - if (test_s()) { - logerr("test_s()\n"); - rc = -1; - goto out; - } - - if (test_s_print_msgs()) { - logerr("test_s_print_msgs()\n"); - rc = -1; - goto out; - } - - if (test_s_print_msg()) { - logerr("test_s_print_msg()\n"); - rc = -1; - goto out; - } - -out: - return !!rc; -} -#endif diff --git a/src/catalog.h b/src/catalog.h deleted file mode 100644 index 9f237a9..0000000 --- a/src/catalog.h +++ /dev/null @@ -1,33 +0,0 @@ -#ifndef CATALOG_H -#define CATALOG_H - -#include "config.h" - -#include <stdio.h> - - -int -i18n_init(void); - -int -i18n_destroy(void); - -const char * -s(const char *const MSGS[], const int msg_id); - -int -s_print_msgs( - const char *const MSGS[], - FILE *restrict stream, - const int msg_begin, - const int msg_end -); - -int -s_print_msg(const char *const MSGS[], FILE *restrict stream, const int msg_id); - -int -dump_translatable_strings(const char *const MSGS[]); - - -#endif diff --git a/src/config.h.in b/src/config.h.in deleted file mode 100644 index dc379e5..0000000 --- a/src/config.h.in +++ /dev/null @@ -1,31 +0,0 @@ -#ifndef CONFIG_H -#define CONFIG_H - - - -/* - From - https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap02.html#tag_02_02_01: - - > For the C programming language, shall define _POSIX_C_SOURCE to be 200809L - > before any header is included -*/ -#define _POSIX_C_SOURCE 200809L - - -/* - From - https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap02.html#tag_02_02_04: - - > For the C programming language, shall define _XOPEN_SOURCE to be 700 before - > any header is included -*/ -#define _XOPEN_SOURCE 700 - - -#define VERSION_MACRO_STRING "@VERSION@" -#define DATE_MACRO_STRING "@DATE@" -#define NAME_MACRO_STRING "@NAME@" -#define LOCALEDIR_MACRO_STRING "@LOCALEDIR@" - -#endif diff --git a/src/i18n.c b/src/i18n.c deleted file mode 100644 index 4363582..0000000 --- a/src/i18n.c +++ /dev/null @@ -1,69 +0,0 @@ -#include "i18n.h" - -#ifdef TEST -#include "logerr.h" -#include "catalog.h" - -#include <stdlib.h> -#endif - -const char *const -MSGS[] = { - "", - [MSG_USAGE_FIRST]="Usage:\n", - [MSG_USAGE_1]=" " NAME_MACRO_STRING " -p FILE [-o DIRECTORY]\n", - [MSG_USAGE_2]=" " NAME_MACRO_STRING " -l FILE [-o DIRECTORY]\n", - [MSG_USAGE_LAST]=" " NAME_MACRO_STRING " [-hV]\n", - [MSG_HELP_FIRST]="\n", - [MSG_HELP_1]="\n", - [MSG_HELP_2]="Options:\n", - [MSG_HELP_3]=" -p FILE parser file to be processed\n", - [MSG_HELP_4]=" -l FILE lexer file to be processed\n", - [MSG_HELP_5]=" -o DIRECTORY output where to place the\n", - [MSG_HELP_6]=" generated files (default .)\n", - [MSG_HELP_7]=" -h, --help show this help message\n", - [MSG_HELP_8]=" -V, --version print the version number\n", - [MSG_HELP_9]="\n", - [MSG_HELP_10]="\n", - [MSG_HELP_11]="Run the " NAME_MACRO_STRING "(1) parser program.\n", - [MSG_HELP_12]="\n", - [MSG_HELP_13]="Here is the explanation for what it does, and the synopsis\n", - [MSG_HELP_14]="of its usage.\n", - [MSG_HELP_15]="\n", - [MSG_HELP_16]="See \"man " NAME_MACRO_STRING "\" for usage information and\n", - [MSG_HELP_17]="\"man " NAME_MACRO_STRING ".tutorial\" for a beginner introduction.\n", - [MSG_HELP_18]="\n", - [MSG_HELP_19]="\n", - [MSG_HELP_20]="Examples:\n", - [MSG_HELP_21]="\n", - [MSG_HELP_22]=" Do a one-line parser:\n", - [MSG_HELP_23]="\n", - [MSG_HELP_24]=" $ " NAME_MACRO_STRING " run md.grammar < README.md\n", - [MSG_HELP_25]="\n", - [MSG_HELP_26]="\n", - [MSG_HELP_27]=" Compile the grammer:\n", - [MSG_HELP_28]="\n", - [MSG_HELP_LAST]=" $ " NAME_MACRO_STRING " build csv.grammar > dunno.alsodunno\n", - [MSG_VERSION]= NAME_MACRO_STRING " " VERSION_MACRO_STRING " " DATE_MACRO_STRING "\n", - [MSG_ERR_NAPI_MISSING_ERRSTR]="Error message from Node-API is empty", - NULL -}; - - -#ifdef TEST -int -main(void) { - int rc = 0; - - if (getenv("DUMP_TRANSLATABLE_STRINGS")) { - if (dump_translatable_strings(MSGS)) { - logerr("dump_translatable_strings(MSGS)\n"); - rc = -1; - goto out; - } - } - -out: - return !!rc; -} -#endif diff --git a/src/i18n.h b/src/i18n.h deleted file mode 100644 index 2b18bbc..0000000 --- a/src/i18n.h +++ /dev/null @@ -1,56 +0,0 @@ -#ifndef I18N_H -#define I18N_H - -#include "config.h" -#include "catalog.h" - -#include <stdio.h> - - -enum MSGCATALOG_ID { - MSG_USAGE_FIRST = 1, - MSG_USAGE_1, - MSG_USAGE_2, - MSG_USAGE_LAST, - MSG_HELP_FIRST, - MSG_HELP_1, - MSG_HELP_2, - MSG_HELP_3, - MSG_HELP_4, - MSG_HELP_5, - MSG_HELP_6, - MSG_HELP_7, - MSG_HELP_8, - MSG_HELP_9, - MSG_HELP_10, - MSG_HELP_11, - MSG_HELP_12, - MSG_HELP_13, - MSG_HELP_14, - MSG_HELP_15, - MSG_HELP_16, - MSG_HELP_17, - MSG_HELP_18, - MSG_HELP_19, - MSG_HELP_20, - MSG_HELP_21, - MSG_HELP_22, - MSG_HELP_23, - MSG_HELP_24, - MSG_HELP_25, - MSG_HELP_26, - MSG_HELP_27, - MSG_HELP_28, - MSG_HELP_LAST, - MSG_VERSION, - MSG_ERR_NAPI_MISSING_ERRSTR, -}; - - -extern const char *const -MSGS[]; - -#define _(msg_id) s(MSGS, msg_id) - - -#endif diff --git a/src/logerr.c b/src/logerr.c deleted file mode 100644 index 936bd28..0000000 --- a/src/logerr.c +++ /dev/null @@ -1,301 +0,0 @@ -#include "logerr.h" - -#include <stdarg.h> -#include <stdlib.h> - -#ifdef TEST -#include "../tests/tests-lib.h" -#include "../tests/slurp.h" -#include <assert.h> -#include <errno.h> -#include <string.h> -#endif - - -void -vlogerr( - const char *const file, - const char *const function, - const int lineno, - FILE *restrict stream, - const char *restrict format, - ... -) { - (void)fprintf(stream, "%s:%s:%d: ", file, function, lineno); - - va_list args; - va_start(args, format); - (void)vfprintf(stream, format, args); - va_end(args); -} - -#ifdef TEST -static const char *const -FNAME = __FILE__ ".txt"; - -static int -test_vlogerr(void) { - int rc = 0; - - test_start("vlogerr()"); - FILE *file = NULL; - char *str = NULL; - - { - testing("empty varargs"); - - file = fopen(FNAME, "w"); - if (!file) { - perror("fopen(FNAME, \"w\")"); - rc = -1; - goto out; - } - - vlogerr(__FILE__, __func__, __LINE__, file, - ""); - - const int ret = fclose(file); - file = NULL; - if (ret) { - perror("fclose(file)"); - rc = -1; - goto out; - } - - if (slurp_for_tests(FNAME, &str)) { - perror("slurp_for_tests(FNAME, &str)"); - rc = -1; - goto out; - } - - const char *const expected = - "src/logerr.c:test_vlogerr:54: "; - - assert(strcmp(expected, str) == 0); - - free(str); - str = NULL; - - test_ok(); - } - { - testing("a newline only"); - - file = fopen(FNAME, "w"); - if (!file) { - perror("fopen(FNAME, \"w\")"); - rc = -1; - goto out; - } - - vlogerr(__FILE__, __func__, __LINE__, file, - "\n"); - - const int ret = fclose(file); - file = NULL; - if (ret) { - perror("fclose(file)"); - rc = -1; - goto out; - } - - if (slurp_for_tests(FNAME, &str)) { - perror("slurp_for_tests(FNAME, &str)"); - rc = -1; - goto out; - } - - const char *const expected = - "src/logerr.c:test_vlogerr:91: \n"; - assert(strcmp(expected, str) == 0); - - free(str); - str = NULL; - - test_ok(); - } - { - testing("static format string"); - - file = fopen(FNAME, "w"); - if (!file) { - perror("fopen(FNAME, \"w\")"); - rc = -1; - goto out; - } - - vlogerr(__FILE__, __func__, __LINE__, file, - "some static string\n"); - - const int ret = fclose(file); - file = NULL; - if (ret) { - perror("fclose(file)"); - rc = -1; - goto out; - } - - if (slurp_for_tests(FNAME, &str)) { - perror("slurp_for_tests(FNAME, &str)"); - rc = -1; - goto out; - } - - const char *const expected = - "src/logerr.c:test_vlogerr:127: some static string\n"; - assert(strcmp(expected, str) == 0); - - free(str); - str = NULL; - - test_ok(); - } - { - testing("single arg format string"); - - file = fopen(FNAME, "w"); - if (!file) { - perror("fopen(FNAME, \"w\")"); - rc = -1; - goto out; - } - - vlogerr(__FILE__, __func__, __LINE__, file, - "fn(%s)\n", "an-arg"); - - const int ret = fclose(file); - file = NULL; - if (ret) { - perror("fclose(file)"); - rc = -1; - goto out; - } - - if (slurp_for_tests(FNAME, &str)) { - perror("slurp_for_tests(FNAME, &str)"); - rc = -1; - goto out; - } - - const char *const expected = - "src/logerr.c:test_vlogerr:163: fn(an-arg)\n"; - assert(strcmp(expected, str) == 0); - - free(str); - str = NULL; - - test_ok(); - } - { - testing("multiple format strings"); - - file = fopen(FNAME, "w"); - if (!file) { - perror("fopen(FNAME, \"w\")"); - rc = -1; - goto out; - } - - vlogerr(__FILE__, __func__, __LINE__, file, - "int (%d), string (%s) and char (%c)\n", - 123, - "another-str", - 'z'); - - const int ret = fclose(file); - file = NULL; - if (ret) { - perror("fclose(file)"); - rc = -1; - goto out; - } - - if (slurp_for_tests(FNAME, &str)) { - perror("slurp_for_tests(FNAME, &str)"); - rc = -1; - goto out; - } - - const char *const expected = - "src/logerr.c:test_vlogerr:199: " - "int (123), string (another-str) and char (z)\n"; - assert(strcmp(expected, str) == 0); - - free(str); - str = NULL; - - test_ok(); - } - -out: - if (str) { - free(str); - } - if (file) { - if (fclose(file)) { - perror("fclose(file)"); - rc = -1; - } - } - return rc; -} - -static int -test_logerr(void) { - int rc = 0; - - test_start("logerr()"); - - { - testing("can be called with an empty string"); - - logerr(""); - - test_ok(); - } - { - testing("can be called with a static string"); - - logerr("some err\n"); - - test_ok(); - } - { - testing("can be called with a formatted string"); - - logerr("some err: %s\n", strerror(errno)); - - test_ok(); - } - { - testing("can be called with formatting arguments"); - - logerr("int: %d\nstr: %s\n", 123, "an example string"); - - test_ok(); - } - - return rc; -} - - -int -main(void) { - int rc = 0; - - if (test_vlogerr()) { - perror("test_vlogerr()"); - rc = -1; - goto out; - } - - if (test_logerr()) { - perror("test_logerr()"); - rc = -1; - goto out; - } - -out: - return !!rc; -} -#endif diff --git a/src/logerr.h b/src/logerr.h deleted file mode 100644 index 77f98bd..0000000 --- a/src/logerr.h +++ /dev/null @@ -1,23 +0,0 @@ -#ifndef LOGERR_H -#define LOGERR_H - -#include "config.h" - -#include <stdio.h> - - -void -vlogerr( - - const char *const file, - const char *const function, - const int lineno, - FILE *restrict stream, - const char *restrict format, - ... -); - -#define logerr(...) vlogerr(__FILE__, __func__, __LINE__, stderr, __VA_ARGS__) - - -#endif diff --git a/src/napi-sqlite.c b/src/napi-sqlite.c deleted file mode 100644 index d4352a2..0000000 --- a/src/napi-sqlite.c +++ /dev/null @@ -1,932 +0,0 @@ -#include "i18n.h" -#include "logerr.h" - -#include <assert.h> -#include <errno.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> - -#include <node/node_api.h> -#include <sqlite3.h> - - -static napi_value ffi_open(napi_env env, napi_callback_info info); -static napi_value ffi_exec(napi_env env, napi_callback_info info); -static napi_value ffi_all (napi_env env, napi_callback_info info); -static napi_value ffi_run (napi_env env, napi_callback_info info); - - -struct NAPIContext { - napi_env env; - napi_value value; - uint32_t index; -}; - -struct Fn { - const char *const label; - napi_value(*const handle)(napi_env env, napi_callback_info info); -}; - -static const struct Fn fns[] = { - { .label = "open", .handle = ffi_open, }, - { NULL, NULL }, -}; - -struct Fn methods[] = { - { .label = "exec", .handle = ffi_exec, }, - { .label = "all", .handle = ffi_all, }, - { .label = "run", .handle = ffi_run, }, - { NULL, NULL }, -}; - -static const napi_type_tag SQLITE_DB_TYPE_TAG = { - 0x0e9614d459f746cc, 0x88b814a5dc5c4cf7 -}; - -static const int -SQLITE_OPEN_FLAGS = - /* - From https://www.sqlite.org/c3ref/open.html: - - > The database is opened for reading and writing, and is created if - > it does not already exist. This is the behavior that is always - > used for sqlite3_open() and sqlite3_open16(). - */ - SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | - - /* - From https://www.sqlite.org/c3ref/open.html: - - > The new database connection will use the "serialized" threading - > mode. This means the multiple threads can safely attempt to use - > the same database connection at the same time. (Mutexes will block - > any actual concurrency, but in this mode there is no harm in - > trying.) - */ - SQLITE_OPEN_FULLMUTEX | - - /* - From https://www.sqlite.org/c3ref/open.html: - - > The database connection comes up in "extended result code mode". - > In other words, the database behaves has if - > sqlite3_extended_result_codes(db,1) where called on the database - > connection as soon as the connection is created. In addition to - > setting the extended result code mode, this flag also causes - > sqlite3_open_v2() to return an extended result code. - - From https://www.sqlite.org/c3ref/extended_result_codes.html: - - > The sqlite3_extended_result_codes() routine enables or disables the - > extended result codes feature of SQLite. The extended result codes - > are disabled by default for historical compatibility. - */ - SQLITE_OPEN_EXRESCODE; - - -static const char *const -FIX_SQLITE_PRAGMAS = - /* - From https://research.cs.wisc.edu/adsl/Publications/alice-osdi14.pdf: - - > Similarly, SQLite does not provide durability under the default - > journal-mode (we became aware of this only after interacting with - > developers), but its documentation seems misleading. - > - > (...) - > - > The developers suggest the SQLite vulnerability is actually not a - > behavior guaranteed by SQLite (specifically, that durability cannot - > be achieved under rollback journaling); we believe the - > documentation is misleading. - > - > (...) - > - > Unclear documentation of application guarantees contributes to the - > confusion about crash vulnerabilities. During discussions with - > developers about durability vulnerabilities, we found that SQLite, - > which proclaims itself as fully ACID-complaint, does not provide - > durability (even optionally) with the default storage engine, - > though the documentation suggests it does. - */ - "PRAGMA journal_mode = WAL;\n" - "PRAGMA synchronous = EXTRA;\n" - - /* - From https://www.sqlite.org/foreignkeys.html: - - > Foreign key constraints are disabled by default (for backwards - > compatibility), so must be enabled separately for each database - > connection. - */ - "PRAGMA foreign_keys = ON;\n" - ; - - -// FIXME: make this async -static napi_value -ffi_exec(napi_env env, napi_callback_info info) { - size_t argc = 1; - napi_value argv[1]; - int sqlite_rc; - napi_status napi_rc; - char *sql = NULL; - size_t sql_size1; - size_t sql_size2; - sqlite3 *db = NULL; - char *error_msg = NULL; - - napi_rc = napi_get_cb_info( - env, - info, - &argc, - argv, - NULL, - (void *)&db - ); - if (napi_rc != napi_ok) { - napi_throw_error( - env, - "111TODO ERRCODE", - "Failed to parse arguments TODO i18n" - ); - goto out; - } - - napi_rc = napi_get_value_string_utf8(env, argv[0], NULL, 0, &sql_size1); - if (napi_rc != napi_ok) { - napi_throw_error( - env, - "222TODO ERRCODE", - "Invalid number was passed as argument TODO i18n" - ); - goto out; - } - - if (sql_size1 == SIZE_MAX) { - napi_throw_error( - env, - "SQLITE_EOVERFLOW", - "TODO " - ); - goto out; - } - sql_size1++; // include the NULL-terminator in size measurement - - sql = malloc(sql_size1); - if (!sql) { - napi_throw_error( - env, - "SQLITE_ENOMEM", - "TODO i18n" - ); - goto out; - } - - napi_rc = napi_get_value_string_utf8( - env, - argv[0], - sql, - sql_size1, - &sql_size2 - ); - if (napi_rc != napi_ok) { - napi_throw_error( - env, - "TODO ERRCODE", - "Invalid number was passed as argument TODO i18n" - ); - goto out; - } - assert(sql_size1 == sql_size2 + 1 && - "Unstable behaviour from Node-API"); - assert(sql); - - sqlite_rc = sqlite3_exec( - db, - sql, - NULL, - NULL, - &error_msg - ); - if (sqlite_rc != SQLITE_OK) { - napi_throw_error( - env, - "3iii33TODO ERRCODE", - sqlite3_errstr(sqlite_rc) - ); - goto out; - } - -out: - if (error_msg) { - sqlite3_free(error_msg); - } - if (sql) { - free(sql); - } - return NULL; -} - - -static int -accumulate_all_results( - void *ctxptr, - int argc, - char **argv, - char **column_names -) { - int rc = 0; - - napi_status napi_rc; - napi_value row = NULL; - - struct NAPIContext *ctx = ctxptr; - napi_env env = ctx->env; - napi_value results = ctx->value; - uint32_t index = ctx->index; - - napi_rc = napi_create_object(env, &row); - if (napi_rc != napi_ok) { - napi_throw_error( - env, - "TODO ERRCODE", - "TODO i18n" - ); - rc = -1; - goto out; - } - - for (int i = 0; i < argc; i++) { - const char *const column_name = column_names[i]; - const char *const column_value = argv[i]; - - napi_value str; // FIXME: dispatch on the type - napi_rc = napi_create_string_utf8( - env, - column_value, - NAPI_AUTO_LENGTH, - &str - ); - if (napi_rc != napi_ok) { - napi_throw_error( - env, - "SQLITE_MiiiETHOD_CREATE", - "TODO i18n" - ); - rc = -1; - goto out; - } - - napi_rc = napi_set_named_property( - env, - row, - column_name, - str - ); - if (napi_rc != napi_ok) { - napi_throw_error( - env, - "iSQLITE_MiETHOD_CREATE", - "TODO i18n" - ); - rc = -1; - goto out; - } - } - - napi_rc = napi_set_element( - env, - results, - index, - row - ); - if (napi_rc != napi_ok) { - napi_throw_error( - env, - "TODO ERRCODE", - "TODO i18n" - ); - rc = -1; - goto out; - } - - ctx->index++; - -out: - return rc; -} - -static napi_value -ffi_all(napi_env env, napi_callback_info info) { - napi_value ret = NULL; - - size_t argc = 1; - napi_value argv[1]; - int sqlite_rc; - napi_status napi_rc; - char *sql = NULL; - size_t sql_size1; - size_t sql_size2; - sqlite3 *db = NULL; - char *error_msg = NULL; - napi_value results_array = NULL; - - napi_rc = napi_get_cb_info( - env, - info, - &argc, - argv, - NULL, - (void *)&db - ); - if (napi_rc != napi_ok) { - napi_throw_error( - env, - "111TODO ERRCODE", - "Failed to parse arguments TODO i18n" - ); - goto out; - } - - napi_rc = napi_get_value_string_utf8(env, argv[0], NULL, 0, &sql_size1); - if (napi_rc != napi_ok) { - napi_throw_error( - env, - "222TODO ERRCODE", - "Invalid number was passed as argument TODO i18n" - ); - goto out; - } - - if (sql_size1 == SIZE_MAX) { - napi_throw_error( - env, - "SQLITE_EOVERFLOW", - "TODO " - ); - goto out; - } - sql_size1++; // include the NULL-terminator in size measurement - - sql = malloc(sql_size1); - if (!sql) { - napi_throw_error( - env, - "SQLITE_ENOMEM", - "TODO i18n" - ); - goto out; - } - - napi_rc = napi_get_value_string_utf8( - env, - argv[0], - sql, - sql_size1, - &sql_size2 - ); - if (napi_rc != napi_ok) { - napi_throw_error( - env, - "TODO ERRCODE", - "Invalid number was passed as argument TODO i18n" - ); - goto out; - } - assert(sql_size1 == sql_size2 + 1 && - "Unstable behaviour from Node-API"); - assert(sql); - - napi_rc = napi_create_array(env, &results_array); - if (napi_rc != napi_ok) { - napi_throw_error( - env, - "TODO ERRCODE", - "Invalid number was passed as argument TODO i18n" - ); - goto out; - } - - struct NAPIContext ctx = { - .env = env, - .value = results_array, - .index = 0, - }; - sqlite_rc = sqlite3_exec( - db, - sql, - accumulate_all_results, - &ctx, - &error_msg - ); - if (sqlite_rc != SQLITE_OK) { - napi_throw_error( - env, - "i3iiii33TODO ERRCODE", - sqlite3_errstr(sqlite_rc) - ); - goto out; - } - - ret = results_array; - -out: - if (error_msg) { - sqlite3_free(error_msg); - } - if (sql) { - free(sql); - } - return ret; -} - -static napi_value -ffi_run(napi_env env, napi_callback_info info) { - napi_value ret = NULL; - - size_t argc = 1; - napi_value argv[1]; - int sqlite_rc; - napi_status napi_rc; - char *sql = NULL; - size_t sql_size1; - size_t sql_size2; - sqlite3 *db = NULL; - char *error_msg = NULL; - napi_value results_array = NULL; - - napi_rc = napi_get_cb_info( - env, - info, - &argc, - argv, - NULL, - (void *)&db - ); - if (napi_rc != napi_ok) { - napi_throw_error( - env, - "111TODO ERRCODE", - "Failed to parse arguments TODO i18n" - ); - goto out; - } - - napi_rc = napi_get_value_string_utf8(env, argv[0], NULL, 0, &sql_size1); - if (napi_rc != napi_ok) { - napi_throw_error( - env, - "222TODO ERRCODE", - "Invalid number was passed as argument TODO i18n" - ); - goto out; - } - - if (sql_size1 == SIZE_MAX) { - napi_throw_error( - env, - "SQLITE_EOVERFLOW", - "TODO " - ); - goto out; - } - sql_size1++; // include the NULL-terminator in size measurement - - sql = malloc(sql_size1); - if (!sql) { - napi_throw_error( - env, - "SQLITE_ENOMEM", - "TODO i18n" - ); - goto out; - } - - napi_rc = napi_get_value_string_utf8( - env, - argv[0], - sql, - sql_size1, - &sql_size2 - ); - if (napi_rc != napi_ok) { - napi_throw_error( - env, - "TODO ERRCODE", - "Invalid number was passed as argument TODO i18n" - ); - goto out; - } - assert(sql_size1 == sql_size2 + 1 && - "Unstable behaviour from Node-API"); - assert(sql); - - napi_rc = napi_create_array(env, &results_array); - if (napi_rc != napi_ok) { - napi_throw_error( - env, - "TODO ERRCODE", - "Invalid number was passed as argument TODO i18n" - ); - goto out; - } - - struct NAPIContext ctx = { - .env = env, - .value = results_array, - .index = 0, - }; - sqlite_rc = sqlite3_exec( - db, - sql, - accumulate_all_results, - &ctx, - &error_msg - ); - if (sqlite_rc != SQLITE_OK) { - napi_throw_error( - env, - "i3iiii33TODO ERRCODE", - sqlite3_errstr(sqlite_rc) - ); - goto out; - } - - ret = results_array; - -out: - if (error_msg) { - sqlite3_free(error_msg); - } - if (sql) { - free(sql); - } - return ret; -} - - -static void -sqlite_error_log_callback(void *_data, int rc, const char *const msg) { - (void)_data; - logerr("%s\n%s\n", sqlite3_errstr(rc), msg); -} - -static void -throw_sqlite_error(napi_env env, sqlite3 *const db) { - const char *const errstr = sqlite3_errstr(sqlite3_errcode(db)); - const char *const errmsg = sqlite3_errmsg(db); - logerr("%s\n%s\n", errstr, errmsg); - if (napi_throw_error(env, errstr, errmsg)) { - logerr("napi_throw_err(%s, \"%s\", \"%s\");\n", - "env", - errstr, - errmsg); - goto out; - } - -out: - return; -} - -static void -throw_node_str_error( - napi_env env, - const char *const errstr, - const char *const errmsg -) { - bool is_pending; - - if (napi_is_exception_pending(env, &is_pending)) { - logerr("napi_is_exception_pending(%s, %s);\n", - "env", - "&is_pending"); - goto out; - } - - if (is_pending) { - logerr("exception already pending, not rethrowing"); - goto out; - } - - logerr("%s\n%s\n", errstr, errmsg); - if (napi_throw_error(env, errstr, errmsg)) { - logerr("napi_throw_error(%s, \"%s\", \"%s\");\n" - "env", - errstr, - errmsg); - goto out; - } - -out: - return; -} - -static void -throw_node_env_error(napi_env env) { - const napi_extended_error_info *error_info = NULL; - - if (napi_get_last_error_info(env, &error_info)) { - logerr("napi_get_last_error_info(%s, %s);\n", - "env", - "&error_info"); - goto out; - } - - const char *const errstr = "SQLITE_NAPI_ERR"; - const char *const errmsg = - error_info->error_message ? - error_info->error_message : - _(MSG_ERR_NAPI_MISSING_ERRSTR); - throw_node_str_error(env, errstr, errmsg); - -out: - return; -} - -static void -finalize_db(napi_env env, void *finalize_data, void *_finalize_hint) { - (void)_finalize_hint; - sqlite3 *db = finalize_data; - - if (sqlite3_close(db)) { - logerr("sqlite3_close(%s);\n", - "db"); - throw_sqlite_error(env, db); - goto out; - } - -out: - return; -} - -static napi_value -ffi_open(napi_env env, napi_callback_info info) { - napi_value ret = NULL; - - size_t argc = 1; - napi_value argv[1]; - char *filename = NULL; - size_t filename_size1; - size_t filename_size2; - sqlite3 *db = NULL; - napi_value wrapped_db = NULL; - char *error_msg = NULL; - - if (napi_get_cb_info(env, info, &argc, argv, NULL, NULL)) { - logerr("napi_get_cb_info(%s, %s, %s, %s, %s, %s);\n", - "env", - "info", - "&argc", - "argv", - "NULL", - "NULL"); - throw_node_env_error(env); - goto out; - } - - if (napi_get_value_string_utf8( - env, - argv[0], - NULL, // first we query the size of the string - 0, - &filename_size1 - )) { - logerr("napi_get_value_string_utf8(%s, %s, %s, %s, %s);\n", - "env", - "argv[0]", - "NULL", - "0", - "&filename_size1"); - throw_node_env_error(env); - goto out; - } - - if (filename_size1 == SIZE_MAX) { - logerr("%s: filename_size1 == SIZE_MAX;\n", strerror(EOVERFLOW)); - throw_node_str_error(env, "EOVERFLOW", strerror(EOVERFLOW)); - goto out; - } - filename_size1++; // include the NULL-terminator in size measurement - - filename = malloc(filename_size1); - if (!filename) { - logerr("malloc(filename_size1): %s\n", strerror(errno)); - throw_node_str_error(env, "ENOMEM", strerror(ENOMEM)); - goto out; - } - - if (napi_get_value_string_utf8( - env, - argv[0], - filename, - filename_size1, - &filename_size2 - )) { - logerr("napi_get_value_string_utf8(%s, %s, %s, %s, %s);\n", - "env", - "argv[0]", - "filename", - "filename_size1", - "&filename_size2"); - throw_node_env_error(env); - goto out; - } - assert(filename_size1 == filename_size2 + 1 && - "Unstable behaviour from Node-API"); - assert(filename && "filename should not be NULL at this point"); - - if (sqlite3_open_v2( - filename, - &db, - SQLITE_OPEN_FLAGS, - NULL - )) { - logerr("sqlite3_open_v2(%s, %s, %s, %s);\n", - "filename", - "&db", - "SQLITE_OPEN_FLAGS", - "NULL"); - throw_node_env_error(env); - goto out; - } - - if (sqlite3_config( - SQLITE_CONFIG_LOG, - sqlite_error_log_callback, - NULL - )) { - logerr("sqlite3_config(%s, %s, %s);\n", - "SQLITE_CONFIG_LOG", - "sqlite_error_log_callback", - "NULL"); - throw_sqlite_error(env, db); - goto out; - } - - if (sqlite3_exec( - db, - FIX_SQLITE_PRAGMAS, - NULL, - NULL, - &error_msg - )) { - logerr("sqlite3_exec(%s, %s, %s, %s, %s);\n", - "db", - "FIX_SQLITE_PRAGMAS", - "NULL", - "NULL", - "&error_msg"); - throw_sqlite_error(env, db); - goto out; - } - - if (napi_create_object(env, &wrapped_db)) { - logerr("napi_create_object(%s, %s);\n", - "env", - "&wrapped_db"); - throw_node_env_error(env); - goto out; - } - - if (napi_type_tag_object( - env, - wrapped_db, - &SQLITE_DB_TYPE_TAG - )) { - logerr("napi_type_tag_object(%s, %s, %s);\n", - "env", - "wrapped_db", - "&SQLITE_DB_TYPE_TAG"); - throw_node_env_error(env); - goto out; - } - - if (napi_wrap( - env, - wrapped_db, - db, - finalize_db, - NULL, - NULL - )) { - logerr("napi_wrap(%s, %s, %s, %s, %s, %s);\n", - "env", - "wrapped_db", - "db", - "finalize_db", - "NULL", - "NULL"); - throw_node_env_error(env); - goto out; - } - - for (size_t i = 0; methods[i].label && methods[i].handle; i++) { - napi_value fn; - if (napi_create_function( - env, - methods[i].label, - NAPI_AUTO_LENGTH, - methods[i].handle, - db, - &fn - )) { - logerr("napi_create_function(%s, %s, %s, %s, %s, %s);\n", - "env", - "methods[i].label", - "NAPI_AUTO_LENGTH", - "methods[i].handle", - "db", - "&fn"); - throw_node_env_error(env); - goto out; - } - - if (napi_set_named_property( - env, - wrapped_db, - methods[i].label, - fn - )) { - logerr("napi_set_named_property(%s, %s, %s, %s);\n", - "env," - "wrapped_db", - "methods[i].label", - "fn"); - throw_node_env_error(env); - goto out; - } - } - ret = wrapped_db; - -out: - if (error_msg) { - sqlite3_free(error_msg); - } - if (filename) { - free(filename); - } - if (!ret) { - if (db) { - if (sqlite3_close(db)) { - logerr("sqlite3_close(%s);\n", - "db"); - } - } - } - return ret; -} - - -static napi_value -ffi_init(napi_env env, napi_value exports) { - napi_value ret = exports; - - napi_status status; - - for (size_t i = 0; fns[i].label && fns[i].handle; i++) { - napi_value fn; - status = napi_create_function( - env, - fns[i].label, - NAPI_AUTO_LENGTH, - fns[i].handle, - NULL, - &fn - ); - if (status != napi_ok) { - ret = NULL; - napi_throw_error( - env, - "SQLITE_FN_CREATE", - "Unable to wrap native function TODO i18n" - ); - goto out; - } - - status = napi_set_named_property( - env, - exports, - fns[i].label, - fn - ); - if (status != napi_ok) { - ret = NULL; - napi_throw_error( - env, - "SQLITE_FN_SETNAME", - "Unable to populate exports TODO i18n" - ); - goto out; - } - } - -out: - return ret; -} - - -NAPI_MODULE_INIT() { - return ffi_init(env, exports); -} diff --git a/src/papo.en.msg b/src/papo.en.msg deleted file mode 100644 index dde462e..0000000 --- a/src/papo.en.msg +++ /dev/null @@ -1,72 +0,0 @@ -1 Usage:\n - -2 papo -p FILE [-o DIRECTORY]\n - -3 papo -l FILE [-o DIRECTORY]\n - -4 papo [-hV]\n - -5 \n - -6 \n - -7 Options:\n - -8 -p FILE parser file to be processed\n - -9 -l FILE lexer file to be processed\n - -10 -o DIRECTORY output where to place the\n - -11 generated files (default .)\n - -12 -h, --help show this help message\n - -13 -V, --version print the version number\n - -14 \n - -15 \n - -16 Run the papo(1) parser program.\n - -17 \n - -18 Here is the explanation for what it does, and the synopsis\n - -19 of its usage.\n - -20 \n - -21 See "man papo" for usage information and\n - -22 "man papo.tutorial" for a beginner introduction.\n - -23 \n - -24 \n - -25 Examples:\n - -26 \n - -27 Do a one-line parser:\n - -28 \n - -29 $ papo run md.grammar < README.md\n - -30 \n - -31 \n - -32 Compile the grammer:\n - -33 \n - -34 $ papo build csv.grammar > dunno.alsodunno\n - -35 papo 0.1.0 1970-01-01\n - -36 Error message from Node-API is empty - |