diff --git a/compiler/c.capnp b/compiler/c.capnp index 5dcb6c0..7dcc53b 100644 --- a/compiler/c.capnp +++ b/compiler/c.capnp @@ -55,3 +55,15 @@ annotation extraheader @0xbadb496d09cf4612 (file): Text; annotation extendedattribute @0xd187bca5c6844c24 (file): Text; # add an extended attribute to each generated function + +annotation codecgen @0xcccaac86283e2609 (file): Void; +# generate codec(encode/decode) to each type + +annotation mapname @0xb9edf6fc2d8972b8 (*): Text; +# the mapped type name which will be encoded + +annotation maplistcount @0xb6ea49eb8a9b0f9e (field): Text; +# the mapped list count field which will be encoded + +annotation mapuniontag @0xdce06d41858f91ac (union, struct): Text; +# the mapped tag (which) of union diff --git a/compiler/capnpc-c.c b/compiler/capnpc-c.c index 747ae2a..80de50a 100644 --- a/compiler/capnpc-c.c +++ b/compiler/capnpc-c.c @@ -9,1744 +9,2529 @@ #include "schema.capnp.h" #include "str.h" +#include +#include +#include #include #include #include -#include -#include #ifdef _WIN32 -#include #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 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 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 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; + 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; + const char *string; + struct string_list *prev; + struct string_list *next; }; -static struct str SRC = STR_INIT, HDR = STR_INIT; -static struct capn g_valcapn; -static struct capn_segment g_valseg; -static int g_valc; -static int g_val0used, g_nullused; +typedef struct { + 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 int g_fieldgetset = 0; +static void fail(int code, char *fmt, ...) { + va_list ap; -static struct capn_tree *g_node_tree; + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + va_end(ap); -static struct node *find_node_mayfail(uint64_t id) { - struct node *s = (struct node*) g_node_tree; - while (s && s->n.id != id) { - s = (struct node*) s->hdr.link[s->n.id < id]; - } - return s; + exit(code); } -static struct node *find_node(uint64_t id) -{ - struct node *s = find_node_mayfail(id); - if (s == NULL) { - fprintf(stderr, "cant find node with id 0x%x%x\n", (uint32_t) (id >> 32), (uint32_t) id); - exit(2); - } - return s; +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 void insert_node(struct node *s) { - struct capn_tree **x = &g_node_tree; - while (*x) { - s->hdr.parent = *x; - x = &(*x)->link[((struct node*)*x)->n.id < s->n.id]; - } - *x = &s->hdr; - g_node_tree = capn_tree_insert(g_node_tree, &s->hdr); +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; +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; - } - } + 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; + *current = malloc(sizeof **current); + (*current)->id = id; + (*current)->left = NULL; + (*current)->right = NULL; - return bst; + return bst; } -static bool contains_id(struct id_bst * bst, uint64_t id) -{ - struct id_bst * current = 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; - } - } + while (current) { + if (id == current->id) { + return true; + } else if (id < current->id) { + current = current->left; + } else { + current = current->right; + } + } - return false; + 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); - } +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; +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; - } + while (*current) { + prev = current; + current = &(*current)->next; + } - *current = malloc(sizeof **current); - (*current)->string = string; - (*current)->prev = prev == NULL ? NULL : *prev; - (*current)->next = NULL; + *current = malloc(sizeof **current); + (*current)->string = string; + (*current)->prev = prev == NULL ? NULL : *prev; + (*current)->next = NULL; - return list; + return list; } -static void free_string_list(struct string_list * list) -{ - if (list) - { - free_string_list(list->next); - free(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(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); +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(nest.id); - if (nn != NULL) { - resolve_names(b, nn, nest.name, file, 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(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(b, n->fields[i].group, n->fields[i].f.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; - } + 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); + str_setlen(b, sz); } -static void define_enum(struct node *n) { - int i; +static void define_enum(capnp_ctx_t *ctx, struct node *n) { + int i; - str_addf(&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(&HDR, ","); - } - str_addf(&HDR, "\n\t%s_%s = %d", n->name.str, e.name.str, i); - } - str_addf(&HDR, "\n};\n"); + 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); + 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 0xcefaf27713042144UL: - if (v.which != Value_text) { - fprintf(stderr, "schema breakage on $C::typedefto annotation\n"); - exit(2); - } + switch (a.id) { + case ANNOTATION_TYPEDEFTO: + if (v.which != Value_text) { + fail(2, "schema breakage on $C::typedefto annotation\n"); + } - str_addf(&HDR, "\ntypedef enum %s %s;\n", n->name.str, v.text.str); - break; - } - } + str_addf(&(ctx->HDR), "\ntypedef enum %s %s;\n", n->name.str, v.text.str); + break; + } + } } -static void decode_value(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); +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(v->t._enum.typeId)->name.str); - break; - case Type__struct: - case Type__interface: - v->tname = strf(&v->tname_buf, "%s_ptr", find_node(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 (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(list_type._struct.typeId)->name.str); - break; - } - } + 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(&g_valcapn); - if (capn_set_text(p, 0, v->v.text)) { - fprintf(stderr, "failed to copy text\n"); - exit(2); - } - p = capn_getp(p, 0, 1); - if (!p.type) - 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; + v->ptrval = p; - bool symbol_provided = symbol; - if (!symbol) { - static struct str buf = STR_INIT; - v->intval = ++g_valc; - symbol = strf(&buf, "capn_val%d", (int) v->intval); - } + 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(&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; + 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(&g_valcapn); - if (capn_setp(p, 0, v->v.anyPointer)) { - fprintf(stderr, "failed to copy object\n"); - exit(2); - } - p = capn_getp(p, 0, 1); - if (!p.type) - 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; + v->ptrval = p; - bool symbol_provided = symbol; - if (!symbol) { - static struct str buf = STR_INIT; - v->intval = ++g_valc; - symbol = strf(&buf, "capn_val%d", (int) v->intval); - } + 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(&SRC, "%s%s %s = {", symbol_provided ? "" : "static ", v->tname, symbol); - if (strcmp(v->tname, "capn_ptr")) - str_addf(&SRC, "{"); + 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(&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)); + 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(&SRC, "}"); + if (strcmp(v->tname, "capn_ptr")) + str_addf(&(ctx->SRC), "}"); - str_addf(&SRC, "};\n"); - } - break; + str_addf(&(ctx->SRC), "};\n"); + } + break; - case Value__interface: - case Value__void: - break; - } + case Value__interface: + case Value__void: + break; + } } -static void define_const(struct node *n) { - struct value v; - decode_value(&v, n->n._const.type, n->n._const.value, n->name.str); +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(&HDR, "extern %s %s;\n", v.tname, n->name.str); - str_addf(&SRC, "%s %s = %d;\n", v.tname, n->name.str, (int) v.intval); - break; + 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(&HDR, "extern %s %s;\n", v.tname, n->name.str); - str_addf(&SRC, "%s %s = %u;\n", v.tname, n->name.str, (uint8_t) 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(&HDR, "extern %s %s;\n", v.tname, n->name.str); - str_addf(&SRC, "%s %s = %u;\n", v.tname, n->name.str, (uint16_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(&HDR, "extern %s %s;\n", v.tname, n->name.str); - str_addf(&SRC, "%s %s = %uu;\n", v.tname, n->name.str, (uint32_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(&HDR, "extern %s %s;\n", v.tname, n->name.str); - str_addf(&SRC, "%s %s = (%s) %uu;\n", v.tname, n->name.str, v.tname, (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(&HDR, "extern %s %s;\n", v.tname, n->name.str); - str_addf(&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_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(&HDR, "extern union capn_conv_f32 %s;\n", n->name.str); - str_addf(&SRC, "union capn_conv_f32 %s = {%#xu};\n", n->name.str, (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(&HDR, "extern union capn_conv_f64 %s;\n", n->name.str); - str_addf(&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_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(&HDR, "extern %s %s;\n", v.tname, n->name.str); - if (!v.ptrval.type) { - str_addf(&SRC, "%s %s;\n", v.tname, n->name.str); - } - 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; - } + case Value__interface: + case Value__void: + break; + } - str_release(&v.tname_buf); + str_release(&v.tname_buf); } -static void decode_field(struct field *fields, Field_list l, int i) { - struct field f; - memset(&f, 0, sizeof(f)); - get_Field(&f.f, l, i); +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)) { - fprintf(stderr, "unexpectedly large code order %d >= %d\n", f.f.codeOrder, capn_len(l)); - exit(3); - } + 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(f.f.group.typeId); - } + if (f.f.which == Field_group) { + f.group = find_node(ctx, f.f.group.typeId); + } - memcpy(&fields[f.f.codeOrder], &f, sizeof(f)); + memcpy(&fields[f.f.codeOrder], &f, sizeof(f)); } static const char *xor_member(struct field *f) { - static struct str buf = STR_INIT; + 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); + 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_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_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_uint32: + return strf(&buf, " ^ %uu", (uint32_t)f->v.intval); - case Value_float32: - return strf(&buf, " ^ %#xu", (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); + 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 ""; - } + 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 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(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); +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; + if (f->v.t.which == Type__void) + return; - str_add(func, tab, -1); + 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) { - 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")) { - 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 { - 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; - } + 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(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); +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; + if (f->v.t.which == Type__void) + return; - str_add(func, tab, -1); + 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) - 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; + 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; - } + 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); - } + 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, var2, var); + } + 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, var, buf, var2); + } + 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), "\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 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; + 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", - }; + 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); - } - } + 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; + return s; } -static void union_block(struct strings *s, struct field *f) { - static struct str buf = STR_INIT; - str_add(&s->ftab, "\t", -1); - set_member(&s->set, f, "p.p", s->ftab.str, strf(&buf, "%s%s", s->var.str, field_name(f))); - get_member(&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); - str_setlen(&s->ftab, s->ftab.len-1); +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; + return f->f.discriminantValue != 0xFFFF; } -static void union_cases(struct strings *s, struct node *n, struct field *first_field, int mask) { - struct field *f, *u = NULL; +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++) { + 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; + 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)); - } + 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(s, u); + 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; - } + 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(struct strings *s, struct node *n, const char *group_name, bool enclose_unions, - 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); -static void do_union(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; +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); + 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); - } + 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); + 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 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(s, n, first_field, (1 << Type__bool)); - union_cases(s, n, first_field, (1 << Type__enum)); - union_cases(s, n, first_field, (1 << Type_int8) | (1 << Type_uint8)); - union_cases(s, n, first_field, (1 << Type_int16) | (1 << Type_uint16)); - union_cases(s, n, first_field, (1 << Type_int32) | (1 << Type_uint32) | (1 << Type_float32)); - union_cases(s, n, first_field, (1 << Type_int64) | (1 << Type_uint64) | (1 << Type_float64)); - union_cases(s, n, first_field, (1 << Type_text)); - union_cases(s, n, first_field, (1 << Type_data)); - union_cases(s, n, first_field, (1 << Type__struct) | (1 << Type__interface) | (1 << Type_anyPointer) | (1 << Type__list)); + if (ctx->g_codecgen) { + char var[256]; + char *p = strstr(tag.str, "->"); - str_addf(&s->decl, "%scapnp_nowarn union {\n", s->dtab.str); - str_add(&s->dtab, "\t", -1); + if (p == NULL) { + fail(2, "bad variable"); + } - /* 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, ","); - } + sprintf(var, "d%s", p); - str_addf(&enums, "\n\t%s_%s = %d", n->name.str, field_name(f), f->f.discriminantValue); + str_addf(&s->encoder, "%sswitch (%s) {\n", s->ftab.str, var); + str_addf(&s->decoder, "%sswitch (%s) {\n", s->ftab.str, tag.str); + } - 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(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); - str_setlen(&s->ftab, s->ftab.len-1); - break; + /* 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)); - 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)); - union_block(s, f); - } - break; + str_addf(&s->decl, "%scapnp_nowarn union {\n", s->dtab.str); + str_add(&s->dtab, "\t", -1); - default: - break; - } - } + /* 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_setlen(&s->dtab, s->dtab.len - 1); + str_addf(&enums, "\n\t%s_%s = %d", n->name.str, field_name(f), + f->f.discriminantValue); - 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); - } + 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; - 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); + 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; - str_addf(&enums, "\n};\n"); - str_add(&s->enums, enums.str, enums.len); - str_release(&enums); + 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(struct strings *s, struct field *f, const char* extattr, const char* extattr_space) { - static struct str buf = STR_INIT; +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(&s->set, f, "p.p", s->ftab.str, strf(&buf, "%s%s", s->var.str, field_name(f))); - get_member(&s->get, f, "p.p", s->ftab.str, strf(&buf, "%s%s", s->var.str, field_name(f))); - break; + 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: - define_group(s, f->group, field_name(f), false, extattr, extattr_space); - 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(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(&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_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(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(&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_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_group(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; +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(&f->v, f->f.slot.type, f->f.slot.defaultValue, NULL); - if (f->v.t.which != Type__void) - empty = 0; - } + 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 && 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 (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); - } + 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(s, f, extattr, extattr_space); + /* 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 (!g_fieldgetset) { - continue; - } + 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 ((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; - } + if (f->v.t.which == Type__void) { + continue; + } - define_getter_functions(n, f, s, extattr, extattr_space); - define_setter_functions(n, f, s, extattr, extattr_space); - } + 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); - } + 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; + const bool keep_union_name = named_union && !enclose_unions; - do_union(s, n, f, keep_union_name ? group_name : NULL, extattr, extattr_space); + do_union(ctx, s, n, f, keep_union_name ? group_name : NULL, extattr, + extattr_space); - while (f < n->fields + flen && in_union(f)) - f++; + while (f < n->fields + flen && in_union(f)) + f++; - /* fields after the unnamed union */ - for (;f < n->fields + flen; f++) { - define_field(s, f, extattr, extattr_space); - } + /* 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 (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 (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); - } + if (group_name) { + str_setlen(&s->var, s->var.len - strlen(group_name) - 1); + } } -static void define_struct(struct node *n, const char* extattr, const char* extattr_space) { - static struct strings s; - int i; +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.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_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); + str_add(&s.dtab, "\t", -1); + str_add(&s.ftab, "\t", -1); + str_add(&s.var, "s->", -1); - define_group(&s, n, NULL, false, extattr, extattr_space); + if (ctx->g_codecgen) { + if (n->n._struct.discriminantCount > 0) { + const char *uniontag = get_mapuniontag(n->n.annotations); + const char *tagname = "which"; - str_add(&HDR, s.enums.str, s.enums.len); + if (uniontag != NULL) { + tagname = uniontag; + } - str_addf(&HDR, "\n%sstruct %s {\n", - s.decl.len == 0 ? "capnp_nowarn " : "", - n->name.str); - str_add(&HDR, s.decl.str, s.decl.len); - str_addf(&HDR, "};\n"); + str_addf(&s.encoder, "\td->which = s->%s;\n", tagname); + str_addf(&s.decoder, "\td->%s = s->which;\n", tagname); + } + } - 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); + define_group(ctx, &s, n, NULL, false, extattr, extattr_space); - switch (a.id) { - case 0xcefaf27713042144UL: - if (v.which != Value_text) { - fprintf(stderr, "schema breakage on $C::typedefto annotation\n"); - exit(2); - } + str_add(&(ctx->HDR), s.enums.str, s.enums.len); - str_addf(&HDR, "\ntypedef struct %s %s;\n", n->name.str, v.text.str); - break; - } - } + 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"); - str_addf(&SRC, "\n%s%s%s_ptr new_%s(struct capn_segment *s) {\n", extattr, extattr_space, n->name.str, n->name.str); - str_addf(&SRC, "\t%s_ptr p;\n", n->name.str); - str_addf(&SRC, "\tp.p = capn_new_struct(s, %d, %d);\n", 8*n->n._struct.dataWordCount, n->n._struct.pointerCount); - str_addf(&SRC, "\treturn p;\n"); - str_addf(&SRC, "}\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); - // adding the ability to get the structure size - str_addf(&HDR, "\nstatic const size_t %s_word_count = %d;\n", n->name.str, n->n._struct.dataWordCount); - str_addf(&HDR, "\nstatic const size_t %s_pointer_count = %d;\n", n->name.str, n->n._struct.pointerCount); - str_addf(&HDR, "\nstatic const size_t %s_struct_bytes_count = %d;\n\n", n->name.str, 8 * (n->n._struct.pointerCount + n->n._struct.dataWordCount)); + switch (a.id) { + case ANNOTATION_TYPEDEFTO: + if (v.which != Value_text) { + fail(2, "schema breakage on $C::typedefto annotation\n"); + } - str_addf(&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(&SRC, "\t%s_list p;\n", n->name.str); - str_addf(&SRC, "\tp.p = capn_new_list(s, len, %d, %d);\n", 8*n->n._struct.dataWordCount, n->n._struct.pointerCount); - str_addf(&SRC, "\treturn p;\n"); - str_addf(&SRC, "}\n"); + str_addf(&(ctx->HDR), "\ntypedef struct %s %s;\n", n->name.str, + v.text.str); + break; + } + } - str_addf(&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(&SRC, "\tcapn_resolve(&p.p);\n\tcapnp_use(s);\n"); - str_add(&SRC, s.get.str, s.get.len); - str_addf(&SRC, "}\n"); + 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"); - str_addf(&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(&SRC, "\tcapn_resolve(&p.p);\n\tcapnp_use(s);\n"); - str_add(&SRC, s.set.str, s.set.len); - str_addf(&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(&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(&SRC, "\t%s_ptr p;\n", n->name.str); - str_addf(&SRC, "\tp.p = capn_getp(l.p, i, 0);\n"); - str_addf(&SRC, "\tread_%s(s, p);\n", n->name.str); - str_addf(&SRC, "}\n"); + 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(&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(&SRC, "\t%s_ptr p;\n", n->name.str); - str_addf(&SRC, "\tp.p = capn_getp(l.p, i, 0);\n"); - str_addf(&SRC, "\twrite_%s(s, p);\n", n->name.str); - str_addf(&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_add(&SRC, s.pub_get.str, s.pub_get.len); - str_add(&SRC, s.pub_set.str, s.pub_set.len); + 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_add(&HDR, s.pub_get_header.str, s.pub_get_header.len); - str_add(&HDR, s.pub_set_header.str, s.pub_set_header.len); + 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_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_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); } -#if 0 -/* Commenting out interfaces until the RPC protocol has been spec'd */ -static int find_offset(struct str *v, int inc, uint64_t mask) { - int i, j; - union {uint64_t u; char c[8];} umask; - umask.u = capn_flip64(mask); - for (i = 0; i < v->len*8; i += inc) { - for (j = i; j < i+inc; j++) { - if (((uint8_t*)v->str)[j/8] & (1 << (j%8))) { - goto loop; - } - } - - for (j = i; j < i+inc; j++) { - ((uint8_t*)v->str)[j/8] |= 1 << (j%8); - } - - return j/inc; -loop: - continue; - } - str_add(v, umask.c, 8); - return (v->len-8)/inc; +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 define_method(struct node *iface, int ord) { - static struct str buf = STR_INIT; - struct member *mbrs; - struct InterfaceNode_Method method; - int i, ptrs = 0, datasz; - - get_InterfaceNode_Method(&method, iface->i.methods, ord); - mbrs = calloc(method.params.p.len, sizeof(*mbrs)); - - str_reset(&buf); - - for (i = 0; i < method.params.p.len; i++) { - struct InterfaceNode_Method_Param param; - struct member *m = &mbrs[i]; - - get_InterfaceNode_Method_Param(¶m, method.params, i); - decode_value(&m->v, param.type, param.defaultValue, NULL); - m->m.name = param.name; - m->m.annotations = param.annotations; - m->m.ordinal = i; - - switch (m->v.t.body_tag) { - case Type__void: - break; - case Type__bool: - m->f.offset = find_offset(&buf, 1, 1); - break; - case Type_int8: - case Type_uint8: - m->f.offset = find_offset(&buf, 8, 0xFF); - break; - case Type_int16: - case Type_uint16: - case Type__enum: - m->f.offset = find_offset(&buf, 16, 0xFFFF); - break; - case Type_int32: - case Type_uint32: - case Type_float32: - m->f.offset = find_offset(&buf, 32, 0xFFFFFFFFu); - break; - case Type_int64: - case Type_uint64: - case Type_float64: - m->f.offset = find_offset(&buf, 64, ~((uint64_t) 0)); - break; - case Type_text: - case Type_data: - case Type__list: - case Type__struct: - case Type__interface: - case Type_anyPointer: - m->f.offset = ptrs++; - break; - } - } - - datasz = buf.len; - - - /* write function to initiate a call */ - - str_addf(&HDR, "\nint write_%s_%s(struct capn_msg*", iface->name.str, method.name.str); - str_addf(&SRC, "\nint write_%s_%s(struct capn_msg *m", iface->name.str, method.name.str); - for (i = 0; i < method.params.p.len; i++) { - struct member *m = &mbrs[i]; - str_addf(&HDR, ", %s %s", m->v.tname, m->m.name.str); - str_addf(&SRC, ", %s a%d", m->v.tname, i); - } - str_addf(&HDR, ");\n"); - str_addf(&SRC, ") {\n"); - - str_addf(&SRC, "\tint err = 0;\n"); - str_addf(&SRC, "\tm->method = %d;\n", ord); - str_addf(&SRC, "\tm->iface = ((uint64_t) %#xu << 32) | %#xu;\n", (uint32_t) (iface->n.id >> 32), (uint32_t) iface->n.id); - - if (datasz || ptrs) { - str_addf(&SRC, "\tm->args = capn_new_struct(m->seg, %d, %d);\n", datasz, ptrs); - } else { - g_nullused = 1; - str_addf(&SRC, "\tm->args = capn_null;\n"); - } - - for (i = 0; i < method.params.p.len; i++) { - set_member(&mbrs[i], "m->args", "\t", strf(&buf, "a%d", i)); - } - - str_addf(&SRC, "\treturn err;\n"); - str_addf(&SRC, "}\n"); - - - /* read function to handle a call */ - - if (datasz || ptrs) { - str_addf(&HDR, "void read_%s_%s(struct capn_msg*", iface->name.str, method.name.str); - str_addf(&SRC, "void read_%s_%s(struct capn_msg *m", iface->name.str, method.name.str); - for (i = 0; i < method.params.p.len; i++) { - struct member *m = &mbrs[i]; - str_addf(&HDR, ", %s *%s", m->v.tname, m->m.name.str); - str_addf(&SRC, ", %s *a%d", m->v.tname, i); - } - str_addf(&HDR, ");\n"); - str_addf(&SRC, ") {\n"); - - for (i = 0; i < method.params.p.len; i++) { - get_member(&mbrs[i], "m->args", "\t", strf(&buf, "*a%d", i)); - } - - str_addf(&SRC, "}\n"); - } - - free(mbrs); +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 capn; + struct capn_segment *current_seg = NULL; + int total_len = 0; + int i; + struct node *n; + + memset(ctx, 0x0, sizeof(*ctx)); + if (capn_init_fp(&capn, fp, 0) < 0) { + return -1; + } + + current_seg = 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(&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 + } -static void declare(struct node *file_node, const char *format, int num) { - struct node *n; - str_addf(&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(&HDR, format, n->name.str, n->name.str, n->name.str); - break; - case 2: - str_addf(&HDR, format, n->name.str, n->name.str); - break; - case 1: - str_addf(&HDR, format, n->name.str); - break; - } - } - } -} - -static void declare_ext(struct node *file_node, const char *format, int num, - const char* extattr, const char* extattr_space) { - struct node *n; - str_addf(&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(&HDR, format, extattr, extattr_space, - n->name.str, n->name.str, n->name.str); - break; - case 2: - str_addf(&HDR, format, extattr, extattr_space, - n->name.str, n->name.str); - break; - case 1: - str_addf(&HDR, format, extattr, extattr_space, - n->name.str); - break; - } - } - } -} - -#define ANNOTATION_NAMESPACE 0xf2c035025fec7c2bUL - -int main() { - struct capn capn; - CodeGeneratorRequest_ptr root; - struct CodeGeneratorRequest req; - struct node *file_node, *n, *f; - struct node *all_files = NULL, *all_structs = NULL; - struct id_bst *used_import_ids = NULL; - int i, j; - uint64_t total_len=0; - struct capn_segment *current_seg; - -#ifdef _WIN32 - /* schemas need to be read in binary mode, not default text mode */ - if(_setmode(_fileno( stdin ), _O_BINARY)==-1) { - fprintf(stderr, "failed to set stdin to binary mode\n"); - return -1; - } -#endif - - if (capn_init_fp(&capn, stdin, 0)==-1) { - fprintf(stderr, "failed to read schema from stdin\n"); - return -1; - } - - current_seg = capn.seglist; - do{ - total_len+=current_seg->len; - current_seg = current_seg->next; - }while(current_seg); - - g_valseg.data = calloc(1, total_len); - g_valseg.cap = total_len; - - root.p = capn_getp(capn_root(&capn), 0, 1); - read_CodeGeneratorRequest(&req, root); - - for (i = 0; i < capn_len(req.nodes); i++) { - n = calloc(1, sizeof(*n)); - get_Node(&n->n, req.nodes, i); - insert_node(n); - - switch (n->n.which) { - case Node_file: - n->next = all_files; - all_files = n; - break; - - case Node__struct: - n->next = all_structs; - all_structs = n; - break; - - default: - break; - } - } - - for (n = all_structs; n != NULL; n = n->next) { - 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(n->fields, n->n._struct.fields, j); - } - } - - for (n = 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) { - fprintf(stderr, "%s: schema breakage on $C::namespace annotation\n", - n->n.displayName.str); - exit(2); - } - if (namespace) { - fprintf(stderr, "%s: $C::namespace annotation appears more than once.\n", - n->n.displayName.str); - exit(2); - } - 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(nest.id); - if (nn) { - resolve_names(&b, nn, nest.name, n, namespace); - } - } - - str_release(&b); - } - - /* find all the used imports */ - for (n = all_structs; n != NULL; n = n->next) { - char *display_name = strdup(n->n.displayName.str); - char *file_name = strtok(display_name, ":"); - - if (!file_name) { - fprintf(stderr, "Unable to determine file name for struct node: %s\n", - n->n.displayName.str); - exit(2); - } - - /* find the file node corresponding to the file name */ - for (f = all_files; f != NULL; f = f->next) { - if (!strcmp(file_name, f->n.displayName.str)) - break; - } - - if (!f) { - fprintf(stderr, "Unable to find file node with file name: %s\n", file_name); - exit(2); - } - - /* mark this import as used */ - if (!contains_id(used_import_ids, f->n.id)) - used_import_ids = insert_id(used_import_ids, f->n.id); - - free(display_name); - } - - for (i = 0; i < capn_len(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 = ""; - - g_valc = 0; - g_valseg.len = 0; - g_val0used = 0; - g_nullused = 0; - capn_init_malloc(&g_valcapn); - capn_append_segment(&g_valcapn, &g_valseg); - - get_CodeGeneratorRequest_RequestedFile(&file_req, req.requestedFiles, i); - file_node = find_node(file_req.id); - if (file_node == NULL) { - fprintf(stderr, "invalid file_node specified\n"); - exit(2); - } - - 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 0x85a8d86d736ba637UL: /* $C::nameinfix */ - if (v.which != Value_text) { - fprintf(stderr, "schema breakage on $C::nameinfix annotation\n"); - exit(2); - } - if (nameinfix) { - fprintf(stderr, "$C::nameinfix annotation appears more than once\n"); - exit(2); - } - nameinfix = v.text.str ? v.text.str : ""; - break; - case 0xf72bc690355d66deUL: /* $C::fieldgetset */ - g_fieldgetset = 1; - break; - case 0x8c99797357b357e9UL: /* $C::donotinclude */ - if (v.which != Value_uint64) - { - fprintf(stderr, "schema breakage on $C::donotinclude annotation\n"); - exit(2); - } - donotinclude_ids = insert_id(donotinclude_ids, v.uint64); - break; - case 0xbadb496d09cf4612UL: /* $C::extraheader("...") */ - if (v.which != Value_text) - { - fprintf(stderr, "schema breakage on $C::extraheader annotation\n"); - exit(2); - } - extraheader_strings = insert_file(extraheader_strings, v.text.str ? v.text.str : ""); - break; - case 0xd187bca5c6844c24UL: /* $C::extendedattribute("...") */ - if (v.which != Value_text) - { - fprintf(stderr, "schema breakage on $C::extendedattribute annotation\n"); - exit(2); - } - if (extattr) { - fprintf(stderr, "$C::extendedattribute annotation appears more than once\n"); - exit(2); - } - if (v.text.str && strlen(v.text.str)) { - extattr = v.text.str; - extattr_space = " "; - } - break; - } - } - if (!nameinfix) - nameinfix = ""; - if (!extattr) - extattr = ""; - - str_reset(&HDR); - str_reset(&SRC); - - str_addf(&HDR, "#ifndef CAPN_%X%X\n", (uint32_t) (file_node->n.id >> 32), (uint32_t) file_node->n.id); - str_addf(&HDR, "#define CAPN_%X%X\n", (uint32_t) (file_node->n.id >> 32), (uint32_t) file_node->n.id); - str_addf(&HDR, "/* AUTO GENERATED - DO NOT EDIT */\n"); - str_addf(&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(&HDR, "%s\n", (*current)->string); - current = &(*current)->prev; - } - str_addf(&HDR, "\n"); - - str_addf(&HDR, "#if CAPN_VERSION != 1\n"); - str_addf(&HDR, "#error \"version mismatch between capnp_c.h and generated code\"\n"); - str_addf(&HDR, "#endif\n\n"); - str_addf(&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(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(&HDR, "#include \"%s%s.h\"\n", base_path, nameinfix); - } - - free_id_bst(used_import_ids); - free_id_bst(donotinclude_ids); - free_string_list(extraheader_strings); - - str_addf(&HDR, "\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n"); - - declare(file_node, "struct %s;\n", 1); - declare(file_node, "typedef struct {capn_ptr p;} %s_ptr;\n", 1); - declare(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(n); - } - } - - for (n = file_node->file_nodes; n != NULL; n = n->next_file_node) { - if (n->n.which == Node__const) { - define_const(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(n, extattr, extattr_space); - } - } - - declare_ext(file_node, "%s%s%s_ptr new_%s(struct capn_segment*);\n", 2, extattr, extattr_space); - declare_ext(file_node, "%s%s%s_list new_%s_list(struct capn_segment*, int len);\n", 2, extattr, extattr_space); - declare_ext(file_node, "%s%svoid read_%s(struct %s*, %s_ptr);\n", 3, extattr, extattr_space); - declare_ext(file_node, "%s%svoid write_%s(const struct %s*, %s_ptr);\n", 3, extattr, extattr_space); - declare_ext(file_node, "%s%svoid get_%s(struct %s*, %s_list, int i);\n", 3, extattr, extattr_space); - declare_ext(file_node, "%s%svoid set_%s(const struct %s*, %s_list, int i);\n", 3, extattr, extattr_space); - - str_addf(&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) { - fprintf(stderr, "failed to open %s: %s\n", b.str, strerror(errno)); - exit(2); - } - fwrite(HDR.str, 1, 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) { - fprintf(stderr, "failed to open %s: %s\n", b.str, strerror(errno)); - exit(2); - } - 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"); - - - if (g_val0used) - fprintf(srcf, "static const capn_text capn_val0 = {0,\"\",0};\n"); - if (g_nullused) - fprintf(srcf, "static const capn_ptr capn_null = {CAPN_NULL};\n"); - - if (g_valseg.len > 8) { - size_t k; - fprintf(srcf, "static const uint8_t capn_buf[%zu] = {", g_valseg.len-8); - for (k = 8; k < g_valseg.len; k++) { - if (k > 8) - fprintf(srcf, ","); - if ((k % 8) == 0) - fprintf(srcf, "\n\t"); - fprintf(srcf, "%u", ((uint8_t*)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", - g_valseg.len-8, g_valseg.len-8); - } - - fwrite(SRC.str, 1, SRC.len, srcf); - fclose(srcf); - - capn_free(&g_valcapn); - } - - return 0; + ctx_init(&ctx, fp); + + ctx_resolve_names(&ctx); + + ctx_mark_used_import(&ctx); + + ctx_gen(&ctx); + + return 0; } diff --git a/examples/book/book.capnp b/examples/book/book.capnp new file mode 100644 index 0000000..23c3f47 --- /dev/null +++ b/examples/book/book.capnp @@ -0,0 +1,28 @@ +@0xf9ffb48dde27c0e6; + +using C = import "/c.capnp"; +$C.fieldgetset; +$C.codecgen; +$C.extraheader("#include "); + +struct Chapter $C.mapname("chapter_t") { + caption @0: Text; + start @1: UInt32; + end @2: UInt32; +} + +struct Publish $C.mapname("publish_t") { + isbn @0: UInt64; + year @1: UInt32; +} +struct Book $C.mapname("book_t") { + title @0: Text; + authors @1: List(Text) $C.mapname("authors") $C.maplistcount("n_authors"); + chapters @5: List(Chapter) $C.maplistcount("n_chapters"); + publish @6: Publish; + magic1 @2: List(UInt32) $C.maplistcount("n_magic1"); + acquire :union $C.mapuniontag("acquire_method") { + buy @3: Text; + donation @4: Text; + } +} diff --git a/examples/book/book.h b/examples/book/book.h new file mode 100644 index 0000000..36decc9 --- /dev/null +++ b/examples/book/book.h @@ -0,0 +1,35 @@ +#if !defined(_BOOK_H_) + +#define _BOOK_H_ 1 + +#include +#include + +typedef struct { + char *caption; + int32_t start; + int32_t end; +} chapter_t; + +typedef struct { + uint64_t isbn; + uint32_t year; +} publish_t; + +typedef struct { + char *title; + int n_authors; + char **authors; + int n_chapters; + chapter_t *chapters; + publish_t publish; + int n_magic1; + uint32_t *magic1; + int acquire_method; + union { + char *buy; + char *donation; + } acquire; +} book_t; + +#endif diff --git a/examples/book/test.c b/examples/book/test.c new file mode 100644 index 0000000..d4c03c4 --- /dev/null +++ b/examples/book/test.c @@ -0,0 +1,128 @@ +#include +#include + +#include "book.capnp.h" +#include "book.h" + +static void usage(char *app) { + fprintf(stderr, "usage: %s encode | %s decode\n", + app); +} + +int encode() { + struct capn c; + book_t book; + char *title = "Book title"; + char *authors[2] = { + "author1", + "author2" + }; + uint32_t magic1[2] = { + 1101,1012 + }; + chapter_t chapters[3] = { + {.caption ="Chapter1", + .start =1, + .end=99}, + {.caption = "Chapter2", + .start = 100, + .end = 150}, + {.caption = "Chapter3", + .start = 151, + .end=199} + }; + publish_t publish = { + .isbn = 335677, + .year =2001 + }; + struct capn_segment *cs; + struct Book b; + Book_ptr p; + + book.title = title; + book.n_authors = 2; + book.authors = authors; + book.n_chapters = 3; + book.chapters = &chapters[0]; + memcpy(&(book.publish), &publish, sizeof(publish)); + book.n_magic1 = 2; + book.magic1 = &magic1[0]; + book.acquire_method = Book_acquire_buy; + book.acquire.buy = "bought from Xinhua book store"; + + capn_init_malloc(&c); + cs = capn_root(&c).seg; + + encode_Book_ptr(cs, &p, &book); + + capn_setp(capn_root(&c), 0, p.p); + + capn_write_fd(&c, write, 1, 0); + + capn_free(&c); + + return 0; +} + +int decode() { + struct capn c; + Book_ptr p; + book_t book; + int i; + + capn_init_fp(&c, stdin, 0); + p.p = capn_getp(capn_root(&c), 0, 1); + + decode_Book_ptr(&book, p); + + printf("title: %s\n", book.title); + + printf("authors(%d):\n", book.n_authors); + + for(i = 0; i < book.n_authors; i ++) { + printf("\t%s\n", book.authors[i]); + } + + printf("chapters(%d):\n", book.n_chapters); + for(i = 0; i < book.n_chapters; i ++) { + printf("\tcaption: %s\n", book.chapters[i].caption); + printf("\tfrom %d to %d\n", + book.chapters[i].start, + book.chapters[i].end); + } + + printf("ISBN: %lu year: %u\n", + book.publish.isbn, + book.publish.year); + + printf("magic1:\n"); + for(i = 0; i < book.n_magic1; i ++) { + printf("\t%d\n", book.magic1[i]); + } + + if (book.acquire_method == Book_acquire_buy) { + printf("%s\n", book.acquire.buy); + } + else { + printf("%s\n", book.acquire.donation); + } + + return 0; +} + +int main(int argc,char *argv[]) { + + if (argc != 2) { + usage(argv[0]); + return -1; + } + + if ( strcmp(argv[1],"encode") == 0) { + encode(); + } + else { + decode(); + } + + return 0; +}