| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| | SLBT_DRIVER_MODE_AR_MERGE) |
| |
| |
| | SLBT_OUTPUT_ARCHIVE_HEADERS \ |
| | SLBT_OUTPUT_ARCHIVE_SYMBOLS \ |
| | SLBT_OUTPUT_ARCHIVE_ARMAPS) |
| |
| |
| | SLBT_PRETTY_POSIX \ |
| | SLBT_PRETTY_HEXDATA) |
| |
| static int slbt_ar_usage( |
| int fdout, |
| const char * program, |
| const char * arg, |
| const struct argv_option ** optv, |
| struct argv_meta * meta, |
| struct slbt_exec_ctx * ectx, |
| int noclr) |
| { |
| char header[512]; |
| bool armode; |
| const char * dash; |
| |
| armode = (dash = strrchr(program,'-')) |
| && !strcmp(++dash,"ar"); |
| |
| snprintf(header,sizeof(header), |
| "Usage: %s%s [options] [ARCHIVE-FILE] [ARCHIVE_FILE] ...\n" |
| "Options:\n", |
| program, |
| armode ? "" : " --mode=ar"); |
| |
| switch (noclr) { |
| case 0: |
| slbt_argv_usage(fdout,header,optv,arg); |
| break; |
| |
| default: |
| slbt_argv_usage_plain(fdout,header,optv,arg); |
| break; |
| } |
| |
| if (ectx) |
| slbt_ectx_free_exec_ctx(ectx); |
| |
| slbt_argv_free(meta); |
| |
| return SLBT_USAGE; |
| } |
| |
| static int slbt_exec_ar_fail( |
| struct slbt_exec_ctx * actx, |
| struct argv_meta * meta, |
| int ret) |
| { |
| slbt_argv_free(meta); |
| slbt_ectx_free_exec_ctx(actx); |
| return ret; |
| } |
| |
| static int slbt_exec_ar_perform_archive_actions( |
| const struct slbt_driver_ctx * dctx, |
| struct slbt_archive_ctx ** arctxv) |
| { |
| struct slbt_archive_ctx ** arctxp; |
| struct slbt_archive_ctx * arctx; |
| bool farname; |
| |
| switch (dctx->cctx->fmtflags & SLBT_PRETTY_FLAGS) { |
| case SLBT_PRETTY_POSIX: |
| farname = (arctxv[0] && arctxv[1]); |
| break; |
| |
| default: |
| farname = true; |
| break; |
| } |
| |
| for (arctxp=arctxv; *arctxp; arctxp++) { |
| if (dctx->cctx->fmtflags & SLBT_DRIVER_MODE_AR_OUTPUTS) |
| if (farname && (slbt_au_output_arname(*arctxp) < 0)) |
| return SLBT_NESTED_ERROR(dctx); |
| |
| if (dctx->cctx->fmtflags & SLBT_OUTPUT_ARCHIVE_MEMBERS) |
| if (slbt_au_output_members((*arctxp)->meta) < 0) |
| return SLBT_NESTED_ERROR(dctx); |
| |
| if (dctx->cctx->fmtflags & SLBT_OUTPUT_ARCHIVE_SYMBOLS) |
| if (slbt_au_output_symbols((*arctxp)->meta) < 0) |
| return SLBT_NESTED_ERROR(dctx); |
| |
| if (dctx->cctx->fmtflags & SLBT_OUTPUT_ARCHIVE_MAPFILE) |
| if (slbt_au_output_mapfile((*arctxp)->meta) < 0) |
| return SLBT_NESTED_ERROR(dctx); |
| } |
| |
| if (dctx->cctx->drvflags & SLBT_DRIVER_MODE_AR_MERGE) { |
| if (slbt_ar_merge_archives(arctxv,&arctx) < 0) |
| return SLBT_NESTED_ERROR(dctx); |
| |
| |
| if (slbt_ar_store_archive(arctx,dctx->cctx->output,0666) < 0) |
| return SLBT_NESTED_ERROR(dctx); |
| } |
| |
| return 0; |
| } |
| |
| int slbt_exec_ar( |
| const struct slbt_driver_ctx * dctx, |
| struct slbt_exec_ctx * ectx) |
| { |
| int ret; |
| int fdout; |
| int fderr; |
| char ** argv; |
| char ** iargv; |
| struct slbt_driver_ctx_impl * ictx; |
| const struct slbt_common_ctx * cctx; |
| struct slbt_archive_ctx ** arctxv; |
| struct slbt_archive_ctx ** arctxp; |
| const char ** unitv; |
| const char ** unitp; |
| size_t nunits; |
| struct slbt_exec_ctx * actx; |
| struct argv_meta * meta; |
| struct argv_entry * entry; |
| const struct argv_option * optv[SLBT_OPTV_ELEMENTS]; |
| |
| |
| if (ectx) |
| actx = 0; |
| else if ((ret = slbt_ectx_get_exec_ctx(dctx,&ectx))) |
| return ret; |
| else |
| actx = ectx; |
| |
| |
| slbt_ectx_reset_arguments(ectx); |
| slbt_disable_placeholders(ectx); |
| |
| ictx = slbt_get_driver_ictx(dctx); |
| cctx = dctx->cctx; |
| iargv = ectx->cargv; |
| |
| fdout = slbt_driver_fdout(dctx); |
| fderr = slbt_driver_fderr(dctx); |
| |
| |
| slbt_optv_init(slbt_ar_options,optv); |
| |
| if (!iargv[1] && (dctx->cctx->drvflags & SLBT_DRIVER_VERBOSITY_USAGE)) |
| return slbt_ar_usage( |
| fdout, |
| dctx->program, |
| 0,optv,0,actx, |
| dctx->cctx->drvflags & SLBT_DRIVER_ANNOTATE_NEVER); |
| |
| |
| if (!(meta = slbt_argv_get( |
| iargv,optv, |
| dctx->cctx->drvflags & SLBT_DRIVER_VERBOSITY_ERRORS |
| ? ARGV_VERBOSITY_ERRORS |
| : ARGV_VERBOSITY_NONE, |
| fdout))) |
| return slbt_exec_ar_fail( |
| actx,meta, |
| SLBT_CUSTOM_ERROR(dctx,SLBT_ERR_AR_FAIL)); |
| |
| |
| argv = ectx->altv; |
| *argv++ = iargv[0]; |
| nunits = 0; |
| |
| for (entry=meta->entries; entry->fopt || entry->arg; entry++) { |
| if (entry->fopt) { |
| switch (entry->tag) { |
| case TAG_AR_HELP: |
| slbt_ar_usage( |
| fdout, |
| dctx->program, |
| 0,optv,0,ectx, |
| dctx->cctx->drvflags |
| & SLBT_DRIVER_ANNOTATE_NEVER); |
| |
| ictx->cctx.drvflags |= SLBT_DRIVER_VERSION; |
| ictx->cctx.drvflags ^= SLBT_DRIVER_VERSION; |
| |
| slbt_argv_free(meta); |
| |
| return SLBT_OK; |
| |
| case TAG_AR_VERSION: |
| ictx->cctx.drvflags |= SLBT_DRIVER_VERSION; |
| break; |
| |
| case TAG_AR_CHECK: |
| ictx->cctx.drvflags |= SLBT_DRIVER_MODE_AR_CHECK; |
| break; |
| |
| case TAG_AR_MERGE: |
| ictx->cctx.drvflags |= SLBT_DRIVER_MODE_AR_MERGE; |
| break; |
| |
| case TAG_AR_OUTPUT: |
| ictx->cctx.output = entry->arg; |
| break; |
| |
| case TAG_AR_PRINT: |
| if (!entry->arg) |
| ictx->cctx.fmtflags |= SLBT_OUTPUT_ARCHIVE_MEMBERS; |
| |
| else if (!strcmp(entry->arg,"members")) |
| ictx->cctx.fmtflags |= SLBT_OUTPUT_ARCHIVE_MEMBERS; |
| |
| else if (!strcmp(entry->arg,"headers")) |
| ictx->cctx.fmtflags |= SLBT_OUTPUT_ARCHIVE_HEADERS; |
| |
| else if (!strcmp(entry->arg,"symbols")) |
| ictx->cctx.fmtflags |= SLBT_OUTPUT_ARCHIVE_SYMBOLS; |
| |
| else if (!strcmp(entry->arg,"armaps")) |
| ictx->cctx.fmtflags |= SLBT_OUTPUT_ARCHIVE_ARMAPS; |
| |
| break; |
| |
| case TAG_AR_MAPFILE: |
| ictx->cctx.fmtflags |= SLBT_OUTPUT_ARCHIVE_MAPFILE; |
| break; |
| |
| case TAG_AR_NOSORT: |
| ictx->cctx.fmtflags |= SLBT_OUTPUT_ARCHIVE_NOSORT; |
| break; |
| |
| case TAG_AR_REGEX: |
| ictx->cctx.regex = entry->arg; |
| break; |
| |
| case TAG_AR_PRETTY: |
| if (!strcmp(entry->arg,"yaml")) { |
| ictx->cctx.fmtflags &= ~(uint64_t)SLBT_PRETTY_FLAGS; |
| ictx->cctx.fmtflags |= SLBT_PRETTY_YAML; |
| |
| } else if (!strcmp(entry->arg,"posix")) { |
| ictx->cctx.fmtflags &= ~(uint64_t)SLBT_PRETTY_FLAGS; |
| ictx->cctx.fmtflags |= SLBT_PRETTY_POSIX; |
| } |
| |
| break; |
| |
| case TAG_AR_POSIX: |
| ictx->cctx.fmtflags &= ~(uint64_t)SLBT_PRETTY_FLAGS; |
| ictx->cctx.fmtflags |= SLBT_PRETTY_POSIX; |
| break; |
| |
| case TAG_AR_YAML: |
| ictx->cctx.fmtflags &= ~(uint64_t)SLBT_PRETTY_FLAGS; |
| ictx->cctx.fmtflags |= SLBT_PRETTY_YAML; |
| break; |
| |
| case TAG_AR_VERBOSE: |
| ictx->cctx.fmtflags |= SLBT_PRETTY_VERBOSE; |
| break; |
| } |
| |
| if (entry->fval) { |
| *argv++ = (char *)entry->arg; |
| } |
| } else { |
| nunits++; |
| }; |
| } |
| |
| |
| if (cctx->drvflags & SLBT_DRIVER_VERSION) { |
| slbt_argv_free(meta); |
| slbt_ectx_free_exec_ctx(actx); |
| return SLBT_OK; |
| } |
| |
| |
| if (cctx->fmtflags & SLBT_DRIVER_MODE_AR_OUTPUTS) { |
| (void)0; |
| |
| } else if (cctx->fmtflags & SLBT_OUTPUT_ARCHIVE_MAPFILE) { |
| (void)0; |
| |
| } else if (!(cctx->drvflags & SLBT_DRIVER_MODE_AR_ACTIONS)) { |
| if (cctx->drvflags & SLBT_DRIVER_VERBOSITY_ERRORS) |
| slbt_dprintf(fderr, |
| "%s: at least one action must be specified\n", |
| dctx->program); |
| |
| return slbt_exec_ar_fail( |
| actx,meta, |
| SLBT_CUSTOM_ERROR( |
| dctx, |
| SLBT_ERR_AR_NO_ACTION_SPECIFIED)); |
| } |
| |
| |
| if ((cctx->drvflags & SLBT_DRIVER_MODE_AR_MERGE) && !cctx->output) { |
| if (cctx->drvflags & SLBT_DRIVER_VERBOSITY_ERRORS) |
| slbt_dprintf(fderr, |
| "%s: archive merging: output must be specified.\n", |
| dctx->program); |
| |
| return slbt_exec_ar_fail( |
| actx,meta, |
| SLBT_CUSTOM_ERROR( |
| dctx, |
| SLBT_ERR_AR_OUTPUT_NOT_SPECIFIED)); |
| } |
| |
| |
| |
| if (cctx->output && !(cctx->drvflags & SLBT_DRIVER_MODE_AR_MERGE)) { |
| if (cctx->drvflags & SLBT_DRIVER_VERBOSITY_ERRORS) |
| slbt_dprintf(fderr, |
| "%s: output may only be specified " |
| "when merging one or more archives.\n", |
| dctx->program); |
| |
| return slbt_exec_ar_fail( |
| actx,meta, |
| SLBT_CUSTOM_ERROR( |
| dctx, |
| SLBT_ERR_AR_OUTPUT_NOT_APPLICABLE)); |
| } |
| |
| |
| |
| if (!nunits) { |
| if (cctx->drvflags & SLBT_DRIVER_VERBOSITY_ERRORS) |
| slbt_dprintf(fderr, |
| "%s: all actions require at least one input unit\n", |
| dctx->program); |
| |
| return slbt_exec_ar_fail( |
| actx,meta, |
| SLBT_CUSTOM_ERROR( |
| dctx, |
| SLBT_ERR_AR_NO_INPUT_SPECIFIED)); |
| } |
| |
| |
| if (!(arctxv = calloc(nunits+1,sizeof(struct slbt_archive_ctx *)))) |
| return slbt_exec_ar_fail( |
| actx,meta, |
| SLBT_SYSTEM_ERROR(dctx,0)); |
| |
| |
| if (!(unitv = calloc(nunits+1,sizeof(const char *)))) { |
| free (arctxv); |
| |
| return slbt_exec_ar_fail( |
| actx,meta, |
| SLBT_SYSTEM_ERROR(dctx,0)); |
| } |
| |
| |
| for (entry=meta->entries,unitp=unitv; entry->fopt || entry->arg; entry++) |
| if (!entry->fopt) |
| *unitp++ = entry->arg; |
| |
| |
| for (unitp=unitv,arctxp=arctxv; *unitp; unitp++,arctxp++) { |
| if (slbt_ar_get_archive_ctx(dctx,*unitp,arctxp) < 0) { |
| for (arctxp=arctxv; *arctxp; arctxp++) |
| slbt_ar_free_archive_ctx(*arctxp); |
| |
| free(unitv); |
| free(arctxv); |
| |
| return slbt_exec_ar_fail( |
| actx,meta, |
| SLBT_NESTED_ERROR(dctx)); |
| } |
| } |
| |
| |
| ret = slbt_exec_ar_perform_archive_actions(dctx,arctxv); |
| |
| |
| for (arctxp=arctxv; *arctxp; arctxp++) |
| slbt_ar_free_archive_ctx(*arctxp); |
| |
| free(unitv); |
| free(arctxv); |
| |
| slbt_argv_free(meta); |
| slbt_ectx_free_exec_ctx(actx); |
| |
| return ret; |
| } |