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