1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
10 * Copyright (C) 2011 Amaury Pouly
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
20 ****************************************************************************/
22 #define _POSIX_C_SOURCE 200809L /* for strdup */
36 LEX_STRING
, /* double-quoted string */
51 enum lexem_type_t type
;
52 /* if str is not NULL, it must be a malloc'd pointer */
68 #define parse_error(ctx, ...) \
69 do { fprintf(stderr, "%s:%d: ", ctx->file, ctx->line); \
70 fprintf(stderr, __VA_ARGS__); exit(2); } while(0)
72 static void advance(struct context_t
*ctx
, int nr_chars
)
76 if(*(ctx
->ptr
++) == '\n')
81 static inline bool eof(struct context_t
*ctx
)
83 return ctx
->ptr
== ctx
->end
;
86 static inline bool next_valid(struct context_t
*ctx
, int nr
)
88 return ctx
->ptr
+ nr
< ctx
->end
;
91 static inline char cur_char(struct context_t
*ctx
)
96 static inline char next_char(struct context_t
*ctx
, int nr
)
101 static inline void locate_lexem(struct lexem_t
*lex
, struct context_t
*ctx
)
103 lex
->file
= ctx
->file
;
104 lex
->line
= ctx
->line
;
107 static void __parse_string(struct context_t
*ctx
, void *user
, void (*emit_fn
)(void *user
, char c
))
111 if(cur_char(ctx
) == '"')
113 else if(cur_char(ctx
) == '\\')
117 parse_error(ctx
, "Unfinished string\n");
118 if(cur_char(ctx
) == '\\') emit_fn(user
, '\\');
119 else if(cur_char(ctx
) == '\'') emit_fn(user
, '\'');
120 else if(cur_char(ctx
) == '\"') emit_fn(user
, '\"');
121 else parse_error(ctx
, "Unknown escape sequence \\%c\n", cur_char(ctx
));
126 emit_fn(user
, cur_char(ctx
));
130 if(eof(ctx
) || cur_char(ctx
) != '"')
131 parse_error(ctx
, "Unfinished string\n");
135 static void __parse_string_emit(void *user
, char c
)
137 char **pstr
= (char **)user
;
141 static void __parse_string_count(void *user
, char c
)
147 static void parse_string(struct context_t
*ctx
, struct lexem_t
*lexem
)
149 locate_lexem(lexem
, ctx
);
153 struct context_t cpy_ctx
= *ctx
;
155 __parse_string(&cpy_ctx
, (void *)&length
, __parse_string_count
);
157 lexem
->type
= LEX_STRING
;
158 lexem
->str
= xmalloc(length
+ 1);
159 lexem
->str
[length
] = 0;
160 char *pstr
= lexem
->str
;
161 __parse_string(ctx
, (void *)&pstr
, __parse_string_emit
);
164 static void parse_ascii_number(struct context_t
*ctx
, struct lexem_t
*lexem
)
166 locate_lexem(lexem
, ctx
);
169 /* we expect n<=4 character and then ' */
174 if(cur_char(ctx
) != '\'')
176 value
= value
<< 8 | cur_char(ctx
);
183 if(eof(ctx
) || cur_char(ctx
) != '\'')
184 parse_error(ctx
, "Unterminated ascii number literal\n");
185 if(len
== 0 || len
> 4)
186 parse_error(ctx
, "Invalid ascii number literal length: only 1 to 4 characters allowed\n");
189 lexem
->type
= LEX_NUMBER
;
193 static void parse_number(struct context_t
*ctx
, struct lexem_t
*lexem
)
195 locate_lexem(lexem
, ctx
);
198 if(cur_char(ctx
) == '0' && next_valid(ctx
, 1) && next_char(ctx
, 1) == 'x')
204 lexem
->type
= LEX_NUMBER
;
206 while(!eof(ctx
) && isxdigit(cur_char(ctx
)))
208 if(base
== 10 && !isdigit(cur_char(ctx
)))
211 if(convxdigit(cur_char(ctx
), &v
))
213 lexem
->num
= base
* lexem
->num
+ v
;
218 static void parse_identifier(struct context_t
*ctx
, struct lexem_t
*lexem
)
220 locate_lexem(lexem
, ctx
);
221 /* remember position */
222 char *old
= ctx
->ptr
;
223 while(!eof(ctx
) && (isalnum(cur_char(ctx
)) || cur_char(ctx
) == '_'))
225 lexem
->type
= LEX_IDENTIFIER
;
226 int len
= ctx
->ptr
- old
;
227 lexem
->str
= xmalloc(len
+ 1);
229 memcpy(lexem
->str
, old
, len
);
232 static void next_lexem(struct context_t
*ctx
, struct lexem_t
*lexem
)
234 #define ret_simple(t, adv) \
235 do {locate_lexem(lexem, ctx); \
241 char c
= cur_char(ctx
);
242 /* skip whitespace */
243 if(c
== ' ' || c
== '\t' || c
== '\n' || c
== '\r')
248 /* skip C++ style comments */
249 if(c
== '/' && next_valid(ctx
, 1) && next_char(ctx
, 1) == '/')
251 while(!eof(ctx
) && cur_char(ctx
) != '\n')
255 /* skip C-style comments */
256 if(c
== '/' && next_valid(ctx
, 1) && next_char(ctx
, 1) == '*')
261 if(!next_valid(ctx
, 1))
262 parse_error(ctx
, "Unterminated comment");
263 if(cur_char(ctx
) == '*' && next_char(ctx
, 1) == '/')
274 if(eof(ctx
)) ret_simple(LEX_EOF
, 0);
275 char c
= cur_char(ctx
);
276 bool nv
= next_valid(ctx
, 1);
277 char nc
= nv
? next_char(ctx
, 1) : 0;
278 if(c
== '(') ret_simple(LEX_LPAREN
, 1);
279 if(c
== ')') ret_simple(LEX_RPAREN
, 1);
280 if(c
== '{') ret_simple(LEX_LBRACE
, 1);
281 if(c
== '}') ret_simple(LEX_RBRACE
, 1);
282 if(c
== '>') ret_simple(LEX_RANGLE
, 1);
283 if(c
== '=') ret_simple(LEX_EQUAL
, 1);
284 if(c
== ';') ret_simple(LEX_SEMICOLON
, 1);
285 if(c
== ',') ret_simple(LEX_COLON
, 1);
286 if(c
== '|') ret_simple(LEX_OR
, 1);
287 if(c
== '<' && nv
&& nc
== '<') ret_simple(LEX_LSHIFT
, 2);
288 if(c
== '<' && nv
&& nc
== '=') ret_simple(LEX_LE
, 2);
289 if(c
== '"') return parse_string(ctx
, lexem
);
290 if(c
== '\'') return parse_ascii_number(ctx
, lexem
);
291 if(isdigit(c
)) return parse_number(ctx
, lexem
);
292 if(isalpha(c
) || c
== '_') return parse_identifier(ctx
, lexem
);
293 parse_error(ctx
, "Unexpected character '%c'\n", c
);
298 static void log_lexem(struct lexem_t
*lexem
)
302 case LEX_EOF
: printf("<eof>"); break;
303 case LEX_EQUAL
: printf("="); break;
304 case LEX_IDENTIFIER
: printf("id(%s)", lexem
->str
); break;
305 case LEX_LPAREN
: printf("("); break;
306 case LEX_RPAREN
: printf(")"); break;
307 case LEX_LBRACE
: printf("{"); break;
308 case LEX_RBRACE
: printf("}"); break;
309 case LEX_SEMICOLON
: printf(";"); break;
310 case LEX_NUMBER
: printf("num(%d)", lexem
->num
); break;
311 case LEX_STRING
: printf("str(%s)", lexem
->str
); break;
312 case LEX_OR
: printf("|"); break;
313 case LEX_LSHIFT
: printf("<<"); break;
314 default: printf("<unk>");
319 struct cmd_source_t
*db_find_source_by_id(struct cmd_file_t
*cmd_file
, const char *id
)
321 struct cmd_source_t
*src
= cmd_file
->source_list
;
324 if(strcmp(src
->identifier
, id
) == 0)
331 struct cmd_option_t
*db_find_option_by_id(struct cmd_option_t
*opt
, const char *name
)
335 if(strcmp(opt
->name
, name
) == 0)
342 #define INVALID_SB_SUBVERSION 0xffff
344 static uint16_t parse_sb_subversion(char *str
)
346 int len
= strlen(str
);
348 if(len
== 0 || len
> 4)
349 return INVALID_SB_SUBVERSION
;
350 for(int i
= 0; i
< len
; i
++)
353 return INVALID_SB_SUBVERSION
;
354 n
= n
<< 4 | (str
[i
] - '0');
359 bool db_parse_sb_version(struct sb_version_t
*ver
, char *str
)
361 int len
= strlen(str
);
365 for(int i
= 0; i
< len
; i
++)
376 ver
->major
= parse_sb_subversion(str
);
377 ver
->minor
= parse_sb_subversion(str
+ pos
[0]);
378 ver
->revision
= parse_sb_subversion(str
+ pos
[1]);
379 return ver
->major
!= INVALID_SB_SUBVERSION
&&
380 ver
->minor
!= INVALID_SB_SUBVERSION
&&
381 ver
->revision
!= INVALID_SB_SUBVERSION
;
385 #define parse_error(lexem, ...) \
386 do { fprintf(stderr, "%s:%d: ", lexem.file, lexem.line); \
387 fprintf(stderr, __VA_ARGS__); exit(2); } while(0)
391 struct context_t ctx
;
392 struct lexem_t lexem
;
395 /* When lexems hold strings (like identifier), it might be useful to steal
396 * the pointer and don't clean the lexem but in other case, one don't want
397 * to keep the pointer to the string and just want to release the memory.
398 * Thus clean_lexem should be true except when one keeps a pointer */
399 static inline void next(struct lex_ctx_t
*ctx
, bool clean_lexem
)
402 free(ctx
->lexem
.str
);
403 memset(&ctx
->lexem
, 0, sizeof(struct lexem_t
));
404 next_lexem(&ctx
->ctx
, &ctx
->lexem
);
407 static uint32_t parse_term_expr(struct lex_ctx_t
*ctx
, struct cmd_option_t
*const_list
)
410 if(ctx
->lexem
.type
== LEX_NUMBER
)
411 ret
= ctx
->lexem
.num
;
412 else if(ctx
->lexem
.type
== LEX_IDENTIFIER
)
414 struct cmd_option_t
*c
= db_find_option_by_id(const_list
, ctx
->lexem
.str
);
416 parse_error(ctx
->lexem
, "Undefined reference to constant '%s'\n", ctx
->lexem
.str
);
418 parse_error(ctx
->lexem
, "Internal error: constant '%s' is not an integer\n", ctx
->lexem
.str
);
422 parse_error(ctx
->lexem
, "Number or constant identifier expected\n");
427 static uint32_t parse_shift_expr(struct lex_ctx_t
*ctx
, struct cmd_option_t
*const_list
)
429 uint32_t v
= parse_term_expr(ctx
, const_list
);
430 while(ctx
->lexem
.type
== LEX_LSHIFT
)
433 v
<<= parse_term_expr(ctx
, const_list
);
438 static uint32_t parse_or_expr(struct lex_ctx_t
*ctx
, struct cmd_option_t
*const_list
)
440 uint32_t v
= parse_shift_expr(ctx
, const_list
);
441 while(ctx
->lexem
.type
== LEX_OR
)
444 v
|= parse_shift_expr(ctx
, const_list
);
449 static uint32_t parse_intexpr(struct lex_ctx_t
*ctx
, struct cmd_option_t
*const_list
)
451 return parse_or_expr(ctx
, const_list
);
454 #define NR_INITIAL_CONSTANTS 4
455 static char *init_const_name
[NR_INITIAL_CONSTANTS
] = {"true", "false", "yes", "no"};
456 static uint32_t init_const_value
[NR_INITIAL_CONSTANTS
] = {1, 0, 1, 0};
458 struct cmd_file_t
*db_parse_file(const char *file
)
461 FILE *f
= fopen(file
, "r");
465 perror("Cannot open db file");
468 fseek(f
, 0, SEEK_END
);
470 fseek(f
, 0, SEEK_SET
);
471 char *buf
= xmalloc(size
);
472 if(fread(buf
, size
, 1, f
) != 1)
475 perror("Cannot read db file");
481 printf("Parsing db file '%s'\n", file
);
482 struct cmd_file_t
*cmd_file
= xmalloc(sizeof(struct cmd_file_t
));
483 memset(cmd_file
, 0, sizeof(struct cmd_file_t
));
485 /* add initial constants */
486 for(int i
= 0; i
< NR_INITIAL_CONSTANTS
; i
++)
488 struct cmd_option_t
*opt
= xmalloc(sizeof(struct cmd_option_t
));
489 memset(opt
, 0, sizeof(struct cmd_option_t
));
490 opt
->name
= strdup(init_const_name
[i
]);
491 opt
->is_string
= false;
492 opt
->val
= init_const_value
[i
];
493 opt
->next
= cmd_file
->constant_list
;
494 cmd_file
->constant_list
= opt
;
497 struct lex_ctx_t lctx
;
498 lctx
.ctx
.file
= file
;
500 lctx
.ctx
.begin
= buf
;
502 lctx
.ctx
.end
= buf
+ size
;
503 #define next(clean_lexem) next(&lctx, clean_lexem)
504 #define lexem lctx.lexem
506 next(false); /* don't clean init lexem because it doesn't exist */
508 if(lexem
.type
== LEX_IDENTIFIER
&& !strcmp(lexem
.str
, "constants"))
511 if(lexem
.type
!= LEX_LBRACE
)
512 parse_error(lexem
, "'{' expected after 'constants'\n");
516 struct cmd_option_t
*opt
= xmalloc(sizeof(struct cmd_option_t
));
517 memset(opt
, 0, sizeof(struct cmd_option_t
));
519 if(lexem
.type
== LEX_RBRACE
)
521 if(lexem
.type
!= LEX_IDENTIFIER
)
522 parse_error(lexem
, "Identifier expected in constants\n");
523 opt
->name
= lexem
.str
;
524 next(false); /* lexem string is kept as option name */
525 if(lexem
.type
!= LEX_EQUAL
)
526 parse_error(lexem
, "'=' expected after identifier\n");
528 opt
->is_string
= false;
529 opt
->val
= parse_intexpr(&lctx
, cmd_file
->constant_list
);
530 opt
->next
= cmd_file
->constant_list
;
531 cmd_file
->constant_list
= opt
;
532 if(lexem
.type
!= LEX_SEMICOLON
)
533 parse_error(lexem
, "';' expected after string\n");
538 if(lexem
.type
== LEX_IDENTIFIER
&& !strcmp(lexem
.str
, "options"))
541 if(lexem
.type
!= LEX_LBRACE
)
542 parse_error(lexem
, "'{' expected after 'options'\n");
547 if(lexem
.type
== LEX_RBRACE
)
549 struct cmd_option_t
*opt
= xmalloc(sizeof(struct cmd_option_t
));
550 memset(opt
, 0, sizeof(struct cmd_option_t
));
551 if(lexem
.type
!= LEX_IDENTIFIER
)
552 parse_error(lexem
, "Identifier expected in options\n");
553 opt
->name
= lexem
.str
;
554 next(false); /* lexem string is kept as option name */
555 if(lexem
.type
!= LEX_EQUAL
)
556 parse_error(lexem
, "'=' expected after identifier\n");
558 if(lexem
.type
== LEX_STRING
)
560 opt
->is_string
= true;
561 opt
->str
= lexem
.str
;
562 next(false); /* lexem string is kept as option name */
566 opt
->is_string
= false;
567 opt
->val
= parse_intexpr(&lctx
, cmd_file
->constant_list
);
569 opt
->next
= cmd_file
->opt_list
;
570 cmd_file
->opt_list
= opt
;
571 if(lexem
.type
!= LEX_SEMICOLON
)
572 parse_error(lexem
, "';' expected after string\n");
577 if(lexem
.type
!= LEX_IDENTIFIER
|| strcmp(lexem
.str
, "sources"))
578 parse_error(lexem
, "'sources' expected\n");
580 if(lexem
.type
!= LEX_LBRACE
)
581 parse_error(lexem
, "'{' expected after 'sources'\n");
586 if(lexem
.type
== LEX_RBRACE
)
588 struct cmd_source_t
*src
= xmalloc(sizeof(struct cmd_source_t
));
589 memset(src
, 0, sizeof(struct cmd_source_t
));
590 if(lexem
.type
!= LEX_IDENTIFIER
)
591 parse_error(lexem
, "identifier expected in sources\n");
592 src
->identifier
= lexem
.str
;
593 next(false); /* lexem string is kept as source name */
594 if(lexem
.type
!= LEX_EQUAL
)
595 parse_error(lexem
, "'=' expected after identifier\n");
597 if(lexem
.type
== LEX_STRING
)
599 src
->is_extern
= false;
600 src
->filename
= lexem
.str
;
601 next(false); /* lexem string is kept as file name */
603 else if(lexem
.type
== LEX_IDENTIFIER
&& !strcmp(lexem
.str
, "extern"))
605 src
->is_extern
= true;
606 src
->filename
= strdup("<extern>"); /* duplicate because it will be free'd */
608 if(lexem
.type
!= LEX_LPAREN
)
609 parse_error(lexem
, "'(' expected after 'extern'\n");
611 src
->extern_nr
= parse_intexpr(&lctx
, cmd_file
->constant_list
);
612 if(lexem
.type
!= LEX_RPAREN
)
613 parse_error(lexem
, "')' expected\n");
617 parse_error(lexem
, "String or 'extern' expected after '='\n");
618 if(lexem
.type
!= LEX_SEMICOLON
)
619 parse_error(lexem
, "';' expected\n");
620 if(db_find_source_by_id(cmd_file
, src
->identifier
) != NULL
)
621 parse_error(lexem
, "Duplicate source identifier\n");
622 /* type filled later */
623 src
->type
= CMD_SRC_UNK
;
624 src
->next
= cmd_file
->source_list
;
625 cmd_file
->source_list
= src
;
629 struct cmd_section_t
*end_sec
= NULL
;
633 if(lexem
.type
== LEX_EOF
)
635 struct cmd_section_t
*sec
= xmalloc(sizeof(struct cmd_section_t
));
636 struct cmd_inst_t
*end_list
= NULL
;
637 memset(sec
, 0, sizeof(struct cmd_section_t
));
638 if(lexem
.type
!= LEX_IDENTIFIER
|| strcmp(lexem
.str
, "section") != 0)
639 parse_error(lexem
, "'section' expected\n");
641 if(lexem
.type
!= LEX_LPAREN
)
642 parse_error(lexem
, "'(' expected after 'section'\n");
644 /* can be any number */
645 sec
->identifier
= parse_intexpr(&lctx
, cmd_file
->constant_list
);
647 if(lexem
.type
== LEX_SEMICOLON
)
652 struct cmd_option_t
*opt
= xmalloc(sizeof(struct cmd_option_t
));
653 memset(opt
, 0, sizeof(struct cmd_option_t
));
654 if(lexem
.type
!= LEX_IDENTIFIER
)
655 parse_error(lexem
, "Identifier expected for section option\n");
656 opt
->name
= lexem
.str
;
657 next(false); /* lexem string is kept as option name */
658 if(lexem
.type
!= LEX_EQUAL
)
659 parse_error(lexem
, "'=' expected after option identifier\n");
661 if(lexem
.type
== LEX_STRING
)
663 opt
->is_string
= true;
664 opt
->str
= lexem
.str
;
665 next(false); /* lexem string is kept as option string */
669 opt
->is_string
= false;
670 opt
->val
= parse_intexpr(&lctx
, cmd_file
->constant_list
);
672 opt
->next
= sec
->opt_list
;
674 }while(lexem
.type
== LEX_COLON
);
676 if(lexem
.type
!= LEX_RPAREN
)
677 parse_error(lexem
, "')' expected after section identifier\n");
679 if(lexem
.type
== LEX_LBRACE
)
681 sec
->is_data
= false;
686 if(lexem
.type
== LEX_RBRACE
)
688 struct cmd_inst_t
*inst
= xmalloc(sizeof(struct cmd_inst_t
));
689 memset(inst
, 0, sizeof(struct cmd_inst_t
));
690 if(lexem
.type
!= LEX_IDENTIFIER
)
691 parse_error(lexem
, "Instruction expected in section\n");
692 if(strcmp(lexem
.str
, "load") == 0)
693 inst
->type
= CMD_LOAD
;
694 else if(strcmp(lexem
.str
, "call") == 0)
695 inst
->type
= CMD_CALL
;
696 else if(strcmp(lexem
.str
, "jump") == 0)
697 inst
->type
= CMD_JUMP
;
698 else if(strcmp(lexem
.str
, "mode") == 0)
699 inst
->type
= CMD_MODE
;
701 parse_error(lexem
, "Instruction expected in section\n");
704 if(inst
->type
== CMD_LOAD
)
706 if(lexem
.type
!= LEX_IDENTIFIER
)
707 parse_error(lexem
, "Identifier expected after instruction\n");
708 inst
->identifier
= lexem
.str
;
709 if(db_find_source_by_id(cmd_file
, inst
->identifier
) == NULL
)
710 parse_error(lexem
, "Undefined reference to source '%s'\n", inst
->identifier
);
711 next(false); /* lexem string kept as identifier */
712 if(lexem
.type
== LEX_RANGLE
)
715 inst
->type
= CMD_LOAD_AT
;
717 inst
->addr
= parse_intexpr(&lctx
, cmd_file
->constant_list
);
719 if(lexem
.type
!= LEX_SEMICOLON
)
720 parse_error(lexem
, "';' expected after command\n");
722 else if(inst
->type
== CMD_CALL
|| inst
->type
== CMD_JUMP
)
724 if(lexem
.type
== LEX_IDENTIFIER
)
726 inst
->identifier
= lexem
.str
;
727 if(db_find_source_by_id(cmd_file
, inst
->identifier
) == NULL
)
728 parse_error(lexem
, "Undefined reference to source '%s'\n", inst
->identifier
);
729 next(false); /* lexem string kept as identifier */
733 inst
->type
= (inst
->type
== CMD_CALL
) ? CMD_CALL_AT
: CMD_JUMP_AT
;
734 inst
->addr
= parse_intexpr(&lctx
, cmd_file
->constant_list
);
737 if(lexem
.type
== LEX_LPAREN
)
740 inst
->argument
= parse_intexpr(&lctx
, cmd_file
->constant_list
);
741 if(lexem
.type
!= LEX_RPAREN
)
742 parse_error(lexem
, "Expected closing brace\n");
745 if(lexem
.type
!= LEX_SEMICOLON
)
746 parse_error(lexem
, "';' expected after command\n");
748 else if(inst
->type
== CMD_MODE
)
750 inst
->argument
= parse_intexpr(&lctx
, cmd_file
->constant_list
);
751 if(lexem
.type
!= LEX_SEMICOLON
)
752 parse_error(lexem
, "Expected ';' after command\n");
755 parse_error(lexem
, "Internal error");
758 sec
->inst_list
= inst
;
763 end_list
->next
= inst
;
768 else if(lexem
.type
== LEX_LE
)
772 if(lexem
.type
!= LEX_IDENTIFIER
)
773 parse_error(lexem
, "Identifier expected after '<='\n");
774 sec
->source_id
= lexem
.str
;
775 next(false); /* lexem string is kept as source id */
776 if(lexem
.type
!= LEX_SEMICOLON
)
777 parse_error(lexem
, "';' expected after identifier\n");
780 parse_error(lexem
, "'{' or '<=' expected after section directive\n");
784 cmd_file
->section_list
= sec
;
800 void db_generate_default_sb_version(struct sb_version_t
*ver
)
802 ver
->major
= ver
->minor
= ver
->revision
= 0x999;
805 void db_free_option_list(struct cmd_option_t
*opt_list
)
809 struct cmd_option_t
*next
= opt_list
->next
;
811 free(opt_list
->name
);
818 void db_free(struct cmd_file_t
*file
)
820 db_free_option_list(file
->opt_list
);
821 db_free_option_list(file
->constant_list
);
822 struct cmd_source_t
*src
= file
->source_list
;
825 struct cmd_source_t
*next
= src
->next
;
826 free(src
->identifier
);
831 if(src
->type
== CMD_SRC_BIN
)
833 if(src
->type
== CMD_SRC_ELF
)
834 elf_release(&src
->elf
);
839 struct cmd_section_t
*sec
= file
->section_list
;
842 struct cmd_section_t
*next
= sec
->next
;
843 db_free_option_list(sec
->opt_list
);
844 free(sec
->source_id
);
845 struct cmd_inst_t
*inst
= sec
->inst_list
;
848 struct cmd_inst_t
*next
= inst
->next
;
849 free(inst
->identifier
);