diff options
Diffstat (limited to 'src/genhash.c')
-rw-r--r-- | src/genhash.c | 106 |
1 files changed, 106 insertions, 0 deletions
diff --git a/src/genhash.c b/src/genhash.c new file mode 100644 index 0000000000..649b8deb2e --- /dev/null +++ b/src/genhash.c @@ -0,0 +1,106 @@ +// Program used to generate static hashes +// +// Uses hashes from khash.h macros library. + +#include <string.h> +#include <stdio.h> +#include <stdlib.h> +#include <errno.h> + +#define USE_LIBC_ALLOCATOR +#include "nvim/lib/khash.h" + +KHASH_MAP_INIT_STR(hash, char *) + +#define CHECK_FAIL(cond, ...) \ + do { \ + if (cond) { \ + fprintf(stderr, __VA_ARGS__); \ + putc('\n', stderr); \ + return 1; \ + } \ + } while (0) + +int main(int argc, char **argv) +{ + if (argc == 2 && strcmp(argv[1], "--help") == 0) { + puts("Usage:"); + puts(" genhash SOURCE TARGET TYPE NAME VALTYPE NULLVAL"); + puts("Transforms keys and values in a form \"key\\nval\\n\" into a hash"); + puts("literal."); + puts(""); + puts("SOURCE is the file name to read keys and values from."); + puts("TARGET is the file name to write to."); + puts("TYPE is the name of the hash type (khash_t argument)."); + puts("NAME is the name of the generated hash."); + puts("VALTYPE is the name of the value type."); + puts("NULLVAL is the value used when no value is available."); + return 0; + } + + CHECK_FAIL(argc != 7, "Expecting six arguments, got %i.", argc); + + const char *const source = argv[1]; + const char *const target = argv[2]; + const char *const type = argv[3]; + const char *const name = argv[4]; + const char *const valtype = argv[5]; + const char *const nullval = argv[6]; + + FILE *fin = fopen(source, "r"); + CHECK_FAIL(!fin, "Failed to open source: %s.", strerror(errno)); + + char keybuf[80]; + char valbuf[4096]; + khash_t(hash) hash = KHASH_EMPTY_TABLE(hash); + while (fgets(keybuf, sizeof(keybuf), fin) != NULL) { + CHECK_FAIL(ferror(fin), "Failed to read key %i from source: %s", + (int) kh_size(&hash), strerror(ferror(fin))); + keybuf[strlen(keybuf) - 1] = 0; + CHECK_FAIL(!fgets(valbuf, sizeof(valbuf), fin), + "Failed to read value for key %i (%s): %s", + (int) kh_size(&hash), keybuf, (ferror(fin) + ? strerror(ferror(fin)) + : "EOF found")); + valbuf[strlen(valbuf) - 1] = 0; + char *const key_copy = strdup(keybuf); + CHECK_FAIL(!key_copy, "Failed to allocate memory for a key"); + int put_ret; + const khiter_t k = kh_put(hash, &hash, key_copy, &put_ret); + CHECK_FAIL(put_ret != 1, "Expecting unused non-empty bucket for key %s", + key_copy); + kh_value(&hash, k) = strdup(valbuf); + CHECK_FAIL(!kh_value(&hash, k), "Failed to allocate memory for a value"); + } + CHECK_FAIL(fclose(fin), "Failed to close source: %s", strerror(errno)); + + FILE *f = fopen(target, "w"); + CHECK_FAIL(!f, strerror(errno)); + fprintf(f, "static const khash_t(%s) %s = {", type, name); + fprintf(f, " .n_buckets = %i,\n", (int) hash.n_buckets); + fprintf(f, " .size = %i,\n", (int) hash.size); + fprintf(f, " .n_occupied = %i,\n", (int) hash.n_occupied); + fprintf(f, " .upper_bound = %i,\n", (int) hash.upper_bound); + fprintf(f, " .flags = (khint32_t[]) {\n"); + for (khint_t i = 0; i < kh_end(&hash); i++) { + fprintf(f, " %i,\n", (int) hash.flags[i]); + } + fprintf(f, " },\n"); + fprintf(f, " .keys = (const char*[]) {\n"); + for (khint_t i = 0; i < kh_end(&hash); i++) { + if (kh_exist(&hash, i)) { + fprintf(f, " \"%s\",\n", hash.keys[i]); + } else { + fprintf(f, " NULL,\n"); + } + } + fprintf(f, " },\n"); + fprintf(f, " .vals = (%s[]) {\n", valtype); + for (khint_t i = 0; i < kh_end(&hash); i++) { + fprintf(f, " %s,\n", (kh_exist(&hash, i) ? hash.vals[i] : nullval)); + } + fprintf(f, " },\n"); + fprintf(f, "};\n"); + fclose(f); + return 0; +} |