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 }