xref: /OK3568_Linux_fs/external/camera_engine_rkaiq/rkaiq/tools/iq_check/src/parser.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
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