1 /*
2 * Copyright (c) 2020, Rockchip Electronics Co., Ltd
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 */
14 #define _GNU_SOURCE
15
16 #include "common.h"
17
18 #include <time.h>
19 #include <string.h>
20
21 /* j2s list helpers */
22 typedef struct {
23 void *data;
24 void *next;
25 void *prev;
26 } j2s_list;
27
j2s_list_add(j2s_list * head,void * data)28 void j2s_list_add(j2s_list *head, void *data) {
29 j2s_list *entry = malloc(sizeof(j2s_list));
30 DASSERT(entry, exit(-1));
31
32 entry->data = data;
33
34 entry->prev = head->prev;
35 entry->next = head;
36 ((j2s_list *)head->prev)->next = entry;
37 head->prev = entry;
38 }
39
j2s_list_del(j2s_list * entry)40 void j2s_list_del(j2s_list *entry) {
41 ((j2s_list *)entry->prev)->next = entry->next;
42 ((j2s_list *)entry->next)->prev = entry->prev;
43 free(entry);
44 }
45
46 #define j2s_list_init(head) \
47 (head)->prev = (head)->next = head; (head)->data = NULL;
48
49 #define j2s_list_empty(head) \
50 ((head)->prev == head)
51
52 #define j2s_list_walk_safe(head, entry, next, obj) \
53 for (entry = (head)->next, next = entry->next, obj = entry->data; \
54 entry != head; \
55 entry = next, next = entry->next, obj = entry->data)
56
57 #define j2s_list_walk(head, entry, obj) \
58 for (entry = (head)->next, obj = entry->data; entry != head; \
59 entry = entry->next, obj = entry->data)
60
61 #define j2s_list_free(head, entry, free_data) \
62 for (entry = (head)->next; entry != head; \
63 entry = entry->next, free(entry->prev)) \
64 if (free_data) free(entry->data)
65
66 #define j2s_list_find(head, entry, obj, s) \
67 j2s_list_walk(head, entry, obj) \
68 if (!strcmp(obj->name, s)) break; \
69 if (entry == head) obj = NULL;
70
71 /* Info about each enums */
72 typedef struct {
73 int id;
74 char name[MAX_NAME]; /* Enum name */
75 j2s_list values; /* value list */
76 int value_id; /* Id of the first enum value */
77 int num_value; /* Number of enum values */
78 } j2s_enum;
79
80 /* Info about each enum values */
81 typedef struct {
82 int id;
83 char name[MAX_NAME]; /* Value name */
84 } j2s_enum_value;
85
86 /* Info about each structs */
87 typedef struct {
88 int id;
89 char name[MAX_NAME]; /* Struct name */
90 j2s_list child; /* Child list */
91 int child_id; /* Id of the first child */
92 } j2s_struct;
93
94 /* Info about each struct members */
95 typedef struct {
96 int id;
97 char name[MAX_NAME]; /* Member name */
98 char type_name[MAX_NAME]; /* Origin type name */
99 j2s_type type;
100 j2s_flag flags;
101
102 char *desc; /* Optional desc string */
103
104 void *next; /* Next child of the parent */
105 j2s_struct *parent; /* Parent struct */
106
107 j2s_struct *struct_obj; /* Struct info(if type is struct) */
108 j2s_enum *enum_obj; /* Enum info(if type is enum) */
109 void *len_obj; /* Dynamic array needs a @<name>_len obj to store len */
110
111 int line; /* Line of the header file */
112 } j2s_obj;
113
114 /* J2S parsing context */
115 typedef struct {
116 j2s_list structs;
117 j2s_list enums;
118 j2s_list objs;
119
120 int num_enum_value;
121 int num_struct;
122 int num_enum;
123 int num_obj;
124
125 int depth;
126
127 bool pending_bool;
128 bool pending_enum;
129 bool pending_struct;
130 bool pending_comment;
131
132 j2s_struct *struct_obj;
133 j2s_enum *enum_obj;
134
135 char *desc;
136
137 j2s_struct *root_struct;
138
139 FILE *fp; /* Input file */
140 int line; /* Line of the header file */
141 } j2s_ctx;
142
143 #define J2S_TYPE(t) [t] = #t
144 const char j2s_types[][MAX_NAME] = {
145 J2S_TYPE(J2S_TYPE_INT_8),
146 J2S_TYPE(J2S_TYPE_UINT_8),
147 J2S_TYPE(J2S_TYPE_INT_16),
148 J2S_TYPE(J2S_TYPE_UINT_16),
149 J2S_TYPE(J2S_TYPE_INT_32),
150 J2S_TYPE(J2S_TYPE_UINT_32),
151 J2S_TYPE(J2S_TYPE_INT_64),
152 J2S_TYPE(J2S_TYPE_UINT_64),
153 J2S_TYPE(J2S_TYPE_FLOAT),
154 J2S_TYPE(J2S_TYPE_DOUBLE),
155 J2S_TYPE(J2S_TYPE_STRING),
156 J2S_TYPE(J2S_TYPE_STRUCT),
157 };
158
159 static inline
j2s_parse_type(const char * type,j2s_flag flags)160 j2s_type j2s_parse_type(const char *type, j2s_flag flags) {
161 if (!strcmp(type, "char") &&
162 (flags & (J2S_FLAG_ARRAY | J2S_FLAG_POINTER)))
163 return J2S_TYPE_STRING;
164 if (!strcmp(type, "char") || !strcmp(type, "bool") ||
165 !strcmp(type, "int8_t"))
166 return J2S_TYPE_INT_8;
167 if (!strcmp(type, "unsigned char") || !strcmp(type, "uint8_t"))
168 return J2S_TYPE_UINT_8;
169 if (!strcmp(type, "short") || !strcmp(type, "int16_t"))
170 return J2S_TYPE_INT_16;
171 if (!strcmp(type, "unsigned short") || !strcmp(type, "uint16_t"))
172 return J2S_TYPE_UINT_16;
173 if (!strcmp(type, "int") || !strcmp(type, "int32_t"))
174 return J2S_TYPE_INT_32;
175 if (!strcmp(type, "unsigned int") || !strcmp(type, "uint32_t"))
176 return J2S_TYPE_UINT_32;
177 if (!strcmp(type, "long") || !strcmp(type, "long long") ||
178 !strcmp(type, "int64_t"))
179 return J2S_TYPE_INT_64;
180 if (!strcmp(type, "unsigned long") ||
181 !strcmp(type, "unsigned long long") || !strcmp(type, "uint64_t"))
182 return J2S_TYPE_UINT_64;
183 if (!strcmp(type, "float"))
184 return J2S_TYPE_FLOAT;
185 if (!strcmp(type, "double"))
186 return J2S_TYPE_DOUBLE;
187
188 /* Fallback to struct, unsupported types would be catched later */
189 return J2S_TYPE_STRUCT;
190 }
191
192 static inline
strip_spaces(char ** buf,bool strip_tails)193 void strip_spaces(char **buf, bool strip_tails) {
194 if (!buf || !*buf)
195 return;
196
197 #define IS_SPACE(c) ((c) == '\t' || (c) == ' ' || (c) == ',' || \
198 (c) == '\'' || (c) == ';' || (c) == '\n' || (c) == '\r')
199
200 /* Strip leading spaces */
201 while (IS_SPACE(*buf[0]))
202 (*buf)++;
203
204 if (!strip_tails)
205 return;
206
207 /* Strip tail spaces */
208 for (int i = strlen(*buf) - 1; i >= 0 && IS_SPACE((*buf)[i]); i--)
209 (*buf)[i] = '\0';
210 }
211
212 /* Strip spaces and compare and eat pattern */
213 static inline
parse_pattern(char ** buf,const char * pattern)214 int parse_pattern(char **buf, const char *pattern) {
215 int ret = -1;
216
217 if (!buf || !*buf)
218 return -1;
219
220 /* Strip spaces */
221 strip_spaces(buf, false);
222
223 /* Compare and eat pattern */
224 if (pattern && !strncmp(*buf, pattern, strlen(pattern))) {
225 *buf += strlen(pattern);
226 ret = 0;
227 }
228
229 /* Strip spaces */
230 strip_spaces(buf, false);
231
232 return ret;
233 }
234
235 /* Return the first pos of a or b */
236 static inline
strchr_first(const char * buf,const char a,const char b)237 char *strchr_first(const char *buf, const char a, const char b) {
238 char *p1, *p2;
239
240 if (a == b)
241 return strchr(buf, a);
242
243 p1 = strchrnul(buf, a);
244 p2 = strchrnul(buf, b);
245
246 if (p1 == p2)
247 return NULL;
248
249 return p1 < p2 ? p1 : p2;
250 }
251
252 static inline
j2s_handle_comment(j2s_ctx * ctx,char * buf)253 void j2s_handle_comment(j2s_ctx *ctx, char *buf) {
254 int size;
255
256 strip_spaces(&buf, true);
257 DBG("comment: %s\n", buf);
258
259 if (!ctx->struct_obj)
260 return;
261
262 if (parse_pattern(&buf, J2S_DESC_MAGIC) < 0)
263 return;
264
265 /* Handle member desc (comments started with magic) */
266
267 if (!ctx->desc)
268 ctx->desc = strdup("");
269 else
270 strcat(ctx->desc, ", ");
271
272 size = strlen(ctx->desc) + strlen(buf) + 10;
273
274 ctx->desc = realloc(ctx->desc, size);
275 DASSERT_MSG(ctx->desc, exit(-1), "desc size too large: %d\n", size);
276
277 strcat(ctx->desc, buf);
278
279 DBG("new desc: %s\n", ctx->desc);
280 }
281
282 static inline
j2s_parse(j2s_ctx * ctx,char * buf)283 int j2s_parse(j2s_ctx *ctx, char *buf) {
284 j2s_enum_value *enum_value = NULL;
285 j2s_struct *struct_obj = NULL;
286 j2s_enum *enum_obj = NULL;
287 j2s_obj *obj = NULL;
288 j2s_flag flags;
289
290 char pending[MAX_LINE] = {0};
291 char *ptr, *type, *name;
292
293 DBG("parsing '%s' at %d\n", buf, ctx->line);
294
295 strip_spaces(&buf, true);
296
297 /* 1. Handle multiline comments */
298 if (ctx->pending_comment) {
299 ptr = strstr(buf, "*/");
300 if (ptr) {
301 /* End of multiline comment */
302 *ptr = '\0';
303
304 j2s_handle_comment(ctx, buf);
305
306 buf = ptr + 2;
307 ctx->pending_comment = false;
308 } else {
309 /* Multiline comments */
310 strip_spaces(&buf, true);
311 while (buf[0] == '*')
312 buf++;
313
314 j2s_handle_comment(ctx, buf);
315 return 0;
316 }
317 }
318
319 /* 2. Handle new comments */
320 ptr = strstr(buf, "/*");
321 if (ptr) {
322 /* Start of comment */
323 char *start = ptr + 2;
324
325 *ptr = '\0';
326 ptr = strstr(start, "*/");
327 if (ptr) {
328 /* Inline comment */
329 *ptr = '\0';
330 ptr += 2;
331
332 j2s_handle_comment(ctx, start);
333
334 /* Remove inline comment */
335 start = buf + strlen(buf);
336 for (int i = 0; i < strlen(ptr) + 1; i++)
337 start[i] = ptr[i];
338
339 return j2s_parse(ctx, buf);
340 } else {
341 /* Start of multiline comments */
342 ctx->pending_comment = true;
343 j2s_handle_comment(ctx, start);
344 }
345 }
346
347 ptr = strstr(buf, "//");
348 if (ptr) {
349 /* One line comment */
350 *ptr = '\0';
351 ptr += 2;
352
353 j2s_handle_comment(ctx, ptr);
354 }
355
356 /* 3. Split buf */
357 strip_spaces(&buf, true);
358 ptr = strchr_first(buf, ';', '{');
359 if (ptr) {
360 ptr++;
361
362 if (*ptr) {
363 strcpy(pending, ptr);
364 *ptr = '\0';
365 strip_spaces(&buf, true);
366
367 DBG("parsing '%s', pending '%s'\n",
368 buf, pending);
369 }
370 }
371
372 /* 4. Filter out empty lines */
373 if (buf[0] == '\0' || buf[0] == '#')
374 goto out;
375
376 /* 5. Handle enum definations */
377 if (!parse_pattern(&buf, "typedef enum")) {
378 DASSERT_MSG(!ctx->struct_obj && !ctx->enum_obj && \
379 !ctx->pending_enum && !ctx->pending_struct && \
380 !ctx->depth, exit(-1),
381 "failed to parse enum at %d\n", ctx->line);
382
383 ctx->pending_enum = true;
384 }
385
386 if (ctx->pending_enum) {
387 if (!strchr(buf, '{')) {
388 DBG("waiting for '{', skip \"%s\"\n", buf);
389 goto out;
390 }
391
392 ctx->depth++;
393
394 /* Handle new enum */
395 DBG("found enum\n");
396
397 ctx->pending_enum = false;
398 ctx->enum_obj = malloc(sizeof(*enum_obj));
399 DASSERT(ctx->enum_obj, exit(-1));
400
401 j2s_list_init(&ctx->enum_obj->values);
402 ctx->enum_obj->value_id = -1;
403 ctx->enum_obj->num_value = 0;
404 goto out;
405 }
406
407 if (ctx->enum_obj) {
408 j2s_enum_value *enum_value;
409
410 if (!parse_pattern(&buf, "}")) {
411 ctx->depth--;
412
413 /* End of enum defination */
414 strip_spaces(&buf, true);
415
416 INFO("adding enum %s\n", buf);
417
418 /* Add to enum list */
419 strncpy(ctx->enum_obj->name, buf,
420 sizeof(ctx->enum_obj->name));
421 ctx->enum_obj->id = ctx->num_enum++;
422 j2s_list_add(&ctx->enums, ctx->enum_obj);
423
424 ctx->enum_obj = NULL;
425 goto out;
426 }
427
428 /* Parsing enum value */
429
430 /* The first word is enum value name */
431 strip_spaces(&buf, true);
432 name = buf;
433 ptr = strchr_first(name, ' ', '=');
434 if (ptr)
435 *ptr = '\0';
436
437 /* Add enum value */
438 enum_value = malloc(sizeof(*enum_value));
439 DASSERT(enum_value, exit(-1));
440
441 enum_value->id = ctx->num_enum_value++;
442 strncpy(enum_value->name, buf,
443 sizeof(enum_value->name));
444 j2s_list_add(&ctx->enum_obj->values, enum_value);
445
446 ctx->enum_obj->num_value++;
447
448 if (ctx->enum_obj->value_id < 0)
449 ctx->enum_obj->value_id = enum_value->id;
450
451 DBG("adding enum value %s\n", enum_value->name);
452 goto out;
453 }
454
455 /* 6. Handle struct definations */
456 if (!parse_pattern(&buf, "typedef struct")) {
457 DASSERT_MSG(!ctx->depth && !ctx->struct_obj, exit(-1),
458 "failed to parse struct at %d\n", ctx->line);
459 ctx->pending_struct = true;
460 }
461
462 /* Waiting for struct defination */
463 if (ctx->depth) {
464 if (!ctx->struct_obj) {
465 if (strchr(buf, '}'))
466 ctx->depth--;
467
468 DBG("waiting for struct, skip \"%s\"\n", buf);
469 goto out;
470 }
471 } else {
472 if (!strchr(buf, '{')) {
473 DBG("waiting for '{', skip \"%s\"\n", buf);
474 goto out;
475 }
476
477 ctx->depth++;
478
479 if (!ctx->pending_struct) {
480 DBG("waiting for struct, skip \"%s\"\n", buf);
481 goto out;
482 }
483
484 /* Handle new struct */
485 DBG("found struct\n");
486
487 ctx->pending_struct = false;
488 ctx->struct_obj = malloc(sizeof(*struct_obj));
489 DASSERT(ctx->struct_obj, exit(-1));
490
491 j2s_list_init(&ctx->struct_obj->child);
492 ctx->struct_obj->child_id = -1;
493 goto out;
494 }
495
496 /* Skip union's { */
497 if (!parse_pattern(&buf, "union {")) {
498 ctx->depth++;
499 goto out;
500 }
501
502 /* union's } or end of struct defination */
503 if (!parse_pattern(&buf, "}")) {
504 DASSERT_MSG(ctx->depth > 0, exit(-1),
505 "} not paired at %d\n", ctx->line);
506
507 ctx->depth--;
508
509 /* End of struct defination */
510 if (!ctx->depth && ctx->struct_obj) {
511 /* Skip packed attribute */
512 parse_pattern(&buf, "__attribute__((packed))");
513
514 /* Parse struct name */
515 strip_spaces(&buf, true);
516 name = buf;
517 ptr = strrchr(name, ' ');
518 if (ptr)
519 name = ptr + 1;
520
521 INFO("adding struct %s\n", name);
522
523 /* Add to struct list */
524 strncpy(ctx->struct_obj->name, name,
525 sizeof(ctx->struct_obj->name));
526 ctx->struct_obj->id = ctx->num_struct++;
527 j2s_list_add(&ctx->structs, ctx->struct_obj);
528
529 /* Using the last struct as root struct */
530 ctx->root_struct = ctx->struct_obj;
531
532 ctx->struct_obj = NULL;
533
534 DASSERT_MSG(!ctx->desc,
535 free(ctx->desc); ctx->desc = NULL,
536 "unhandled desc: '%s'\n", ctx->desc);
537 }
538 goto out;
539 }
540
541 /* 7. Handle struct members */
542
543 /* Handle special bool defination */
544 if (!strcmp(buf, "_Bool")) {
545 DASSERT_MSG(!ctx->pending_bool, exit(-1),
546 "failed to parse bool at %d\n", ctx->line);
547
548 ctx->pending_bool = true;
549 goto out;
550 }
551
552 flags = 0;
553
554 /* Detect array and strip it */
555 ptr = strrchr(buf, '[');
556 if (ptr) {
557 DBG("'%s' is an array\n", buf);
558
559 *ptr = '\0';
560 flags |= J2S_FLAG_ARRAY;
561
562 /* Detect dep array */
563 ptr = strrchr(buf, '[');
564 if (ptr) {
565 DBG("\tand a dep array %s\n", buf);
566
567 *ptr = '\0';
568 flags |= J2S_FLAG_DEP_ARRAY;
569
570 DASSERT_MSG(!strrchr(buf, '['), return -1,
571 "array too dep at %d\n", ctx->line);
572 }
573 }
574
575 /* Detect pointer */
576 ptr = strrchr(buf, '*');
577 if (ptr) {
578 DBG("'%s' is a pointer\n", buf);
579
580 *ptr = ' '; /* Would be stripped later */
581 flags |= J2S_FLAG_POINTER;
582
583 ptr = strrchr(buf, '*');
584 if (ptr) {
585 DBG("\tand a dep pointer %s\n", buf);
586
587 *ptr = ' '; /* Would be stripped later */
588 flags |= J2S_FLAG_DEP_POINTER;
589
590 DASSERT_MSG(!strrchr(buf, '*'), return -1,
591 "pointer too dep at %d\n", ctx->line);
592 }
593 }
594
595 /* Extract type and name */
596 ptr = strrchr(buf, ' ');
597 if (ctx->pending_bool) {
598 DASSERT_MSG(!ptr, exit(-1),
599 "failed to parse bool at %d\n", ctx->line);
600 ctx->pending_bool = false;
601 type = "bool";
602 name = buf;
603 } else {
604 DASSERT_MSG(ptr, exit(-1),
605 "parse member error from '%s' at %d\n",
606 buf, ctx->line);
607 *ptr = '\0';
608 type = buf;
609 name = ptr + 1;
610 }
611
612 parse_pattern(&type, "const");
613 strip_spaces(&type, true);
614 strip_spaces(&name, true);
615
616 /* Detect typedef array pointer */
617 if (!parse_pattern(&type, "array_ptr_")) {
618 DBG("'%s' is an array pointer\n", name);
619
620 /* Remove member desc */
621 if (type[0] <= '9' && type[0] >= '0')
622 type = strchr(type, '_') + 1;
623
624 flags |= J2S_FLAG_ARRAY_POINTER;
625 }
626
627 /* Detect typedef array */
628 if (!parse_pattern(&type, "array_")) {
629 DBG("'%s' is an array\n", name);
630
631 DASSERT_MSG(!(flags & J2S_FLAG_DEP_ARRAY), return -1,
632 "array too dep at %d\n", ctx->line);
633 DASSERT_MSG(!(flags & J2S_FLAG_DEP_POINTER), return -1,
634 "pointer too dep at %d\n", ctx->line);
635
636 /* Remove member desc */
637 if (type[0] <= '9' && type[0] >= '0')
638 type = strchr(type, '_') + 1;
639
640 if (flags & J2S_FLAG_ARRAY) {
641 flags |= J2S_FLAG_DEP_ARRAY;
642 } else if (flags & J2S_FLAG_POINTER) {
643 flags |= J2S_FLAG_ARRAY_POINTER;
644
645 /* Set it later */
646 flags &= ~J2S_FLAG_POINTER;
647 } else {
648 flags |= J2S_FLAG_ARRAY;
649 }
650 }
651
652 /* Check for dep type limits */
653 if (flags & J2S_FLAG_ARRAY_POINTER) {
654 DASSERT_MSG(!(flags & J2S_FLAG_ARRAY), return -1,
655 "array too dep at %d\n", ctx->line);
656 DASSERT_MSG(!(flags & J2S_FLAG_POINTER), return -1,
657 "pointer too dep at %d\n", ctx->line);
658 DASSERT_MSG(!(flags & J2S_FLAG_DEP_ARRAY), return -1,
659 "array too dep at %d\n", ctx->line);
660 DASSERT_MSG(!(flags & J2S_FLAG_DEP_POINTER), return -1,
661 "pointer too dep at %d\n", ctx->line);
662
663 flags |= J2S_FLAG_ARRAY;
664 flags |= J2S_FLAG_POINTER;
665 } else if (flags & J2S_FLAG_DEP_ARRAY) {
666 DASSERT_MSG(!(flags & J2S_FLAG_POINTER), return -1,
667 "array too dep at %d\n", ctx->line);
668 } else if (flags & J2S_FLAG_DEP_POINTER) {
669 DASSERT_MSG(!(flags & J2S_FLAG_ARRAY), return -1,
670 "pointer too dep at %d\n", ctx->line);
671 }
672
673 /* Prepare member obj */
674 obj = calloc(1, sizeof(*obj));
675 DASSERT(obj, exit(-1));
676
677 obj->id = ctx->num_obj++;
678 obj->line = ctx->line;
679
680 strncpy(obj->type_name, type, sizeof(obj->type_name));
681 strncpy(obj->name, name, sizeof(obj->name));
682 obj->flags = flags;
683 obj->desc = ctx->desc;
684 ctx->desc = NULL;
685
686 /* Parse obj type and check type limits */
687 obj->type = j2s_parse_type(type, flags);
688
689 static bool type_warn_once = false;
690 if (!type_warn_once &&
691 (obj->type == J2S_TYPE_INT_64 ||
692 obj->type == J2S_TYPE_UINT_64)) {
693 type_warn_once = true;
694
695 WARN("64 bit type might have precision issue!\n");
696 }
697
698 if (obj->type != J2S_TYPE_STRING) {
699 DASSERT_MSG(!(flags & J2S_FLAG_DEP_POINTER), return -1,
700 "dep pointer only for string at %d\n", ctx->line);
701
702 if (flags & J2S_FLAG_ARRAY &&
703 flags & J2S_FLAG_POINTER)
704 DASSERT_MSG(flags & J2S_FLAG_ARRAY_POINTER,
705 return -1,
706 "pointer array only for string at %d\n",
707 ctx->line);
708 }
709
710 obj->parent = ctx->struct_obj;
711
712 j2s_list_add(&ctx->objs, obj);
713
714 /* Link with prev child */
715 if (ctx->struct_obj->child_id < 0) {
716 ctx->struct_obj->child_id = obj->id;
717 } else {
718 j2s_obj *tmp_obj =
719 ((j2s_list *)ctx->struct_obj->child.prev)->data;
720 tmp_obj->next = obj;
721 }
722
723 j2s_list_add(&ctx->struct_obj->child, obj);
724
725 if (obj->desc) {
726 DBG("adding member %s with desc: %s\n",
727 obj->name, obj->desc);
728 } else {
729 DBG("adding member %s\n", obj->name);
730 }
731
732 out:
733 if (pending[0])
734 return j2s_parse(ctx, pending);
735
736 return 0;
737 }
738
739 /* Dump parsed header */
740 static inline
j2s_dump(j2s_ctx * ctx)741 void j2s_dump(j2s_ctx *ctx) {
742 j2s_list *entry, *next;
743 j2s_enum_value *enum_value;
744 j2s_struct *struct_obj;
745 j2s_enum *enum_obj;
746 j2s_obj *obj;
747 int magic;
748
749 srand(time(NULL));
750 magic = rand();
751
752 printf("#include <stdint.h>\n");
753 printf("#include \"j2s.h\"\n\n");
754
755 printf("#define J2S_MAGIC %d\n", magic);
756 printf("#define J2S_NUM_OBJ %d\n", ctx->num_obj);
757 printf("#define J2S_NUM_STRUCT %d\n", ctx->num_struct);
758 printf("#define J2S_NUM_ENUM %d\n", ctx->num_enum);
759 printf("#define J2S_NUM_ENUM_VALUE %d\n\n", ctx->num_enum_value);
760
761 printf("static j2s_obj objs[J2S_NUM_OBJ];\n");
762 printf("static j2s_struct structs[J2S_NUM_STRUCT];\n");
763 printf("static j2s_enum enums[J2S_NUM_ENUM];\n");
764 printf("static j2s_enum_value enum_values[J2S_NUM_ENUM_VALUE];\n\n");
765
766 printf("static void _j2s_init(j2s_ctx *ctx) {\n");
767 printf("\tj2s_obj *obj;\n\n");
768
769 printf("\tctx->magic = J2S_MAGIC;\n");
770 printf("\tctx->priv = NULL;\n");
771
772 printf("\tctx->objs = (j2s_obj *)&objs;\n");
773 printf("\tctx->structs = (j2s_struct *)&structs;\n");
774 printf("\tctx->enums = (j2s_enum *)&enums;\n");
775 printf("\tctx->enum_values = (j2s_enum_value *)&enum_values;\n\n");
776
777 printf("\tctx->num_obj = J2S_NUM_OBJ;\n");
778 printf("\tctx->num_struct = J2S_NUM_STRUCT;\n");
779 printf("\tctx->num_enum = J2S_NUM_ENUM;\n");
780 printf("\tctx->num_enum_value = J2S_NUM_ENUM_VALUE;\n\n");
781
782 printf("\n#ifndef J2S_ENABLE_DESC\n");
783 printf("\tctx->num_desc = 0;\n");
784 printf("#else\n");
785 printf("\tstatic const char *descs[J2S_NUM_OBJ];\n");
786 printf("\tctx->descs = (const char **)descs;\n");
787 printf("\tctx->num_desc = J2S_NUM_OBJ;\n");
788 printf("#endif\n\n");
789
790 struct_obj = ctx->root_struct;
791 INFO("root struct: %s\n", struct_obj->name);
792
793 printf("\tctx->root_index = %d;\n\n", struct_obj->id);
794
795 /* Dump obj list */
796 j2s_list_walk_safe(&ctx->objs, entry, next, obj) {
797 printf("\tobj = &ctx->objs[%d];\n", obj->id);
798
799 printf("\tstrcpy(obj->name, \"%s\");\n", obj->name);
800 printf("\tobj->type = %s;\n", j2s_types[obj->type]);
801
802 #define DUMP_FLAG(flags, FLAG) \
803 if (flags & FLAG) printf("| "#FLAG)
804
805 printf("\tobj->flags = 0 ");
806 DUMP_FLAG(obj->flags, J2S_FLAG_ARRAY);
807 DUMP_FLAG(obj->flags, J2S_FLAG_POINTER);
808 DUMP_FLAG(obj->flags, J2S_FLAG_DEP_ARRAY);
809 DUMP_FLAG(obj->flags, J2S_FLAG_DEP_POINTER);
810 DUMP_FLAG(obj->flags, J2S_FLAG_ARRAY_POINTER);
811 printf(";\n");
812
813 #define MEMBER_DEP_0 "((%s*)0)->%s"
814 #define MEMBER_DEP_1 MEMBER_DEP_0 "[0]"
815 #define MEMBER_DEP_2 MEMBER_DEP_1 "[0]"
816
817 printf("\tobj->offset = (uintptr_t)&" MEMBER_DEP_0 ";\n",
818 obj->parent->name, obj->name);
819
820 if (obj->flags & (J2S_FLAG_ARRAY | J2S_FLAG_POINTER)) {
821 printf("\tobj->elem_size = sizeof(" MEMBER_DEP_1 ");\n",
822 obj->parent->name, obj->name);
823
824 } else {
825 printf("\tobj->elem_size = sizeof(" MEMBER_DEP_0 ");\n",
826 obj->parent->name, obj->name);
827 }
828
829 if ((obj->flags & J2S_FLAG_ARRAY &&
830 obj->flags & J2S_FLAG_POINTER) ||
831 obj->flags & J2S_FLAG_DEP_ARRAY ||
832 obj->flags & J2S_FLAG_DEP_POINTER) {
833 printf("\tobj->base_elem_size = "
834 "sizeof(" MEMBER_DEP_2 ");\n",
835 obj->parent->name, obj->name);
836 } else {
837 printf("\tobj->base_elem_size = obj->elem_size;\n");
838 }
839
840 if (J2S_IS_ARRAY(obj)) {
841 printf("\tobj->num_elem = (sizeof(" MEMBER_DEP_0 ") / "
842 "obj->elem_size);\n",
843 obj->parent->name, obj->name);
844 } else {
845 printf("\tobj->num_elem = 1;\n");
846 }
847
848 /* Dynamic array needs a "<name>_len" sibling */
849 if ((obj->type != J2S_TYPE_STRING &&
850 obj->flags & J2S_FLAG_POINTER) ||
851 (obj->type == J2S_TYPE_STRING &&
852 (obj->flags & J2S_FLAG_DEP_POINTER ||
853 obj->flags & J2S_FLAG_ARRAY_POINTER))) {
854 j2s_obj *len_obj;
855 char len_name[MAX_NAME + 5];
856 snprintf(len_name, MAX_NAME + 5, "%s_len", obj->name);
857
858 j2s_list_find(&obj->parent->child, entry,
859 len_obj, len_name);
860
861 DASSERT_MSG(len_obj, exit(-1),
862 "missing %s\n", len_name);
863 DASSERT_MSG(len_obj->type <= J2S_TYPE_UINT_64 &&
864 !len_obj->flags,
865 exit(-1), "%s should be int\n", len_name);
866
867 obj->len_obj = len_obj;
868 }
869
870 printf("\tobj->len_index = %d;\n",
871 obj->len_obj ? ((j2s_obj *)obj->len_obj)->id : -1);
872 printf("\tobj->next_index = %d;\n",
873 obj->next ? ((j2s_obj *)obj->next)->id : -1);
874 printf("\tobj->struct_index = %d;\n",
875 obj->struct_obj ? obj->struct_obj->id : -1);
876 printf("\tobj->enum_index = %d;\n",
877 obj->enum_obj ? obj->enum_obj->id : -1);
878
879 if (obj->desc) {
880 char *ptr;
881
882 while (ptr = strchr(obj->desc, '"'))
883 *ptr = '\'';
884
885 /* Check default value for enum in desc */
886 if (obj->enum_obj) {
887 ptr = strstr(obj->desc, "default=");
888 if (ptr) {
889 char buf[MAX_LINE];
890 char *name = buf;
891
892 strcpy(name, ptr + strlen("default="));
893 ptr = strchr_first(name, ' ', ',');
894 if (ptr)
895 *ptr = '\0';
896
897 strip_spaces(&name, true);
898
899 j2s_list_find(&obj->enum_obj->values,
900 entry, enum_value, name);
901
902 DASSERT_MSG(enum_value, exit(-1),
903 "invalid default enum "
904 "%s for %s\n",
905 name, obj->name);
906 }
907 }
908
909 printf("#ifdef J2S_ENABLE_DESC\n");
910 printf("\tctx->descs[%d] = \"%s\";\n",
911 obj->id, obj->desc);
912 printf("#endif\n");
913 }
914
915 printf("\n");
916 }
917
918 /* Dump struct list */
919 j2s_list_walk_safe(&ctx->structs, entry, next, struct_obj) {
920 printf("\tstrcpy(ctx->structs[%d].name, \"%s\");\n",
921 struct_obj->id, struct_obj->name);
922 printf("\tctx->structs[%d].child_index = %d;\n",
923 struct_obj->id, struct_obj->child_id);
924 }
925
926 /* Dump enum list */
927 j2s_list_walk_safe(&ctx->enums, entry, next, enum_obj) {
928 printf("\n\tstrcpy(ctx->enums[%d].name, \"%s\");\n",
929 enum_obj->id, enum_obj->name);
930 printf("\tctx->enums[%d].value_index = %d;\n",
931 enum_obj->id, enum_obj->value_id);
932 printf("\tctx->enums[%d].num_value = %d;\n\n",
933 enum_obj->id, enum_obj->num_value);
934
935 j2s_list_walk(&enum_obj->values, entry, enum_value) {
936 printf("\tstrcpy(ctx->enum_values[%d].name, \"%s\");\n",
937 enum_value->id, enum_value->name);
938 printf("\tctx->enum_values[%d].value = %s;\n",
939 enum_value->id, enum_value->name);
940 }
941 }
942
943 printf("}\n");
944 }
945
main(int argc,char ** argv)946 int main(int argc, char** argv) {
947 j2s_list *entry, *next;
948 j2s_struct *struct_obj;
949 j2s_enum *enum_obj;
950 j2s_obj *obj;
951 j2s_ctx ctx = {0};
952 char buf[MAX_LINE];
953
954 j2s_list_init(&ctx.objs);
955 j2s_list_init(&ctx.structs);
956 j2s_list_init(&ctx.enums);
957
958 DASSERT_MSG(argc > 1, return -1,
959 "usage: %s <input header> [root struct]\n", argv[0]);
960
961 INFO("start parsing %s\n", argv[1]);
962 ctx.fp = fopen(argv[1],"r");
963 DASSERT_MSG(ctx.fp, return -1, "failed to open %s\n", argv[1]);
964
965 while (fgets(buf, MAX_LINE, ctx.fp)) {
966 ctx.line++;
967 j2s_parse(&ctx, buf);
968 }
969
970 INFO("finished parsing %s\n", argv[1]);
971 fclose(ctx.fp);
972
973 /* Set objs' struct/enum obj and check unsupported type */
974 j2s_list_walk_safe(&ctx.objs, entry, next, obj) {
975 if (obj->type != J2S_TYPE_STRUCT)
976 continue;
977
978 j2s_list_find(&ctx.structs, entry, struct_obj, obj->type_name);
979
980 if (struct_obj) {
981 obj->struct_obj = struct_obj;
982 } else {
983 j2s_list_find(&ctx.enums, entry,
984 enum_obj, obj->type_name);
985
986 DASSERT_MSG(enum_obj, exit(-1),
987 "unknown type '%s' at %d\n",
988 obj->type_name, obj->line);
989
990 obj->type = J2S_TYPE_INT_32;
991 obj->enum_obj = enum_obj;
992 }
993 }
994
995 /* Handle specified root struct */
996 if (argc > 2) {
997 INFO("specified root struct: %s\n", argv[2]);
998
999 j2s_list_find(&ctx.structs, entry, struct_obj, argv[2]);
1000 ctx.root_struct = struct_obj;
1001 }
1002
1003 DASSERT_MSG(ctx.root_struct, exit(-1), "no root struct!\n");
1004
1005 /* Dump parsed header */
1006 j2s_dump(&ctx);
1007
1008 /* Free lists */
1009 j2s_list_walk_safe(&ctx.structs, entry, next, struct_obj)
1010 j2s_list_free(&struct_obj->child, entry, false);
1011 j2s_list_free(&ctx.structs, entry, true);
1012
1013 j2s_list_walk(&ctx.objs, entry, obj)
1014 free(obj->desc);
1015 j2s_list_free(&ctx.objs, entry, true);
1016
1017 j2s_list_walk_safe(&ctx.enums, entry, next, enum_obj)
1018 j2s_list_free(&enum_obj->values, entry, true);
1019 j2s_list_free(&ctx.enums, entry, true);
1020
1021 return 0;
1022 }
1023