From a8e2a1e28f3c5c3f08d2a3e10000d98e3031e075 Mon Sep 17 00:00:00 2001 From: Sara Date: Mon, 11 Sep 2023 18:46:01 +0200 Subject: [PATCH] can now generate basic *_to_json functions --- src/kwil_generate.c | 162 +++++++++++++++++++++++++++++++++++++++ src/kwil_generate.h | 13 ++++ test_files/header.kwil.h | 107 ++++++++++++++++++++++++++ 3 files changed, 282 insertions(+) create mode 100644 src/kwil_generate.c create mode 100644 src/kwil_generate.h create mode 100644 test_files/header.kwil.h diff --git a/src/kwil_generate.c b/src/kwil_generate.c new file mode 100644 index 0000000..55a3349 --- /dev/null +++ b/src/kwil_generate.c @@ -0,0 +1,162 @@ +#include "kwil_generate.h" +#include +#include +#include + +static +int kwil_header_generated_file_name(struct kwil_header_t* self, char** out) { + int len = strlen(self->file_name); + char* filename = malloc(len + 5); + strncpy(filename, self->file_name, len-2); + strcpy(filename + len-2, ".kwil.h"); + *out = filename; + return len; +} + +static +int kwil_typename_to_prefix(const char* restrict type_name, char* out_prefix, size_t out_size) { + int len = strlen(type_name); + if(len > out_size) { + return 1; + } + // generate a function prefix for a type name + strcpy(out_prefix, type_name); + + // remove _t postfix if relevant + if(strcmp(out_prefix + len -3, "_t") == 0) { + *(out_prefix + len - 3) = '\0'; + } + return strlen(out_prefix); +} + +int kwil_header_generate(struct kwil_header_t* self) { + char file_buffer[255]; + char* filename; + kwil_header_generated_file_name(self, &filename); + + FILE* file = fopen(filename, "w+"); + setvbuf(file, file_buffer, _IOLBF, 255); + + if(!file) { + printf("Failed to open kwil header for writing"); + free(filename); + return 1; + } + + fprintf(file, "#include \n" + "#define KWIL_GEN_IMPL(...)\\\n"); + + for(int type_index = 0; type_index < self->types_len; ++type_index) { + struct kwil_type_t* type = self->types + type_index; + switch(type->type_tag) { + case KWIL_TYPE_STRUCT: + kwil_struct_generate_to_json(&type->struct_type, file, type->type_name); + break; + case KWIL_TYPE_ENUM: + //kwil_enum_generate_to_string(&type->enum_type, file, type->type_name); + break; + } + } + + fprintf(file, "\n"); + fclose(file); + free(filename); + + return 0; +} + +static +void kwil_field_generate_to_string(struct kwil_field_t* self, FILE* file) { + switch(self->type_tag) { + case KWIL_FIELD_CHAR: + if(self->array_length > 0 || self->array_dynamic) { + fprintf(file, " if(src->%s != NULL) {\\\n" + " json_len += sprintf(json + json_len, \"\\\"%%s\\\"\", src->%s);\\\n" + " }\\\n", + self->name_str, self->name_str); + } + break; + case KWIL_FIELD_INT: + fprintf(file, " json_len += sprintf(json + json_len, \"%%d\", src->%s);\\\n", self->name_str); + break; + case KWIL_FIELD_FLOAT: + fprintf(file, " json_len += sprintf(json + json_len, \"%%f\", src->%s);\\\n", self->name_str); + break; + case KWIL_FIELD_UNSIGNED: + fprintf(file, " json_len += sprintf(json + json_len, \"%%u\", src->%s);\\\n", self->name_str); + break; + default: break; + } +} + +static +void kwil_field_get_serialized_length(struct kwil_field_t* self, FILE* file) { + size_t len = strlen(self->name_str) + 4; // "name": , + + fprintf(file, " /* length of %s */\\\n" + " json_capacity += %zu", + self->name_str, len); + + switch(self->type_tag) { + case KWIL_FIELD_CHAR: + if(self->array_dynamic || self->array_length > 0) { + fprintf(file, " + strlen(src->%s);\\\n", self->name_str); + } else { + fprintf(file, " + 3;\\\n"); + } + break; + case KWIL_FIELD_INT: + fprintf(file, "+ snprintf(NULL, 0, \"%%d\", src->%s);\\\n", self->name_str); + break; + case KWIL_FIELD_UNSIGNED: + fprintf(file, " + snprintf(NULL, 0, \"%%du\", src->%s);\\\n", self->name_str); + break; + case KWIL_FIELD_FLOAT: + fprintf(file, " + snprintf(NULL, 0, \"%%f\", src->%s);\\\n", self->name_str); + break; + case KWIL_FIELD_CUSTOM: + case KWIL_FIELD_UNKNOWN: + fprintf(file, ";\\\n"); + break; + } +} + +int kwil_struct_generate_to_json(struct kwil_struct_t* self, FILE* file, const char* type_name) { + char prefix[48]; + kwil_typename_to_prefix(type_name, prefix, 47); + + fprintf(file, "int %s_to_json(struct %s* src, char** out_json) {\\\n" + " int json_capacity = 2; \\\n" // allocate at least two for "{}\0" + , prefix, type_name); + + for(int field_index = 0; field_index < self->fields_len; ++field_index) { + kwil_field_get_serialized_length(self->fields + field_index, file); + } + + fprintf(file, " char* json = malloc(json_capacity);\\\n" + " int json_len = 1;\\\n" + " strcpy(json, \"{\");\\\n" + " *out_json = json;\\\n"); + + for(int field_index = 0; field_index < self->fields_len; ++field_index) { + kwil_field_generate_to_json(self->fields + field_index, file); + } + + fprintf(file, " strcpy(json + json_len - 1, \"}\");\\\n" + " return json_capacity;\\\n" + "}\\\n"); + fflush(file); + + return 0; +} + +int kwil_field_generate_to_json(struct kwil_field_t* self, FILE* file) { + fprintf(file, " /* field: %s */\\\n", self->name_str); + fprintf(file, " json_len += sprintf(json + json_len, \"\\\"%s\\\":\");\\\n", + self->name_str); + kwil_field_generate_to_string(self, file); + fprintf(file, " strcpy(json + json_len, \",\");\\\n" + " ++json_len;\\\n"); + return 0; +} + diff --git a/src/kwil_generate.h b/src/kwil_generate.h new file mode 100644 index 0000000..c55ab19 --- /dev/null +++ b/src/kwil_generate.h @@ -0,0 +1,13 @@ +#ifndef _kwil_generate_H +#define _kwil_generate_H + +#include "kwil_def.h" +#include + +extern int kwil_header_generate(struct kwil_header_t* self); + +extern int kwil_struct_generate_to_json(struct kwil_struct_t* self, FILE* file, const char* type_name); +extern int kwil_field_generate_to_json(struct kwil_field_t* self, FILE* file); +extern int kwil_enum_generate_to_json(struct kwil_enum_t* self, FILE* file, const char* type_name); + +#endif // !_kwil_generate_H diff --git a/test_files/header.kwil.h b/test_files/header.kwil.h new file mode 100644 index 0000000..049a99f --- /dev/null +++ b/test_files/header.kwil.h @@ -0,0 +1,107 @@ +#include +#define KWIL_GEN_IMPL(...)\ +int struct_A_to_json(struct struct_A* src, char** out_json) {\ + int json_capacity = 2; \ + /* length of b */\ + json_capacity += 5+ snprintf(NULL, 0, "%d", src->b);\ + /* length of a */\ + json_capacity += 5 + snprintf(NULL, 0, "%f", src->a);\ + /* length of u */\ + json_capacity += 5 + snprintf(NULL, 0, "%du", src->u);\ + /* length of dyn_str */\ + json_capacity += 11 + strlen(src->dyn_str);\ + char* json = malloc(json_capacity);\ + int json_len = 1;\ + strcpy(json, "{");\ + *out_json = json;\ + /* field: b */\ + json_len += sprintf(json + json_len, "\"b\":");\ + json_len += sprintf(json + json_len, "%d", src->b);\ + strcpy(json + json_len, ",");\ + ++json_len;\ + /* field: a */\ + json_len += sprintf(json + json_len, "\"a\":");\ + json_len += sprintf(json + json_len, "%f", src->a);\ + strcpy(json + json_len, ",");\ + ++json_len;\ + /* field: u */\ + json_len += sprintf(json + json_len, "\"u\":");\ + json_len += sprintf(json + json_len, "%u", src->u);\ + strcpy(json + json_len, ",");\ + ++json_len;\ + /* field: dyn_str */\ + json_len += sprintf(json + json_len, "\"dyn_str\":");\ + if(src->dyn_str != NULL) {\ + json_len += sprintf(json + json_len, "\"%s\"", src->dyn_str);\ + }\ + strcpy(json + json_len, ",");\ + ++json_len;\ + strcpy(json + json_len - 1, "}");\ + return json_capacity;\ +}\ +int struct_B_to_json(struct struct_B* src, char** out_json) {\ + int json_capacity = 2; \ + /* length of f */\ + json_capacity += 5 + snprintf(NULL, 0, "%f", src->f);\ + /* length of i */\ + json_capacity += 5+ snprintf(NULL, 0, "%d", src->i);\ + /* length of str */\ + json_capacity += 7 + strlen(src->str);\ + /* length of str_static */\ + json_capacity += 14 + strlen(src->str_static);\ + /* length of other_struct */\ + json_capacity += 16;\ + /* length of other_struct_typedef */\ + json_capacity += 24;\ + /* length of other_enum */\ + json_capacity += 14;\ + /* length of other_enum_typedef */\ + json_capacity += 22;\ + char* json = malloc(json_capacity);\ + int json_len = 1;\ + strcpy(json, "{");\ + *out_json = json;\ + /* field: f */\ + json_len += sprintf(json + json_len, "\"f\":");\ + json_len += sprintf(json + json_len, "%f", src->f);\ + strcpy(json + json_len, ",");\ + ++json_len;\ + /* field: i */\ + json_len += sprintf(json + json_len, "\"i\":");\ + json_len += sprintf(json + json_len, "%d", src->i);\ + strcpy(json + json_len, ",");\ + ++json_len;\ + /* field: str */\ + json_len += sprintf(json + json_len, "\"str\":");\ + if(src->str != NULL) {\ + json_len += sprintf(json + json_len, "\"%s\"", src->str);\ + }\ + strcpy(json + json_len, ",");\ + ++json_len;\ + /* field: str_static */\ + json_len += sprintf(json + json_len, "\"str_static\":");\ + if(src->str_static != NULL) {\ + json_len += sprintf(json + json_len, "\"%s\"", src->str_static);\ + }\ + strcpy(json + json_len, ",");\ + ++json_len;\ + /* field: other_struct */\ + json_len += sprintf(json + json_len, "\"other_struct\":");\ + strcpy(json + json_len, ",");\ + ++json_len;\ + /* field: other_struct_typedef */\ + json_len += sprintf(json + json_len, "\"other_struct_typedef\":");\ + strcpy(json + json_len, ",");\ + ++json_len;\ + /* field: other_enum */\ + json_len += sprintf(json + json_len, "\"other_enum\":");\ + strcpy(json + json_len, ",");\ + ++json_len;\ + /* field: other_enum_typedef */\ + json_len += sprintf(json + json_len, "\"other_enum_typedef\":");\ + strcpy(json + json_len, ",");\ + ++json_len;\ + strcpy(json + json_len - 1, "}");\ + return json_capacity;\ +}\ +