nostrdb

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

flatcc_cli.c (17440B)


      1 #include <stdio.h>
      2 #include <string.h>
      3 #include <stdlib.h>
      4 
      5 #include "flatcc/flatcc.h"
      6 #include "config.h"
      7 
      8 #define VERSION FLATCC_VERSION_TEXT
      9 #define TITLE FLATCC_TITLE_TEXT
     10 
     11 void usage(FILE *fp)
     12 {
     13     fprintf(fp, "%s\n", TITLE);
     14     fprintf(fp, "version: %s\n", VERSION);
     15     fprintf(fp, "usage: flatcc [options] file [...]\n");
     16     fprintf(fp, "options:\n"
     17             "  --reader                   (default) Generate reader\n"
     18             "  -c, --common               Generate common include header(s)\n"
     19             "  --common_reader            Generate common reader include header(s)\n"
     20             "  --common_builder           Generate common builder include header(s)\n"
     21             "  -w, --builder              Generate builders (writable buffers)\n"
     22             "  -v, --verifier             Generate verifier\n"
     23             "  -r, --recursive            Recursively generate included schema files\n"
     24             "  -a                         Generate all (like -cwvr)\n"
     25             "  -g                         Use _get suffix only to avoid conflicts\n"
     26             "  -d                         Dependency file like gcc -MMD\n"
     27             "  -I<inpath>                 Search path for include files (multiple allowed)\n"
     28             "  -o<outpath>                Write files relative to this path (dir must exist)\n"
     29             "  --stdout                   Concatenate all output to stdout\n"
     30             "  --outfile=<file>           Like --stdout, but to a file.\n"
     31             "  --depfile=<file>           Dependency file like gcc -MF.\n"
     32             "  --deptarget=<file>         Override --depfile target like gcc -MT.\n"
     33             "  --prefix=<prefix>          Add prefix to all generated names (no _ added)\n"
     34             "  --common-prefix=<prefix>   Replace 'flatbuffers' prefix in common files\n"
     35 #if FLATCC_REFLECTION
     36             "  --schema                   Generate binary schema (.bfbs)\n"
     37             "  --schema-length=no         Add length prefix to binary schema\n"
     38 #endif
     39             "  --verifier                 Generate verifier for schema\n"
     40             "  --json-parser              Generate json parser for schema\n"
     41             "  --json-printer             Generate json printer for schema\n"
     42             "  --json                     Generate both json parser and printer for schema\n"
     43             "  --version                  Show version\n"
     44             "  -h | --help                Help message\n"
     45     );
     46 }
     47 
     48 void help(FILE *fp)
     49 {
     50     usage(fp);
     51     fprintf(fp,
     52         "\n"
     53         "This is a flatbuffer compatible compiler implemented in C generating C\n"
     54         "source. It is largely compatible with the flatc compiler provided by\n"
     55         "Google Fun Propulsion Lab but does not support JSON objects or binary\n"
     56         "schema.\n"
     57         "\n"
     58         "By example 'flatcc monster.fbs' generates a 'monster.h' file which\n"
     59         "provides functions to read a flatbuffer. A common include header is also\n"
     60         "required. The common file is generated with the -c option. The reader\n"
     61         "has no external dependencies.\n"
     62         "\n"
     63         "The -w (--builder) option enables code generation to build buffers:\n"
     64         "`flatbuffers -w monster.fbs` will generate `monster.h` and\n"
     65         "`monster_builder.h`, and also a builder specific common file with the\n"
     66         "-cw option. The builder must link with the extern `flatbuilder` library.\n"
     67         "\n"
     68         "-v (--verifier) generates a verifier file per schema. It depends on the\n"
     69         "runtime library but not on other generated files, except other included\n"
     70         "verifiers.\n"
     71         "\n"
     72         "-r (--recursive) generates all schema included recursively.\n"
     73         "\n"
     74         "--reader is the default option to generate reader output but can be used\n"
     75         "explicitly together with other options that would otherwise disable it.\n"
     76         "\n"
     77         "All C output can be concated to a single file using --stdout or\n"
     78         "--outfile with content produced in dependency order. The outfile is\n"
     79         "relative to cwd.\n"
     80         "\n"
     81         "-g Only add '_get' suffix to read accessors such that, for example,\n"
     82         "only 'Monster_name_get(monster)` will be generated and not also\n"
     83         "'Monster_name(monster)'. This avoids potential conflicts with\n"
     84         "other generated symbols when a schema change is impractical.\n"
     85         "\n"
     86         "-d generates a dependency file, e.g. 'monster.fbs.d' in the output dir.\n"
     87         "\n"
     88         "--depfile implies -d but accepts an explicit filename with a path\n"
     89         "relative to cwd. The dependency files content is a gnu make rule with a\n"
     90         "target followed by the included schema files The target must match how\n"
     91         "it is seen by the rest of the build system and defaults to e.g.\n"
     92         "'monster_reader.h' or 'monster.bfbs' paths relative to the working\n"
     93         "directory.\n"
     94         "\n"
     95         "--deptarget overrides the default target for --depfile, simiar to gcc -MT.\n"
     96         "\n"
     97 
     98 #if FLATCC_REFLECTION
     99         "--schema will generate a binary .bfbs file for each top-level schema file.\n"
    100         "Can be used with --stdout if no C output is specified. When used with multiple\n"
    101         "files --schema-length=yes is recommend.\n"
    102         "\n"
    103         "--schema-length adds a length prefix of type uoffset_t to binary schema so\n"
    104         "they can be concatenated - the aligned buffer starts after the prefix.\n"
    105         "\n"
    106 #else
    107         "Flatbuffers binary schema support (--schema) has been disabled."
    108         "\n"
    109 #endif
    110         "--json-parser generates a file that implements a fast typed json parser for\n"
    111         "the schema. It depends on some flatcc headers and the runtime library but\n"
    112         "not on other generated files except other parsers from included schema.\n"
    113         "\n"
    114         "--json-printer generates a file that implements json printers for the schema\n"
    115         "and has dependencies similar to --json-parser.\n"
    116         "\n"
    117         "--json is generates both printer and parser.\n"
    118         "\n"
    119 #if FLATCC_REFLECTION
    120 #if 0 /* Disable deprecated features. */
    121         "DEPRECATED:\n"
    122         "  --schema-namespace controls if typenames in schema are prefixed a namespace.\n"
    123         "  namespaces should always be present.\n"
    124         "\n"
    125 #endif
    126 #endif
    127         "The generated source can redefine offset sizes by including a modified\n"
    128         "`flatcc_types.h` file. The flatbuilder library must then be compiled with the\n"
    129         "same `flatcc_types.h` file. In this case --prefix and --common-prefix options\n"
    130         "may be helpful to avoid conflict with standard offset sizes.\n"
    131         "\n"
    132         "The output size may seem bulky, but most content is rarely used inline\n"
    133         "functions and macros. The compiled binary need not be large.\n"
    134         "\n"
    135         "The generated source assumes C11 functionality for alignment, compile\n"
    136         "time assertions and inline functions but an optional set of portability\n"
    137         "headers can be included to work with most any compiler. The portability\n"
    138         "layer is not throughly tested so a platform specific test is required\n"
    139         "before production use. Upstream patches are welcome.\n");
    140 }
    141 
    142 enum { noarg, suffixarg, nextarg };
    143 
    144 int parse_bool_arg(const char *a)
    145 {
    146     if (strcmp(a, "0") == 0 || strcmp(a, "no") == 0) {
    147         return 0;
    148     }
    149     if (strcmp(a, "1") == 0 || strcmp(a, "yes") == 0) {
    150         return 1;
    151     }
    152     fprintf(stderr, "invalid boolean argument: '%s', must be '0', '1', 'yes' or 'no'\n", a);
    153     return -1;
    154 }
    155 
    156 int match_long_arg(const char *option, const char *s, size_t n)
    157 {
    158     return strncmp(option, s, n) == 0 && strlen(option) == n;
    159 }
    160 
    161 int set_opt(flatcc_options_t *opts, const char *s, const char *a)
    162 {
    163     int ret = noarg;
    164     size_t n = strlen(s);
    165     const char *v = strchr(s, '=');
    166     if (v) {
    167         a = v + 1;
    168         n = (size_t)(v - s);
    169     }
    170     if (*s == 'h' || 0 == strcmp("-help", s)) {
    171         /* stdout so less and more works. */
    172         help(stdout);
    173         exit(0);
    174     }
    175     if (0 == strcmp("-version", s)) {
    176         fprintf(stdout, "%s\n", TITLE);
    177         fprintf(stdout, "version: %s\n", VERSION);
    178         exit(0);
    179     }
    180     if (0 == strcmp("-stdout", s)) {
    181         opts->gen_stdout = 1;
    182         return noarg;
    183     }
    184     if (0 == strcmp("-common", s)) {
    185         opts->cgen_common_reader = 1;
    186         opts->cgen_common_builder = 1;
    187         return noarg;
    188     }
    189     if (0 == strcmp("-common_reader", s)) {
    190         opts->cgen_common_reader = 1;
    191         return noarg;
    192     }
    193     if (0 == strcmp("-common_builder", s)) {
    194         opts->cgen_common_builder = 1;
    195         return noarg;
    196     }
    197     if (0 == strcmp("-reader", s)) {
    198         opts->cgen_reader = 1;
    199         return noarg;
    200     }
    201     if (0 == strcmp("-builder", s)) {
    202         opts->cgen_builder = 1;
    203         return noarg;
    204     }
    205     if (0 == strcmp("-verifier", s)) {
    206         opts->cgen_verifier = 1;
    207         return noarg;
    208     }
    209     if (0 == strcmp("-recursive", s)) {
    210         opts->cgen_recursive = 1;
    211         return noarg;
    212     }
    213 #if FLATCC_REFLECTION
    214     if (0 == strcmp("-schema", s)) {
    215         opts->bgen_bfbs = 1;
    216         return noarg;
    217     }
    218 #endif
    219     if (0 == strcmp("-json-parser", s)) {
    220         opts->cgen_json_parser = 1;
    221         return noarg;
    222     }
    223     if (0 == strcmp("-json-printer", s)) {
    224         opts->cgen_json_printer = 1;
    225         return noarg;
    226     }
    227     if (0 == strcmp("-json", s)) {
    228         opts->cgen_json_parser = 1;
    229         opts->cgen_json_printer = 1;
    230         return noarg;
    231     }
    232 #if FLATCC_REFLECTION
    233 #if 0 /* Disable deprecated features. */
    234     if (match_long_arg("-schema-namespace", s, n)) {
    235         fprintf(stderr, "warning: --schema-namespace is deprecated\n"
    236                         "         a namespace is added by default and should always be present\n");
    237         if (!a) {
    238             fprintf(stderr, "--schema-namespace option needs an argument\n");
    239             exit(-1);
    240         }
    241         if(0 > (opts->bgen_qualify_names = parse_bool_arg(a))) {
    242             exit(-1);
    243         }
    244         return v ? noarg : nextarg;
    245     }
    246     if (match_long_arg("-schema-length", s, n)) {
    247         if (!a) {
    248             fprintf(stderr, "--schema-length option needs an argument\n");
    249             exit(-1);
    250         }
    251         if(0 > (opts->bgen_length_prefix = parse_bool_arg(a))) {
    252             exit(-1);
    253         }
    254         return v ? noarg : nextarg;
    255     }
    256 #endif
    257 #endif
    258     if (match_long_arg("-depfile", s, n)) {
    259         if (!a) {
    260             fprintf(stderr, "--depfile option needs an argument\n");
    261             exit(-1);
    262         }
    263         opts->gen_depfile = a;
    264         opts->gen_dep = 1;
    265         return v ? noarg : nextarg;
    266     }
    267     if (match_long_arg("-deptarget", s, n)) {
    268         if (!a) {
    269             fprintf(stderr, "--deptarget option needs an argument\n");
    270             exit(-1);
    271         }
    272         opts->gen_deptarget = a;
    273         return v ? noarg : nextarg;
    274     }
    275     if (match_long_arg("-outfile", s, n)) {
    276         if (!a) {
    277             fprintf(stderr, "--outfile option needs an argument\n");
    278             exit(-1);
    279         }
    280         opts->gen_outfile= a;
    281         return v ? noarg : nextarg;
    282     }
    283     if (match_long_arg("-common-prefix", s, n)) {
    284         if (!a) {
    285             fprintf(stderr, "--common-prefix option needs an argument\n");
    286             exit(-1);
    287         }
    288         opts->nsc = a;
    289         return v ? noarg : nextarg;
    290     }
    291     if (match_long_arg("-prefix", s, n)) {
    292         if (!a) {
    293             fprintf(stderr, "-n option needs an argument\n");
    294             exit(-1);
    295         }
    296         opts->ns = a;
    297         return v ? noarg : nextarg;
    298     }
    299     switch (*s) {
    300     case '-':
    301         fprintf(stderr, "invalid option: -%s\n", s);
    302         exit(-1);
    303     case 'I':
    304         if (s[1]) {
    305             ret = suffixarg;
    306             a = s + 1;
    307         } else if (!a) {
    308             fprintf(stderr, "-I option needs an argument\n");
    309             exit(-1);
    310         } else {
    311             ret = nextarg;
    312         }
    313         opts->inpaths[opts->inpath_count++] = a;
    314         return ret;
    315     case 'o':
    316         if (opts->outpath) {
    317             fprintf(stderr, "-o option can only be specified once\n");
    318             exit(-1);
    319         }
    320         if (s[1]) {
    321             ret = suffixarg;
    322             a = s + 1;
    323         } else if (!a) {
    324             fprintf(stderr, "-o option needs an argument\n");
    325             exit(-1);
    326         } else {
    327             ret = nextarg;
    328         }
    329         opts->outpath = a;
    330         return ret;
    331     case 'w':
    332         opts->cgen_builder = 1;
    333         return noarg;
    334     case 'v':
    335         opts->cgen_verifier = 1;
    336         return noarg;
    337     case 'c':
    338         opts->cgen_common_reader = 1;
    339         opts->cgen_common_builder = 1;
    340         return noarg;
    341     case 'r':
    342         opts->cgen_recursive = 1;
    343         return noarg;
    344     case 'g':
    345         opts->cgen_no_conflicts = 1;
    346         return noarg;
    347     case 'd':
    348         opts->gen_dep = 1;
    349         return noarg;
    350     case 'a':
    351         opts->cgen_reader = 1;
    352         opts->cgen_builder = 1;
    353         opts->cgen_verifier = 1;
    354         opts->cgen_common_reader = 1;
    355         opts->cgen_common_builder = 1;
    356         opts->cgen_recursive = 1;
    357         return noarg;
    358     default:
    359         fprintf(stderr, "invalid option: -%c\n", *s);
    360         exit(-1);
    361     }
    362     return noarg;
    363 }
    364 
    365 int get_opt(flatcc_options_t *opts, const char *s, const char *a)
    366 {
    367     if (s[1] == '-') {
    368         return nextarg == set_opt(opts, s + 1, a);
    369     }
    370     ++s;
    371     if (*s == 0) {
    372         fprintf(stderr, "- is not a valid option\n");
    373         exit(-1);
    374     }
    375     while (*s) {
    376         switch (set_opt(opts, s, a)) {
    377         case noarg:
    378             ++s;
    379             continue;
    380         case suffixarg:
    381             return 0;
    382         case nextarg:
    383             return 1;
    384         }
    385     }
    386     return noarg;
    387 }
    388 
    389 void parse_opts(int argc, const char *argv[], flatcc_options_t *opts)
    390 {
    391     int i;
    392     const char *s, *a;
    393 
    394     for (i = 1; i < argc; ++i) {
    395         if (argv[i][0] == '-') {
    396             s = argv[i];
    397             a = i + 1 < argc ? argv[i + 1] : 0;
    398             i += get_opt(opts, s, a);
    399         } else {
    400             opts->srcpaths[opts->srcpath_count++] = argv[i];
    401         }
    402     }
    403 }
    404 
    405 int main(int argc, const char *argv[])
    406 {
    407     flatcc_options_t opts;
    408     flatcc_context_t ctx = 0;
    409     int i, ret, cgen;
    410     const char **src;
    411 
    412     ctx = 0;
    413     ret = 0;
    414     if (argc < 2) {
    415         usage(stderr);
    416         exit(-1);
    417     }
    418     flatcc_init_options(&opts);
    419     if (!(opts.inpaths = malloc((size_t)argc * sizeof(char *)))) {
    420         fprintf(stderr, "memory allocation failure\n");
    421         exit(-1);
    422     }
    423     if (!(opts.srcpaths = malloc((size_t)argc * sizeof(char *)))) {
    424         fprintf(stderr, "memory allocation failure\n");
    425         free((void *)opts.inpaths);
    426         exit(-1);
    427     }
    428 
    429     parse_opts(argc, argv, &opts);
    430     if (opts.cgen_builder && opts.cgen_common_reader) {
    431         opts.cgen_common_builder = 1;
    432     }
    433     if (opts.srcpath_count == 0) {
    434         /* No input files, so only generate header(s). */
    435         if (!(opts.cgen_common_reader || opts.cgen_common_builder) || opts.bgen_bfbs) {
    436             fprintf(stderr, "filename missing\n");
    437             goto fail;
    438         }
    439         if (!(ctx = flatcc_create_context(&opts, 0, 0, 0))) {
    440             fprintf(stderr, "internal error: failed to create parsing context\n");
    441             goto fail;
    442         }
    443         if (flatcc_generate_files(ctx)) {
    444             goto fail;
    445         }
    446         flatcc_destroy_context(ctx);
    447         ctx = 0;
    448         goto done;
    449     }
    450     cgen = opts.cgen_reader || opts.cgen_builder || opts.cgen_verifier
    451         || opts.cgen_common_reader || opts.cgen_common_builder
    452         || opts.cgen_json_parser || opts.cgen_json_printer;
    453     if (!opts.bgen_bfbs && (!cgen || opts.cgen_builder || opts.cgen_verifier)) {
    454         /* Assume default if no other output specified when deps required it. */
    455         opts.cgen_reader = 1;
    456     }
    457     if (opts.bgen_bfbs && cgen) {
    458         if (opts.gen_stdout) {
    459             fprintf(stderr, "--stdout cannot be used with mixed text and binary output");
    460             goto fail;
    461         }
    462         if (opts.gen_outfile) {
    463             fprintf(stderr, "--outfile cannot be used with mixed text and binary output");
    464             goto fail;
    465         }
    466     }
    467     if (opts.gen_deptarget && !opts.gen_depfile) {
    468         fprintf(stderr, "--deptarget cannot be used without --depfile");
    469         goto fail;
    470     }
    471     if (opts.gen_stdout && opts.gen_outfile) {
    472         fprintf(stderr, "--outfile cannot be used with --stdout");
    473         goto fail;
    474     }
    475     for (i = 0, src = opts.srcpaths; i < opts.srcpath_count; ++i, ++src) {
    476         if (!(ctx = flatcc_create_context(&opts, *src, 0, 0))) {
    477             fprintf(stderr, "internal error: failed to create parsing context\n");
    478             goto fail;
    479         }
    480         if (flatcc_parse_file(ctx, *src)) {
    481             goto fail;
    482         }
    483         if (flatcc_generate_files(ctx)) {
    484             goto fail;
    485         }
    486         flatcc_destroy_context(ctx);
    487         ctx = 0;
    488         /* for --stdout and --outfile options: append to file and skip generating common headers. */
    489         opts.gen_append = 1;
    490     }
    491     goto done;
    492 fail:
    493     ret = -1;
    494 done:
    495     if (ctx) {
    496         flatcc_destroy_context(ctx);
    497         ctx = 0;
    498     }
    499     if (ret) {
    500         fprintf(stderr, "output failed\n");
    501     }
    502     free((void *)opts.inpaths);
    503     free((void *)opts.srcpaths);
    504     return ret;
    505 }