diff --git a/Makefile b/Makefile index 9531ab7..74d6212 100644 --- a/Makefile +++ b/Makefile @@ -14,7 +14,7 @@ clean: capn.so: capn-malloc.o capn-stream.o capn.o $(CC) -shared $(LDFLAGS) $^ -o $@ -capnpc-c: compiler/capnpc-c.o compiler/schema.capnp.o capn.so +capnpc-c: compiler/capnpc-c.o compiler/schema.capnp.o compiler/str.o capn.so $(CC) $(LDFLAGS) $^ -o $@ test: capn-test diff --git a/compiler/capnpc-c.c b/compiler/capnpc-c.c index 45650c6..e5cfef3 100644 --- a/compiler/capnpc-c.c +++ b/compiler/capnpc-c.c @@ -1,34 +1,603 @@ #include "schema.capnp.h" +#include "str.h" +#include +#include +#include -struct scope { +struct node { struct capn_tree hdr; - struct scope *enclosing; - capn_text name; - uint64_t id; + struct Node n; + struct node *next; + struct node *first_child, *next_child; + struct str name; + union { + struct StructNode structNode; + struct EnumNode enumNode; + struct InterfaceNode interfaceNode; + struct ConstNode constNode; + struct FileNode fileNode; + } u; }; -struct scope *find_scope(struct scope *s, uint64_t id) { - while (s && s->id != id) { - s = (struct scope*) s->hdr.link[s->id < id]; +static struct node *g_files; +static FILE *HDR, *SRC; + +static struct capn_tree *g_node_tree; + +struct node *find_node(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]; + } + if (s == NULL) { + fprintf(stderr, "cant find node with id %#llx\n", id); + exit(2); } return s; } -struct capn_tree *insert_scope(struct capn_tree *root, struct scope *s) { - struct capn_tree **x = &root; +static void insert_node(struct node *s) { + struct capn_tree **x = &g_node_tree; while (*x) { s->hdr.parent = *x; - x = &(*x)->link[((struct scope*)*x)->id < s->id]; + x = &(*x)->link[((struct node*)*x)->n.id < s->n.id]; } *x = &s->hdr; - return capn_tree_insert(root, &s->hdr); + g_node_tree = capn_tree_insert(g_node_tree, &s->hdr); } +static void resolve_names(struct str *b, struct node *n, capn_text name, struct node *file) { + int i, sz = b->len; + str_add(b, name.str, name.len); + str_add(&n->name, b->str, b->len); + str_add(b, "_", 1); + + for (i = n->n.nestedNodes.p.len-1; i >= 0; i--) { + struct Node_NestedNode nest; + get_Node_NestedNode(&nest, n->n.nestedNodes, i); + resolve_names(b, find_node(nest.id), nest.name, file); + } + + n->next_child = file->first_child; + file->first_child = n; + str_setlen(b, sz); +} + +static void define_enum(struct node *n) { + int i; + + fprintf(HDR, "\nenum %s {", n->name.str); + for (i = 0; i < n->u.enumNode.enumerants.p.len; i++) { + struct EnumNode_Enumerant ee; + get_EnumNode_Enumerant(&ee, n->u.enumNode.enumerants, i); + if (i) { + fprintf(HDR, ","); + } + fprintf(HDR, "\n\t%s_%s = %d", n->name.str, ee.name.str, i); + } + fprintf(HDR, "\n};\n"); +} + +struct member { + unsigned int is_valid : 1; + struct StructNode_Member m; + struct StructNode_Field f; + struct StructNode_Union u; + struct Type t; + struct Value v; + struct node *type; + struct Type list; + struct member *mbrs; + int idx; +}; + +static void set_member(FILE *f, struct member *m, const char *tab, const char *var) { + if (m->t.body_tag == Type_voidType) + return; + + fputs(tab, f); + + switch (m->t.body_tag) { + case Type_voidType: + break; + case Type_boolType: + fprintf(f, "err = err || capn_write1(p.p, %d, %s);\n", m->f.offset, var); + break; + case Type_int8Type: + fprintf(f, "err = err || capn_write8(p.p, %d, (uint8_t) %s);\n", m->f.offset, var); + break; + case Type_int16Type: + case Type_enumType: + fprintf(f, "err = err || capn_write16(p.p, %d, (uint16_t) %s);\n", 2*m->f.offset, var); + break; + case Type_int32Type: + fprintf(f, "err = err || capn_write32(p.p, %d, (uint32_t) %s);\n", 4*m->f.offset, var); + break; + case Type_int64Type: + fprintf(f, "err = err || capn_write64(p.p, %d, (uint64_t) %s);\n", 8*m->f.offset, var); + break; + case Type_uint8Type: + fprintf(f, "err = err || capn_write8(p.p, %d, %s);\n", m->f.offset, var); + break; + case Type_uint16Type: + fprintf(f, "err = err || capn_write16(p.p, %d, %s);\n", 2*m->f.offset, var); + break; + case Type_uint32Type: + fprintf(f, "err = err || capn_write32(p.p, %d, %s);\n", 4*m->f.offset, var); + break; + case Type_uint64Type: + fprintf(f, "err = err || capn_write64(p.p, %d, %s);\n", 8*m->f.offset, var); + break; + case Type_float32Type: + fprintf(f, "err = err || capn_write_float(p.p, %d, %s, 0.0f);\n", 4*m->f.offset, var); + break; + case Type_float64Type: + fprintf(f, "err = err || capn_write_double(p.p, %d, %s, 0.0);\n", 4*m->f.offset, var); + break; + case Type_textType: + fprintf(f, "err = err || capn_set_text(p.p, %d, %s);\n", m->f.offset, var); + break; + case Type_dataType: + fprintf(f, "err = err || capn_set_data(p.p, %d, %s);\n", m->f.offset, var); + break; + case Type_structType: + case Type_interfaceType: + fprintf(f, "err = err || capn_setp(p.p, %d, %s.p);\n", m->f.offset, var); + break; + case Type_objectType: + fprintf(f, "err = err || capn_setp(p.p, %d, %s);\n", m->f.offset, var); + break; + case Type_listType: + switch (m->list.body_tag) { + case Type_boolType: + case Type_int8Type: + case Type_uint8Type: + case Type_int16Type: + case Type_uint16Type: + case Type_enumType: + case Type_int32Type: + case Type_uint32Type: + case Type_int64Type: + case Type_uint64Type: + case Type_float32Type: + case Type_float64Type: + case Type_structType: + case Type_interfaceType: + fprintf(f, "err = err || capn_setp(p.p, %d, %s.p);\n", m->f.offset, var); + break; + case Type_voidType: + case Type_textType: + case Type_dataType: + case Type_objectType: + case Type_listType: + fprintf(f, "err = err || capn_setp(p.p, %d, %s);\n", m->f.offset, var); + break; + } + } +} + +static void get_member(FILE *f, struct member *m, const char *tab, const char *var) { + if (m->t.body_tag == Type_voidType) + return; + + fputs(tab, f); + fputs(var, f); + + switch (m->t.body_tag) { + case Type_voidType: + break; + case Type_boolType: + fprintf(f, " = (capn_read8(p.p, %d) & %d) != 0;\n", + m->f.offset/8, 1 << (m->f.offset%8)); + break; + case Type_int8Type: + fprintf(f, " = (int8_t) capn_read8(p.p, %d);\n", m->f.offset); + break; + case Type_int16Type: + fprintf(f, " = (int16_t) capn_read16(p.p, %d);\n", 2*m->f.offset); + break; + case Type_int32Type: + fprintf(f, " = (int32_t) capn_read32(p.p, %d);\n", 4*m->f.offset); + break; + case Type_int64Type: + fprintf(f, " = (int64_t) capn_read64(p.p, %d);\n", 8*m->f.offset); + break; + case Type_uint8Type: + fprintf(f, " = capn_read8(p.p, %d);\n", m->f.offset); + break; + case Type_uint16Type: + fprintf(f, " = capn_read16(p.p, %d);\n", 2*m->f.offset); + break; + case Type_uint32Type: + fprintf(f, " = capn_read32(p.p, %d);\n", 4*m->f.offset); + break; + case Type_uint64Type: + fprintf(f, " = capn_read64(p.p, %d);\n", 8*m->f.offset); + break; + case Type_float32Type: + fprintf(f, " = capn_read_float(p.p, %d, 0.0f);\n", 4*m->f.offset); + break; + case Type_float64Type: + fprintf(f, " = capn_read_double(p.p, %d, 0.0);\n", 8*m->f.offset); + break; + case Type_textType: + fprintf(f, " = capn_get_text(p.p, %d);\n", m->f.offset); + break; + case Type_dataType: + fprintf(f, " = capn_get_data(p.p, %d);\n", m->f.offset); + break; + case Type_enumType: + fprintf(f, " = (enum %s) capn_read16(p.p, %d);\n", m->type->name.str, 2*m->f.offset); + break; + case Type_structType: + case Type_interfaceType: + fprintf(f, ".p = capn_getp(p.p, %d);\n", m->f.offset); + break; + case Type_objectType: + fprintf(f, " = capn_getp(p.p, %d);\n", m->f.offset); + break; + case Type_listType: + switch (m->list.body_tag) { + case Type_boolType: + case Type_int8Type: + case Type_uint8Type: + case Type_int16Type: + case Type_uint16Type: + case Type_enumType: + case Type_int32Type: + case Type_uint32Type: + case Type_int64Type: + case Type_uint64Type: + case Type_float32Type: + case Type_float64Type: + case Type_structType: + case Type_interfaceType: + fprintf(f, ".p = capn_getp(p.p, %d);\n", m->f.offset); + break; + case Type_voidType: + case Type_textType: + case Type_dataType: + case Type_objectType: + case Type_listType: + fprintf(f, " = capn_getp(p.p, %d);\n", m->f.offset); + break; + } + } +} + +static void union_cases(struct node *n, struct member *m, int set, int mask) { + static struct str buf = STR_INIT; + struct member *u = NULL; + int j; + + for (j = 0; j < m->u.members.p.len; j++) { + if (mask & (1 << m->mbrs[j].t.body_tag)) { + u = &m->mbrs[j]; + fprintf(SRC, "\tcase %s_%s:\n", n->name.str, u->m.name.str); + } + } + + if (!u) + return; + + str_reset(&buf); + str_addf(&buf, "s->%s.%s", m->m.name.str, u->m.name.str); + + if (u->t.body_tag == Type_voidType) { + /* nothing to do */ + } else if (set) { + set_member(SRC, u, "\t\t", buf.str); + } else { + get_member(SRC, u, "\t\t", buf.str); + } + + fprintf(SRC, "\t\tbreak;\n"); +} + +static void do_union(struct node *n, struct member *m, int set) { + if (set) { + fprintf(SRC, "\terr = err || capn_write16(p.p, %d, s->%s_tag);\n", + 2*m->u.discriminantOffset, m->m.name.str); + } else { + fprintf(SRC, "\ts->%s_tag = (enum %s_%s) capn_read16(p.p, %d);\n", + m->m.name.str, n->name.str, m->m.name.str, 2*m->u.discriminantOffset); + } + + fprintf(SRC, "\n\tswitch (s->%s_tag) {\n", m->m.name.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(n, m, set, (1 << Type_voidType)); + union_cases(n, m, set, (1 << Type_boolType)); + union_cases(n, m, set, (1 << Type_int8Type) | (1 << Type_uint8Type)); + union_cases(n, m, set, (1 << Type_int16Type) | (1 << Type_uint16Type) | (1 << Type_enumType)); + union_cases(n, m, set, (1 << Type_int32Type) | (1 << Type_uint32Type) | (1 << Type_float32Type)); + union_cases(n, m, set, (1 << Type_int64Type) | (1 << Type_uint64Type) | (1 << Type_float64Type)); + union_cases(n, m, set, (1 << Type_textType)); + union_cases(n, m, set, (1 << Type_dataType)); + union_cases(n, m, set, (1 << Type_structType) | (1 << Type_interfaceType) | (1 << Type_objectType) | (1 << Type_listType)); + + fprintf(SRC, "\t}\n"); +} + +static void print_member(FILE *f, struct member *m, const char *tab) { + if (m->t.body_tag == Type_voidType) + return; + + fputs(tab, f); + + switch (m->t.body_tag) { + case Type_voidType: + break; + case Type_boolType: + fprintf(f, "unsigned int %s : 1;\n", m->m.name.str); + break; + case Type_int8Type: + fprintf(f, "int8_t %s;\n", m->m.name.str); + break; + case Type_int16Type: + fprintf(f, "int16_t %s;\n", m->m.name.str); + break; + case Type_int32Type: + fprintf(f, "int32_t %s;\n", m->m.name.str); + break; + case Type_int64Type: + fprintf(f, "int64_t %s;\n", m->m.name.str); + break; + case Type_uint8Type: + fprintf(f, "uint8_t %s;\n", m->m.name.str); + break; + case Type_uint16Type: + fprintf(f, "uint16_t %s;\n", m->m.name.str); + break; + case Type_uint32Type: + fprintf(f, "uint32_t %s;\n", m->m.name.str); + break; + case Type_uint64Type: + fprintf(f, "uint64_t %s;\n", m->m.name.str); + break; + case Type_float32Type: + fprintf(f, "float %s;\n", m->m.name.str); + break; + case Type_float64Type: + fprintf(f, "double %s;\n", m->m.name.str); + break; + case Type_textType: + fprintf(f, "capn_text %s;\n", m->m.name.str); + break; + case Type_dataType: + fprintf(f, "capn_data %s;\n", m->m.name.str); + break; + case Type_enumType: + fprintf(f, "enum %s %s;\n", m->type->name.str, m->m.name.str); + break; + case Type_structType: + case Type_interfaceType: + fprintf(f, "%s_ptr %s;\n", m->type->name.str, m->m.name.str); + break; + case Type_objectType: + fprintf(f, "capn_ptr %s;\n", m->m.name.str); + break; + case Type_listType: + switch (m->list.body_tag) { + case Type_voidType: + fprintf(f, "capn_ptr %s;\n", m->m.name.str); + break; + case Type_boolType: + fprintf(f, "capn_list1 %s;\n", m->m.name.str); + break; + case Type_int8Type: + case Type_uint8Type: + fprintf(f, "capn_list8 %s;\n", m->m.name.str); + break; + case Type_int16Type: + case Type_uint16Type: + case Type_enumType: + fprintf(f, "capn_list16 %s;\n", m->m.name.str); + break; + case Type_int32Type: + case Type_uint32Type: + fprintf(f, "capn_list32 %s;\n", m->m.name.str); + break; + case Type_int64Type: + case Type_uint64Type: + fprintf(f, "capn_list64 %s;\n", m->m.name.str); + break; + case Type_float32Type: + fprintf(f, "capn_list_float %s;\n", m->m.name.str); + break; + case Type_float64Type: + fprintf(f, "capn_list_double %s;\n", m->m.name.str); + break; + case Type_textType: + case Type_dataType: + case Type_objectType: + case Type_listType: + fprintf(f, "capn_ptr %s;\n", m->m.name.str); + break; + case Type_structType: + case Type_interfaceType: + fprintf(f, "%s_list %s;\n", m->type->name.str, m->m.name.str); + break; + } + } +} + +static struct member *decode_member(struct member *mbrs, StructNode_Member_list l, int i) { + struct member m; + m.is_valid = 1; + m.idx = i; + get_StructNode_Member(&m.m, l, i); + + if (m.m.codeOrder >= l.p.len) { + fprintf(stderr, "unexpectedly large code order %d >= %d\n", m.m.codeOrder, l.p.len); + exit(3); + } + + if (m.m.body_tag == StructNode_Member_fieldMember) { + read_StructNode_Field(&m.f, m.m.body.fieldMember); + read_Type(&m.t, m.f.type); + read_Value(&m.v, m.f.defaultValue); + + switch (m.t.body_tag) { + case Type_enumType: + case Type_structType: + case Type_interfaceType: + m.type = find_node(m.t.body.enumType); + break; + + case Type_listType: + read_Type(&m.list, m.t.body.listType); + + switch (m.list.body_tag) { + case Type_enumType: + case Type_structType: + case Type_interfaceType: + m.type = find_node(m.list.body.enumType); + break; + default: + break; + } + + default: + break; + } + } + + memcpy(&mbrs[m.m.codeOrder], &m, sizeof(m)); + return &mbrs[m.m.codeOrder]; +} + +static void define_struct(struct node *n) { + static struct str buf = STR_INIT; + + int i, j, mlen = n->u.structNode.members.p.len; + struct member *mbrs = calloc(mlen, sizeof(*mbrs)); + + /* get list of members in code order and emit union enums */ + for (i = 0; i < mlen; i++) { + struct member *m = decode_member(mbrs, n->u.structNode.members, i); + + if (m->m.body_tag == StructNode_Member_unionMember) { + int first, ulen; + + /* get union members in code order */ + read_StructNode_Union(&m->u, m->m.body.unionMember); + ulen = m->u.members.p.len; + m->mbrs = calloc(ulen, sizeof(*m->mbrs)); + for (j = 0; j < ulen; j++) { + decode_member(m->mbrs, m->u.members, j); + } + + /* emit union enum definition */ + first = 1; + fprintf(HDR, "\nenum %s_%s {", n->name.str, m->m.name.str); + for (j = 0; j < ulen; j++) { + struct member *u = &m->mbrs[j]; + if (!u->is_valid) continue; + if (!first) fprintf(HDR, ","); + fprintf(HDR, "\n\t%s_%s = %d", n->name.str, u->m.name.str, u->idx); + first = 0; + } + fprintf(HDR, "\n};\n"); + } + } + + /* emit struct definition */ + fprintf(HDR, "\nstruct %s {\n", n->name.str); + for (i = 0; i < mlen; i++) { + struct member *m = &mbrs[i]; + if (!m->is_valid) + continue; + + switch (m->m.body_tag) { + case StructNode_Member_fieldMember: + print_member(HDR, m, "\t"); + break; + case StructNode_Member_unionMember: + fprintf(HDR, "\tenum %s_%s %s_tag;\n", n->name.str, m->m.name.str, m->m.name.str); + fprintf(HDR, "\tunion {\n"); + for (j = 0; j < m->u.members.p.len; j++) { + print_member(HDR, &m->mbrs[j], "\t\t"); + } + fprintf(HDR, "\t} %s;\n", m->m.name.str); + break; + } + } + fprintf(HDR, "};\n"); + + fprintf(SRC, "\nvoid read_%s(struct %s *s, %s_ptr p) {\n", n->name.str, n->name.str, n->name.str); + for (i = 0; i < mlen; i++) { + struct member *m = &mbrs[i]; + if (!m->is_valid) continue; + + switch (m->m.body_tag) { + case StructNode_Member_fieldMember: + str_reset(&buf); + str_addf(&buf, "s->%s", m->m.name.str); + get_member(SRC, m, "\t", buf.str); + break; + case StructNode_Member_unionMember: + do_union(n, m, 0); + break; + } + } + fprintf(SRC, "}\n"); + + fprintf(SRC, "int write_%s(const struct %s *s, %s_ptr p) {\n", n->name.str, n->name.str, n->name.str); + fprintf(SRC, "\tint err = 0;\n"); + for (i = 0; i < mlen; i++) { + struct member *m = &mbrs[i]; + if (!m->is_valid) continue; + + switch (m->m.body_tag) { + case StructNode_Member_fieldMember: + if (m->t.body_tag != Type_voidType) { + str_reset(&buf); + str_addf(&buf, "s->%s", m->m.name.str); + set_member(SRC, m, "\t", buf.str); + } + break; + case StructNode_Member_unionMember: + do_union(n, m, 1); + break; + } + } + fprintf(SRC, "\treturn err;\n}\n"); + + fprintf(SRC, "void get_%s(struct %s *s, %s_list l, int i) {\n", n->name.str, n->name.str, n->name.str); + fprintf(SRC, "\t%s_ptr p = {capn_getp(l.p, i)};\n", n->name.str); + fprintf(SRC, "\tread_%s(s, p);\n", n->name.str); + fprintf(SRC, "}\n"); + + fprintf(SRC, "int set_%s(const struct %s *s, %s_list l, int i) {\n", n->name.str, n->name.str, n->name.str); + fprintf(SRC, "\t%s_ptr p = {capn_getp(l.p, i)};\n", n->name.str); + fprintf(SRC, "\treturn write_%s(s, p);\n", n->name.str); + fprintf(SRC, "}\n"); +} + +static void declare_structs(struct node *n, const char *format, int num) { + fprintf(HDR, "\n"); + for (n = n->first_child; n != NULL; n = n->next_child) { + if (n->n.body_tag == Node_structNode) { + switch (num) { + case 3: + fprintf(HDR, format, n->name.str, n->name.str, n->name.str); + break; + case 1: + fprintf(HDR, format, n->name.str); + break; + } + } + } +} int main() { struct capn capn; CodeGeneratorRequest_ptr root; struct CodeGeneratorRequest req; - int i, j; + struct node *n; + int i; if (capn_init_fp(&capn, stdin, 0)) { fprintf(stderr, "failed to read schema from stdin\n"); @@ -38,54 +607,112 @@ int main() { root.p = capn_get_root(&capn); read_CodeGeneratorRequest(&req, root); - for (i = 0; i < req.nodes.p.size; i++) { - struct Node N; - struct FileNode F; - struct StructNode S; - struct EnumNode E; - struct InterfaceNode I; - struct ConstNode C; - struct AnnotationNode A; + for (i = 0; i < req.nodes.p.len; i++) { + n = calloc(1, sizeof(*n)); + get_Node(&n->n, req.nodes, i); + insert_node(n); - get_Node(&N, req.nodes, i); - fprintf(stderr, "node %s id:%#llx scope:%#llx type:%d\n", - N.displayName.str, N.id, N.scopeId, N.body_tag); - - switch (N.body_tag) { + switch (n->n.body_tag) { case Node_fileNode: - read_FileNode(&F, N.body.fileNode); - for (j = 0; j < F.imports.p.size; j++) { - struct FileNode_Import fi; - get_FileNode_Import(&fi, F.imports, j); - fprintf(stderr, "\timport %#llx %s\n", fi.id, fi.name.str); - } + n->next = g_files; + g_files = n; + read_FileNode(&n->u.fileNode, n->n.body.fileNode); break; case Node_structNode: - read_StructNode(&S, N.body.structNode); - fprintf(stderr, "\tstruct %d %d %d\n", - S.dataSectionWordSize, S.pointerSectionSize, S.preferredListEncoding); - for (j = 0; j < S.members.p.size; j++) { - } + read_StructNode(&n->u.structNode, n->n.body.structNode); break; case Node_enumNode: - read_EnumNode(&E, N.body.enumNode); - for (j = 0; j < E.enumerants.p.size; j++) { - struct EnumNode_Enumerant ee; - get_EnumNode_Enumerant(&ee, E.enumerants, j); - fprintf(stderr, "\tenum %d %s %d\n", j, ee.name.str, ee.codeOrder); - } + read_EnumNode(&n->u.enumNode, n->n.body.enumNode); break; case Node_interfaceNode: - read_InterfaceNode(&I, N.body.interfaceNode); + read_InterfaceNode(&n->u.interfaceNode, n->n.body.interfaceNode); break; case Node_constNode: - read_ConstNode(&C, N.body.constNode); + read_ConstNode(&n->u.constNode, n->n.body.constNode); break; - case Node_annotationNode: - read_AnnotationNode(&A, N.body.annotationNode); + default: break; } } + for (n = g_files; n != NULL; n = n->next) { + struct str b = STR_INIT; + + for (i = n->n.nestedNodes.p.len-1; i >= 0; i--) { + struct Node_NestedNode nest; + get_Node_NestedNode(&nest, n->n.nestedNodes, i); + resolve_names(&b, find_node(nest.id), nest.name, n); + } + + str_release(&b); + } + + for (i = 0; i < req.requestedFiles.p.len; i++) { + struct str b = STR_INIT; + struct node *s; + char *p; + n = find_node(capn_get64(req.requestedFiles, i)); + + str_reset(&b); + str_addf(&b, "%s.h", n->n.displayName.str); + HDR = fopen(b.str, "w"); + if (!HDR) { + fprintf(stderr, "failed to open %s: %s\n", b.str, strerror(errno)); + exit(2); + } + + str_reset(&b); + str_addf(&b, "%s.c", n->n.displayName.str); + SRC = fopen(b.str, "w"); + if (!SRC) { + fprintf(stderr, "failed to open %s: %s\n", b.str, strerror(errno)); + exit(2); + } + + fprintf(HDR, "#ifndef CAPN_%llx\n", n->n.id); + fprintf(HDR, "#define CAPN_%llx\n", n->n.id); + fprintf(HDR, "/* AUTO GENERATED DO NOT EDIT*/\n"); + fprintf(HDR, "#include \n"); + + for (i = 0; i < n->u.fileNode.imports.p.len; i++) { + struct FileNode_Import im; + get_FileNode_Import(&im, n->u.fileNode.imports, i); + fprintf(HDR, "#include \"%s.h\"\n", im.name.str); + } + + fprintf(HDR, "\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n"); + + p = strrchr(n->n.displayName.str, '/'); + fprintf(SRC, "#include \"%s.h\"\n", p ? p+1 : n->n.displayName.str); + fprintf(SRC, "/* AUTO GENERATED DO NOT EDIT*/\n"); + + declare_structs(n, "struct %s;\n", 1); + declare_structs(n, "typedef struct {capn_ptr p;} %s_ptr;\n", 1); + declare_structs(n, "typedef struct {capn_ptr p;} %s_list;\n", 1); + declare_structs(n, "void read_%s(struct %s*, %s_ptr);\n", 3); + declare_structs(n, "int write_%s(const struct %s*, %s_ptr);\n", 3); + declare_structs(n, "void get_%s(struct %s*, %s_list, int i);\n", 3); + declare_structs(n, "int set_%s(const struct %s*, %s_list, int i);\n", 3); + + for (s = n->first_child; s != NULL; s = s->next_child) { + switch (s->n.body_tag) { + case Node_structNode: + define_struct(s); + break; + case Node_enumNode: + define_enum(s); + break; + default: + break; + } + } + + fprintf(HDR, "\n#ifdef __cplusplus\n}\n#endif\n#endif\n"); + str_release(&b); + fclose(HDR); + fclose(SRC); + HDR = SRC = NULL; + } + return 0; } diff --git a/compiler/schema.capnp.c b/compiler/schema.capnp.c index 2636390..b230c85 100644 --- a/compiler/schema.capnp.c +++ b/compiler/schema.capnp.c @@ -140,13 +140,13 @@ void read_Type(struct Type *s, Type_ptr p) { s->body.listType.p = capn_getp(p.p, 0); break; case Type_enumType: - s->body.enumType = capn_read64(p.p, 0); + s->body.enumType = capn_read64(p.p, 8); break; case Type_structType: - s->body.structType = capn_read64(p.p, 0); + s->body.structType = capn_read64(p.p, 8); break; case Type_interfaceType: - s->body.interfaceType = capn_read64(p.p, 0); + s->body.interfaceType = capn_read64(p.p, 8); break; default: break; diff --git a/compiler/str.c b/compiler/str.c new file mode 100644 index 0000000..d078076 --- /dev/null +++ b/compiler/str.c @@ -0,0 +1,96 @@ +#include "str.h" +#include +#include +#include + +#ifndef va_copy +# ifdef _MSC_VER +# define va_copy(d,s) d = s +# elif defined __GNUC__ +# define va_copy(d,s) __builtin_va_copy(d,s) +# else +# error +# endif +#endif + +char str_static[] = "\0"; + +void str_reserve(struct str *v, int sz) { + if (sz < v->cap) + return; + + v->cap = (v->cap * 2) + 16; + if (sz > v->cap) { + v->cap = (sz + 8) & ~7; + } + + if (v->str == str_static) { + v->str = NULL; + } + + v->str = realloc(v->str, v->cap + 1); +} + +void str_add(struct str *v, const char *str, int sz) { + if (sz < 0) + sz = strlen(str); + str_reserve(v, v->len + sz); + memcpy(v->str+v->len, str, sz); + v->len += sz; + v->str[v->len] = '\0'; +} + +int str_vaddf(struct str *v, const char* format, va_list ap) { + str_reserve(v, v->len + 1); + + for (;;) { + int ret; + + char* buf = v->str + v->len; + int bufsz = v->cap - v->len; + + va_list aq; + va_copy(aq, ap); + + /* We initialise buf[bufsz] to \0 to detect when snprintf runs out of + * buffer by seeing whether it overwrites it. + */ + buf[bufsz] = '\0'; + ret = vsnprintf(buf, bufsz + 1, format, aq); + + if (ret > bufsz) { + /* snprintf has told us the size of buffer required (ISO C99 + * behavior) + */ + str_reserve(v, v->len + ret); + + } else if (ret >= 0) { + /* success */ + v->len += ret; + return ret; + + } else if (buf[bufsz] != '\0') { + /* snprintf has returned an error but has written to the end of the + * buffer (MSVC behavior). The buffer is not large enough so grow + * and retry. This can also occur with a format error if it occurs + * right on the boundary, but then we grow the buffer and can + * figure out its an error next time around. + */ + str_reserve(v, v->len + bufsz + 1); + + } else { + /* snprintf has returned an error but has not written to the last + * character in the buffer. We have a format error. + */ + return -1; + } + } +} + + +int str_addf(struct str *v, const char* format, ...) { + va_list ap; + va_start(ap, format); + return str_vaddf(v, format, ap); +} + diff --git a/compiler/str.h b/compiler/str.h new file mode 100644 index 0000000..727d663 --- /dev/null +++ b/compiler/str.h @@ -0,0 +1,42 @@ +/* vim: set sw=8 ts=8 sts=8 noet: */ +#include +#include + +struct str { + char *str; + int len, cap; +}; + +extern char str_static[]; +#define STR_INIT {str_static, 0, 0} + +void str_reserve(struct str *v, int sz); + +static void str_release(struct str *v) { + if (v->cap) { + free(v->str); + } +} + +static void str_reset(struct str *v) { + v->len = 0; + v->str[0] = '\0'; +} + +static void str_setlen(struct str *v, int sz) { + str_reserve(v, sz); + v->str[sz] = '\0'; + v->len = sz; +} + +#ifdef __GNUC__ +#define ATTR(FMT, ARGS) __attribute__((format(printf,FMT,ARGS))) +#else +#define ATTR(FMT, ARGS) +#endif + +void str_add(struct str *v, const char *str, int sz); +int str_vaddf(struct str *v, const char *format, va_list ap) ATTR(2,0); +int str_addf(struct str *v, const char *format, ...) ATTR(2,3); + +