codegen_c_json_printer.c (29303B)
1 #include "codegen_c.h" 2 #include "flatcc/flatcc_types.h" 3 4 /* -DFLATCC_PORTABLE may help if inttypes.h is missing. */ 5 #ifndef PRId64 6 #include <inttypes.h> 7 #endif 8 9 static int gen_json_printer_pretext(fb_output_t *out) 10 { 11 fprintf(out->fp, 12 "#ifndef %s_JSON_PRINTER_H\n" 13 "#define %s_JSON_PRINTER_H\n", 14 out->S->basenameup, out->S->basenameup); 15 16 fprintf(out->fp, "\n/* " FLATCC_GENERATED_BY " */\n\n"); 17 fprintf(out->fp, "#include \"flatcc/flatcc_json_printer.h\"\n"); 18 fb_gen_c_includes(out, "_json_printer.h", "_JSON_PRINTER_H"); 19 gen_prologue(out); 20 fprintf(out->fp, "\n"); 21 return 0; 22 } 23 24 static int gen_json_printer_footer(fb_output_t *out) 25 { 26 gen_epilogue(out); 27 fprintf(out->fp, 28 "#endif /* %s_JSON_PRINTER_H */\n", 29 out->S->basenameup); 30 return 0; 31 } 32 33 static int gen_json_printer_enum(fb_output_t *out, fb_compound_type_t *ct) 34 { 35 fb_symbol_t *sym; 36 fb_member_t *member; 37 fb_scoped_name_t snt, snref; 38 const char *tp, *tn, *ns; 39 int bit_flags; 40 uint64_t mask = 0; 41 char *constwrap = ""; 42 char *ut = ""; 43 fb_scalar_type_t st = ct->type.st; 44 45 fb_clear(snt); 46 fb_clear(snref); 47 fb_compound_name(ct, &snt); 48 tp = scalar_type_prefix(st); 49 tn = scalar_type_name(st); 50 ns = scalar_type_ns(st, out->nsc); 51 52 bit_flags = !!(ct->metadata_flags & fb_f_bit_flags); 53 if (bit_flags) { 54 switch (ct->size) { 55 case 1: 56 mask = UINT8_MAX, constwrap = "UINT8_C", ut = "uint8_t"; 57 break; 58 case 2: 59 mask = UINT16_MAX, constwrap = "UINT16_C", ut = "uint16_t"; 60 break; 61 case 4: 62 mask = UINT32_MAX, constwrap = "UINT32_C", ut = "uint32_t"; 63 break; 64 default: 65 mask = UINT64_MAX, constwrap = "UINT64_C", ut = "uint64_t"; 66 break; 67 } 68 for (sym = ct->members; sym; sym = sym->link) { 69 member = (fb_member_t *)sym; 70 switch (member->value.type) { 71 case vt_uint: 72 mask &= ~(uint64_t)member->value.u; 73 break; 74 case vt_int: 75 mask &= ~(uint64_t)member->value.i; 76 break; 77 case vt_bool: 78 mask &= ~(uint64_t)member->value.b; 79 break; 80 } 81 } 82 } 83 84 fprintf(out->fp, 85 "static void %s_print_json_enum(flatcc_json_printer_t *ctx, %s%s v)\n{\n", 86 snt.text, ns, tn); 87 if (bit_flags) { 88 if (strcmp(ut, tn)) { 89 fprintf(out->fp, " %s x = (%s)v;\n", ut, ut); 90 } else { 91 fprintf(out->fp, " %s x = v;\n", ut); 92 } 93 fprintf(out->fp, 94 " int multiple = 0 != (x & (x - 1));\n" 95 " int i = 0;\n"); 96 97 fprintf(out->fp, "\n"); 98 /* 99 * If the value is not entirely within the known bit flags, print as 100 * a number. 101 */ 102 if (mask) { 103 fprintf(out->fp, 104 " if ((x & %s(0x%"PRIx64")) || x == 0) {\n" 105 " flatcc_json_printer_%s(ctx, v);\n" 106 " return;\n" 107 " }\n", 108 constwrap, mask, tp); 109 } 110 /* 111 * Test if multiple bits set. We may have a configuration option 112 * that requires multiple flags to be quoted like `color: "Red Green"` 113 * but unquoted if just a single value like `color: Green`. 114 * 115 * The index `i` is used to add space separators much like an 116 * index is provided for struct members to handle comma. 117 */ 118 fprintf(out->fp, " flatcc_json_printer_delimit_enum_flags(ctx, multiple);\n"); 119 for (sym = ct->members; sym; sym = sym->link) { 120 member = (fb_member_t *)sym; 121 switch (member->value.type) { 122 case vt_uint: 123 fprintf(out->fp, " if (x & %s(0x%"PRIx64")) flatcc_json_printer_enum_flag(ctx, i++, \"%.*s\", %ld);\n", 124 constwrap, member->value.u, (int)sym->ident->len, sym->ident->text, sym->ident->len); 125 break; 126 case vt_int: 127 fprintf(out->fp, " if (x & %s(0x%"PRIx64")) flatcc_json_printer_enum_flag(ctx, i++, \"%.*s\", %ld);\n", 128 constwrap, (uint64_t)member->value.i, (int)sym->ident->len, sym->ident->text, sym->ident->len); 129 break; 130 case vt_bool: 131 fprintf(out->fp, " if (x & %s(0x%"PRIx64")) flatcc_json_printer_enum_flag(ctx, i++, \"%.*s\", %ld);\n", 132 constwrap, (uint64_t)member->value.b, (int)sym->ident->len, sym->ident->text, sym->ident->len); 133 break; 134 default: 135 gen_panic(out, "internal error: unexpected value type for enum json_print"); 136 break; 137 } 138 } 139 fprintf(out->fp, " flatcc_json_printer_delimit_enum_flags(ctx, multiple);\n"); 140 } else { 141 fprintf(out->fp, "\n switch (v) {\n"); 142 for (sym = ct->members; sym; sym = sym->link) { 143 member = (fb_member_t *)sym; 144 switch (member->value.type) { 145 case vt_uint: 146 fprintf(out->fp, " case %s(%"PRIu64"): flatcc_json_printer_enum(ctx, \"%.*s\", %ld); break;\n", 147 constwrap, member->value.u, (int)sym->ident->len, sym->ident->text, sym->ident->len); 148 break; 149 case vt_int: 150 fprintf(out->fp, " case %s(%"PRId64"): flatcc_json_printer_enum(ctx, \"%.*s\", %ld); break;\n", 151 constwrap, member->value.i, (int)sym->ident->len, sym->ident->text, sym->ident->len); 152 break; 153 case vt_bool: 154 fprintf(out->fp, " case %s(%u): flatcc_json_printer_enum(ctx, \"%.*s\", %ld); break;\n", 155 constwrap, member->value.b, (int)sym->ident->len, sym->ident->text, sym->ident->len); 156 break; 157 default: 158 gen_panic(out, "internal error: unexpected value type for enum json_print"); 159 break; 160 } 161 } 162 fprintf(out->fp, 163 " default: flatcc_json_printer_%s(ctx, v); break;\n" 164 " }\n", 165 tp); 166 } 167 fprintf(out->fp, "}\n\n"); 168 return 0; 169 } 170 171 static int gen_json_printer_union_type(fb_output_t *out, fb_compound_type_t *ct) 172 { 173 fb_symbol_t *sym; 174 fb_member_t *member; 175 fb_scoped_name_t snt; 176 177 fb_clear(snt); 178 fb_compound_name(ct, &snt); 179 180 fprintf(out->fp, 181 "static void %s_print_json_union_type(flatcc_json_printer_t *ctx, flatbuffers_utype_t type)\n" 182 "{\n switch (type) {\n", 183 snt.text); 184 for (sym = ct->members; sym; sym = sym->link) { 185 member = (fb_member_t *)sym; 186 if (member->type.type == vt_missing) { 187 continue; 188 } 189 fprintf(out->fp, 190 " case %u:\n" 191 " flatcc_json_printer_enum(ctx, \"%.*s\", %ld);\n" 192 " break;\n", 193 (unsigned)member->value.u, (int)sym->ident->len, sym->ident->text, sym->ident->len); 194 } 195 fprintf(out->fp, 196 " default:\n" 197 " flatcc_json_printer_enum(ctx, \"NONE\", 4);\n" 198 " break;\n"); 199 fprintf(out->fp, 200 " }\n}\n\n"); 201 return 0; 202 } 203 204 static int gen_json_printer_union_member(fb_output_t *out, fb_compound_type_t *ct) 205 { 206 fb_symbol_t *sym; 207 fb_member_t *member; 208 fb_scoped_name_t snt, snref; 209 210 fb_clear(snt); 211 fb_clear(snref); 212 fb_compound_name(ct, &snt); 213 214 fprintf(out->fp, 215 "static void %s_print_json_union(flatcc_json_printer_t *ctx, flatcc_json_printer_union_descriptor_t *ud)\n" 216 "{\n switch (ud->type) {\n", 217 snt.text); 218 for (sym = ct->members; sym; sym = sym->link) { 219 member = (fb_member_t *)sym; 220 switch (member->type.type) { 221 case vt_missing: 222 continue; 223 case vt_compound_type_ref: 224 fb_compound_name(member->type.ct, &snref); 225 switch (member->type.ct->symbol.kind) { 226 case fb_is_table: 227 fprintf(out->fp, 228 " case %u:\n" 229 " flatcc_json_printer_union_table(ctx, ud, %s_print_json_table);\n" 230 " break;\n", 231 (unsigned)member->value.u, snref.text); 232 continue; 233 case fb_is_struct: 234 fprintf(out->fp, 235 " case %u:\n" 236 " flatcc_json_printer_union_struct(ctx, ud, %s_print_json_struct);\n" 237 " break;\n", 238 (unsigned)member->value.u, snref.text); 239 continue; 240 default: 241 gen_panic(out, "internal error: unexpected union type\n"); 242 return -1; 243 } 244 case vt_string_type: 245 fprintf(out->fp, 246 " case %u:\n" 247 " flatcc_json_printer_union_string(ctx, ud);\n" 248 " break;\n", 249 (unsigned)member->value.u); 250 continue; 251 default: 252 gen_panic(out, "internal error: unexpected union type\n"); 253 return -1; 254 } 255 } 256 fprintf(out->fp, 257 " default:\n" 258 " break;\n"); 259 fprintf(out->fp, 260 " }\n}\n\n"); 261 return 0; 262 } 263 264 static int gen_json_printer_union(fb_output_t *out, fb_compound_type_t *ct) 265 { 266 gen_json_printer_union_type(out, ct); 267 gen_json_printer_union_member(out, ct); 268 return 0; 269 } 270 271 static int gen_json_printer_struct(fb_output_t *out, fb_compound_type_t *ct) 272 { 273 fb_symbol_t *sym; 274 fb_member_t *member; 275 fb_scoped_name_t snt, snref; 276 int index = 0; 277 const char *tp; 278 279 fb_clear(snt); 280 fb_clear(snref); 281 fb_compound_name(ct, &snt); 282 283 fprintf(out->fp, 284 "static void %s_print_json_struct(flatcc_json_printer_t *ctx, const void *p)\n" 285 "{\n", 286 snt.text); 287 for (sym = ct->members; sym; ++index, sym = sym->link) { 288 member = (fb_member_t *)sym; 289 if (member->metadata_flags & fb_f_deprecated) { 290 continue; 291 } 292 switch (member->type.type) { 293 case vt_scalar_type: 294 tp = scalar_type_prefix(member->type.st); 295 fprintf( 296 out->fp, 297 " flatcc_json_printer_%s_struct_field(ctx, %d, p, %"PRIu64", \"%.*s\", %ld);\n", 298 tp, index, (uint64_t)member->offset, (int)sym->ident->len, sym->ident->text, sym->ident->len); 299 break; 300 case vt_fixed_array_type: 301 tp = scalar_type_prefix(member->type.st); 302 fprintf( 303 out->fp, 304 " flatcc_json_printer_%s_array_struct_field(ctx, %d, p, %"PRIu64", \"%.*s\", %ld, %d);\n", 305 tp, index, (uint64_t)member->offset, (int)sym->ident->len, sym->ident->text, sym->ident->len, member->type.len); 306 break; 307 case vt_fixed_array_compound_type_ref: 308 fb_compound_name(member->type.ct, &snref); 309 switch (member->type.ct->symbol.kind) { 310 case fb_is_enum: 311 #if FLATCC_JSON_PRINT_MAP_ENUMS 312 tp = scalar_type_prefix(member->type.ct->type.st); 313 fprintf(out->fp, 314 " flatcc_json_printer_%s_enum_array_struct_field(ctx, %d, p, %"PRIu64", \"%.*s\", %ld, %d, %s_print_json_enum);\n", 315 tp, index, (uint64_t)member->offset, (int)sym->ident->len, sym->ident->text, sym->ident->len, member->type.len, snref.text); 316 break; 317 #else 318 tp = scalar_type_prefix(member->type.ct->type.st); 319 fprintf( 320 out->fp, 321 " flatcc_json_printer_%s_array_struct_field(ctx, %d, p, %"PRIu64", \"%.*s\", %ld, %d);\n", 322 tp, index, (uint64_t)member->offset, (int)sym->ident->len, sym->ident->text, sym->ident->len, member->type.len); 323 break; 324 #endif 325 case fb_is_struct: 326 fprintf(out->fp, 327 " flatcc_json_printer_embedded_struct_array_field(ctx, %d, p, %"PRIu64", \"%.*s\", %ld, %"PRIu64", %"PRIu64", %s_print_json_struct);\n", 328 index, (uint64_t)member->offset, (int)sym->ident->len, sym->ident->text, sym->ident->len, 329 (uint64_t)member->type.ct->size, (uint64_t)member->type.len, snref.text); 330 } 331 break; 332 case vt_compound_type_ref: 333 fb_compound_name(member->type.ct, &snref); 334 switch (member->type.ct->symbol.kind) { 335 case fb_is_enum: 336 #if FLATCC_JSON_PRINT_MAP_ENUMS 337 tp = scalar_type_prefix(member->type.ct->type.st); 338 fprintf(out->fp, 339 " flatcc_json_printer_%s_enum_struct_field(ctx, %d, p, %"PRIu64", \"%.*s\", %ld, %s_print_json_enum);\n", 340 tp, index, (uint64_t)member->offset, (int)sym->ident->len, sym->ident->text, sym->ident->len, snref.text); 341 break; 342 #else 343 tp = scalar_type_prefix(member->type.ct->type.st); 344 fprintf( 345 out->fp, 346 " flatcc_json_printer_%s_struct_field(ctx, %d, p, %"PRIu64", \"%.*s\", %ld);\n", 347 tp, index, (uint64_t)member->offset, (int)sym->ident->len, sym->ident->text, sym->ident->len); 348 break; 349 #endif 350 case fb_is_struct: 351 fprintf(out->fp, 352 " flatcc_json_printer_embedded_struct_field(ctx, %d, p, %"PRIu64", \"%.*s\", %ld, %s_print_json_struct);\n", 353 index, (uint64_t)member->offset, (int)sym->ident->len, sym->ident->text, sym->ident->len, snref.text); 354 break; 355 } 356 break; 357 } 358 } 359 fprintf(out->fp, "}\n\n"); 360 fprintf(out->fp, 361 "static inline int %s_print_json_as_root(flatcc_json_printer_t *ctx, const void *buf, size_t bufsiz, const char *fid)\n" 362 "{\n return flatcc_json_printer_struct_as_root(ctx, buf, bufsiz, fid, %s_print_json_struct);\n}\n\n", 363 snt.text, snt.text); 364 return 0; 365 } 366 367 static int gen_json_printer_table(fb_output_t *out, fb_compound_type_t *ct) 368 { 369 fb_symbol_t *sym; 370 fb_member_t *member; 371 fb_scoped_name_t snt, snref; 372 const char *tp; 373 int is_optional; 374 int ret = 0; 375 376 fb_clear(snt); 377 fb_clear(snref); 378 fb_compound_name(ct, &snt); 379 380 /* Fields are printed in field id order for consistency across schema version. */ 381 fprintf(out->fp, 382 "static void %s_print_json_table(flatcc_json_printer_t *ctx, flatcc_json_printer_table_descriptor_t *td)\n" 383 "{", 384 snt.text); 385 386 for (sym = ct->members; sym; sym = sym->link) { 387 member = (fb_member_t *)sym; 388 sym = &member->symbol; 389 if (member->metadata_flags & fb_f_deprecated) { 390 continue; 391 } 392 is_optional = !!(member->flags & fb_fm_optional); 393 fprintf(out->fp, "\n "); 394 switch (member->type.type) { 395 case vt_scalar_type: 396 tp = scalar_type_prefix(member->type.st); 397 if (is_optional) { 398 fprintf( out->fp, 399 "flatcc_json_printer_%s_optional_field(ctx, td, %"PRIu64", \"%.*s\", %ld);", 400 tp, member->id, (int)sym->ident->len, sym->ident->text, sym->ident->len); 401 } else { 402 fb_literal_t literal; 403 if (!print_literal(member->type.st, &member->value, literal)) return -1; 404 fprintf( out->fp, 405 "flatcc_json_printer_%s_field(ctx, td, %"PRIu64", \"%.*s\", %ld, %s);", 406 tp, member->id, (int)sym->ident->len, sym->ident->text, sym->ident->len, literal); 407 } 408 break; 409 case vt_vector_type: 410 if (member->metadata_flags & (fb_f_base64 | fb_f_base64url)) { 411 fprintf(out->fp, 412 "flatcc_json_printer_uint8_vector_base64_field(ctx, td, %"PRIu64", \"%.*s\", %ld, %u);", 413 member->id, (int)sym->ident->len, sym->ident->text, sym->ident->len, 414 !(member->metadata_flags & fb_f_base64)); 415 } else if (member->nest) { 416 fb_compound_name((fb_compound_type_t *)&member->nest->symbol, &snref); 417 if (member->nest->symbol.kind == fb_is_table) { 418 /* 419 * Always set fid to 0 since it is difficult to know what is right. 420 * We do know the type from the field attribute. 421 */ 422 fprintf(out->fp, 423 "flatcc_json_printer_table_as_nested_root(ctx, td, %"PRIu64", \"%.*s\", %ld, 0, %s_print_json_table);", 424 member->id, (int)sym->ident->len, sym->ident->text, sym->ident->len, snref.text); 425 } else { 426 /* 427 * Always set fid to 0 since it is difficult to know what is right. 428 * We do know the type from the field attribute. 429 */ 430 fprintf(out->fp, 431 "flatcc_json_printer_struct_as_nested_root(ctx, td, %"PRIu64", \"%.*s\", %ld, 0, %s_print_json_struct);", 432 member->id, (int)sym->ident->len, sym->ident->text, sym->ident->len, snref.text); 433 } 434 } else { 435 tp = scalar_type_prefix(member->type.st); 436 fprintf(out->fp, 437 "flatcc_json_printer_%s_vector_field(ctx, td, %"PRIu64", \"%.*s\", %ld);", 438 tp, member->id, (int)sym->ident->len, sym->ident->text, sym->ident->len); 439 } 440 break; 441 case vt_string_type: 442 fprintf(out->fp, 443 "flatcc_json_printer_string_field(ctx, td, %"PRIu64", \"%.*s\", %ld);", 444 member->id, (int)sym->ident->len, sym->ident->text, sym->ident->len); 445 break; 446 case vt_vector_string_type: 447 fprintf(out->fp, 448 "flatcc_json_printer_string_vector_field(ctx, td, %"PRIu64", \"%.*s\", %ld);", 449 member->id, (int)sym->ident->len, sym->ident->text, sym->ident->len); 450 break; 451 case vt_compound_type_ref: 452 fb_compound_name(member->type.ct, &snref); 453 switch (member->type.ct->symbol.kind) { 454 case fb_is_enum: 455 tp = scalar_type_prefix(member->type.ct->type.st); 456 #if FLATCC_JSON_PRINT_MAP_ENUMS 457 if (is_optional) { 458 fprintf(out->fp, 459 "flatcc_json_printer_%s_enum_optional_field(ctx, td, %"PRIu64", \"%.*s\", %ld, %s_print_json_enum);", 460 tp, member->id, (int)sym->ident->len, sym->ident->text, sym->ident->len, snref.text); 461 } else { 462 fb_literal_t literal; 463 if (!print_literal(member->type.ct->type.st, &member->value, literal)) return -1; 464 fprintf(out->fp, 465 "flatcc_json_printer_%s_enum_field(ctx, td, %"PRIu64", \"%.*s\", %ld, %s, %s_print_json_enum);", 466 tp, member->id, (int)sym->ident->len, sym->ident->text, sym->ident->len, literal, snref.text); 467 } 468 #else 469 if (is_optional) { 470 fprintf( out->fp, 471 "flatcc_json_printer_%s_optional_field(ctx, td, %"PRIu64", \"%.*s\", %ld);", 472 tp, member->id, (int)sym->ident->len, sym->ident->text, sym->ident->len); 473 } else { 474 fb_literal_t literal; 475 if (!print_literal(member->type.ct->type.st, &member->value, literal)) return -1; 476 fprintf( out->fp, 477 "flatcc_json_printer_%s_field(ctx, td, %"PRIu64", \"%.*s\", %ld, %s);", 478 tp, member->id, (int)sym->ident->len, sym->ident->text, sym->ident->len, literal); 479 } 480 #endif 481 break; 482 case fb_is_struct: 483 fprintf(out->fp, 484 "flatcc_json_printer_struct_field(ctx, td, %"PRIu64", \"%.*s\", %ld, %s_print_json_struct);", 485 member->id, (int)sym->ident->len, sym->ident->text, sym->ident->len, snref.text); 486 break; 487 case fb_is_table: 488 fprintf(out->fp, 489 "flatcc_json_printer_table_field(ctx, td, %"PRIu64", \"%.*s\", %ld, %s_print_json_table);", 490 member->id, (int)sym->ident->len, sym->ident->text, sym->ident->len, snref.text); 491 break; 492 case fb_is_union: 493 fprintf(out->fp, 494 "flatcc_json_printer_union_field(ctx, td, %"PRIu64", \"%.*s\", %ld, " 495 "%s_print_json_union_type, %s_print_json_union);", 496 member->id, (int)sym->ident->len, sym->ident->text, sym->ident->len, snref.text, snref.text); 497 break; 498 default: 499 gen_panic(out, "internal error: unexpected compound type for table json_print"); 500 goto fail; 501 } 502 break; 503 case vt_vector_compound_type_ref: 504 fb_compound_name(member->type.ct, &snref); 505 switch (member->type.ct->symbol.kind) { 506 case fb_is_table: 507 fprintf(out->fp, 508 "flatcc_json_printer_table_vector_field(ctx, td, %"PRIu64", \"%.*s\", %ld, %s_print_json_table);", 509 member->id, (int)sym->ident->len, sym->ident->text, sym->ident->len, snref.text); 510 break; 511 case fb_is_enum: 512 tp = scalar_type_prefix(member->type.ct->type.st); 513 #if FLATCC_JSON_PRINT_MAP_ENUMS 514 fprintf(out->fp, 515 "flatcc_json_printer_%s_enum_vector_field(ctx, td, %"PRIu64", \"%.*s\", %ld, %s_print_json_enum);", 516 tp, member->id, (int)sym->ident->len, sym->ident->text, sym->ident->len, snref.text); 517 break; 518 #else 519 fprintf(out->fp, 520 "flatcc_json_printer_%s_vector_field(ctx, td, %"PRIu64", \"%.*s\", %ld);", 521 tp, member->id, (int)sym->ident->len, sym->ident->text, sym->ident->len); 522 break; 523 #endif 524 case fb_is_struct: 525 fprintf(out->fp, 526 "flatcc_json_printer_struct_vector_field(ctx, td, %"PRIu64", \"%.*s\", %ld, %"PRIu64", %s_print_json_struct);", 527 member->id, (int)sym->ident->len, sym->ident->text, sym->ident->len, (uint64_t)member->size, snref.text); 528 break; 529 case fb_is_union: 530 fprintf(out->fp, 531 "flatcc_json_printer_union_vector_field(ctx, td, %"PRIu64", \"%.*s\", %ld, " 532 "%s_print_json_union_type, %s_print_json_union);", 533 member->id, (int)sym->ident->len, sym->ident->text, sym->ident->len, snref.text, snref.text); 534 break; 535 536 default: 537 gen_panic(out, "internal error: unexpected vector compound type for table json_print"); 538 goto fail; 539 } 540 break; 541 } 542 } 543 fprintf(out->fp, "\n}\n\n"); 544 fprintf(out->fp, 545 "static inline int %s_print_json_as_root(flatcc_json_printer_t *ctx, const void *buf, size_t bufsiz, const char *fid)\n" 546 "{\n return flatcc_json_printer_table_as_root(ctx, buf, bufsiz, fid, %s_print_json_table);\n}\n\n", 547 snt.text, snt.text); 548 done: 549 return ret; 550 fail: 551 ret = -1; 552 goto done; 553 } 554 555 /* 556 * Only tables are mutually recursive. Structs are sorted and unions are 557 * defined earlier, depending on the table prototypes. 558 */ 559 static int gen_json_printer_prototypes(fb_output_t *out) 560 { 561 fb_symbol_t *sym; 562 fb_scoped_name_t snt; 563 fb_symbol_t *root_type = out->S->root_type.type; 564 565 fb_clear(snt); 566 567 if (root_type) 568 switch (root_type->kind) { 569 case fb_is_table: 570 case fb_is_struct: 571 fprintf(out->fp, 572 "/*\n" 573 " * Prints the default root table or struct from a buffer which must have\n" 574 " * the schema declared file identifier, if any. It is also possible to\n" 575 " * call the type specific `print_json_as_root` function wich accepts an\n" 576 " * optional identifier (or 0) as argument. The printer `ctx` object must\n" 577 " * be initialized with the appropriate output type, or it can be 0 which\n" 578 " * defaults to stdout. NOTE: `ctx` is not generally allowed to be null, only\n" 579 " * here for a simplified interface.\n" 580 " */\n"); 581 fprintf(out->fp, 582 "static int %s_print_json(flatcc_json_printer_t *ctx, const char *buf, size_t bufsiz);\n\n", 583 out->S->basename); 584 break; 585 default: 586 break; 587 } 588 589 for (sym = out->S->symbols; sym; sym = sym->link) { 590 switch (sym->kind) { 591 case fb_is_union: 592 fb_compound_name((fb_compound_type_t *)sym, &snt); 593 fprintf(out->fp, 594 "static void %s_print_json_union_type(flatcc_json_printer_t *ctx, flatbuffers_utype_t type);\n" 595 "static void %s_print_json_union(flatcc_json_printer_t *ctx, flatcc_json_printer_union_descriptor_t *ud);\n", 596 snt.text, snt.text); 597 break; 598 case fb_is_table: 599 fb_compound_name((fb_compound_type_t *)sym, &snt); 600 fprintf(out->fp, 601 "static void %s_print_json_table(flatcc_json_printer_t *ctx, flatcc_json_printer_table_descriptor_t *td);\n", 602 snt.text); 603 break; 604 case fb_is_struct: 605 fb_compound_name((fb_compound_type_t *)sym, &snt); 606 fprintf(out->fp, 607 "static void %s_print_json_struct(flatcc_json_printer_t *ctx, const void *p);\n", 608 snt.text); 609 break; 610 } 611 } 612 fprintf(out->fp, "\n"); 613 return 0; 614 } 615 616 static int gen_json_printer_enums(fb_output_t *out) 617 { 618 fb_symbol_t *sym; 619 620 for (sym = out->S->symbols; sym; sym = sym->link) { 621 switch (sym->kind) { 622 case fb_is_enum: 623 gen_json_printer_enum(out, (fb_compound_type_t *)sym); 624 } 625 } 626 return 0; 627 } 628 629 static int gen_json_printer_unions(fb_output_t *out) 630 { 631 fb_symbol_t *sym; 632 633 for (sym = out->S->symbols; sym; sym = sym->link) { 634 switch (sym->kind) { 635 case fb_is_union: 636 gen_json_printer_union(out, (fb_compound_type_t *)sym); 637 } 638 } 639 return 0; 640 } 641 642 static int gen_json_printer_structs(fb_output_t *out) 643 { 644 fb_symbol_t *sym; 645 646 for (sym = out->S->symbols; sym; sym = sym->link) { 647 switch (sym->kind) { 648 case fb_is_struct: 649 gen_json_printer_struct(out, (fb_compound_type_t *)sym); 650 } 651 } 652 return 0; 653 } 654 655 static int gen_json_printer_tables(fb_output_t *out) 656 { 657 fb_symbol_t *sym; 658 659 for (sym = out->S->symbols; sym; sym = sym->link) { 660 switch (sym->kind) { 661 case fb_is_table: 662 gen_json_printer_table(out, (fb_compound_type_t *)sym); 663 } 664 } 665 return 0; 666 } 667 668 /* Same for structs and tables. */ 669 static int gen_root_type_printer(fb_output_t *out, fb_compound_type_t *ct) 670 { 671 fb_scoped_name_t snt; 672 673 fb_clear(snt); 674 fb_compound_name(ct, &snt); 675 676 fprintf(out->fp, 677 "static int %s_print_json(flatcc_json_printer_t *ctx, const char *buf, size_t bufsiz)\n", 678 out->S->basename); 679 fprintf(out->fp, 680 "{\n" 681 " flatcc_json_printer_t printer;\n" 682 "\n" 683 " if (ctx == 0) {\n" 684 " ctx = &printer;\n" 685 " flatcc_json_printer_init(ctx, 0);\n" 686 " }\n" 687 " return %s_print_json_as_root(ctx, buf, bufsiz, ", 688 snt.text); 689 if (out->S->file_identifier.type == vt_string) { 690 fprintf(out->fp, 691 "\"%.*s\");\n", 692 out->S->file_identifier.s.len, out->S->file_identifier.s.s); 693 } else { 694 fprintf(out->fp, 695 "0);"); 696 } 697 fprintf(out->fp, 698 "}\n\n"); 699 return 0; 700 } 701 702 static int gen_json_root_printer(fb_output_t *out) 703 { 704 fb_symbol_t *root_type = out->S->root_type.type; 705 706 if (!root_type) { 707 return 0; 708 } 709 if (root_type) { 710 switch (root_type->kind) { 711 case fb_is_table: 712 case fb_is_struct: 713 return gen_root_type_printer(out, (fb_compound_type_t *)root_type); 714 default: 715 break; 716 } 717 } 718 return 0; 719 } 720 721 int fb_gen_c_json_printer(fb_output_t *out) 722 { 723 gen_json_printer_pretext(out); 724 gen_json_printer_prototypes(out); 725 gen_json_printer_enums(out); 726 gen_json_printer_unions(out); 727 gen_json_printer_structs(out); 728 gen_json_printer_tables(out); 729 gen_json_root_printer(out); 730 gen_json_printer_footer(out); 731 return 0; 732 }