| |
| |
| |
| |
| |
| |
| #include <stdint.h> |
| #include <unistd.h> |
| #include <fcntl.h> |
| |
| #include <cparser/ast/type_t.h> |
| #include <cparser/driver/c_driver.h> |
| #include <cparser/driver/driver.h> |
| #include <cparser/driver/driver_t.h> |
| #include <cparser/driver/target.h> |
| #include <cparser/driver/tempfile.h> |
| #include <cparser/firm/ast2firm.h> |
| #include <cparser/firm/firm_opt.h> |
| #include <cparser/parser/parser.h> |
| #include <cparser/parser/preprocessor.h> |
| |
| #define ARGV_DRIVER |
| |
| #include <apimagic/apimagic.h> |
| #include "apimagic_version.h" |
| #include "apimagic_driver_impl.h" |
| #include "argv/argv.h" |
| |
| |
| static const struct amgc_source_version amgc_src_version = { |
| AMGC_TAG_VER_MAJOR, |
| AMGC_TAG_VER_MINOR, |
| AMGC_TAG_VER_PATCH, |
| APIMAGIC_GIT_VERSION |
| }; |
| |
| struct amgc_driver_ctx_alloc { |
| struct argv_meta * meta; |
| struct amgc_action * actions; |
| struct amgc_driver_ctx_impl ctx; |
| uint64_t guard; |
| const char * units[]; |
| }; |
| |
| static uint32_t amgc_argv_flags(uint32_t flags) |
| { |
| uint32_t ret = ARGV_CLONE_VECTOR; |
| |
| if (flags & AMGC_DRIVER_VERBOSITY_NONE) |
| ret |= ARGV_VERBOSITY_NONE; |
| |
| if (flags & AMGC_DRIVER_VERBOSITY_ERRORS) |
| ret |= ARGV_VERBOSITY_ERRORS; |
| |
| if (flags & AMGC_DRIVER_VERBOSITY_STATUS) |
| ret |= ARGV_VERBOSITY_STATUS; |
| |
| return ret; |
| } |
| |
| static int amgc_driver_usage( |
| int fdout, |
| const char * program, |
| const char * arg, |
| const struct argv_option ** optv, |
| struct argv_meta * meta) |
| { |
| char header[512]; |
| |
| snprintf(header,sizeof(header), |
| "Usage: %s [options] <file>...\n" "Options:\n", |
| program); |
| |
| argv_usage(fdout,header,optv,arg); |
| argv_free(meta); |
| |
| return AMGC_USAGE; |
| } |
| |
| static struct amgc_driver_ctx_impl * amgc_driver_ctx_alloc( |
| struct argv_meta * meta, |
| const struct amgc_fd_ctx * fdctx, |
| const struct amgc_common_ctx * cctx, |
| size_t nunits, |
| size_t nactions) |
| { |
| struct amgc_driver_ctx_alloc * ictx; |
| struct amgc_action * actions; |
| size_t size; |
| struct argv_entry * entry; |
| const char ** aunits; |
| int elements; |
| |
| size = sizeof(struct amgc_driver_ctx_alloc); |
| size += (nunits+1)*sizeof(const char *); |
| |
| if (!(ictx = calloc(1,size))) |
| return 0; |
| |
| if (!(actions = calloc(nactions+1,sizeof(*ictx->actions)))) { |
| free(ictx); |
| return 0; |
| } |
| |
| memcpy(&ictx->ctx.fdctx,fdctx,sizeof(*fdctx)); |
| memcpy(&ictx->ctx.cctx,cctx,sizeof(*cctx)); |
| |
| for (entry=meta->entries,aunits=ictx->units; entry->fopt || entry->arg; entry++) |
| if (!entry->fopt) |
| *aunits++ = entry->arg; |
| |
| elements = sizeof(ictx->ctx.erribuf) / sizeof(*ictx->ctx.erribuf); |
| |
| ictx->ctx.errinfp = &ictx->ctx.erriptr[0]; |
| ictx->ctx.erricap = &ictx->ctx.erriptr[--elements]; |
| |
| ictx->meta = meta; |
| ictx->ctx.fdtmpin = -1; |
| ictx->actions = actions; |
| ictx->ctx.actions = actions; |
| ictx->ctx.ctx.units = ictx->units; |
| ictx->ctx.ctx.errv = ictx->ctx.errinfp; |
| return &ictx->ctx; |
| } |
| |
| static int amgc_get_driver_ctx_fail(struct argv_meta * meta) |
| { |
| argv_free(meta); |
| return -1; |
| } |
| |
| static int amgc_init_cparser(void) |
| { |
| init_temp_files(); |
| init_default_driver(); |
| init_driver(); |
| init_preprocessor(); |
| init_parser(); |
| init_ast(); |
| init_firm_opt(); |
| init_firm_target(); |
| |
| target_setup(); |
| |
| return 0; |
| } |
| |
| int amgc_get_driver_ctx( |
| char ** argv, |
| char ** envp, |
| uint32_t flags, |
| const struct amgc_fd_ctx * fdctx, |
| struct amgc_driver_ctx ** pctx) |
| { |
| struct amgc_driver_ctx_impl * ctx; |
| struct amgc_common_ctx cctx; |
| const struct argv_option * optv[AMGC_OPTV_ELEMENTS]; |
| struct argv_meta * meta; |
| struct argv_entry * entry; |
| size_t nunits; |
| size_t nactions; |
| const char * program; |
| |
| (void)envp; |
| |
| if (!fdctx) { |
| fdctx = &(const struct amgc_fd_ctx) { |
| .fdin = STDIN_FILENO, |
| .fdout = STDOUT_FILENO, |
| .fderr = STDERR_FILENO, |
| .fdlog = (-1), |
| .fdcwd = AT_FDCWD, |
| .fddst = AT_FDCWD, |
| }; |
| } |
| |
| argv_optv_init(amgc_default_options,optv); |
| |
| if (!(meta = argv_get( |
| argv,optv, |
| amgc_argv_flags(flags), |
| fdctx->fderr))) |
| return -1; |
| |
| nunits = 0; |
| nactions= 0; |
| program = argv_program_name(argv[0]); |
| memset(&cctx,0,sizeof(cctx)); |
| cctx.drvflags = flags; |
| |
| if (!argv[1] && (flags & AMGC_DRIVER_VERBOSITY_USAGE)) |
| return amgc_driver_usage( |
| fdctx->fderr, |
| program,0, |
| optv,meta); |
| |
| |
| cctx.std = STANDARD_C99; |
| |
| |
| for (entry=meta->entries; entry->fopt || entry->arg; entry++) { |
| if (entry->fopt) { |
| switch (entry->tag) { |
| case TAG_HELP: |
| if (flags & AMGC_DRIVER_VERBOSITY_USAGE) |
| return amgc_driver_usage( |
| fdctx->fderr, |
| program,entry->arg, |
| optv,meta); |
| |
| case TAG_VERSION: |
| cctx.drvflags |= AMGC_DRIVER_VERSION; |
| break; |
| |
| case TAG_LANG_STD: |
| cctx.std = amgc_lang_std_from_string(entry->arg); |
| break; |
| |
| default: |
| nactions++; |
| break; |
| } |
| } else |
| nunits++; |
| } |
| |
| if (amgc_init_cparser()) |
| return amgc_get_driver_ctx_fail(meta); |
| |
| if (!(ctx = amgc_driver_ctx_alloc(meta,fdctx,&cctx,nunits,nactions))) |
| return amgc_get_driver_ctx_fail(meta); |
| |
| |
| for (entry=meta->entries,nactions=0; entry->fopt || entry->arg; entry++) |
| if (entry->fopt) |
| switch (entry->tag) { |
| case TAG_PRINT_ENUMS: |
| ctx->actions[nactions].type = AMGC_ACTION_OUTPUT; |
| ctx->actions[nactions++].action = AMGC_OUTPUT_ENUM; |
| break; |
| |
| case TAG_LIST_ENUMS: |
| ctx->actions[nactions].type = AMGC_ACTION_OUTPUT; |
| ctx->actions[nactions++].action = AMGC_LIST_ENUM; |
| break; |
| |
| case TAG_PRINT_TYPEDEFS: |
| ctx->actions[nactions].type = AMGC_ACTION_OUTPUT; |
| ctx->actions[nactions].action = AMGC_OUTPUT_TYPEDEF; |
| |
| if (!strcmp("primary",entry->arg)) |
| ctx->actions[nactions++].subset = TYPE_ATOMIC; |
| break; |
| |
| case TAG_PRINT_STRUCTS: |
| ctx->actions[nactions].type = AMGC_ACTION_OUTPUT; |
| ctx->actions[nactions++].action = AMGC_OUTPUT_STRUCT; |
| break; |
| |
| case TAG_PRINT_UNIONS: |
| ctx->actions[nactions].type = AMGC_ACTION_OUTPUT; |
| ctx->actions[nactions++].action = AMGC_OUTPUT_UNION; |
| break; |
| } |
| |
| ctx->ctx.program = program; |
| ctx->ctx.cctx = &ctx->cctx; |
| ctx->cctx.actions = ctx->actions; |
| ctx->cctx.ccenv = &ctx->ccenv; |
| |
| *pctx = &ctx->ctx; |
| return AMGC_OK; |
| } |
| |
| static void amgc_exit_cparser(void) |
| { |
| exit_firm_opt(); |
| exit_ast2firm(); |
| exit_ast(); |
| exit_parser(); |
| exit_preprocessor(); |
| exit_driver(); |
| exit_default_driver(); |
| exit_temp_files(); |
| } |
| |
| static void amgc_free_driver_ctx_impl(struct amgc_driver_ctx_alloc * ictx) |
| { |
| argv_free(ictx->meta); |
| free(ictx->actions); |
| free(ictx); |
| amgc_exit_cparser(); |
| } |
| |
| void amgc_free_driver_ctx(struct amgc_driver_ctx * ctx) |
| { |
| struct amgc_driver_ctx_alloc * ictx; |
| uintptr_t addr; |
| |
| if (ctx) { |
| addr = (uintptr_t)ctx - offsetof(struct amgc_driver_ctx_impl,ctx); |
| addr = addr - offsetof(struct amgc_driver_ctx_alloc,ctx); |
| ictx = (struct amgc_driver_ctx_alloc *)addr; |
| amgc_free_driver_ctx_impl(ictx); |
| } |
| } |
| |
| const struct amgc_source_version * amgc_source_version(void) |
| { |
| return &amgc_src_version; |
| } |
| |
| int amgc_get_driver_fdctx( |
| const struct amgc_driver_ctx * dctx, |
| struct amgc_fd_ctx * fdctx) |
| { |
| struct amgc_driver_ctx_impl * ictx; |
| |
| ictx = amgc_get_driver_ictx(dctx); |
| |
| fdctx->fdin = ictx->fdctx.fdin; |
| fdctx->fdout = ictx->fdctx.fdout; |
| fdctx->fderr = ictx->fdctx.fderr; |
| fdctx->fdlog = ictx->fdctx.fdlog; |
| fdctx->fdcwd = ictx->fdctx.fdcwd; |
| fdctx->fddst = ictx->fdctx.fddst; |
| |
| return 0; |
| } |
| |
| int amgc_set_driver_fdctx( |
| struct amgc_driver_ctx * dctx, |
| const struct amgc_fd_ctx * fdctx) |
| { |
| struct amgc_driver_ctx_impl * ictx; |
| |
| ictx = amgc_get_driver_ictx(dctx); |
| |
| ictx->fdctx.fdin = fdctx->fdin; |
| ictx->fdctx.fdout = fdctx->fdout; |
| ictx->fdctx.fderr = fdctx->fderr; |
| ictx->fdctx.fdlog = fdctx->fdlog; |
| ictx->fdctx.fdcwd = fdctx->fdcwd; |
| ictx->fdctx.fddst = fdctx->fddst; |
| |
| return 0; |
| } |