/* capnpc-c.c * * Copyright (C) 2013 James McKaskill * * This software may be modified and distributed under the terms * of the MIT license. See the LICENSE file for details. */ #define _POSIX_C_SOURCE 200809L #include "schema.capnp.h" #include "str.h" #include #include #include #include #include #include #ifdef _WIN32 #include #include #endif #if defined(__linux) #define _fileno fileno #endif #define ANNOTATION_NAMESPACE 0xf2c035025fec7c2bUL #define ANNOTATION_FIELDGETSET 0xf72bc690355d66deUL #define ANNOTATION_DONOTINCLUDE 0x8c99797357b357e9UL #define ANNOTATION_TYPEDEFTO 0xcefaf27713042144UL #define ANNOTATION_EXTRAHEADER 0xbadb496d09cf4612UL #define ANNOTATION_EXTENDEDATTRIBUTE 0xd187bca5c6844c24UL #define ANNOTATION_CODECGEN 0xcccaac86283e2609UL #define ANNOTATION_MAPNAME 0xb9edf6fc2d8972b8UL #define ANNOTATION_NAMEINFIX 0x85a8d86d736ba637UL #define ANNOTATION_MAPLISTCOUNT 0xb6ea49eb8a9b0f9eUL #define ANNOTATION_MAPUNIONTAG 0xdce06d41858f91acUL struct value { struct Type t; const char *tname; struct str tname_buf; struct Value v; capn_ptr ptrval; int64_t intval; }; struct field { struct Field f; struct value v; struct node *group; }; struct node { struct capn_tree hdr; struct Node n; struct node *next; struct node *file_nodes, *next_file_node; struct str name; struct field *fields; }; struct id_bst { uint64_t id; struct id_bst *left; struct id_bst *right; }; struct string_list { const char *string; struct string_list *prev; struct string_list *next; }; typedef struct { struct capn capn; struct str HDR; struct str SRC; struct capn_segment g_valseg; struct capn g_valcapn; int g_valc; int g_val0used, g_nullused; int g_fieldgetset; int g_codecgen; struct capn_tree *g_node_tree; CodeGeneratorRequest_ptr root; struct CodeGeneratorRequest req; struct node *file_node; struct node *all_files; struct node *all_structs; struct id_bst *used_import_ids; } capnp_ctx_t; static void fail(int code, char *fmt, ...) { va_list ap; va_start(ap, fmt); vfprintf(stderr, fmt, ap); va_end(ap); exit(code); } static struct node *find_node_mayfail(capnp_ctx_t *ctx, uint64_t id) { struct node *s = (struct node *)ctx->g_node_tree; while (s && s->n.id != id) { s = (struct node *)s->hdr.link[s->n.id < id]; } return s; } static struct node *find_node(capnp_ctx_t *ctx, uint64_t id) { struct node *s = find_node_mayfail(ctx, id); if (s == NULL) { fail(2, "cant find node with id 0x%x%x\n", (uint32_t)(id >> 32), (uint32_t)id); } return s; } static void insert_node(capnp_ctx_t *ctx, struct node *s) { struct capn_tree **x = &(ctx->g_node_tree); while (*x) { s->hdr.parent = *x; x = &(*x)->link[((struct node *)*x)->n.id < s->n.id]; } *x = &s->hdr; ctx->g_node_tree = capn_tree_insert(ctx->g_node_tree, &s->hdr); } /* id_bst implementation */ static struct id_bst *insert_id(struct id_bst *bst, uint64_t id) { struct id_bst **current = &bst; while (*current) { if (id > (*current)->id) { current = &(*current)->right; } else if (id < (*current)->id) { current = &(*current)->left; } else { return bst; } } *current = malloc(sizeof **current); (*current)->id = id; (*current)->left = NULL; (*current)->right = NULL; return bst; } static bool contains_id(struct id_bst *bst, uint64_t id) { struct id_bst *current = bst; while (current) { if (id == current->id) { return true; } else if (id < current->id) { current = current->left; } else { current = current->right; } } return false; } static void free_id_bst(struct id_bst *bst) { if (bst) { free_id_bst(bst->left); free_id_bst(bst->right); free(bst); } } /* string_list implementation */ static struct string_list *insert_file(struct string_list *list, const char *string) { struct string_list **current = &list; struct string_list **prev = NULL; while (*current) { prev = current; current = &(*current)->next; } *current = malloc(sizeof **current); (*current)->string = string; (*current)->prev = prev == NULL ? NULL : *prev; (*current)->next = NULL; return list; } static void free_string_list(struct string_list *list) { if (list) { free_string_list(list->next); free(list); } } static const char *get_text_annotation(Annotation_list l, unsigned long id) { int i; for (i = capn_len(l) - 1; i >= 0; i--) { struct Annotation a; struct Value v; get_Annotation(&a, l, i); read_Value(&v, a.value); if (a.id == id) { if (v.which != Value_text) { fail(2, "annotation is not string"); } return v.text.str; } } return NULL; } static const char *get_mapname(Annotation_list l) { return get_text_annotation(l, ANNOTATION_MAPNAME); } static const char *get_maplistcount(Annotation_list l) { return get_text_annotation(l, ANNOTATION_MAPLISTCOUNT); } static const char *get_mapuniontag(Annotation_list l) { return get_text_annotation(l, ANNOTATION_MAPUNIONTAG); } /* resolve_names recursively follows the nestedNodes tree in order to * set node->name. * It also builds up the list of nodes within a file (file_nodes and * next_file_node). */ static void resolve_names(capnp_ctx_t *ctx, struct str *b, struct node *n, capn_text name, struct node *file, const char *namespace) { int i, sz = b->len; str_add(b, namespace, -1); str_add(b, name.str, name.len); str_add(&n->name, b->str, b->len); str_add(b, "_", 1); for (i = capn_len(n->n.nestedNodes) - 1; i >= 0; i--) { struct Node_NestedNode nest; get_Node_NestedNode(&nest, n->n.nestedNodes, i); struct node *nn = find_node(ctx, nest.id); if (nn != NULL) { resolve_names(ctx, b, nn, nest.name, file, namespace); } } if (n->n.which == Node__struct) { for (i = capn_len(n->n._struct.fields) - 1; i >= 0; i--) { if (n->fields[i].group) { resolve_names(ctx, b, n->fields[i].group, n->fields[i].f.name, file, namespace); } } } if (n->n.which != Node__struct || !n->n._struct.isGroup) { n->next_file_node = file->file_nodes; file->file_nodes = n; } str_setlen(b, sz); } static void define_enum(capnp_ctx_t *ctx, struct node *n) { int i; str_addf(&(ctx->HDR), "\nenum %s {", n->name.str); for (i = 0; i < capn_len(n->n._enum.enumerants); i++) { struct Enumerant e; get_Enumerant(&e, n->n._enum.enumerants, i); if (i) { str_addf(&(ctx->HDR), ","); } str_addf(&(ctx->HDR), "\n\t%s_%s = %d", n->name.str, e.name.str, i); } str_addf(&(ctx->HDR), "\n};\n"); for (i = capn_len(n->n.annotations) - 1; i >= 0; i--) { struct Annotation a; struct Value v; get_Annotation(&a, n->n.annotations, i); read_Value(&v, a.value); switch (a.id) { case ANNOTATION_TYPEDEFTO: if (v.which != Value_text) { fail(2, "schema breakage on $C::typedefto annotation\n"); } str_addf(&(ctx->HDR), "\ntypedef enum %s %s;\n", n->name.str, v.text.str); break; } } } static void decode_value(capnp_ctx_t *ctx, struct value *v, Type_ptr type, Value_ptr value, const char *symbol) { struct Type list_type; memset(v, 0, sizeof(*v)); read_Type(&v->t, type); read_Value(&v->v, value); switch (v->t.which) { case Type__void: v->tname = "void"; break; case Type__bool: v->tname = "unsigned"; break; case Type_int8: v->tname = "int8_t"; break; case Type_int16: v->tname = "int16_t"; break; case Type_int32: v->tname = "int32_t"; break; case Type_int64: v->tname = "int64_t"; break; case Type_uint8: v->tname = "uint8_t"; break; case Type_uint16: v->tname = "uint16_t"; break; case Type_uint32: v->tname = "uint32_t"; break; case Type_uint64: v->tname = "uint64_t"; break; case Type_float32: v->tname = "float"; break; case Type_float64: v->tname = "double"; break; case Type_text: v->tname = "capn_text"; break; case Type_data: v->tname = "capn_data"; break; case Type__enum: v->tname = strf(&v->tname_buf, "enum %s", find_node(ctx, v->t._enum.typeId)->name.str); break; case Type__struct: case Type__interface: v->tname = strf(&v->tname_buf, "%s_ptr", find_node(ctx, v->t._struct.typeId)->name.str); break; case Type_anyPointer: v->tname = "capn_ptr"; break; case Type__list: read_Type(&list_type, v->t._list.elementType); switch (list_type.which) { case Type__void: v->tname = "capn_ptr"; break; case Type__bool: v->tname = "capn_list1"; break; case Type_int8: case Type_uint8: v->tname = "capn_list8"; break; case Type_int16: case Type_uint16: case Type__enum: v->tname = "capn_list16"; break; case Type_int32: case Type_uint32: case Type_float32: v->tname = "capn_list32"; break; case Type_int64: case Type_uint64: case Type_float64: v->tname = "capn_list64"; break; case Type_text: case Type_data: case Type_anyPointer: case Type__list: v->tname = "capn_ptr"; break; case Type__struct: case Type__interface: v->tname = strf(&v->tname_buf, "%s_list", find_node(ctx, list_type._struct.typeId)->name.str); break; } } switch (v->v.which) { case Value__bool: v->intval = v->v._bool; break; case Value_int8: case Value_uint8: v->intval = v->v.int8; break; case Value_int16: case Value_uint16: v->intval = v->v.int16; break; case Value__enum: v->intval = v->v._enum; break; case Value_int32: case Value_uint32: case Value_float32: v->intval = v->v.int32; break; case Value_int64: case Value_float64: case Value_uint64: v->intval = v->v.int64; break; case Value_text: if (v->v.text.len) { capn_ptr p = capn_root(&(ctx->g_valcapn)); if (capn_set_text(p, 0, v->v.text)) { fail(2, "fail to copy text\n"); } p = capn_getp(p, 0, 1); if (!p.type) break; v->ptrval = p; bool symbol_provided = symbol; if (!symbol) { static struct str buf = STR_INIT; v->intval = ++(ctx->g_valc); symbol = strf(&buf, "capn_val%d", (int)v->intval); } str_addf(&(ctx->SRC), "%scapn_text %s = {%d,(char*)&capn_buf[%d],(struct " "capn_segment*)&capn_seg};\n", symbol_provided ? "" : "static ", symbol, p.len - 1, (int)(p.data - p.seg->data - 8)); } break; case Value_data: case Value__struct: case Value_anyPointer: case Value__list: if (v->v.anyPointer.type) { capn_ptr p = capn_root(&(ctx->g_valcapn)); if (capn_setp(p, 0, v->v.anyPointer)) { fail(2, "failed to copy object\n"); } p = capn_getp(p, 0, 1); if (!p.type) break; v->ptrval = p; bool symbol_provided = symbol; if (!symbol) { static struct str buf = STR_INIT; v->intval = ++(ctx->g_valc); symbol = strf(&buf, "capn_val%d", (int)v->intval); } str_addf(&(ctx->SRC), "%s%s %s = {", symbol_provided ? "" : "static ", v->tname, symbol); if (strcmp(v->tname, "capn_ptr")) str_addf(&(ctx->SRC), "{"); str_addf(&(ctx->SRC), "%d,%d,%d,%d,%d,%d,%d,(char*)&capn_buf[%d],(struct " "capn_segment*)&capn_seg", p.type, p.has_ptr_tag, p.is_list_member, p.is_composite_list, p.datasz, p.ptrs, p.len, (int)(p.data - p.seg->data - 8)); if (strcmp(v->tname, "capn_ptr")) str_addf(&(ctx->SRC), "}"); str_addf(&(ctx->SRC), "};\n"); } break; case Value__interface: case Value__void: break; } } static void define_const(capnp_ctx_t *ctx, struct node *n) { struct value v; decode_value(ctx, &v, n->n._const.type, n->n._const.value, n->name.str); switch (v.v.which) { case Value__bool: case Value_int8: case Value_int16: case Value_int32: str_addf(&(ctx->HDR), "extern %s %s;\n", v.tname, n->name.str); str_addf(&(ctx->SRC), "%s %s = %d;\n", v.tname, n->name.str, (int)v.intval); break; case Value_uint8: str_addf(&(ctx->HDR), "extern %s %s;\n", v.tname, n->name.str); str_addf(&(ctx->SRC), "%s %s = %u;\n", v.tname, n->name.str, (uint8_t)v.intval); break; case Value_uint16: str_addf(&(ctx->HDR), "extern %s %s;\n", v.tname, n->name.str); str_addf(&(ctx->SRC), "%s %s = %u;\n", v.tname, n->name.str, (uint16_t)v.intval); break; case Value_uint32: str_addf(&(ctx->HDR), "extern %s %s;\n", v.tname, n->name.str); str_addf(&(ctx->SRC), "%s %s = %uu;\n", v.tname, n->name.str, (uint32_t)v.intval); break; case Value__enum: str_addf(&(ctx->HDR), "extern %s %s;\n", v.tname, n->name.str); str_addf(&(ctx->SRC), "%s %s = (%s) %uu;\n", v.tname, n->name.str, v.tname, (uint32_t)v.intval); break; case Value_int64: case Value_uint64: str_addf(&(ctx->HDR), "extern %s %s;\n", v.tname, n->name.str); str_addf(&(ctx->SRC), "%s %s = ((uint64_t) %#xu << 32) | %#xu;\n", v.tname, n->name.str, (uint32_t)(v.intval >> 32), (uint32_t)v.intval); break; case Value_float32: str_addf(&(ctx->HDR), "extern union capn_conv_f32 %s;\n", n->name.str); str_addf(&(ctx->SRC), "union capn_conv_f32 %s = {%#xu};\n", n->name.str, (uint32_t)v.intval); break; case Value_float64: str_addf(&(ctx->HDR), "extern union capn_conv_f64 %s;\n", n->name.str); str_addf(&(ctx->SRC), "union capn_conv_f64 %s = {((uint64_t) %#xu << 32) | %#xu};\n", n->name.str, (uint32_t)(v.intval >> 32), (uint32_t)v.intval); break; case Value_text: case Value_data: case Value__struct: case Value_anyPointer: case Value__list: str_addf(&(ctx->HDR), "extern %s %s;\n", v.tname, n->name.str); if (!v.ptrval.type) { str_addf(&(ctx->SRC), "%s %s;\n", v.tname, n->name.str); } break; case Value__interface: case Value__void: break; } str_release(&v.tname_buf); } static void decode_field(capnp_ctx_t *ctx, struct field *fields, Field_list l, int i) { struct field f; memset(&f, 0, sizeof(f)); get_Field(&f.f, l, i); if (f.f.codeOrder >= capn_len(l)) { fail(3, "unexpectedly large code order %d >= %d\n", f.f.codeOrder, capn_len(l)); } if (f.f.which == Field_group) { f.group = find_node(ctx, f.f.group.typeId); } memcpy(&fields[f.f.codeOrder], &f, sizeof(f)); } static const char *xor_member(struct field *f) { static struct str buf = STR_INIT; if (f->v.intval) { switch (f->v.v.which) { case Value_int8: case Value_int16: case Value_int32: return strf(&buf, " ^ %d", (int32_t)f->v.intval); case Value_uint8: return strf(&buf, " ^ %uu", (uint8_t)f->v.intval); case Value_uint16: case Value__enum: return strf(&buf, " ^ %uu", (uint16_t)f->v.intval); case Value_uint32: return strf(&buf, " ^ %uu", (uint32_t)f->v.intval); case Value_float32: return strf(&buf, " ^ %#xu", (uint32_t)f->v.intval); case Value_int64: return strf(&buf, " ^ ((int64_t)((uint64_t) %#xu << 32) ^ %#xu)", (uint32_t)(f->v.intval >> 32), (uint32_t)f->v.intval); case Value_uint64: case Value_float64: return strf(&buf, " ^ ((uint64_t) %#xu << 32) ^ %#xu", (uint32_t)(f->v.intval >> 32), (uint32_t)f->v.intval); default: return ""; } } else { return ""; } } static const char *ptr_member(struct field *f, const char *var) { static struct str buf = STR_INIT; if (!strcmp(f->v.tname, "capn_ptr")) { return var; } else if (var[0] == '*') { return strf(&buf, "%s->p", var + 1); } else { return strf(&buf, "%s.p", var); } } static void set_member(capnp_ctx_t *ctx, struct str *func, struct field *f, const char *ptr, const char *tab, const char *var) { const char *xor = xor_member(f); const char *pvar = ptr_member(f, var); if (f->v.t.which == Type__void) return; str_add(func, tab, -1); switch (f->v.t.which) { case Type__bool: str_addf(func, "capn_write1(%s, %d, %s != %d);\n", ptr, f->f.slot.offset, var, (int)f->v.intval); break; case Type_int8: str_addf(func, "capn_write8(%s, %d, (uint8_t) (%s%s));\n", ptr, f->f.slot.offset, var, xor); break; case Type_int16: case Type__enum: str_addf(func, "capn_write16(%s, %d, (uint16_t) (%s%s));\n", ptr, 2 * f->f.slot.offset, var, xor); break; case Type_int32: str_addf(func, "capn_write32(%s, %d, (uint32_t) (%s%s));\n", ptr, 4 * f->f.slot.offset, var, xor); break; case Type_int64: str_addf(func, "capn_write64(%s, %d, (uint64_t) (%s%s));\n", ptr, 8 * f->f.slot.offset, var, xor); break; case Type_uint8: str_addf(func, "capn_write8(%s, %d, %s%s);\n", ptr, f->f.slot.offset, var, xor); break; case Type_uint16: str_addf(func, "capn_write16(%s, %d, %s%s);\n", ptr, 2 * f->f.slot.offset, var, xor); break; case Type_uint32: str_addf(func, "capn_write32(%s, %d, %s%s);\n", ptr, 4 * f->f.slot.offset, var, xor); break; case Type_float32: str_addf(func, "capn_write32(%s, %d, capn_from_f32(%s)%s);\n", ptr, 4 * f->f.slot.offset, var, xor); break; case Type_uint64: str_addf(func, "capn_write64(%s, %d, %s%s);\n", ptr, 8 * f->f.slot.offset, var, xor); break; case Type_float64: str_addf(func, "capn_write64(%s, %d, capn_from_f64(%s)%s);\n", ptr, 8 * f->f.slot.offset, var, xor); break; case Type_text: if (f->v.ptrval.type) { ctx->g_val0used = 1; str_addf(func, "capn_set_text(%s, %d, (%s.str != capn_val%d.str) ? %s : " "capn_val0);\n", ptr, f->f.slot.offset, var, (int)f->v.intval, var); } else { str_addf(func, "capn_set_text(%s, %d, %s);\n", ptr, f->f.slot.offset, var); } break; case Type_data: case Type__struct: case Type__interface: case Type__list: case Type_anyPointer: if (!f->v.intval) { str_addf(func, "capn_setp(%s, %d, %s);\n", ptr, f->f.slot.offset, pvar); } else if (!strcmp(f->v.tname, "capn_ptr")) { ctx->g_nullused = 1; str_addf( func, "capn_setp(%s, %d, (%s.data != capn_val%d.data) ? %s : capn_null);\n", ptr, f->f.slot.offset, pvar, (int)f->v.intval, pvar); } else { ctx->g_nullused = 1; str_addf(func, "capn_setp(%s, %d, (%s.data != capn_val%d.p.data) ? %s : " "capn_null);\n", ptr, f->f.slot.offset, pvar, (int)f->v.intval, pvar); } break; default: break; } } static void get_member(capnp_ctx_t *ctx, struct str *func, struct field *f, const char *ptr, const char *tab, const char *var) { const char *xor = xor_member(f); const char *pvar = ptr_member(f, var); if (f->v.t.which == Type__void) return; str_add(func, tab, -1); switch (f->v.t.which) { case Type__bool: str_addf(func, "%s = (capn_read8(%s, %d) & %d) != %d;\n", var, ptr, f->f.slot.offset / 8, 1 << (f->f.slot.offset % 8), ((int)f->v.intval) << (f->f.slot.offset % 8)); return; case Type_int8: str_addf(func, "%s = (int8_t) ((int8_t)capn_read8(%s, %d))%s;\n", var, ptr, f->f.slot.offset, xor); return; case Type_int16: str_addf(func, "%s = (int16_t) ((int16_t)capn_read16(%s, %d))%s;\n", var, ptr, 2 * f->f.slot.offset, xor); return; case Type_int32: str_addf(func, "%s = (int32_t) ((int32_t)capn_read32(%s, %d))%s;\n", var, ptr, 4 * f->f.slot.offset, xor); return; case Type_int64: str_addf(func, "%s = (int64_t) ((int64_t)(capn_read64(%s, %d))%s);\n", var, ptr, 8 * f->f.slot.offset, xor); return; case Type_uint8: str_addf(func, "%s = capn_read8(%s, %d)%s;\n", var, ptr, f->f.slot.offset, xor); return; case Type_uint16: str_addf(func, "%s = capn_read16(%s, %d)%s;\n", var, ptr, 2 * f->f.slot.offset, xor); return; case Type_uint32: str_addf(func, "%s = capn_read32(%s, %d)%s;\n", var, ptr, 4 * f->f.slot.offset, xor); return; case Type_uint64: str_addf(func, "%s = capn_read64(%s, %d)%s;\n", var, ptr, 8 * f->f.slot.offset, xor); return; case Type_float32: str_addf(func, "%s = capn_to_f32(capn_read32(%s, %d)%s);\n", var, ptr, 4 * f->f.slot.offset, xor); return; case Type_float64: str_addf(func, "%s = capn_to_f64(capn_read64(%s, %d)%s);\n", var, ptr, 8 * f->f.slot.offset, xor); return; case Type__enum: str_addf(func, "%s = (%s)(int) capn_read16(%s, %d)%s;\n", var, f->v.tname, ptr, 2 * f->f.slot.offset, xor); return; case Type_text: if (!f->v.intval) ctx->g_val0used = 1; str_addf(func, "%s = capn_get_text(%s, %d, capn_val%d);\n", var, ptr, f->f.slot.offset, (int)f->v.intval); return; case Type_data: str_addf(func, "%s = capn_get_data(%s, %d);\n", var, ptr, f->f.slot.offset); break; case Type__struct: case Type__interface: case Type_anyPointer: case Type__list: str_addf(func, "%s = capn_getp(%s, %d, 0);\n", pvar, ptr, f->f.slot.offset); break; default: return; } if (f->v.intval) { str_addf(func, "%sif (!%s.type) {\n", tab, pvar); str_addf(func, "%s\t%s = capn_val%d;\n", tab, var, (int)f->v.intval); str_addf(func, "%s}\n", tab); } } static void mk_simple_list_encoder(struct str *func, const char *tab, const char *list_type, const char *setf, const char *dvar, const char *cvar, const char *svar) { str_add(func, tab, -1); str_addf(func, "if (1) {\n"); str_add(func, tab, -1); str_addf(func, "\tint i_;\n"); if (strcmp(list_type, "text") == 0) { str_add(func, tab, -1); str_addf(func, "\td->%s = capn_new_ptr_list(cs, s->%s);\n", dvar, cvar); str_add(func, tab, -1); str_addf(func, "\tfor(i_ = 0; i_ < s->%s; i_ ++) {\n", cvar); str_add(func, tab, -1); str_addf(func, "\t\tcapn_text text_ = {.str = s->%s[i_], .len = " "strlen(s->%s[i_]),.seg " "= NULL};\n", svar, svar); str_add(func, tab, -1); str_addf(func, "\t\tcapn_set_text(d->%s, i_, text_);\n", dvar); str_add(func, tab, -1); str_addf(func, "\t}\n"); } else { str_add(func, tab, -1); str_addf(func, "\td->%s = capn_new_%s(cs, s->%s);\n", dvar, list_type, cvar); str_add(func, tab, -1); str_addf(func, "\tfor(i_ = 0; i_ < s->%s; i_ ++) {\n", cvar); str_add(func, tab, -1); str_addf(func, "\t\tcapn_%s(d->%s, i_, s->%s[i_]);\n", setf, dvar, svar); str_add(func, tab, -1); str_addf(func, "\t}\n"); } str_add(func, tab, -1); str_addf(func, "}\n"); } static void mk_simple_list_decoder(struct str *func, const char *tab, const char *list_type, const char *getf, const char *dvar, const char *cvar, const char *svar) { str_add(func, tab, -1); str_addf(func, "if (1) {\n"); str_add(func, tab, -1); str_addf(func, "\tint i_, nc_;\n"); if (strcmp(list_type, "text") == 0) { str_add(func, tab, -1); str_addf(func, "\tcapn_resolve(&(s->%s));\n", svar); str_add(func, tab, -1); str_addf(func, "\tnc_ = s->%s.len;\n", svar); str_add(func, tab, -1); str_addf(func, "\td->%s = (char **)calloc(nc_, sizeof(char *));\n", dvar); str_add(func, tab, -1); str_addf(func, "\tfor(i_ = 0; i_ < nc_; i_ ++) {\n"); str_add(func, tab, -1); str_addf(func, "\t\tcapn_text text_ = capn_get_text(s->%s, i_, capn_val0);\n", svar); str_add(func, tab, -1); str_addf(func, "\t\td->%s[i_] = strdup(text_.str);\n", dvar); str_add(func, tab, -1); str_addf(func, "\t}\n"); } else { str_add(func, tab, -1); str_addf(func, "\tcapn_resolve(&(s->%s.p));\n", svar); str_add(func, tab, -1); str_addf(func, "\tnc_ = s->%s.p.len;\n", svar); str_add(func, tab, -1); str_addf(func, "\td->%s = (%s *)calloc(nc_, sizeof(%s));\n", dvar, list_type, list_type); str_add(func, tab, -1); str_addf(func, "\tfor(i_ = 0; i_ < nc_; i_ ++) {\n"); str_add(func, tab, -1); str_addf(func, "\t\td->%s[i_] = capn_%s(s->%s, i_);\n", dvar, getf, svar); str_add(func, tab, -1); str_addf(func, "\t}\n"); } str_add(func, tab, -1); str_addf(func, "d->%s = nc_;\n", cvar); str_add(func, tab, -1); str_addf(func, "}\n"); } static void gen_call_list_encoder(capnp_ctx_t *ctx, struct str *func, struct Type *type, const char *tab, const char *var, const char *countvar, const char *var2) { struct node *n = NULL; str_add(func, tab, -1); switch (type->which) { case Type__bool: mk_simple_list_encoder(func, tab, "list1", "set1", var, countvar, var2); break; case Type_int8: case Type_uint8: mk_simple_list_encoder(func, tab, "list8", "set8", var, countvar, var2); break; case Type_int16: case Type_uint16: mk_simple_list_encoder(func, tab, "list16", "set16", var, countvar, var2); break; case Type_int32: case Type_uint32: case Type_float32: mk_simple_list_encoder(func, tab, "list32", "set32", var, countvar, var2); break; case Type_int64: case Type_uint64: case Type_float64: mk_simple_list_encoder(func, tab, "list64", "set64", var, countvar, var2); break; case Type_text: mk_simple_list_encoder(func, tab, "text", NULL, var, countvar, var2); break; case Type__struct: n = find_node(ctx, type->_struct.typeId); if (n != NULL) { char *dtypename = n->name.str; str_addf(func, "encode_%s_list(cs, &(d->%s), s->%s, s->%s);\n", dtypename, var, countvar, var2); } break; } } static void gen_call_list_decoder(capnp_ctx_t *ctx, struct str *func, struct Type *type, const char *tab, const char *var, const char *countvar, const char *var2) { char *t = NULL; struct node *n = NULL; str_add(func, tab, -1); switch (type->which) { case Type__bool: t = "uint8_t"; mk_simple_list_decoder(func, tab, t, "get1", var, countvar, var2); break; case Type_int8: case Type_uint8: if (type->which == Type_int8) { t = "int8_t"; } else { t = "uint8_t"; } mk_simple_list_decoder(func, tab, t, "get8", var, countvar, var2); break; case Type_int16: case Type_uint16: if (type->which == Type_int16) { t = "int16_t"; } else { t = "uint16_t"; } mk_simple_list_decoder(func, tab, t, "get16", var, countvar, var2); break; case Type_int32: case Type_uint32: case Type_float32: if (type->which == Type_int32) { t = "int32_t"; } else if (type->which == Type_uint32) { t = "uint32_t"; } else { t = "float"; } mk_simple_list_decoder(func, tab, t, "get32", var, countvar, var2); break; case Type_int64: case Type_uint64: case Type_float64: if (type->which == Type_int64) { t = "int64_t"; } else if (type->which == Type_uint64) { t = "uint64_t"; } else { t = "double"; } mk_simple_list_decoder(func, tab, t, "get64", var, countvar, var2); break; case Type_text: mk_simple_list_decoder(func, tab, "text", NULL, var, countvar, var2); break; case Type__struct: n = find_node(ctx, type->_struct.typeId); if (n != NULL) { char *dtypename = n->name.str; str_addf(func, "decode_%s_list(&(d->%s), &(d->%s), s->%s);\n", dtypename, countvar, var, var2); } break; } } static void encode_member(capnp_ctx_t *ctx, struct str *func, struct field *f, const char *tab, const char *var, const char *var2) { struct Type list_type; struct node *n = NULL; if (f->v.t.which == Type__void) { return; } if (var2 == NULL) { var2 = var; } switch (f->v.t.which) { case Type__bool: case Type_int8: case Type_int16: case Type_int32: case Type_int64: case Type_uint8: case Type_uint16: case Type_uint32: case Type_uint64: case Type_float32: case Type_float64: case Type__enum: str_add(func, tab, -1); str_addf(func, "d->%s = s->%s;\n", var, var2); break; case Type_text: str_add(func, tab, -1); str_addf(func, "d->%s.str = s->%s;\n", var, var2); str_add(func, tab, -1); str_addf(func, "d->%s.len = strlen(s->%s);\n", var, var2); str_add(func, tab, -1); str_addf(func, "d->%s.seg = NULL;\n", var); break; case Type__struct: n = find_node(ctx, f->v.t._struct.typeId); if (n != NULL) { str_add(func, tab, -1); str_addf(func, "encode_%s_ptr(cs, &(d->%s), s->%s);\n", n->name.str, var, var2); } break; case Type__list: read_Type(&list_type, f->v.t._list.elementType); if (list_type.which != Type__void) { char *name = NULL; char *ncount = NULL; char buf[256]; name = (char *)get_mapname(f->f.annotations); if (name == NULL) { var2 = var; } else { var2 = name; } ncount = (char *)get_maplistcount(f->f.annotations); if (ncount != NULL) { sprintf(buf, "%s", ncount); } else { sprintf(buf, "n_%s", var2); } gen_call_list_encoder(ctx, func, &list_type, tab, var, buf, var2); } break; default: str_add(func, tab, -1); str_addf(func, "\t /* %s %s */\n", var, var2); break; } } static void decode_member(capnp_ctx_t *ctx, struct str *func, struct field *f, const char *tab, const char *var, const char *var2) { struct Type list_type; struct node *n = NULL; if (f->v.t.which == Type__void) { return; } if (var2 == NULL) { var2 = var; } switch (f->v.t.which) { case Type__bool: case Type_int8: case Type_int16: case Type_int32: case Type_int64: case Type_uint8: case Type_uint16: case Type_uint32: case Type_uint64: case Type_float32: case Type_float64: case Type__enum: str_add(func, tab, -1); str_addf(func, "d->%s = s->%s;\n", var2, var); break; case Type_text: str_add(func, tab, -1); str_addf(func, "d->%s = strdup(s->%s.str);\n", var2, var); break; case Type__struct: n = find_node(ctx, f->v.t._struct.typeId); if (n != NULL) { str_add(func, tab, -1); str_addf(func, "decode_%s_ptr(&(d->%s), s->%s);\n", n->name.str, var2, var); } break; case Type__list: read_Type(&list_type, f->v.t._list.elementType); if (list_type.which != Type__void) { char *name = NULL; char *ncount = NULL; char buf[256]; name = (char *)get_mapname(f->f.annotations); if (name == NULL) { var2 = var; } else { var2 = name; } ncount = (char *)get_maplistcount(f->f.annotations); if (ncount != NULL) { sprintf(buf, "%s", ncount); } else { char buf2[256]; char *p; strcpy(buf2, var2); p = strchr(buf2, '.'); if (p != NULL) { *p = 0x0; p++; } strcpy(buf, buf2); if (p != NULL) { strcat(buf, "."); sprintf(&buf[strlen(buf)], "n_%s", p); } } gen_call_list_decoder(ctx, func, &list_type, tab, var2, buf, var); } break; default: str_add(func, tab, -1); str_addf(func, "\t /* %s %s */\n", var2, var); break; } } void mk_struct_list_encoder(capnp_ctx_t *ctx, struct node *n) { if (n == NULL) { return; } if (1) { char *mapname = (char *)get_mapname(n->n.annotations); char buf[256]; if (mapname == NULL) { sprintf(buf, "struct %s_", n->name.str); } else { strcpy(buf, mapname); } str_addf(&(ctx->SRC), "void encode_%s_list(struct capn_segment *cs, %s_list *l,int " "count,%s *s) {\n", n->name.str, n->name.str, buf); str_addf(&(ctx->SRC), "\t%s_list lst;\n", n->name.str); str_addf(&(ctx->SRC), "\tint i;\n"); str_addf(&(ctx->SRC), "\tlst = new_%s_list(cs, count);\n", n->name.str); str_addf(&(ctx->SRC), "\tfor(i = 0; i < count; i ++) {\n"); str_addf(&(ctx->SRC), "\t\tstruct %s d;\n", n->name.str); str_addf(&(ctx->SRC), "\t\tencode_%s(cs, &d, &(s[i]));\n", n->name.str); str_addf(&(ctx->SRC), "\t\tset_%s(&d, lst, i);\n", n->name.str); str_addf(&(ctx->SRC), "\t}\n"); str_addf(&(ctx->SRC), "\t(*l) = lst;\n"); str_addf(&(ctx->SRC), "}\n"); } } void mk_struct_ptr_encoder(capnp_ctx_t *ctx, struct node *n) { char *mapname; char buf[256]; if (n == NULL) { return; } mapname = (char *)get_mapname(n->n.annotations); if (mapname == NULL) { sprintf(buf, "struct %s_", n->name.str); } else { strcpy(buf, mapname); } str_addf(&(ctx->SRC), "void encode_%s_ptr(struct capn_segment *cs, %s_ptr *p," "%s *s) {\n", n->name.str, n->name.str, buf); str_addf(&(ctx->SRC), "\t%s_ptr ptr;\n", n->name.str); str_addf(&(ctx->SRC), "\tstruct %s d;\n", n->name.str); str_addf(&(ctx->SRC), "\tptr = new_%s(cs);\n", n->name.str); str_addf(&(ctx->SRC), "\tencode_%s(cs, &d, s);\n", n->name.str); str_addf(&(ctx->SRC), "\twrite_%s(&d, ptr);\n", n->name.str); str_addf(&(ctx->SRC), "\t(*p) = ptr;\n"); str_addf(&(ctx->SRC), "}\n"); } void mk_struct_list_decoder(capnp_ctx_t *ctx, struct node *n) { if (n == NULL) { return; } if (1) { char *mapname = (char *)get_mapname(n->n.annotations); char buf[256]; if (mapname == NULL) { sprintf(buf, "struct %s_", n->name.str); } else { strcpy(buf, mapname); } str_addf(&(ctx->SRC), "void decode_%s_list(int *pcount, %s **d, %s_list list) {\n", n->name.str, buf, n->name.str); str_addf(&(ctx->SRC), "\tint i;\n"); str_addf(&(ctx->SRC), "\tint nc;\n"); str_addf(&(ctx->SRC), "\t%s *ptr;\n", buf); str_addf(&(ctx->SRC), "\tcapn_resolve(&(list.p));\n"); str_addf(&(ctx->SRC), "\tnc = list.p.len;\n"); str_addf(&(ctx->SRC), "\tptr = (%s *)calloc(nc, sizeof(%s));\n", buf, buf); str_addf(&(ctx->SRC), "\tfor(i = 0; i < nc; i ++) {\n"); str_addf(&(ctx->SRC), "\t\tstruct %s s;\n", n->name.str); str_addf(&(ctx->SRC), "\t\tget_%s(&s, list, i);\n", n->name.str); str_addf(&(ctx->SRC), "\t\tdecode_%s(&(ptr[i]), &s);\n", n->name.str); str_addf(&(ctx->SRC), "\t}\n"); str_addf(&(ctx->SRC), "\t(*d) = ptr;\n"); str_addf(&(ctx->SRC), "\t(*pcount) = nc;\n"); str_addf(&(ctx->SRC), "}\n"); } } void mk_struct_ptr_decoder(capnp_ctx_t *ctx, struct node *n) { char *mapname; char buf[256]; if (n == NULL) { return; } mapname = (char *)get_mapname(n->n.annotations); if (mapname == NULL) { sprintf(buf, "struct %s_", n->name.str); } else { strcpy(buf, mapname); } str_addf(&(ctx->SRC), "void decode_%s_ptr(%s **d," "%s_ptr p) {\n", n->name.str, buf, n->name.str); str_addf(&(ctx->SRC), "\tstruct %s s;\n", n->name.str); str_addf(&(ctx->SRC), "\t*d = (%s *)calloc(1, sizeof(%s));\n", buf, buf); str_addf(&(ctx->SRC), "\tread_%s(&s, p);\n", n->name.str); str_addf(&(ctx->SRC), "\tdecode_%s(*d, &s);\n", n->name.str); str_addf(&(ctx->SRC), "}\n"); } struct strings { struct str ftab; struct str dtab; struct str get; struct str set; struct str encoder; struct str decoder; struct str enums; struct str decl; struct str var; struct str pub_get; struct str pub_get_header; struct str pub_set; struct str pub_set_header; }; static const char *field_name(struct field *f) { static struct str buf = STR_INIT; static const char *reserved[] = { /* C++11 reserved words */ "alignas", "alignof", "and", "and_eq", "asm", "auto", "bitand", "bitor", "bool", "break", "case", "catch", "char", "char16_t", "char32_t", "class", "compl", "const", "constexpr", "const_cast", "continue", "decltype", "default", "delete", "do", "double", "dynamic_cast", "else", "enum", "explicit", "export", "extern", "false", "float", "for", "friend", "goto", "if", "inline", "int", "long", "mutable", "namespace", "new", "noexcept", "not", "not_eq", "nullptr", "operator", "or", "or_eq", "private", "protected", "public", "register", "reinterpret_cast", "return", "short", "signed", "sizeof", "static", "static_assert", "static_cast", "struct", "switch", "template", "this", "thread_local", "throw", "true", "try", "typedef", "typeid", "typename", "union", "unsigned", "using", "virtual", "void", "volatile", "wchar_t", "while", "xor", "xor_eq", /* COM reserved words */ "interface", "module", "import", /* capn reserved otherwise Value_ptr enum and type collide */ "ptr", "list", /* C11 keywords not reserved in C++ */ "restrict", "_Alignas", "_Alignof", "_Atomic", "_Bool", "_Complex", "_Generic", "_Imaginary", "_Noreturn", "_Static_assert", "_Thread_local", /* capn reserved for parameter names */ "p", }; size_t i; const char *s = f->f.name.str; for (i = 0; i < sizeof(reserved) / sizeof(reserved[0]); i++) { if (!strcmp(s, reserved[i])) { return strf(&buf, "_%s", s); } } return s; } static void union_block(capnp_ctx_t *ctx, struct strings *s, struct field *f, const char *u1, const char *u2) { static struct str buf = STR_INIT; str_add(&s->ftab, "\t", -1); set_member(ctx, &s->set, f, "p.p", s->ftab.str, strf(&buf, "%s%s", s->var.str, field_name(f))); get_member(ctx, &s->get, f, "p.p", s->ftab.str, strf(&buf, "%s%s", s->var.str, field_name(f))); str_addf(&s->set, "%sbreak;\n", s->ftab.str); str_addf(&s->get, "%sbreak;\n", s->ftab.str); if (ctx->g_codecgen) { char var1[256]; char var2[256]; char *mapname = (char *)get_mapname(f->f.annotations); if (u2 == NULL) { u2 = u1; } if (mapname == NULL) { mapname = (char *)field_name(f); } if (u1 != NULL) { sprintf(var1, "%s.%s", u1, field_name(f)); sprintf(var2, "%s.%s", u2, mapname); } else { strcpy(var1, field_name(f)); strcpy(var2, mapname); } encode_member(ctx, &s->encoder, f, s->ftab.str, var1, var2); str_addf(&s->encoder, "%sbreak;\n", s->ftab.str); decode_member(ctx, &s->decoder, f, s->ftab.str, var1, var2); str_addf(&s->decoder, "%sbreak;\n", s->ftab.str); } str_setlen(&s->ftab, s->ftab.len - 1); } static int in_union(struct field *f) { return f->f.discriminantValue != 0xFFFF; } static void union_cases(capnp_ctx_t *ctx, struct strings *s, struct node *n, struct field *first_field, int mask) { struct field *f, *u = NULL; for (f = first_field; f < n->fields + capn_len(n->n._struct.fields) && in_union(f); f++) { if (f->f.which != Field_slot) continue; if (f->v.ptrval.type || f->v.intval) continue; if ((mask & (1 << f->v.t.which)) == 0) continue; u = f; str_addf(&s->set, "%scase %s_%s:\n", s->ftab.str, n->name.str, field_name(f)); str_addf(&s->get, "%scase %s_%s:\n", s->ftab.str, n->name.str, field_name(f)); if (ctx->g_codecgen) { str_addf(&s->encoder, "%scase %s_%s:\n", s->ftab.str, n->name.str, field_name(f)); str_addf(&s->decoder, "%scase %s_%s:\n", s->ftab.str, n->name.str, field_name(f)); } if (u) { union_block(ctx, s, u, &(n->n.displayName.str[n->n.displayNamePrefixLength]), NULL); } } } static void declare_slot(struct strings *s, struct field *f) { switch (f->v.t.which) { case Type__void: break; case Type__bool: str_addf(&s->decl, "%s%s %s : 1;\n", s->dtab.str, f->v.tname, field_name(f)); break; default: str_addf(&s->decl, "%s%s %s;\n", s->dtab.str, f->v.tname, field_name(f)); break; } } static void define_group(capnp_ctx_t *ctx, struct strings *s, struct node *n, const char *group_name, bool enclose_unions, const char *extattr, const char *extattr_space); static void do_union(capnp_ctx_t *ctx, struct strings *s, struct node *n, struct field *first_field, const char *union_name, const char *extattr, const char *extattr_space) { int tagoff = 2 * n->n._struct.discriminantOffset; struct field *f; static struct str tag = STR_INIT; struct str enums = STR_INIT; str_reset(&tag); if (union_name) { str_addf(&tag, "%.*s_which", s->var.len - 1, s->var.str); str_addf(&enums, "enum %s_which {", n->name.str); str_addf(&s->decl, "%senum %s_which %s_which;\n", s->dtab.str, n->name.str, union_name); str_addf(&s->get, "%s%s = (enum %s_which)(int) capn_read16(p.p, %d);\n", s->ftab.str, tag.str, n->name.str, tagoff); } else { str_addf(&tag, "%swhich", s->var.str); str_addf(&enums, "enum %s_which {", n->name.str); str_addf(&s->decl, "%senum %s_which which;\n", s->dtab.str, n->name.str); str_addf(&s->get, "%s%s = (enum %s_which)(int) capn_read16(p.p, %d);\n", s->ftab.str, tag.str, n->name.str, tagoff); } str_addf(&s->set, "%scapn_write16(p.p, %d, %s);\n", s->ftab.str, tagoff, tag.str); str_addf(&s->set, "%sswitch (%s) {\n", s->ftab.str, tag.str); str_addf(&s->get, "%sswitch (%s) {\n", s->ftab.str, tag.str); if (ctx->g_codecgen) { char var[256]; char *p = strstr(tag.str, "->"); if (p == NULL) { fail(2, "bad variable"); } sprintf(var, "d%s", p); str_addf(&s->encoder, "%sswitch (%s) {\n", s->ftab.str, var); str_addf(&s->decoder, "%sswitch (%s) {\n", s->ftab.str, tag.str); } /* if we have a bunch of the same C type with zero defaults, we * only need to emit one switch block as the layout will line up * in the C union */ union_cases(ctx, s, n, first_field, (1 << Type__bool)); union_cases(ctx, s, n, first_field, (1 << Type__enum)); union_cases(ctx, s, n, first_field, (1 << Type_int8) | (1 << Type_uint8)); union_cases(ctx, s, n, first_field, (1 << Type_int16) | (1 << Type_uint16)); union_cases(ctx, s, n, first_field, (1 << Type_int32) | (1 << Type_uint32) | (1 << Type_float32)); union_cases(ctx, s, n, first_field, (1 << Type_int64) | (1 << Type_uint64) | (1 << Type_float64)); union_cases(ctx, s, n, first_field, (1 << Type_text)); union_cases(ctx, s, n, first_field, (1 << Type_data)); union_cases(ctx, s, n, first_field, (1 << Type__struct) | (1 << Type__interface) | (1 << Type_anyPointer) | (1 << Type__list)); str_addf(&s->decl, "%scapnp_nowarn union {\n", s->dtab.str); str_add(&s->dtab, "\t", -1); /* when we have defaults or groups we have to emit each case seperately */ for (f = first_field; f < n->fields + capn_len(n->n._struct.fields) && in_union(f); f++) { if (f > first_field) { str_addf(&enums, ","); } str_addf(&enums, "\n\t%s_%s = %d", n->name.str, field_name(f), f->f.discriminantValue); switch (f->f.which) { case Field_group: str_addf(&s->get, "%scase %s_%s:\n", s->ftab.str, n->name.str, field_name(f)); str_addf(&s->set, "%scase %s_%s:\n", s->ftab.str, n->name.str, field_name(f)); str_add(&s->ftab, "\t", -1); // When we add a union inside a union, we need to enclose it in its // own struct so that its members do not overwrite its own // discriminant. define_group(ctx, s, f->group, field_name(f), true, extattr, extattr_space); str_addf(&s->get, "%sbreak;\n", s->ftab.str); str_addf(&s->set, "%sbreak;\n", s->ftab.str); if (ctx->g_codecgen) { str_addf(&s->encoder, "%sbreak;\n", s->ftab.str); str_addf(&s->decoder, "%sbreak;\n", s->ftab.str); } str_setlen(&s->ftab, s->ftab.len - 1); break; case Field_slot: declare_slot(s, f); if (f->v.ptrval.type || f->v.intval) { str_addf(&s->get, "%scase %s_%s:\n", s->ftab.str, n->name.str, field_name(f)); str_addf(&s->set, "%scase %s_%s:\n", s->ftab.str, n->name.str, field_name(f)); if (ctx->g_codecgen) { str_addf(&s->encoder, "%scase %s_%s:\n", s->ftab.str, n->name.str, field_name(f)); str_addf(&s->decoder, "%scase %s_%s:\n", s->ftab.str, n->name.str, field_name(f)); } union_block( ctx, s, f, NULL /*&(n->n.displayName.str[n->n.displayNamePrefixLength]) */, NULL); } break; default: break; } } str_setlen(&s->dtab, s->dtab.len - 1); if (union_name) { str_addf(&s->decl, "%s} %s;\n", s->dtab.str, union_name); } else { str_addf(&s->decl, "%s};\n", s->dtab.str); } str_addf(&s->get, "%sdefault:\n%s\tbreak;\n%s}\n", s->ftab.str, s->ftab.str, s->ftab.str); str_addf(&s->set, "%sdefault:\n%s\tbreak;\n%s}\n", s->ftab.str, s->ftab.str, s->ftab.str); if (ctx->g_codecgen) { str_addf(&s->encoder, "%sdefault:\n%s\tbreak;\n%s}\n", s->ftab.str, s->ftab.str, s->ftab.str); str_addf(&s->decoder, "%sdefault:\n%s\tbreak;\n%s}\n", s->ftab.str, s->ftab.str, s->ftab.str); } str_addf(&enums, "\n};\n"); str_add(&s->enums, enums.str, enums.len); str_release(&enums); } static void define_field(capnp_ctx_t *ctx, struct strings *s, struct field *f, const char *extattr, const char *extattr_space) { static struct str buf = STR_INIT; switch (f->f.which) { case Field_slot: declare_slot(s, f); set_member(ctx, &s->set, f, "p.p", s->ftab.str, strf(&buf, "%s%s", s->var.str, field_name(f))); get_member(ctx, &s->get, f, "p.p", s->ftab.str, strf(&buf, "%s%s", s->var.str, field_name(f))); if (ctx->g_codecgen) { encode_member(ctx, &s->encoder, f, s->ftab.str, field_name(f), get_mapname(f->f.annotations)); decode_member(ctx, &s->decoder, f, s->ftab.str, field_name(f), get_mapname(f->f.annotations)); } break; case Field_group: if (ctx->g_codecgen) { if (f->group != NULL) { int flen = capn_len(f->group->n._struct.fields); int ulen = f->group->n._struct.discriminantCount; if ((ulen == flen) && (ulen > 0)) { if (field_name(f) != NULL) { char *uniontag = (char *)get_mapuniontag(f->f.annotations); char buf[256]; if (uniontag != NULL) { strcpy(buf, uniontag); } else { sprintf(buf, "%s_which", field_name(f)); } str_addf(&s->encoder, "\td->%s_which = s->%s;\n", field_name(f), buf); str_addf(&s->decoder, "\td->%s = s->%s_which;\n", buf, field_name(f)); } } } } define_group(ctx, s, f->group, field_name(f), false, extattr, extattr_space); break; } } static void define_getter_functions(capnp_ctx_t *ctx, struct node *node, struct field *field, struct strings *s, const char *extattr, const char *extattr_space) { /** * define getter */ str_addf(&s->pub_get_header, "\n%s%s%s %s_get_%s(%s_ptr p);\n", extattr, extattr_space, field->v.tname, node->name.str, field_name(field), node->name.str); str_addf(&s->pub_get, "\n%s%s%s %s_get_%s(%s_ptr p)\n", extattr, extattr_space, field->v.tname, node->name.str, field_name(field), node->name.str); struct str getter_body = STR_INIT; get_member(ctx, &getter_body, field, "p.p", "", field_name(field)); str_addf(&s->pub_get, "{\n"); str_addf(&s->pub_get, "%s%s %s;\n", s->ftab.str, field->v.tname, field_name(field)); str_addf(&s->pub_get, "%s%s", s->ftab.str, getter_body.str); str_release(&getter_body); str_addf(&s->pub_get, "%sreturn %s;\n}\n", s->ftab.str, field_name(field)); } static void define_setter_functions(capnp_ctx_t *ctx, struct node *node, struct field *field, struct strings *s, const char *extattr, const char *extattr_space) { str_addf(&s->pub_set_header, "\n%s%svoid %s_set_%s(%s_ptr p, %s %s);\n", extattr, extattr_space, node->name.str, field_name(field), node->name.str, field->v.tname, field_name(field)); str_addf(&s->pub_set, "\n%s%svoid %s_set_%s(%s_ptr p, %s %s)\n", extattr, extattr_space, node->name.str, field_name(field), node->name.str, field->v.tname, field_name(field)); struct str setter_body = STR_INIT; set_member(ctx, &setter_body, field, "p.p", s->ftab.str, field_name(field)); str_addf(&s->pub_set, "{\n%s}\n", setter_body.str); str_release(&setter_body); } static void define_encode_function(capnp_ctx_t *ctx, struct node *node, struct strings *s, const char *extattr, const char *extattr_space) {} static void define_group(capnp_ctx_t *ctx, struct strings *s, struct node *n, const char *group_name, bool enclose_unions, const char *extattr, const char *extattr_space) { struct field *f; int flen = capn_len(n->n._struct.fields); int ulen = n->n._struct.discriminantCount; /* named union is where all group members are in the union */ int named_union = (group_name && ulen == flen && ulen > 0); int named_struct = (group_name && !named_union); int empty = 1; for (f = n->fields; f < n->fields + flen; f++) { decode_value(ctx, &f->v, f->f.slot.type, f->f.slot.defaultValue, NULL); if (f->v.t.which != Type__void) empty = 0; } if (named_struct && empty) { str_addf(&s->decl, "%s/* struct { -empty- } %s; */\n", s->dtab.str, group_name); return; } if (named_struct) { str_addf(&s->decl, "%scapnp_nowarn struct {\n", s->dtab.str); str_add(&s->dtab, "\t", 1); } if (group_name) { str_addf(&s->var, "%s.", group_name); } /* fields before the union members */ for (f = n->fields; f < n->fields + flen && !in_union(f); f++) { define_field(ctx, s, f, extattr, extattr_space); if (!ctx->g_fieldgetset) { continue; } if ((n->n.which == Node__struct && n->n._struct.isGroup)) { // Don't emit in-place getters and setters for groups because they // are defined as anonymous structs inside their parent struct. // We could do it, but nested structs shouldn't be accessed // in-place anyway. continue; } if (f->v.t.which == Type__void) { continue; } define_getter_functions(ctx, n, f, s, extattr, extattr_space); define_setter_functions(ctx, n, f, s, extattr, extattr_space); } if (ulen > 0) { if (enclose_unions) { // When we are already inside a union, so we need to enclose the union // with its disciminant. str_addf(&s->decl, "%scapnp_nowarn struct {\n", s->dtab.str); str_add(&s->dtab, "\t", 1); } const bool keep_union_name = named_union && !enclose_unions; do_union(ctx, s, n, f, keep_union_name ? group_name : NULL, extattr, extattr_space); while (f < n->fields + flen && in_union(f)) f++; /* fields after the unnamed union */ for (; f < n->fields + flen; f++) { define_field(ctx, s, f, extattr, extattr_space); } if (enclose_unions) { str_setlen(&s->dtab, s->dtab.len - 1); str_addf(&s->decl, "%s} %s;\n", s->dtab.str, group_name); } } if (named_struct) { str_setlen(&s->dtab, s->dtab.len - 1); str_addf(&s->decl, "%s} %s;\n", s->dtab.str, group_name); } if (group_name) { str_setlen(&s->var, s->var.len - strlen(group_name) - 1); } } static void define_struct(capnp_ctx_t *ctx, struct node *n, const char *extattr, const char *extattr_space) { static struct strings s; int i; str_reset(&s.dtab); str_reset(&s.ftab); str_reset(&s.get); str_reset(&s.set); str_reset(&s.encoder); str_reset(&s.decoder); str_reset(&s.enums); str_reset(&s.decl); str_reset(&s.var); str_reset(&s.pub_get); str_reset(&s.pub_set); str_reset(&s.pub_get_header); str_reset(&s.pub_set_header); str_add(&s.dtab, "\t", -1); str_add(&s.ftab, "\t", -1); str_add(&s.var, "s->", -1); if (ctx->g_codecgen) { if (n->n._struct.discriminantCount > 0) { const char *uniontag = get_mapuniontag(n->n.annotations); const char *tagname = "which"; if (uniontag != NULL) { tagname = uniontag; } str_addf(&s.encoder, "\td->which = s->%s;\n", tagname); str_addf(&s.decoder, "\td->%s = s->which;\n", tagname); } } define_group(ctx, &s, n, NULL, false, extattr, extattr_space); str_add(&(ctx->HDR), s.enums.str, s.enums.len); str_addf(&(ctx->HDR), "\n%sstruct %s {\n", s.decl.len == 0 ? "capnp_nowarn " : "", n->name.str); str_add(&(ctx->HDR), s.decl.str, s.decl.len); str_addf(&(ctx->HDR), "};\n"); for (i = capn_len(n->n.annotations) - 1; i >= 0; i--) { struct Annotation a; struct Value v; get_Annotation(&a, n->n.annotations, i); read_Value(&v, a.value); switch (a.id) { case ANNOTATION_TYPEDEFTO: if (v.which != Value_text) { fail(2, "schema breakage on $C::typedefto annotation\n"); } str_addf(&(ctx->HDR), "\ntypedef struct %s %s;\n", n->name.str, v.text.str); break; } } str_addf(&(ctx->SRC), "\n%s%s%s_ptr new_%s(struct capn_segment *s) {\n", extattr, extattr_space, n->name.str, n->name.str); str_addf(&(ctx->SRC), "\t%s_ptr p;\n", n->name.str); str_addf(&(ctx->SRC), "\tp.p = capn_new_struct(s, %d, %d);\n", 8 * n->n._struct.dataWordCount, n->n._struct.pointerCount); str_addf(&(ctx->SRC), "\treturn p;\n"); str_addf(&(ctx->SRC), "}\n"); // adding the ability to get the structure size str_addf(&(ctx->HDR), "\nstatic const size_t %s_word_count = %d;\n", n->name.str, n->n._struct.dataWordCount); str_addf(&(ctx->HDR), "\nstatic const size_t %s_pointer_count = %d;\n", n->name.str, n->n._struct.pointerCount); str_addf(&(ctx->HDR), "\nstatic const size_t %s_struct_bytes_count = %d;\n\n", n->name.str, 8 * (n->n._struct.pointerCount + n->n._struct.dataWordCount)); str_addf(&(ctx->SRC), "%s%s%s_list new_%s_list(struct capn_segment *s, int len) {\n", extattr, extattr_space, n->name.str, n->name.str); str_addf(&(ctx->SRC), "\t%s_list p;\n", n->name.str); str_addf(&(ctx->SRC), "\tp.p = capn_new_list(s, len, %d, %d);\n", 8 * n->n._struct.dataWordCount, n->n._struct.pointerCount); str_addf(&(ctx->SRC), "\treturn p;\n"); str_addf(&(ctx->SRC), "}\n"); str_addf(&(ctx->SRC), "%s%svoid read_%s(struct %s *s capnp_unused, %s_ptr p) {\n", extattr, extattr_space, n->name.str, n->name.str, n->name.str); str_addf(&(ctx->SRC), "\tcapn_resolve(&p.p);\n\tcapnp_use(s);\n"); str_add(&(ctx->SRC), s.get.str, s.get.len); str_addf(&(ctx->SRC), "}\n"); str_addf(&(ctx->SRC), "%s%svoid write_%s(const struct %s *s capnp_unused, %s_ptr p) {\n", extattr, extattr_space, n->name.str, n->name.str, n->name.str); str_addf(&(ctx->SRC), "\tcapn_resolve(&p.p);\n\tcapnp_use(s);\n"); str_add(&(ctx->SRC), s.set.str, s.set.len); str_addf(&(ctx->SRC), "}\n"); str_addf(&(ctx->SRC), "%s%svoid get_%s(struct %s *s, %s_list l, int i) {\n", extattr, extattr_space, n->name.str, n->name.str, n->name.str); str_addf(&(ctx->SRC), "\t%s_ptr p;\n", n->name.str); str_addf(&(ctx->SRC), "\tp.p = capn_getp(l.p, i, 0);\n"); str_addf(&(ctx->SRC), "\tread_%s(s, p);\n", n->name.str); str_addf(&(ctx->SRC), "}\n"); str_addf(&(ctx->SRC), "%s%svoid set_%s(const struct %s *s, %s_list l, int i) {\n", extattr, extattr_space, n->name.str, n->name.str, n->name.str); str_addf(&(ctx->SRC), "\t%s_ptr p;\n", n->name.str); str_addf(&(ctx->SRC), "\tp.p = capn_getp(l.p, i, 0);\n"); str_addf(&(ctx->SRC), "\twrite_%s(s, p);\n", n->name.str); str_addf(&(ctx->SRC), "}\n"); if (ctx->g_codecgen) { const char *mapname = get_mapname(n->n.annotations); char buf[256]; if (mapname == NULL) { sprintf(buf, "struct %s_", n->name.str); } else { strcpy(buf, mapname); } str_addf( &(ctx->SRC), "\nvoid encode_%s(struct capn_segment *cs,struct %s *d, %s *s) {\n", n->name.str, n->name.str, buf); str_addf(&(ctx->SRC), "%s\n", s.encoder.str); str_addf(&(ctx->SRC), "}\n"); str_addf(&(ctx->SRC), "\nvoid decode_%s(%s *d, struct %s *s) {\n", n->name.str, buf, n->name.str); str_addf(&(ctx->SRC), "%s\n", s.decoder.str); str_addf(&(ctx->SRC), "}\n"); } str_add(&(ctx->SRC), s.pub_get.str, s.pub_get.len); str_add(&(ctx->SRC), s.pub_set.str, s.pub_set.len); str_add(&(ctx->HDR), s.pub_get_header.str, s.pub_get_header.len); str_add(&(ctx->HDR), s.pub_set_header.str, s.pub_set_header.len); } static void declare(capnp_ctx_t *ctx, struct node *file_node, const char *format, int num) { struct node *n; str_addf(&(ctx->HDR), "\n"); for (n = file_node->file_nodes; n != NULL; n = n->next_file_node) { if (n->n.which == Node__struct && !n->n._struct.isGroup) { switch (num) { case 3: str_addf(&(ctx->HDR), format, n->name.str, n->name.str, n->name.str); break; case 2: str_addf(&(ctx->HDR), format, n->name.str, n->name.str); break; case 1: str_addf(&(ctx->HDR), format, n->name.str); break; } } } } static void declare_ext(capnp_ctx_t *ctx, struct node *file_node, const char *format, int num, const char *extattr, const char *extattr_space) { struct node *n; str_addf(&(ctx->HDR), "\n"); for (n = file_node->file_nodes; n != NULL; n = n->next_file_node) { if (n->n.which == Node__struct && !n->n._struct.isGroup) { switch (num) { case 3: str_addf(&(ctx->HDR), format, extattr, extattr_space, n->name.str, n->name.str, n->name.str); break; case 2: str_addf(&(ctx->HDR), format, extattr, extattr_space, n->name.str, n->name.str); break; case 1: str_addf(&(ctx->HDR), format, extattr, extattr_space, n->name.str); break; } } } } static void mk_codec_declares(capnp_ctx_t *ctx, const char *n1, const char *n2) { str_addf(&(ctx->HDR), "void encode_%s(struct capn_segment *,struct %s *, %s *);\n", n1, n1, n2); str_addf(&(ctx->HDR), "void decode_%s(%s *, struct %s *);\n", n1, n2, n1); str_addf(&(ctx->HDR), "void encode_%s_list(struct capn_segment *,%s_list *, int, %s *);\n", n1, n1, n2); str_addf(&(ctx->HDR), "void decode_%s_list(int *, %s **, %s_list);\n", n1, n2, n1); str_addf(&(ctx->HDR), "void encode_%s_ptr(struct capn_segment*, %s_ptr *, %s *);\n", n1, n1, n2); str_addf(&(ctx->HDR), "void decode_%s_ptr(%s **, %s_ptr);\n", n1, n2, n1); } static void declare_codec(capnp_ctx_t *ctx, struct node *file_node) { struct node *n; str_addf(&(ctx->HDR), "\n"); for (n = file_node->file_nodes; n != NULL; n = n->next_file_node) { if (n->n.which == Node__struct && !n->n._struct.isGroup) { const char *mapname = get_mapname(n->n.annotations); if (mapname == NULL) { mk_codec_declares(ctx, n->name.str, n->name.str); } else { mk_codec_declares(ctx, n->name.str, mapname); } str_addf(&(ctx->HDR), "\n"); } } } int ctx_init(capnp_ctx_t *ctx, FILE *fp) { struct capn_segment *current_seg = NULL; int total_len = 0; int i; struct node *n; memset(ctx, 0x0, sizeof(*ctx)); if (capn_init_fp(&(ctx->capn), fp, 0) < 0) { return -1; } current_seg = ctx->capn.seglist; while (current_seg != NULL) { total_len += current_seg->len; current_seg = current_seg->next; } ctx->g_valseg.data = calloc(1, total_len); ctx->g_valseg.cap = total_len; ctx->root.p = capn_getp(capn_root(&(ctx->capn)), 0, 1); read_CodeGeneratorRequest(&(ctx->req), ctx->root); for (i = 0; i < capn_len(ctx->req.nodes); i++) { n = calloc(1, sizeof(*n)); get_Node(&n->n, ctx->req.nodes, i); insert_node(ctx, n); switch (n->n.which) { case Node_file: n->next = ctx->all_files; ctx->all_files = n; break; case Node__struct: n->next = ctx->all_structs; ctx->all_structs = n; break; default: break; } } for (n = ctx->all_structs; n != NULL; n = n->next) { int j; n->fields = calloc(capn_len(n->n._struct.fields), sizeof(n->fields[0])); for (j = 0; j < capn_len(n->n._struct.fields); j++) { decode_field(ctx, n->fields, n->n._struct.fields, j); } } return 0; } int ctx_resolve_names(capnp_ctx_t *ctx) { struct node *n; int i, j; for (n = ctx->all_files; n != NULL; n = n->next) { struct str b = STR_INIT; const char *namespace = NULL; /* apply name space if present */ for (j = capn_len(n->n.annotations) - 1; j >= 0; j--) { struct Annotation a; struct Value v; get_Annotation(&a, n->n.annotations, j); read_Value(&v, a.value); if (a.id == ANNOTATION_NAMESPACE) { if (v.which != Value_text) { fail(2, "%s: schema breakage on $C::namespace annotation\n", n->n.displayName.str); } if (namespace) { fail(2, "%s: $C::namespace annotation appears more than once.\n", n->n.displayName.str); } namespace = v.text.str ? v.text.str : ""; } } if (!namespace) namespace = ""; for (i = capn_len(n->n.nestedNodes) - 1; i >= 0; i--) { struct Node_NestedNode nest; get_Node_NestedNode(&nest, n->n.nestedNodes, i); struct node *nn = find_node_mayfail(ctx, nest.id); if (nn) { resolve_names(ctx, &b, nn, nest.name, n, namespace); } } str_release(&b); } return 0; } int ctx_mark_used_import(capnp_ctx_t *ctx) { struct node *n; struct node *f; /* find all the used imports */ for (n = ctx->all_structs; n != NULL; n = n->next) { char *display_name = strdup(n->n.displayName.str); char *file_name = strtok(display_name, ":"); if (!file_name) { fail(2, "Unable to determine file name for struct node: %s\n", n->n.displayName.str); } /* find the file node corresponding to the file name */ for (f = ctx->all_files; f != NULL; f = f->next) { if (!strcmp(file_name, f->n.displayName.str)) break; } if (!f) { fail(2, "Unable to find file node with file name: %s\n", file_name); } /* mark this import as used */ if (!contains_id(ctx->used_import_ids, f->n.id)) ctx->used_import_ids = insert_id(ctx->used_import_ids, f->n.id); free(display_name); } return 0; } int ctx_gen(capnp_ctx_t *ctx) { int i, j; struct node *file_node; struct node *n; for (i = 0; i < capn_len(ctx->req.requestedFiles); i++) { struct CodeGeneratorRequest_RequestedFile file_req; static struct str b = STR_INIT; char *p; const char *nameinfix = NULL; FILE *srcf, *hdrf; struct id_bst *donotinclude_ids = NULL; struct string_list *extraheader_strings = NULL; const char *extattr = NULL; const char *extattr_space = ""; ctx->g_valc = 0; ctx->g_valseg.len = 0; ctx->g_val0used = 0; ctx->g_nullused = 0; capn_init_malloc(&(ctx->g_valcapn)); capn_append_segment(&(ctx->g_valcapn), &(ctx->g_valseg)); get_CodeGeneratorRequest_RequestedFile(&file_req, ctx->req.requestedFiles, i); file_node = find_node(ctx, file_req.id); if (file_node == NULL) { fail(2, "invalid file_node specified\n"); } for (j = capn_len(file_node->n.annotations) - 1; j >= 0; j--) { struct Annotation a; struct Value v; get_Annotation(&a, file_node->n.annotations, j); read_Value(&v, a.value); switch (a.id) { case ANNOTATION_NAMEINFIX: /* $C::nameinfix */ if (v.which != Value_text) { fail(2, "schema breakage on $C::nameinfix annotation\n"); } if (nameinfix) { fail(2, "$C::nameinfix annotation appears more than once\n"); } nameinfix = v.text.str ? v.text.str : ""; break; case ANNOTATION_FIELDGETSET: /* $C::fieldgetset */ ctx->g_fieldgetset = 1; break; case ANNOTATION_DONOTINCLUDE: /* $C::donotinclude */ if (v.which != Value_uint64) { fail(2, "schema breakage on $C::donotinclude annotation\n"); } donotinclude_ids = insert_id(donotinclude_ids, v.uint64); break; case ANNOTATION_EXTRAHEADER: /* $C::extraheader("...") */ if (v.which != Value_text) { fail(2, "schema breakage on $C::extraheader annotation\n"); } extraheader_strings = insert_file(extraheader_strings, v.text.str ? v.text.str : ""); break; case ANNOTATION_EXTENDEDATTRIBUTE: /* $C::extendedattribute("...") */ if (v.which != Value_text) { fail(2, "schema breakage on $C::extendedattribute annotation\n"); } if (extattr) { fail(2, "$C::extendedattribute annotation appears more than once\n"); } if (v.text.str && strlen(v.text.str)) { extattr = v.text.str; extattr_space = " "; } break; case ANNOTATION_CODECGEN: ctx->g_codecgen = 1; break; } } if (!nameinfix) nameinfix = ""; if (!extattr) extattr = ""; str_reset(&(ctx->HDR)); str_reset(&(ctx->SRC)); str_addf(&(ctx->HDR), "#ifndef CAPN_%X%X\n", (uint32_t)(file_node->n.id >> 32), (uint32_t)file_node->n.id); str_addf(&(ctx->HDR), "#define CAPN_%X%X\n", (uint32_t)(file_node->n.id >> 32), (uint32_t)file_node->n.id); str_addf(&(ctx->HDR), "/* AUTO GENERATED - DO NOT EDIT */\n"); str_addf(&(ctx->HDR), "#include \n"); /* Do [extraheader] in declaration order. */ struct string_list **current = &extraheader_strings; struct string_list **prev = &extraheader_strings; while (*current) { prev = current; current = &(*current)->next; } current = prev; while (*current) { str_addf(&(ctx->HDR), "%s\n", (*current)->string); current = &(*current)->prev; } str_addf(&(ctx->HDR), "\n"); str_addf(&(ctx->HDR), "#if CAPN_VERSION != 1\n"); str_addf( &(ctx->HDR), "#error \"version mismatch between capnp_c.h and generated code\"\n"); str_addf(&(ctx->HDR), "#endif\n\n"); str_addf(&(ctx->HDR), "#ifndef capnp_nowarn\n" "# ifdef __GNUC__\n" "# define capnp_nowarn __extension__\n" "# else\n" "# define capnp_nowarn\n" "# endif\n" "#endif\n\n"); for (j = 0; j < capn_len(file_req.imports); j++) { struct CodeGeneratorRequest_RequestedFile_Import im; get_CodeGeneratorRequest_RequestedFile_Import(&im, file_req.imports, j); // Check if this import is in the "do not include" list. if (contains_id(donotinclude_ids, im.id)) { continue; } // Check if this import is used at all. if (!contains_id(ctx->used_import_ids, im.id)) { continue; } // Ignore leading slashes when generating C file #include's. // This signifies an absolute import in a library directory. const char *base_path = im.name.str[0] == '/' ? &im.name.str[1] : im.name.str; str_addf(&(ctx->HDR), "#include \"%s%s.h\"\n", base_path, nameinfix); } free_id_bst(ctx->used_import_ids); free_id_bst(donotinclude_ids); free_string_list(extraheader_strings); str_addf(&(ctx->HDR), "\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n"); declare(ctx, file_node, "struct %s;\n", 1); declare(ctx, file_node, "typedef struct {capn_ptr p;} %s_ptr;\n", 1); declare(ctx, file_node, "typedef struct {capn_ptr p;} %s_list;\n", 1); for (n = file_node->file_nodes; n != NULL; n = n->next_file_node) { if (n->n.which == Node__enum) { define_enum(ctx, n); } } for (n = file_node->file_nodes; n != NULL; n = n->next_file_node) { if (n->n.which == Node__const) { define_const(ctx, n); } } for (n = file_node->file_nodes; n != NULL; n = n->next_file_node) { if (n->n.which == Node__struct && !n->n._struct.isGroup) { define_struct(ctx, n, extattr, extattr_space); mk_struct_list_encoder(ctx, n); mk_struct_ptr_encoder(ctx, n); mk_struct_list_decoder(ctx, n); mk_struct_ptr_decoder(ctx, n); } } declare_ext(ctx, file_node, "%s%s%s_ptr new_%s(struct capn_segment*);\n", 2, extattr, extattr_space); declare_ext(ctx, file_node, "%s%s%s_list new_%s_list(struct capn_segment*, int len);\n", 2, extattr, extattr_space); declare_ext(ctx, file_node, "%s%svoid read_%s(struct %s*, %s_ptr);\n", 3, extattr, extattr_space); declare_ext(ctx, file_node, "%s%svoid write_%s(const struct %s*, %s_ptr);\n", 3, extattr, extattr_space); declare_ext(ctx, file_node, "%s%svoid get_%s(struct %s*, %s_list, int i);\n", 3, extattr, extattr_space); declare_ext(ctx, file_node, "%s%svoid set_%s(const struct %s*, %s_list, int i);\n", 3, extattr, extattr_space); if (ctx->g_codecgen) { declare_codec(ctx, file_node); } str_addf(&(ctx->HDR), "\n#ifdef __cplusplus\n}\n#endif\n#endif\n"); /* write out the header */ hdrf = fopen(strf(&b, "%s%s.h", file_node->n.displayName.str, nameinfix), "w"); if (!hdrf) { fail(2, "failed to open %s: %s\n", b.str, strerror(errno)); } fwrite((ctx->HDR).str, 1, (ctx->HDR).len, hdrf); fclose(hdrf); /* write out the source */ srcf = fopen(strf(&b, "%s%s.c", file_node->n.displayName.str, nameinfix), "w"); if (!srcf) { fail(2, "failed to open %s: %s\n", b.str, strerror(errno)); } p = strrchr(file_node->n.displayName.str, '/'); fprintf(srcf, "#include \"%s%s.h\"\n", p ? p + 1 : file_node->n.displayName.str, nameinfix); fprintf(srcf, "/* AUTO GENERATED - DO NOT EDIT */\n"); fprintf(srcf, "#ifdef __GNUC__\n" "# define capnp_unused __attribute__((unused))\n" "# define capnp_use(x) (void) (x);\n" "#else\n" "# define capnp_unused\n" "# define capnp_use(x)\n" "#endif\n\n"); fprintf(srcf, "#include \n" "#include \n"); if (ctx->g_val0used) fprintf(srcf, "static const capn_text capn_val0 = {0,\"\",0};\n"); if (ctx->g_nullused) fprintf(srcf, "static const capn_ptr capn_null = {CAPN_NULL};\n"); if (ctx->g_valseg.len > 8) { size_t k; fprintf(srcf, "static const uint8_t capn_buf[%zu] = {", ctx->g_valseg.len - 8); for (k = 8; k < ctx->g_valseg.len; k++) { if (k > 8) fprintf(srcf, ","); if ((k % 8) == 0) fprintf(srcf, "\n\t"); fprintf(srcf, "%u", ((uint8_t *)ctx->g_valseg.data)[k]); } fprintf(srcf, "\n};\n"); fprintf(srcf, "static const struct capn_segment capn_seg = " "{{0},0,0,0,(char*)&capn_buf[0],%zu,%zu,0};\n", ctx->g_valseg.len - 8, ctx->g_valseg.len - 8); } fwrite((ctx->SRC).str, 1, (ctx->SRC).len, srcf); fclose(srcf); capn_free(&(ctx->g_valcapn)); } return 0; } int main(int argc, char *argv[]) { capnp_ctx_t ctx; FILE *fp = NULL; if (argc > 2) { fail(2, "too many arguments\n"); } else if (argc == 2) { fp = fopen(argv[1], "rb"); if (fp == NULL) { perror("fopen"); return -1; } } else { fp = stdin; } #if defined(_WIN32) if (_setmode(_fileno(fp), _O_BINARY) == -1) { fail(-1, "fail to set stdin to binary mode\n"); } #endif ctx_init(&ctx, fp); ctx_resolve_names(&ctx); ctx_mark_used_import(&ctx); ctx_gen(&ctx); return 0; }