nostrdb

an unfairly fast embedded nostr database backed by lmdb
git clone git://jb55.com/nostrdb
Log | Files | Refs | Submodules | README | LICENSE

codegen_c.c (8054B)


      1 #include "codegen_c.h"
      2 #include "fileio.h"
      3 #include "pstrutil.h"
      4 #include "../../external/hash/str_set.h"
      5 
      6 int fb_open_output_file(fb_output_t *out, const char *name, size_t len, const char *ext)
      7 {
      8     char *path;
      9     int ret;
     10     const char *prefix = out->opts->outpath ? out->opts->outpath : "";
     11     size_t prefix_len = strlen(prefix);
     12 
     13     if (out->fp) {
     14         return 0;
     15     }
     16     checkmem((path = fb_create_join_path_n(prefix, prefix_len, name, len, ext, 1)));
     17     out->fp = fopen(path, "wb");
     18     ret = 0;
     19     if (!out->fp) {
     20         fprintf(stderr, "error opening file for write: %s\n", path);
     21         ret = -1;
     22     }
     23     free(path);
     24     return ret;
     25 }
     26 
     27 void fb_close_output_file(fb_output_t *out)
     28 {
     29     /* Concatenate covers either stdout or a file. */
     30     if (!out->opts->gen_outfile && !out->opts->gen_stdout && out->fp) {
     31         fclose(out->fp);
     32         out->fp = 0;
     33     }
     34     /* Keep out->fp open for next file. */
     35 }
     36 
     37 void fb_end_output_c(fb_output_t *out)
     38 {
     39     if (out->fp != stdout && out->fp) {
     40         fclose(out->fp);
     41     }
     42     out->fp = 0;
     43 }
     44 
     45 /*
     46  * If used with --stdout or concat=<file>, we assume there
     47  * are no other language outputs at the same time.
     48  */
     49 int fb_init_output_c(fb_output_t *out, fb_options_t *opts)
     50 {
     51     const char *nsc;
     52     char *path = 0;
     53     size_t n;
     54     const char *mode = opts->gen_append ? "ab" : "wb";
     55     const char *prefix = opts->outpath ? opts->outpath : "";
     56     int ret = -1;
     57 
     58     memset(out, 0, sizeof(*out));
     59     out->opts = opts;
     60     nsc = opts->nsc;
     61     if (nsc) {
     62         n = strlen(opts->nsc);
     63         if (n > FLATCC_NAMESPACE_MAX) {
     64             fprintf(stderr, "common namespace argument is limited to %i characters\n", (int)FLATCC_NAMESPACE_MAX);
     65             return -1;
     66         }
     67     } else {
     68         nsc = FLATCC_DEFAULT_NAMESPACE_COMMON;
     69         n = strlen(nsc);
     70     }
     71     strncpy(out->nsc, nsc, FLATCC_NAMESPACE_MAX);
     72     out->nsc[FLATCC_NAMESPACE_MAX] = '\0';
     73     if (n) {
     74         out->nsc[n] = '_';
     75         out->nsc[n + 1] = '\0';
     76     }
     77     pstrcpyupper(out->nscup, out->nsc);
     78     out->nscup[n] = '\0'; /* No trailing _ */
     79     out->spacing = opts->cgen_spacing;
     80     if (opts->gen_stdout) {
     81         out->fp = stdout;
     82         return 0;
     83     }
     84     if (!out->opts->gen_outfile) {
     85         /* Normal operation to multiple header filers. */
     86         return 0;
     87     }
     88     checkmem((path = fb_create_join_path(prefix, out->opts->gen_outfile, "", 1)));
     89     out->fp = fopen(path, mode);
     90     if (!out->fp) {
     91         fprintf(stderr, "error opening file for write: %s\n", path);
     92         ret = -1;
     93         goto done;
     94     }
     95     ret = 0;
     96 done:
     97     if (path) {
     98         free(path);
     99     }
    100     return ret;
    101 }
    102 
    103 static void _str_set_destructor(void *context, char *item)
    104 {
    105     (void)context;
    106 
    107     free(item);
    108 }
    109 
    110 /*
    111  * Removal of duplicate inclusions is only for a cleaner output - it is
    112  * not stricly necessary because the preprocessor handles include
    113  * guards. The guards are required to deal with concatenated files
    114  * regardless unless we generate special code for concatenation.
    115  */
    116 void fb_gen_c_includes(fb_output_t *out, const char *ext, const char *extup)
    117 {
    118     fb_include_t *inc = out->S->includes;
    119     char *basename, *basenameup, *s;
    120     str_set_t set;
    121 
    122     fb_clear(set);
    123 
    124     /* Don't include our own file. */
    125     str_set_insert_item(&set, fb_copy_path(out->S->basenameup), ht_keep);
    126     while (inc) {
    127         checkmem((basename = fb_create_basename(
    128                     inc->name.s.s, (size_t)inc->name.s.len, out->opts->default_schema_ext)));
    129         inc = inc->link;
    130         checkmem((basenameup = fb_copy_path(basename)));
    131         s = basenameup;
    132         while (*s) {
    133             *s = (char)toupper(*s);
    134             ++s;
    135         }
    136         if (str_set_insert_item(&set, basenameup, ht_keep)) {
    137             free(basenameup);
    138             free(basename);
    139             continue;
    140         }
    141         /* The include guard is needed when concatening output. */
    142         fprintf(out->fp,
    143             "#ifndef %s%s\n"
    144             "#include \"%s%s\"\n"
    145             "#endif\n",
    146             basenameup, extup, basename, ext);
    147         free(basename);
    148         /* `basenameup` stored in str_set. */
    149     }
    150     str_set_destroy(&set, _str_set_destructor, 0);
    151 }
    152 
    153 int fb_copy_scope(fb_scope_t *scope, char *buf)
    154 {
    155     size_t n, len;
    156     fb_ref_t *name;
    157 
    158     len = (size_t)scope->prefix.len;
    159     for (name = scope->name; name; name = name->link) {
    160         n = (size_t)name->ident->len;
    161         len += n + 1;
    162     }
    163     if (len > FLATCC_NAMESPACE_MAX + 1) {
    164         buf[0] = '\0';
    165         return -1;
    166     }
    167     len = (size_t)scope->prefix.len;
    168     memcpy(buf, scope->prefix.s, len);
    169     for (name = scope->name; name; name = name->link) {
    170         n = (size_t)name->ident->len;
    171         memcpy(buf + len, name->ident->text, n);
    172         len += n + 1;
    173         buf[len - 1] = '_';
    174     }
    175     buf[len] = '\0';
    176     return (int)len;
    177 }
    178 
    179 void fb_scoped_symbol_name(fb_scope_t *scope, fb_symbol_t *sym, fb_scoped_name_t *sn)
    180 {
    181     fb_token_t *t = sym->ident;
    182 
    183     if (sn->scope != scope) {
    184         if (0 > (sn->scope_len = fb_copy_scope(scope, sn->text))) {
    185             sn->scope_len = 0;
    186             fprintf(stderr, "skipping too long namespace\n");
    187         }
    188     }
    189     sn->len = (int)t->len;
    190     sn->total_len = sn->scope_len + sn->len;
    191     if (sn->total_len > FLATCC_NAME_BUFSIZ - 1) {
    192         fprintf(stderr, "warning: truncating identifier: %.*s\n", sn->len, t->text);
    193         sn->len = FLATCC_NAME_BUFSIZ - sn->scope_len - 1;
    194         sn->total_len = sn->scope_len + sn->len;
    195     }
    196     memcpy(sn->text + sn->scope_len, t->text, (size_t)sn->len);
    197     sn->text[sn->total_len] = '\0';
    198 }
    199 
    200 int fb_codegen_common_c(fb_output_t *out)
    201 {
    202     size_t nsc_len;
    203     int ret;
    204 
    205     nsc_len = strlen(out->nsc) - 1;
    206     ret = 0;
    207     if (out->opts->cgen_common_reader) {
    208         if (fb_open_output_file(out, out->nsc, nsc_len, "_common_reader.h")) {
    209             return -1;
    210         }
    211         ret = fb_gen_common_c_header(out);
    212         fb_close_output_file(out);
    213     }
    214     if (!ret && out->opts->cgen_common_builder) {
    215         if (fb_open_output_file(out, out->nsc, nsc_len, "_common_builder.h")) {
    216             return -1;
    217         }
    218         fb_gen_common_c_builder_header(out);
    219         fb_close_output_file(out);
    220     }
    221     return ret;
    222 }
    223 
    224 int fb_codegen_c(fb_output_t *out, fb_schema_t *S)
    225 {
    226     size_t basename_len;
    227     /* OK if no files were processed. */
    228     int ret = 0;
    229 
    230     out->S = S;
    231     out->current_scope = fb_scope_table_find(&S->root_schema->scope_index, 0, 0);
    232     basename_len = strlen(out->S->basename);
    233     if (out->opts->cgen_reader) {
    234         if (fb_open_output_file(out, out->S->basename, basename_len, "_reader.h")) {
    235             ret = -1;
    236             goto done;
    237         }
    238         if ((ret = fb_gen_c_reader(out))) {
    239             goto done;
    240         }
    241         fb_close_output_file(out);
    242     }
    243     if (out->opts->cgen_builder) {
    244         if (fb_open_output_file(out, out->S->basename, basename_len, "_builder.h")) {
    245             ret = -1;
    246             goto done;
    247         }
    248         if ((ret = fb_gen_c_builder(out))) {
    249                     goto done;
    250         }
    251         fb_close_output_file(out);
    252     }
    253     if (out->opts->cgen_verifier) {
    254         if (fb_open_output_file(out, out->S->basename, basename_len, "_verifier.h")) {
    255             ret = -1;
    256             goto done;
    257         }
    258         if ((ret = fb_gen_c_verifier(out))) {
    259             goto done;
    260         }
    261         fb_close_output_file(out);
    262     }
    263     if (out->opts->cgen_json_parser) {
    264         if (fb_open_output_file(out, out->S->basename, basename_len, "_json_parser.h")) {
    265             ret = -1;
    266             goto done;
    267         }
    268         if ((ret = fb_gen_c_json_parser(out))) {
    269             goto done;
    270         }
    271         fb_close_output_file(out);
    272     }
    273     if (out->opts->cgen_json_printer) {
    274         if (fb_open_output_file(out, out->S->basename, basename_len, "_json_printer.h")) {
    275             ret = -1;
    276             goto done;
    277         }
    278         if ((ret = fb_gen_c_json_printer(out))) {
    279             goto done;
    280         }
    281         fb_close_output_file(out);
    282     }
    283 done:
    284     return ret;
    285 }