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