/* * Copyright (c) 2020, Rockchip Electronics Co., Ltd * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ #define _GNU_SOURCE #include "common.h" #include #include /* j2s list helpers */ typedef struct { void *data; void *next; void *prev; } j2s_list; void j2s_list_add(j2s_list *head, void *data) { j2s_list *entry = malloc(sizeof(j2s_list)); DASSERT(entry, exit(-1)); entry->data = data; entry->prev = head->prev; entry->next = head; ((j2s_list *)head->prev)->next = entry; head->prev = entry; } void j2s_list_del(j2s_list *entry) { ((j2s_list *)entry->prev)->next = entry->next; ((j2s_list *)entry->next)->prev = entry->prev; free(entry); } #define j2s_list_init(head) \ (head)->prev = (head)->next = head; (head)->data = NULL; #define j2s_list_empty(head) \ ((head)->prev == head) #define j2s_list_walk_safe(head, entry, next, obj) \ for (entry = (head)->next, next = entry->next, obj = entry->data; \ entry != head; \ entry = next, next = entry->next, obj = entry->data) #define j2s_list_walk(head, entry, obj) \ for (entry = (head)->next, obj = entry->data; entry != head; \ entry = entry->next, obj = entry->data) #define j2s_list_free(head, entry, free_data) \ for (entry = (head)->next; entry != head; \ entry = entry->next, free(entry->prev)) \ if (free_data) free(entry->data) #define j2s_list_find(head, entry, obj, s) \ j2s_list_walk(head, entry, obj) \ if (!strcmp(obj->name, s)) break; \ if (entry == head) obj = NULL; /* Info about each enums */ typedef struct { int id; char name[MAX_NAME]; /* Enum name */ j2s_list values; /* value list */ int value_id; /* Id of the first enum value */ int num_value; /* Number of enum values */ } j2s_enum; /* Info about each enum values */ typedef struct { int id; char name[MAX_NAME]; /* Value name */ } j2s_enum_value; /* Info about each structs */ typedef struct { int id; char name[MAX_NAME]; /* Struct name */ j2s_list child; /* Child list */ int child_id; /* Id of the first child */ } j2s_struct; /* Info about each struct members */ typedef struct { int id; char name[MAX_NAME]; /* Member name */ char type_name[MAX_NAME]; /* Origin type name */ j2s_type type; j2s_flag flags; char *desc; /* Optional desc string */ void *next; /* Next child of the parent */ j2s_struct *parent; /* Parent struct */ j2s_struct *struct_obj; /* Struct info(if type is struct) */ j2s_enum *enum_obj; /* Enum info(if type is enum) */ void *len_obj; /* Dynamic array needs a @_len obj to store len */ int line; /* Line of the header file */ } j2s_obj; /* J2S parsing context */ typedef struct { j2s_list structs; j2s_list enums; j2s_list objs; int num_enum_value; int num_struct; int num_enum; int num_obj; int depth; bool pending_bool; bool pending_enum; bool pending_struct; bool pending_comment; j2s_struct *struct_obj; j2s_enum *enum_obj; char *desc; j2s_struct *root_struct; FILE *fp; /* Input file */ int line; /* Line of the header file */ } j2s_ctx; #define J2S_TYPE(t) [t] = #t const char j2s_types[][MAX_NAME] = { J2S_TYPE(J2S_TYPE_INT_8), J2S_TYPE(J2S_TYPE_UINT_8), J2S_TYPE(J2S_TYPE_INT_16), J2S_TYPE(J2S_TYPE_UINT_16), J2S_TYPE(J2S_TYPE_INT_32), J2S_TYPE(J2S_TYPE_UINT_32), J2S_TYPE(J2S_TYPE_INT_64), J2S_TYPE(J2S_TYPE_UINT_64), J2S_TYPE(J2S_TYPE_FLOAT), J2S_TYPE(J2S_TYPE_DOUBLE), J2S_TYPE(J2S_TYPE_STRING), J2S_TYPE(J2S_TYPE_STRUCT), }; static inline j2s_type j2s_parse_type(const char *type, j2s_flag flags) { if (!strcmp(type, "char") && (flags & (J2S_FLAG_ARRAY | J2S_FLAG_POINTER))) return J2S_TYPE_STRING; if (!strcmp(type, "char") || !strcmp(type, "bool") || !strcmp(type, "int8_t")) return J2S_TYPE_INT_8; if (!strcmp(type, "unsigned char") || !strcmp(type, "uint8_t")) return J2S_TYPE_UINT_8; if (!strcmp(type, "short") || !strcmp(type, "int16_t")) return J2S_TYPE_INT_16; if (!strcmp(type, "unsigned short") || !strcmp(type, "uint16_t")) return J2S_TYPE_UINT_16; if (!strcmp(type, "int") || !strcmp(type, "int32_t")) return J2S_TYPE_INT_32; if (!strcmp(type, "unsigned int") || !strcmp(type, "uint32_t")) return J2S_TYPE_UINT_32; if (!strcmp(type, "long") || !strcmp(type, "long long") || !strcmp(type, "int64_t")) return J2S_TYPE_INT_64; if (!strcmp(type, "unsigned long") || !strcmp(type, "unsigned long long") || !strcmp(type, "uint64_t")) return J2S_TYPE_UINT_64; if (!strcmp(type, "float")) return J2S_TYPE_FLOAT; if (!strcmp(type, "double")) return J2S_TYPE_DOUBLE; /* Fallback to struct, unsupported types would be catched later */ return J2S_TYPE_STRUCT; } static inline void strip_spaces(char **buf, bool strip_tails) { if (!buf || !*buf) return; #define IS_SPACE(c) ((c) == '\t' || (c) == ' ' || (c) == ',' || \ (c) == '\'' || (c) == ';' || (c) == '\n' || (c) == '\r') /* Strip leading spaces */ while (IS_SPACE(*buf[0])) (*buf)++; if (!strip_tails) return; /* Strip tail spaces */ for (int i = strlen(*buf) - 1; i >= 0 && IS_SPACE((*buf)[i]); i--) (*buf)[i] = '\0'; } /* Strip spaces and compare and eat pattern */ static inline int parse_pattern(char **buf, const char *pattern) { int ret = -1; if (!buf || !*buf) return -1; /* Strip spaces */ strip_spaces(buf, false); /* Compare and eat pattern */ if (pattern && !strncmp(*buf, pattern, strlen(pattern))) { *buf += strlen(pattern); ret = 0; } /* Strip spaces */ strip_spaces(buf, false); return ret; } /* Return the first pos of a or b */ static inline char *strchr_first(const char *buf, const char a, const char b) { char *p1, *p2; if (a == b) return strchr(buf, a); p1 = strchrnul(buf, a); p2 = strchrnul(buf, b); if (p1 == p2) return NULL; return p1 < p2 ? p1 : p2; } static inline void j2s_handle_comment(j2s_ctx *ctx, char *buf) { int size; strip_spaces(&buf, true); DBG("comment: %s\n", buf); if (!ctx->struct_obj) return; if (parse_pattern(&buf, J2S_DESC_MAGIC) < 0) return; /* Handle member desc (comments started with magic) */ if (!ctx->desc) ctx->desc = strdup(""); else strcat(ctx->desc, ", "); size = strlen(ctx->desc) + strlen(buf) + 10; ctx->desc = realloc(ctx->desc, size); DASSERT_MSG(ctx->desc, exit(-1), "desc size too large: %d\n", size); strcat(ctx->desc, buf); DBG("new desc: %s\n", ctx->desc); } static inline int j2s_parse(j2s_ctx *ctx, char *buf) { j2s_enum_value *enum_value = NULL; j2s_struct *struct_obj = NULL; j2s_enum *enum_obj = NULL; j2s_obj *obj = NULL; j2s_flag flags; char pending[MAX_LINE] = {0}; char *ptr, *type, *name; DBG("parsing '%s' at %d\n", buf, ctx->line); strip_spaces(&buf, true); /* 1. Handle multiline comments */ if (ctx->pending_comment) { ptr = strstr(buf, "*/"); if (ptr) { /* End of multiline comment */ *ptr = '\0'; j2s_handle_comment(ctx, buf); buf = ptr + 2; ctx->pending_comment = false; } else { /* Multiline comments */ strip_spaces(&buf, true); while (buf[0] == '*') buf++; j2s_handle_comment(ctx, buf); return 0; } } /* 2. Handle new comments */ ptr = strstr(buf, "/*"); if (ptr) { /* Start of comment */ char *start = ptr + 2; *ptr = '\0'; ptr = strstr(start, "*/"); if (ptr) { /* Inline comment */ *ptr = '\0'; ptr += 2; j2s_handle_comment(ctx, start); /* Remove inline comment */ start = buf + strlen(buf); for (int i = 0; i < strlen(ptr) + 1; i++) start[i] = ptr[i]; return j2s_parse(ctx, buf); } else { /* Start of multiline comments */ ctx->pending_comment = true; j2s_handle_comment(ctx, start); } } ptr = strstr(buf, "//"); if (ptr) { /* One line comment */ *ptr = '\0'; ptr += 2; j2s_handle_comment(ctx, ptr); } /* 3. Split buf */ strip_spaces(&buf, true); ptr = strchr_first(buf, ';', '{'); if (ptr) { ptr++; if (*ptr) { strcpy(pending, ptr); *ptr = '\0'; strip_spaces(&buf, true); DBG("parsing '%s', pending '%s'\n", buf, pending); } } /* 4. Filter out empty lines */ if (buf[0] == '\0' || buf[0] == '#') goto out; /* 5. Handle enum definations */ if (!parse_pattern(&buf, "typedef enum")) { DASSERT_MSG(!ctx->struct_obj && !ctx->enum_obj && \ !ctx->pending_enum && !ctx->pending_struct && \ !ctx->depth, exit(-1), "failed to parse enum at %d\n", ctx->line); ctx->pending_enum = true; } if (ctx->pending_enum) { if (!strchr(buf, '{')) { DBG("waiting for '{', skip \"%s\"\n", buf); goto out; } ctx->depth++; /* Handle new enum */ DBG("found enum\n"); ctx->pending_enum = false; ctx->enum_obj = malloc(sizeof(*enum_obj)); DASSERT(ctx->enum_obj, exit(-1)); j2s_list_init(&ctx->enum_obj->values); ctx->enum_obj->value_id = -1; ctx->enum_obj->num_value = 0; goto out; } if (ctx->enum_obj) { j2s_enum_value *enum_value; if (!parse_pattern(&buf, "}")) { ctx->depth--; /* End of enum defination */ strip_spaces(&buf, true); INFO("adding enum %s\n", buf); /* Add to enum list */ strncpy(ctx->enum_obj->name, buf, sizeof(ctx->enum_obj->name)); ctx->enum_obj->id = ctx->num_enum++; j2s_list_add(&ctx->enums, ctx->enum_obj); ctx->enum_obj = NULL; goto out; } /* Parsing enum value */ /* The first word is enum value name */ strip_spaces(&buf, true); name = buf; ptr = strchr_first(name, ' ', '='); if (ptr) *ptr = '\0'; /* Add enum value */ enum_value = malloc(sizeof(*enum_value)); DASSERT(enum_value, exit(-1)); enum_value->id = ctx->num_enum_value++; strncpy(enum_value->name, buf, sizeof(enum_value->name)); j2s_list_add(&ctx->enum_obj->values, enum_value); ctx->enum_obj->num_value++; if (ctx->enum_obj->value_id < 0) ctx->enum_obj->value_id = enum_value->id; DBG("adding enum value %s\n", enum_value->name); goto out; } /* 6. Handle struct definations */ if (!parse_pattern(&buf, "typedef struct")) { DASSERT_MSG(!ctx->depth && !ctx->struct_obj, exit(-1), "failed to parse struct at %d\n", ctx->line); ctx->pending_struct = true; } /* Waiting for struct defination */ if (ctx->depth) { if (!ctx->struct_obj) { if (strchr(buf, '}')) ctx->depth--; DBG("waiting for struct, skip \"%s\"\n", buf); goto out; } } else { if (!strchr(buf, '{')) { DBG("waiting for '{', skip \"%s\"\n", buf); goto out; } ctx->depth++; if (!ctx->pending_struct) { DBG("waiting for struct, skip \"%s\"\n", buf); goto out; } /* Handle new struct */ DBG("found struct\n"); ctx->pending_struct = false; ctx->struct_obj = malloc(sizeof(*struct_obj)); DASSERT(ctx->struct_obj, exit(-1)); j2s_list_init(&ctx->struct_obj->child); ctx->struct_obj->child_id = -1; goto out; } /* Skip union's { */ if (!parse_pattern(&buf, "union {")) { ctx->depth++; goto out; } /* union's } or end of struct defination */ if (!parse_pattern(&buf, "}")) { DASSERT_MSG(ctx->depth > 0, exit(-1), "} not paired at %d\n", ctx->line); ctx->depth--; /* End of struct defination */ if (!ctx->depth && ctx->struct_obj) { /* Skip packed attribute */ parse_pattern(&buf, "__attribute__((packed))"); /* Parse struct name */ strip_spaces(&buf, true); name = buf; ptr = strrchr(name, ' '); if (ptr) name = ptr + 1; INFO("adding struct %s\n", name); /* Add to struct list */ strncpy(ctx->struct_obj->name, name, sizeof(ctx->struct_obj->name)); ctx->struct_obj->id = ctx->num_struct++; j2s_list_add(&ctx->structs, ctx->struct_obj); /* Using the last struct as root struct */ ctx->root_struct = ctx->struct_obj; ctx->struct_obj = NULL; DASSERT_MSG(!ctx->desc, free(ctx->desc); ctx->desc = NULL, "unhandled desc: '%s'\n", ctx->desc); } goto out; } /* 7. Handle struct members */ /* Handle special bool defination */ if (!strcmp(buf, "_Bool")) { DASSERT_MSG(!ctx->pending_bool, exit(-1), "failed to parse bool at %d\n", ctx->line); ctx->pending_bool = true; goto out; } flags = 0; /* Detect array and strip it */ ptr = strrchr(buf, '['); if (ptr) { DBG("'%s' is an array\n", buf); *ptr = '\0'; flags |= J2S_FLAG_ARRAY; /* Detect dep array */ ptr = strrchr(buf, '['); if (ptr) { DBG("\tand a dep array %s\n", buf); *ptr = '\0'; flags |= J2S_FLAG_DEP_ARRAY; DASSERT_MSG(!strrchr(buf, '['), return -1, "array too dep at %d\n", ctx->line); } } /* Detect pointer */ ptr = strrchr(buf, '*'); if (ptr) { DBG("'%s' is a pointer\n", buf); *ptr = ' '; /* Would be stripped later */ flags |= J2S_FLAG_POINTER; ptr = strrchr(buf, '*'); if (ptr) { DBG("\tand a dep pointer %s\n", buf); *ptr = ' '; /* Would be stripped later */ flags |= J2S_FLAG_DEP_POINTER; DASSERT_MSG(!strrchr(buf, '*'), return -1, "pointer too dep at %d\n", ctx->line); } } /* Extract type and name */ ptr = strrchr(buf, ' '); if (ctx->pending_bool) { DASSERT_MSG(!ptr, exit(-1), "failed to parse bool at %d\n", ctx->line); ctx->pending_bool = false; type = "bool"; name = buf; } else { DASSERT_MSG(ptr, exit(-1), "parse member error from '%s' at %d\n", buf, ctx->line); *ptr = '\0'; type = buf; name = ptr + 1; } parse_pattern(&type, "const"); strip_spaces(&type, true); strip_spaces(&name, true); /* Detect typedef array pointer */ if (!parse_pattern(&type, "array_ptr_")) { DBG("'%s' is an array pointer\n", name); /* Remove member desc */ if (type[0] <= '9' && type[0] >= '0') type = strchr(type, '_') + 1; flags |= J2S_FLAG_ARRAY_POINTER; } /* Detect typedef array */ if (!parse_pattern(&type, "array_")) { DBG("'%s' is an array\n", name); DASSERT_MSG(!(flags & J2S_FLAG_DEP_ARRAY), return -1, "array too dep at %d\n", ctx->line); DASSERT_MSG(!(flags & J2S_FLAG_DEP_POINTER), return -1, "pointer too dep at %d\n", ctx->line); /* Remove member desc */ if (type[0] <= '9' && type[0] >= '0') type = strchr(type, '_') + 1; if (flags & J2S_FLAG_ARRAY) { flags |= J2S_FLAG_DEP_ARRAY; } else if (flags & J2S_FLAG_POINTER) { flags |= J2S_FLAG_ARRAY_POINTER; /* Set it later */ flags &= ~J2S_FLAG_POINTER; } else { flags |= J2S_FLAG_ARRAY; } } /* Check for dep type limits */ if (flags & J2S_FLAG_ARRAY_POINTER) { DASSERT_MSG(!(flags & J2S_FLAG_ARRAY), return -1, "array too dep at %d\n", ctx->line); DASSERT_MSG(!(flags & J2S_FLAG_POINTER), return -1, "pointer too dep at %d\n", ctx->line); DASSERT_MSG(!(flags & J2S_FLAG_DEP_ARRAY), return -1, "array too dep at %d\n", ctx->line); DASSERT_MSG(!(flags & J2S_FLAG_DEP_POINTER), return -1, "pointer too dep at %d\n", ctx->line); flags |= J2S_FLAG_ARRAY; flags |= J2S_FLAG_POINTER; } else if (flags & J2S_FLAG_DEP_ARRAY) { DASSERT_MSG(!(flags & J2S_FLAG_POINTER), return -1, "array too dep at %d\n", ctx->line); } else if (flags & J2S_FLAG_DEP_POINTER) { DASSERT_MSG(!(flags & J2S_FLAG_ARRAY), return -1, "pointer too dep at %d\n", ctx->line); } /* Prepare member obj */ obj = calloc(1, sizeof(*obj)); DASSERT(obj, exit(-1)); obj->id = ctx->num_obj++; obj->line = ctx->line; strncpy(obj->type_name, type, sizeof(obj->type_name)); strncpy(obj->name, name, sizeof(obj->name)); obj->flags = flags; obj->desc = ctx->desc; ctx->desc = NULL; /* Parse obj type and check type limits */ obj->type = j2s_parse_type(type, flags); static bool type_warn_once = false; if (!type_warn_once && (obj->type == J2S_TYPE_INT_64 || obj->type == J2S_TYPE_UINT_64)) { type_warn_once = true; WARN("64 bit type might have precision issue!\n"); } if (obj->type != J2S_TYPE_STRING) { DASSERT_MSG(!(flags & J2S_FLAG_DEP_POINTER), return -1, "dep pointer only for string at %d\n", ctx->line); if (flags & J2S_FLAG_ARRAY && flags & J2S_FLAG_POINTER) DASSERT_MSG(flags & J2S_FLAG_ARRAY_POINTER, return -1, "pointer array only for string at %d\n", ctx->line); } obj->parent = ctx->struct_obj; j2s_list_add(&ctx->objs, obj); /* Link with prev child */ if (ctx->struct_obj->child_id < 0) { ctx->struct_obj->child_id = obj->id; } else { j2s_obj *tmp_obj = ((j2s_list *)ctx->struct_obj->child.prev)->data; tmp_obj->next = obj; } j2s_list_add(&ctx->struct_obj->child, obj); if (obj->desc) { DBG("adding member %s with desc: %s\n", obj->name, obj->desc); } else { DBG("adding member %s\n", obj->name); } out: if (pending[0]) return j2s_parse(ctx, pending); return 0; } /* Dump parsed header */ static inline void j2s_dump(j2s_ctx *ctx) { j2s_list *entry, *next; j2s_enum_value *enum_value; j2s_struct *struct_obj; j2s_enum *enum_obj; j2s_obj *obj; int magic; srand(time(NULL)); magic = rand(); printf("#include \n"); printf("#include \"j2s.h\"\n\n"); printf("#define J2S_MAGIC %d\n", magic); printf("#define J2S_NUM_OBJ %d\n", ctx->num_obj); printf("#define J2S_NUM_STRUCT %d\n", ctx->num_struct); printf("#define J2S_NUM_ENUM %d\n", ctx->num_enum); printf("#define J2S_NUM_ENUM_VALUE %d\n\n", ctx->num_enum_value); printf("static void _j2s_init(j2s_ctx *ctx) {\n"); printf("\tj2s_obj *obj;\n\n"); printf("\tstatic j2s_obj objs[J2S_NUM_OBJ];\n"); printf("\tstatic j2s_struct structs[J2S_NUM_STRUCT];\n"); printf("\tstatic j2s_enum enums[J2S_NUM_ENUM];\n"); printf("\tstatic j2s_enum_value enum_values[J2S_NUM_ENUM_VALUE];\n\n"); printf("\tctx->magic = J2S_MAGIC;\n"); printf("\tctx->priv = NULL;\n"); printf("\tctx->objs = (j2s_obj *)&objs;\n"); printf("\tctx->structs = (j2s_struct *)&structs;\n"); printf("\tctx->enums = (j2s_enum *)&enums;\n"); printf("\tctx->enum_values = (j2s_enum_value *)&enum_values;\n\n"); printf("\tctx->num_obj = J2S_NUM_OBJ;\n"); printf("\tctx->num_struct = J2S_NUM_STRUCT;\n"); printf("\tctx->num_enum = J2S_NUM_ENUM;\n"); printf("\tctx->num_enum_value = J2S_NUM_ENUM_VALUE;\n\n"); printf("\n#ifndef J2S_ENABLE_DESC\n"); printf("\tctx->num_desc = 0;\n"); printf("#else\n"); printf("\tstatic const char *descs[J2S_NUM_OBJ];\n"); printf("\tctx->descs = (const char **)descs;\n"); printf("\tctx->num_desc = J2S_NUM_OBJ;\n"); printf("#endif\n\n"); struct_obj = ctx->root_struct; INFO("root struct: %s\n", struct_obj->name); printf("\tctx->root_index = %d;\n\n", struct_obj->id); /* Dump obj list */ j2s_list_walk_safe(&ctx->objs, entry, next, obj) { printf("\tobj = &ctx->objs[%d];\n", obj->id); printf("\tstrcpy(obj->name, \"%s\");\n", obj->name); printf("\tobj->type = %s;\n", j2s_types[obj->type]); #define DUMP_FLAG(flags, FLAG) \ if (flags & FLAG) printf("| "#FLAG) printf("\tobj->flags = 0 "); DUMP_FLAG(obj->flags, J2S_FLAG_ARRAY); DUMP_FLAG(obj->flags, J2S_FLAG_POINTER); DUMP_FLAG(obj->flags, J2S_FLAG_DEP_ARRAY); DUMP_FLAG(obj->flags, J2S_FLAG_DEP_POINTER); DUMP_FLAG(obj->flags, J2S_FLAG_ARRAY_POINTER); printf(";\n"); #define MEMBER_DEP_0 "((%s*)0)->%s" #define MEMBER_DEP_1 MEMBER_DEP_0 "[0]" #define MEMBER_DEP_2 MEMBER_DEP_1 "[0]" printf("\tobj->offset = (uintptr_t)&" MEMBER_DEP_0 ";\n", obj->parent->name, obj->name); if (obj->flags & (J2S_FLAG_ARRAY | J2S_FLAG_POINTER)) { printf("\tobj->elem_size = sizeof(" MEMBER_DEP_1 ");\n", obj->parent->name, obj->name); } else { printf("\tobj->elem_size = sizeof(" MEMBER_DEP_0 ");\n", obj->parent->name, obj->name); } if ((obj->flags & J2S_FLAG_ARRAY && obj->flags & J2S_FLAG_POINTER) || obj->flags & J2S_FLAG_DEP_ARRAY || obj->flags & J2S_FLAG_DEP_POINTER) { printf("\tobj->base_elem_size = " "sizeof(" MEMBER_DEP_2 ");\n", obj->parent->name, obj->name); } else { printf("\tobj->base_elem_size = obj->elem_size;\n"); } if (J2S_IS_ARRAY(obj)) { printf("\tobj->num_elem = (sizeof(" MEMBER_DEP_0 ") / " "obj->elem_size);\n", obj->parent->name, obj->name); } else { printf("\tobj->num_elem = 1;\n"); } /* Dynamic array needs a "_len" sibling */ if ((obj->type != J2S_TYPE_STRING && obj->flags & J2S_FLAG_POINTER) || (obj->type == J2S_TYPE_STRING && (obj->flags & J2S_FLAG_DEP_POINTER || obj->flags & J2S_FLAG_ARRAY_POINTER))) { j2s_obj *len_obj; char len_name[MAX_NAME + 5]; snprintf(len_name, MAX_NAME + 5, "%s_len", obj->name); j2s_list_find(&obj->parent->child, entry, len_obj, len_name); DASSERT_MSG(len_obj, exit(-1), "missing %s\n", len_name); DASSERT_MSG(len_obj->type <= J2S_TYPE_UINT_64 && !len_obj->flags, exit(-1), "%s should be int\n", len_name); obj->len_obj = len_obj; } printf("\tobj->len_index = %d;\n", obj->len_obj ? ((j2s_obj *)obj->len_obj)->id : -1); printf("\tobj->next_index = %d;\n", obj->next ? ((j2s_obj *)obj->next)->id : -1); printf("\tobj->struct_index = %d;\n", obj->struct_obj ? obj->struct_obj->id : -1); printf("\tobj->enum_index = %d;\n", obj->enum_obj ? obj->enum_obj->id : -1); if (obj->desc) { char *ptr; while (ptr = strchr(obj->desc, '"')) *ptr = '\''; /* Check default value for enum in desc */ if (obj->enum_obj) { ptr = strstr(obj->desc, "default="); if (ptr) { char buf[MAX_LINE]; char *name = buf; strcpy(name, ptr + strlen("default=")); ptr = strchr_first(name, ' ', ','); if (ptr) *ptr = '\0'; strip_spaces(&name, true); j2s_list_find(&obj->enum_obj->values, entry, enum_value, name); DASSERT_MSG(enum_value, exit(-1), "invalid default enum " "%s for %s\n", name, obj->name); } } printf("#ifdef J2S_ENABLE_DESC\n"); printf("\tctx->descs[%d] = \"%s\";\n", obj->id, obj->desc); printf("#endif\n"); } printf("\n"); } /* Dump struct list */ j2s_list_walk_safe(&ctx->structs, entry, next, struct_obj) { printf("\tstrcpy(ctx->structs[%d].name, \"%s\");\n", struct_obj->id, struct_obj->name); printf("\tctx->structs[%d].child_index = %d;\n", struct_obj->id, struct_obj->child_id); } /* Dump enum list */ j2s_list_walk_safe(&ctx->enums, entry, next, enum_obj) { printf("\n\tstrcpy(ctx->enums[%d].name, \"%s\");\n", enum_obj->id, enum_obj->name); printf("\tctx->enums[%d].value_index = %d;\n", enum_obj->id, enum_obj->value_id); printf("\tctx->enums[%d].num_value = %d;\n\n", enum_obj->id, enum_obj->num_value); j2s_list_walk(&enum_obj->values, entry, enum_value) { printf("\tstrcpy(ctx->enum_values[%d].name, \"%s\");\n", enum_value->id, enum_value->name); printf("\tctx->enum_values[%d].value = %s;\n", enum_value->id, enum_value->name); } } printf("}\n"); } int main(int argc, char** argv) { j2s_list *entry, *next; j2s_struct *struct_obj; j2s_enum *enum_obj; j2s_obj *obj; j2s_ctx ctx = {0}; char buf[MAX_LINE]; j2s_list_init(&ctx.objs); j2s_list_init(&ctx.structs); j2s_list_init(&ctx.enums); DASSERT_MSG(argc > 1, return -1, "usage: %s [root struct]\n", argv[0]); INFO("start parsing %s\n", argv[1]); ctx.fp = fopen(argv[1],"r"); DASSERT_MSG(ctx.fp, return -1, "failed to open %s\n", argv[1]); while (fgets(buf, MAX_LINE, ctx.fp)) { ctx.line++; j2s_parse(&ctx, buf); } INFO("finished parsing %s\n", argv[1]); fclose(ctx.fp); /* Set objs' struct/enum obj and check unsupported type */ j2s_list_walk_safe(&ctx.objs, entry, next, obj) { if (obj->type != J2S_TYPE_STRUCT) continue; j2s_list_find(&ctx.structs, entry, struct_obj, obj->type_name); if (struct_obj) { obj->struct_obj = struct_obj; } else { j2s_list_find(&ctx.enums, entry, enum_obj, obj->type_name); DASSERT_MSG(enum_obj, exit(-1), "unknown type '%s' at %d\n", obj->type_name, obj->line); obj->type = J2S_TYPE_INT_32; obj->enum_obj = enum_obj; } } /* Handle specified root struct */ if (argc > 2) { INFO("specified root struct: %s\n", argv[2]); j2s_list_find(&ctx.structs, entry, struct_obj, argv[2]); ctx.root_struct = struct_obj; } DASSERT_MSG(ctx.root_struct, exit(-1), "no root struct!\n"); /* Dump parsed header */ j2s_dump(&ctx); /* Free lists */ j2s_list_walk_safe(&ctx.structs, entry, next, struct_obj) j2s_list_free(&struct_obj->child, entry, false); j2s_list_free(&ctx.structs, entry, true); j2s_list_walk(&ctx.objs, entry, obj) free(obj->desc); j2s_list_free(&ctx.objs, entry, true); j2s_list_walk_safe(&ctx.enums, entry, next, enum_obj) j2s_list_free(&enum_obj->values, entry, true); j2s_list_free(&ctx.enums, entry, true); return 0; }