rewrite option descriptors to be single string

This reduces the number of relocations on PIE binaries, and also
reduces the executable size. Parsing of the options is slightly
sped up as only the exact matching option group parser is called.
cute-signatures
Timo Teräs 2020-05-04 21:45:11 +03:00
parent 791f93fcbe
commit 1d7123d837
16 changed files with 567 additions and 439 deletions

374
src/apk.c
View File

@ -13,6 +13,7 @@
#include <fcntl.h>
#include <ctype.h>
#include <errno.h>
#include <assert.h>
#include <signal.h>
#include <stdarg.h>
#include <stdlib.h>
@ -35,7 +36,6 @@
#include "apk_print.h"
#include "apk_io.h"
static const struct apk_option_group *default_optgroups[] = { &optgroup_global, NULL };
static struct list_head apk_applet_list;
#define foreach_applet(iter) list_for_each_entry(iter, &apk_applet_list, node)
@ -75,112 +75,185 @@ static struct apk_repository_list *apk_repository_new(const char *url)
return r;
}
static int option_parse_global(void *ctx, struct apk_db_options *dbopts, int optch, const char *optarg)
enum {
OPT_GLOBAL_allow_untrusted,
OPT_GLOBAL_arch,
OPT_GLOBAL_cache_dir,
OPT_GLOBAL_cache_max_age,
OPT_GLOBAL_force,
OPT_GLOBAL_force_binary_stdout,
OPT_GLOBAL_force_broken_world,
OPT_GLOBAL_force_non_repository,
OPT_GLOBAL_force_old_apk,
OPT_GLOBAL_force_overwrite,
OPT_GLOBAL_force_refresh,
OPT_GLOBAL_help,
OPT_GLOBAL_interactive,
OPT_GLOBAL_keys_dir,
OPT_GLOBAL_no_cache,
OPT_GLOBAL_no_network,
OPT_GLOBAL_no_progress,
OPT_GLOBAL_print_arch,
OPT_GLOBAL_progress,
OPT_GLOBAL_progress_fd,
OPT_GLOBAL_purge,
OPT_GLOBAL_quiet,
OPT_GLOBAL_repositories_file,
OPT_GLOBAL_repository,
OPT_GLOBAL_root,
OPT_GLOBAL_update_cache,
OPT_GLOBAL_verbose,
OPT_GLOBAL_version,
OPT_GLOBAL_wait,
#ifdef TEST_MODE
OPT_GLOBAL_test_instdb,
OPT_GLOBAL_test_repo,
OPT_GLOBAL_test_world,
#endif
};
static const char optiondesc_global[] =
APK_OPTGROUP("Global")
APK_OPT1n("allow-untrusted")
APK_OPT1R("arch")
APK_OPT1R("cache-dir")
APK_OPT1R("cache-max-age")
APK_OPT2n("force", "f")
APK_OPT1n("force-binary-stdout")
APK_OPT1n("force-broken-world")
APK_OPT1n("force-non-repository")
APK_OPT1n("force-old-apk")
APK_OPT1n("force-overwrite")
APK_OPT1n("force-refresh")
APK_OPT2n("help", "h")
APK_OPT2n("interactive", "i")
APK_OPT1R("keys-dir")
APK_OPT1n("no-cache")
APK_OPT1n("no-network")
APK_OPT1n("no-progress")
APK_OPT1n("print-arch")
APK_OPT1n("progress")
APK_OPT1R("progress-fd")
APK_OPT1n("purge")
APK_OPT2n("quiet", "q")
APK_OPT1R("repositories-file")
APK_OPT2R("repository", "X")
APK_OPT2R("root", "p")
APK_OPT2n("update-cache", "U")
APK_OPT2n("verbose", "v")
APK_OPT2n("version", "V")
APK_OPT1R("wait")
#ifdef TEST_MODE
APK_OPT1R("test-instdb")
APK_OPT1R("test-repo")
APK_OPT1R("test-world")
#endif
;
static int option_parse_global(void *ctx, struct apk_db_options *dbopts, int opt, const char *optarg)
{
struct apk_repository_list *repo;
switch (optch) {
case 'h': return -EINVAL;
case 'p':
switch (opt) {
case OPT_GLOBAL_help:
return -EINVAL;
case OPT_GLOBAL_root:
dbopts->root = optarg;
break;
case 0x107:
case OPT_GLOBAL_keys_dir:
dbopts->keys_dir = optarg;
break;
case 0x108:
case OPT_GLOBAL_repositories_file:
dbopts->repositories_file = optarg;
break;
case 'X':
case OPT_GLOBAL_repository:
repo = apk_repository_new(optarg);
if (repo) list_add(&repo->list, &dbopts->repository_list);
break;
case 'q':
case OPT_GLOBAL_quiet:
apk_verbosity--;
break;
case 'v':
case OPT_GLOBAL_verbose:
apk_verbosity++;
break;
case 'V':
case OPT_GLOBAL_version:
version();
return -ESHUTDOWN;
case 'f':
case OPT_GLOBAL_force:
apk_force |= APK_FORCE_OVERWRITE | APK_FORCE_OLD_APK
| APK_FORCE_BROKEN_WORLD | APK_FORCE_NON_REPOSITORY
| APK_FORCE_BINARY_STDOUT;
break;
case 0x120:
case OPT_GLOBAL_force_overwrite:
apk_force |= APK_FORCE_OVERWRITE;
break;
case 0x121:
case OPT_GLOBAL_force_old_apk:
apk_force |= APK_FORCE_OLD_APK;
break;
case 0x122:
case OPT_GLOBAL_force_broken_world:
apk_force |= APK_FORCE_BROKEN_WORLD;
break;
case 0x123:
case OPT_GLOBAL_force_refresh:
apk_force |= APK_FORCE_REFRESH;
break;
case 0x124:
case OPT_GLOBAL_force_non_repository:
apk_force |= APK_FORCE_NON_REPOSITORY;
break;
case 0x125:
case OPT_GLOBAL_force_binary_stdout:
apk_force |= APK_FORCE_BINARY_STDOUT;
break;
case 'i':
case OPT_GLOBAL_interactive:
apk_flags |= APK_INTERACTIVE;
break;
case 0x101:
case OPT_GLOBAL_progress:
apk_flags |= APK_PROGRESS;
break;
case 0x104:
apk_flags |= APK_SIMULATE;
break;
case 0x110:
case OPT_GLOBAL_no_progress:
apk_flags &= ~APK_PROGRESS;
break;
case 0x10f:
case OPT_GLOBAL_progress_fd:
apk_progress_fd = atoi(optarg);
break;
case 0x103:
case OPT_GLOBAL_allow_untrusted:
apk_flags |= APK_ALLOW_UNTRUSTED;
break;
case 0x106:
case OPT_GLOBAL_purge:
apk_flags |= APK_PURGE;
break;
case 0x105:
case OPT_GLOBAL_wait:
dbopts->lock_wait = atoi(optarg);
break;
case 0x109:
case OPT_GLOBAL_no_network:
apk_flags |= APK_NO_NETWORK;
break;
case 0x115:
case OPT_GLOBAL_no_cache:
apk_flags |= APK_NO_CACHE;
break;
case 0x116:
case OPT_GLOBAL_cache_dir:
dbopts->cache_dir = optarg;
break;
case 'U':
case OPT_GLOBAL_update_cache:
/* Make it one minute, to avoid updating indexes twice
* when doing self-upgrade's re-exec */
dbopts->cache_max_age = 60;
break;
case 0x119:
case OPT_GLOBAL_cache_max_age:
dbopts->cache_max_age = atoi(optarg) * 60;
break;
case 0x112:
case OPT_GLOBAL_arch:
dbopts->arch = optarg;
break;
case 0x114:
case OPT_GLOBAL_print_arch:
puts(APK_DEFAULT_ARCH);
return -ESHUTDOWN;
#ifdef TEST_MODE
case 0x200:
case OPT_GLOBAL_test_repo:
*apk_string_array_add(&test_repos) = (char*) optarg;
break;
case 0x201:
case OPT_GLOBAL_test_instdb:
test_installed_db = optarg;
break;
case 0x202:
case OPT_GLOBAL_test_world:
test_world = optarg;
break;
#endif
@ -190,69 +263,48 @@ static int option_parse_global(void *ctx, struct apk_db_options *dbopts, int opt
return 0;
}
static const struct apk_option options_global[] = {
{ 'h', "help" },
{ 'p', "root", required_argument },
{ 'X', "repository", required_argument },
{ 'q', "quiet" },
{ 'v', "verbose" },
{ 'i', "interactive" },
{ 'V', "version" },
{ 'f', "force" },
{ 0x125, "force-binary-stdout" },
{ 0x122, "force-broken-world" },
{ 0x124, "force-non-repository" },
{ 0x121, "force-old-apk" },
{ 0x120, "force-overwrite" },
{ 0x123, "force-refresh" },
{ 'U', "update-cache" },
{ 0x101, "progress" },
{ 0x10f, "progress-fd", required_argument },
{ 0x110, "no-progress" },
{ 0x106, "purge" },
{ 0x103, "allow-untrusted" },
{ 0x105, "wait", required_argument },
{ 0x107, "keys-dir", required_argument },
{ 0x108, "repositories-file", required_argument },
{ 0x109, "no-network" },
{ 0x115, "no-cache" },
{ 0x116, "cache-dir", required_argument },
{ 0x119, "cache-max-age", required_argument },
{ 0x112, "arch", required_argument },
{ 0x114, "print-arch" },
#ifdef TEST_MODE
{ 0x200, "test-repo", required_argument },
{ 0x201, "test-instdb", required_argument },
{ 0x202, "test-world", required_argument },
#endif
};
const struct apk_option_group optgroup_global = {
.name = "Global",
.options = options_global,
.num_options = ARRAY_SIZE(options_global),
.desc = optiondesc_global,
.parse = option_parse_global,
};
static int option_parse_commit(void *ctx, struct apk_db_options *dbopts, int optch, const char *optarg)
enum {
OPT_COMMIT_clean_protected,
OPT_COMMIT_initramfs_diskless_boot,
OPT_COMMIT_no_commit_hooks,
OPT_COMMIT_no_scripts,
OPT_COMMIT_overlay_from_stdin,
OPT_COMMIT_simulate,
};
static const char optiondesc_commit[] =
APK_OPTGROUP("commit")
APK_OPT1n("clean-protected")
APK_OPT1n("initramfs-diskless-boot")
APK_OPT1n("no-commit-hooks")
APK_OPT1n("no-scripts")
APK_OPT1n("overlay-from-stdin")
APK_OPT2n("simulate", "s");
static int option_parse_commit(void *ctx, struct apk_db_options *dbopts, int opt, const char *optarg)
{
switch (optch) {
case 's':
switch (opt) {
case OPT_COMMIT_simulate:
apk_flags |= APK_SIMULATE;
break;
case 0x102:
case OPT_COMMIT_clean_protected:
apk_flags |= APK_CLEAN_PROTECTED;
break;
case 0x111:
case OPT_COMMIT_overlay_from_stdin:
apk_flags |= APK_OVERLAY_FROM_STDIN;
break;
case 0x113:
case OPT_COMMIT_no_scripts:
apk_flags |= APK_NO_SCRIPTS;
break;
case 0x117:
case OPT_COMMIT_no_commit_hooks:
apk_flags |= APK_NO_COMMIT_HOOKS;
break;
case 0x118:
case OPT_COMMIT_initramfs_diskless_boot:
dbopts->open_flags |= APK_OPENF_CREATE;
apk_flags |= APK_NO_COMMIT_HOOKS;
apk_force |= APK_FORCE_OVERWRITE | APK_FORCE_OLD_APK
@ -264,19 +316,8 @@ static int option_parse_commit(void *ctx, struct apk_db_options *dbopts, int opt
return 0;
}
static const struct apk_option options_commit[] = {
{ 's', "simulate" },
{ 0x102, "clean-protected" },
{ 0x111, "overlay-from-stdin" },
{ 0x113, "no-scripts" },
{ 0x117, "no-commit-hooks" },
{ 0x118, "initramfs-diskless-boot" },
};
const struct apk_option_group optgroup_commit = {
.name = "Commit",
.options = options_commit,
.num_options = ARRAY_SIZE(options_commit),
.desc = optiondesc_commit,
.parse = option_parse_commit,
};
@ -315,28 +356,81 @@ static struct apk_applet *deduce_applet(int argc, char **argv)
return find_applet(prog + 4);
for (i = 1; i < argc; i++) {
if (argv[i][0] == '-')
continue;
if (argv[i][0] == '-') continue;
a = find_applet(argv[i]);
if (a != NULL)
return a;
if (a) return a;
}
return NULL;
}
static void merge_options(struct option *opts, const struct apk_option *ao, int num)
static int parse_options(int argc, char **argv, struct apk_applet *applet, void *ctx, struct apk_db_options *dbopts)
{
int i;
const struct apk_option_group *default_optgroups[] = { &optgroup_global, NULL };
const struct apk_option_group *og, **optgroups = default_optgroups;
struct option all_options[80], *opt;
char short_options[256], *sopt;
unsigned short short_option_val[64];
int r, p, help_requested = 0, num_short;
for (i = 0; i < num; i++, opts++, ao++) {
opts->name = ao->name ?: "";
opts->has_arg = ao->has_arg;
opts->flag = NULL;
opts->val = ao->val;
memset(short_option_val, 0, sizeof short_option_val);
if (applet && applet->optgroups[0]) optgroups = applet->optgroups;
for (p = 0, opt = &all_options[0], sopt = short_options; (og = optgroups[p]) != 0; p++) {
assert(opt < &all_options[ARRAY_SIZE(all_options)]);
assert(sopt < &short_options[sizeof short_options]);
const char *d = og->desc + strlen(og->desc) + 1;
for (r = 0; *d; r++) {
opt->val = (p << 10) + r;
opt->flag = 0;
opt->has_arg = no_argument;
if ((unsigned char)*d == 0xaf) {
opt->has_arg = required_argument;
d++;
}
num_short = 1;
if ((unsigned char)*d >= 0xf0)
num_short = *d++ & 0x0f;
for (; num_short > 0; num_short--) {
assert(*d >= 64 && *d < 128);
short_option_val[*d - 64] = opt->val;
*sopt++ = *d++;
if (opt->has_arg != no_argument)
*sopt++ = ':';
}
opt->name = d;
opt++;
d += strlen(d) + 1;
}
}
opts->name = NULL;
opt->name = 0;
*sopt = 0;
r = 0;
while ((p = getopt_long(argc, argv, short_options, all_options, NULL)) != -1) {
if (p >= 64 && p < 128) p = short_option_val[p - 64];
og = optgroups[p >> 10];
r = og->parse(ctx, dbopts, p & 0x3ff, optarg);
if (r == 0) continue;
if (r == -EINVAL) {
help_requested = 1;
continue;
}
if (r != -ENOTSUP) return r;
}
if (help_requested || r == -ENOTSUP)
return usage(applet);
if (applet == NULL) {
if (argc > 1) {
apk_error("'%s' is not an apk command. See 'apk --help'.", argv[1]);
return 1;
}
return usage(NULL);
}
return 0;
}
static void fini_openssl(void)
@ -407,14 +501,11 @@ static void on_sigint(int s)
int main(int argc, char **argv)
{
struct apk_applet *applet;
char short_options[256], *sopt;
struct option *opt, *all_options;
int i, p, r, num_options, help_requested = 0;
void *ctx = NULL;
struct apk_db_options dbopts;
const struct apk_option_group **optgroups = default_optgroups;
struct apk_string_array *args;
struct apk_applet *applet;
int r;
apk_string_array_init(&args);
#ifdef TEST_MODE
@ -434,13 +525,6 @@ int main(int argc, char **argv)
setup_terminal();
applet = deduce_applet(argc, argv);
if (applet && applet->optgroups[0]) optgroups = applet->optgroups;
for (i = 0, num_options = 1; optgroups[i]; i++)
num_options += optgroups[i]->num_options;
all_options = alloca(sizeof(struct option) * num_options);
for (i = r = 0; optgroups[i]; r += optgroups[i]->num_options, i++)
merge_options(&all_options[r], optgroups[i]->options, optgroups[i]->num_options);
if (applet != NULL) {
if (applet->context_size != 0)
ctx = calloc(1, applet->context_size);
@ -448,45 +532,13 @@ int main(int argc, char **argv)
apk_flags |= applet->forced_flags;
apk_force |= applet->forced_force;
}
for (opt = all_options, sopt = short_options; opt->name != NULL; opt++) {
if (opt->flag == NULL &&
opt->val <= 0xff && isalnum(opt->val)) {
*(sopt++) = opt->val;
if (opt->has_arg != no_argument)
*(sopt++) = ':';
}
}
*(sopt++) = 0;
init_openssl();
setup_automatic_flags();
fetchConnectionCacheInit(32, 4);
while ((p = getopt_long(argc, argv, short_options, all_options, NULL)) != -1) {
for (i = 0; optgroups[i]; i++) {
r = optgroups[i]->parse(ctx, &dbopts, p, optarg);
if (r == 0) break;
if (r == -EINVAL) {
help_requested = 1;
break;
}
if (r != -ENOTSUP) goto err;
}
}
if (help_requested || r == -ENOTSUP) {
r = usage(applet);
goto err;
}
if (applet == NULL) {
if (argc > 1) {
r = 1;
apk_error("'%s' is not an apk command. See 'apk --help'.", argv[1]);
} else
r = usage(NULL);
goto err;
}
r = parse_options(argc, argv, applet, ctx, &dbopts);
if (r != 0) goto err;
argc -= optind;
argv += optind;
@ -519,7 +571,7 @@ int main(int argc, char **argv)
if (test_installed_db != NULL) {
apk_db_index_read(&db, apk_istream_from_file(AT_FDCWD, test_installed_db), -1);
}
for (i = 0; i < test_repos->num; i++) {
for (int i = 0; i < test_repos->num; i++) {
apk_blob_t spec = APK_BLOB_STR(test_repos->item[i]), name, tag;
int repo_tag = 0, repo = APK_REPOSITORY_FIRST_CONFIGURED + i;
@ -561,10 +613,8 @@ int main(int argc, char **argv)
#endif
err:
if (r == -ESHUTDOWN)
r = 0;
if (ctx)
free(ctx);
if (r == -ESHUTDOWN) r = 0;
if (ctx) free(ctx);
fetchConnectionCacheClose();
apk_string_array_free(&args);

View File

@ -17,19 +17,17 @@
#include "apk_defines.h"
#include "apk_database.h"
struct apk_option {
int val;
const char *name;
int has_arg;
};
#define APK_OPTAPPLET "\x00"
#define APK_OPTGROUP(_name) _name "\x00"
#define APK_OPT1n(_opt) "\xf0" _opt "\x00"
#define APK_OPT1R(_opt) "\xaf" "\xf0" _opt "\x00"
#define APK_OPT2n(_opt, _short) _short _opt "\x00"
#define APK_OPT2R(_opt, _short) "\xaf" _short _opt "\x00"
struct apk_option_group {
const char *name;
int num_options;
const struct apk_option *options;
const char *desc;
int (*parse)(void *ctx, struct apk_db_options *dbopts,
int optch, const char *optarg);
int opt, const char *optarg);
};
struct apk_applet {

View File

@ -23,24 +23,40 @@ struct add_ctx {
unsigned short extract_flags;
};
static int option_parse_applet(void *ctx, struct apk_db_options *dbopts, int optch, const char *optarg)
enum {
OPT_ADD_initdb,
OPT_ADD_latest,
OPT_ADD_no_chown,
OPT_ADD_upgrade,
OPT_ADD_virtual,
};
static const char option_desc[] =
APK_OPTAPPLET
APK_OPT1n("initdb")
APK_OPT2n("latest", "l")
APK_OPT1n("no-chown")
APK_OPT2n("upgrade", "u")
APK_OPT2R("virtual", "t");
static int option_parse_applet(void *ctx, struct apk_db_options *dbopts, int opt, const char *optarg)
{
struct add_ctx *actx = (struct add_ctx *) ctx;
switch (optch) {
case 0x10000:
switch (opt) {
case OPT_ADD_initdb:
dbopts->open_flags |= APK_OPENF_CREATE;
break;
case 0x10001:
actx->extract_flags |= APK_EXTRACTF_NO_CHOWN;
break;
case 'u':
actx->solver_flags |= APK_SOLVERF_UPGRADE;
break;
case 'l':
case OPT_ADD_latest:
actx->solver_flags |= APK_SOLVERF_LATEST;
break;
case 't':
case OPT_ADD_no_chown:
actx->extract_flags |= APK_EXTRACTF_NO_CHOWN;
break;
case OPT_ADD_upgrade:
actx->solver_flags |= APK_SOLVERF_UPGRADE;
break;
case OPT_ADD_virtual:
actx->virtpkg = optarg;
break;
default:
@ -49,18 +65,8 @@ static int option_parse_applet(void *ctx, struct apk_db_options *dbopts, int opt
return 0;
}
static const struct apk_option options_applet[] = {
{ 0x10000, "initdb" },
{ 0x10001, "no-chown" },
{ 'u', "upgrade" },
{ 'l', "latest" },
{ 't', "virtual", required_argument },
};
static const struct apk_option_group optgroup_applet = {
.name = "Add",
.options = options_applet,
.num_options = ARRAY_SIZE(options_applet),
.desc = option_desc,
.parse = option_parse_applet,
};

View File

@ -37,24 +37,40 @@ struct audit_ctx {
unsigned packages_only : 1;
};
static int option_parse_applet(void *ctx, struct apk_db_options *dbopts, int optch, const char *optarg)
enum {
OPT_AUDIT_backup,
OPT_AUDIT_check_permissions,
OPT_AUDIT_packages,
OPT_AUDIT_recursive,
OPT_AUDIT_system,
};
static const char option_desc[] =
APK_OPTAPPLET
APK_OPT1n("backup")
APK_OPT1n("check-permissions")
APK_OPT1n("packages")
APK_OPT2n("recursive", "r")
APK_OPT1n("system");
static int option_parse_applet(void *ctx, struct apk_db_options *dbopts, int opt, const char *optarg)
{
struct audit_ctx *actx = (struct audit_ctx *) ctx;
switch (optch) {
case 0x10000:
switch (opt) {
case OPT_AUDIT_backup:
actx->mode = MODE_BACKUP;
break;
case 0x10001:
case OPT_AUDIT_system:
actx->mode = MODE_SYSTEM;
break;
case 0x10002:
case OPT_AUDIT_check_permissions:
actx->check_permissions = 1;
break;
case 0x10003:
case OPT_AUDIT_packages:
actx->packages_only = 1;
break;
case 'r':
case OPT_AUDIT_recursive:
actx->recursive = 1;
break;
default:
@ -63,18 +79,8 @@ static int option_parse_applet(void *ctx, struct apk_db_options *dbopts, int opt
return 0;
}
static const struct apk_option options_applet[] = {
{ 0x10000, "backup" },
{ 0x10001, "system" },
{ 0x10002, "check-permissions" },
{ 'r', "recursive" },
{ 0x10003, "packages" },
};
static const struct apk_option_group optgroup_applet = {
.name = "Audit",
.options = options_applet,
.num_options = ARRAY_SIZE(options_applet),
.desc = option_desc,
.parse = option_parse_applet,
};

View File

@ -30,15 +30,25 @@ struct cache_ctx {
unsigned short solver_flags;
};
static int option_parse_applet(void *ctx, struct apk_db_options *dbopts, int optch, const char *optarg)
enum {
OPT_CACHE_latest,
OPT_CACHE_upgrade,
};
static const char option_desc[] =
APK_OPTAPPLET
APK_OPT2n("latest", "l")
APK_OPT2n("upgrade", "u");
static int option_parse_applet(void *ctx, struct apk_db_options *dbopts, int opt, const char *optarg)
{
struct cache_ctx *cctx = (struct cache_ctx *) ctx;
switch (optch) {
case 'u':
switch (opt) {
case OPT_CACHE_upgrade:
cctx->solver_flags |= APK_SOLVERF_UPGRADE;
break;
case 'l':
case OPT_CACHE_latest:
cctx->solver_flags |= APK_SOLVERF_LATEST;
break;
default:
@ -47,15 +57,8 @@ static int option_parse_applet(void *ctx, struct apk_db_options *dbopts, int opt
return 0;
}
static const struct apk_option options_applet[] = {
{ 'u', "upgrade" },
{ 'l', "latest" },
};
static const struct apk_option_group optgroup_applet = {
.name = "Cache",
.options = options_applet,
.num_options = ARRAY_SIZE(options_applet),
.desc = option_desc,
.parse = option_parse_applet,
};

View File

@ -21,12 +21,20 @@ struct del_ctx {
int errors;
};
static int option_parse_applet(void *pctx, struct apk_db_options *dbopts, int optch, const char *optarg)
enum {
OPT_DEL_redepends,
};
static const char option_desc[] =
APK_OPTAPPLET
APK_OPT2n("rdepends", "r");
static int option_parse_applet(void *pctx, struct apk_db_options *dbopts, int opt, const char *optarg)
{
struct del_ctx *ctx = (struct del_ctx *) pctx;
switch (optch) {
case 'r':
switch (opt) {
case OPT_DEL_redepends:
ctx->recursive_delete = 1;
break;
default:
@ -35,14 +43,8 @@ static int option_parse_applet(void *pctx, struct apk_db_options *dbopts, int op
return 0;
}
static const struct apk_option options_applet[] = {
{ 'r', "rdepends" },
};
static const struct apk_option_group optgroup_applet = {
.name = "Delete",
.options = options_applet,
.num_options = ARRAY_SIZE(options_applet),
.desc = option_desc,
.parse = option_parse_applet,
};

View File

@ -24,15 +24,25 @@ struct dot_ctx {
int installed_only : 1;
};
static int option_parse_applet(void *pctx, struct apk_db_options *dbopts, int optch, const char *optarg)
enum {
OPT_DOT_errors,
OPT_DOT_installed,
};
static const char option_desc[] =
APK_OPTAPPLET
APK_OPT1n("errors")
APK_OPT1n("installed");
static int option_parse_applet(void *pctx, struct apk_db_options *dbopts, int opt, const char *optarg)
{
struct dot_ctx *ctx = (struct dot_ctx *) pctx;
switch (optch) {
case 0x10000:
switch (opt) {
case OPT_DOT_errors:
ctx->errors_only = 1;
break;
case 0x10001:
case OPT_DOT_installed:
ctx->installed_only = 1;
dbopts->open_flags &= ~APK_OPENF_NO_INSTALLED;
break;
@ -42,15 +52,8 @@ static int option_parse_applet(void *pctx, struct apk_db_options *dbopts, int op
return 0;
}
static const struct apk_option options_applet[] = {
{ 0x10000, "errors" },
{ 0x10001, "installed" },
};
static const struct apk_option_group optgroup_applet = {
.name = "Dot",
.options = options_applet,
.num_options = ARRAY_SIZE(options_applet),
.desc = option_desc,
.parse = option_parse_applet,
};

View File

@ -68,21 +68,40 @@ static int cup(void)
return write(STDOUT_FILENO, buf, len) != len;
}
static int option_parse_applet(void *ctx, struct apk_db_options *dbopts, int optch, const char *optarg)
enum {
OPT_FETCH_link,
OPT_FETCH_recursive,
OPT_FETCH_output,
OPT_FETCH_simulate,
OPT_FETCH_stdout,
};
static const char option_desc[] =
APK_OPTAPPLET
APK_OPT2n("link", "l")
APK_OPT2n("recursive", "R")
APK_OPT2R("output", "o")
APK_OPT1n("simulate")
APK_OPT2n("stdout", "s");
static int option_parse_applet(void *ctx, struct apk_db_options *dbopts, int opt, const char *optarg)
{
struct fetch_ctx *fctx = (struct fetch_ctx *) ctx;
switch (optch) {
case 'R':
switch (opt) {
case OPT_FETCH_simulate:
apk_flags |= APK_SIMULATE;
break;
case OPT_FETCH_recursive:
fctx->flags |= FETCH_RECURSIVE;
break;
case 's':
case OPT_FETCH_stdout:
fctx->flags |= FETCH_STDOUT;
break;
case 'L':
case OPT_FETCH_link:
fctx->flags |= FETCH_LINK;
break;
case 'o':
case OPT_FETCH_output:
fctx->outdir_fd = openat(AT_FDCWD, optarg, O_RDONLY | O_CLOEXEC);
break;
default:
@ -91,18 +110,8 @@ static int option_parse_applet(void *ctx, struct apk_db_options *dbopts, int opt
return 0;
}
static const struct apk_option options_applet[] = {
{ 'L', "link" },
{ 'R', "recursive" },
{ 0x104, "simulate" },
{ 's', "stdout" },
{ 'o', "output", required_argument },
};
static const struct apk_option_group optgroup_applet = {
.name = "Fetch",
.options = options_applet,
.num_options = ARRAY_SIZE(options_applet),
.desc = option_desc,
.parse = option_parse_applet,
};

View File

@ -24,24 +24,40 @@ struct fix_ctx {
int errors;
};
static int option_parse_applet(void *pctx, struct apk_db_options *dbopts, int optch, const char *optarg)
enum {
OPT_FIX_depends,
OPT_FIX_directory_permissions,
OPT_FIX_reinstall,
OPT_FIX_upgrade,
OPT_FIX_xattr,
};
static const char option_desc[] =
APK_OPTAPPLET
APK_OPT2n("depends", "d")
APK_OPT1n("directory-permissions")
APK_OPT2n("reinstall", "r")
APK_OPT2n("upgrade", "u")
APK_OPT2n("xattr", "x");
static int option_parse_applet(void *pctx, struct apk_db_options *dbopts, int opt, const char *optarg)
{
struct fix_ctx *ctx = (struct fix_ctx *) pctx;
switch (optch) {
case 'd':
switch (opt) {
case OPT_FIX_depends:
ctx->fix_depends = 1;
break;
case 'x':
ctx->fix_xattrs = 1;
case OPT_FIX_directory_permissions:
ctx->fix_directory_permissions = 1;
break;
case 'u':
ctx->solver_flags |= APK_SOLVERF_UPGRADE;
break;
case 'r':
case OPT_FIX_reinstall:
ctx->solver_flags |= APK_SOLVERF_REINSTALL;
break;
case 0x10000:
ctx->fix_directory_permissions = 1;
case OPT_FIX_upgrade:
ctx->solver_flags |= APK_SOLVERF_UPGRADE;
break;
case OPT_FIX_xattr:
ctx->fix_xattrs = 1;
break;
default:
return -ENOTSUP;
@ -49,18 +65,8 @@ static int option_parse_applet(void *pctx, struct apk_db_options *dbopts, int op
return 0;
}
static const struct apk_option options_applet[] = {
{ 'd', "depends" },
{ 'r', "reinstall" },
{ 'u', "upgrade" },
{ 'x', "xattr" },
{ 0x10000, "directory-permissions" },
};
static const struct apk_option_group optgroup_applet = {
.name = "Fix",
.options = options_applet,
.num_options = ARRAY_SIZE(options_applet),
.desc = option_desc,
.parse = option_parse_applet,
};

View File

@ -32,21 +32,35 @@ struct index_ctx {
int method;
};
static int option_parse_applet(void *ctx, struct apk_db_options *dbopts, int optch, const char *optarg)
enum {
OPT_INDEX_description,
OPT_INDEX_index,
OPT_INDEX_output,
OPT_INDEX_rewrite_arch,
};
static const char option_desc[] =
APK_OPTAPPLET
APK_OPT2R("description", "d")
APK_OPT2R("index", "x")
APK_OPT2R("output", "o")
APK_OPT1R("rewrite-arch");
static int option_parse_applet(void *ctx, struct apk_db_options *dbopts, int opt, const char *optarg)
{
struct index_ctx *ictx = (struct index_ctx *) ctx;
switch (optch) {
case 'x':
ictx->index = optarg;
break;
case 'o':
ictx->output = optarg;
break;
case 'd':
switch (opt) {
case OPT_INDEX_description:
ictx->description = optarg;
break;
case 0x10000:
case OPT_INDEX_index:
ictx->index = optarg;
break;
case OPT_INDEX_output:
ictx->output = optarg;
break;
case OPT_INDEX_rewrite_arch:
ictx->rewrite_arch = apk_blob_atomize(APK_BLOB_STR(optarg));
break;
default:
@ -55,17 +69,8 @@ static int option_parse_applet(void *ctx, struct apk_db_options *dbopts, int opt
return 0;
}
static const struct apk_option options_applet[] = {
{ 'o', "output", required_argument },
{ 'x', "index", required_argument },
{ 'd', "description", required_argument },
{ 0x10000, "rewrite-arch", required_argument },
};
static const struct apk_option_group optgroup_applet = {
.name = "Index",
.options = options_applet,
.num_options = ARRAY_SIZE(options_applet),
.desc = option_desc,
.parse = option_parse_applet,
};

View File

@ -366,57 +366,93 @@ static void print_name_info(struct apk_database *db, const char *match, struct a
info_subaction(ctx, p->pkg);
}
static int option_parse_applet(void *pctx, struct apk_db_options *dbopts, int optch, const char *optarg)
enum {
OPT_INFO_all,
OPT_INFO_contents,
OPT_INFO_depends,
OPT_INFO_description,
OPT_INFO_install_if,
OPT_INFO_installed,
OPT_INFO_license,
OPT_INFO_provides,
OPT_INFO_rdepends,
OPT_INFO_replaces,
OPT_INFO_rinstall_if,
OPT_INFO_size,
OPT_INFO_triggers,
OPT_INFO_webpage,
OPT_INFO_who_owns,
};
static const char option_desc[] =
APK_OPTAPPLET
APK_OPT2n("all", "a")
APK_OPT2n("contents", "L")
APK_OPT2n("depends", "R")
APK_OPT2n("description", "d")
APK_OPT1n("install-if")
APK_OPT2n("installed", "e")
APK_OPT1n("license")
APK_OPT2n("provides", "P")
APK_OPT2n("rdepends", "r")
APK_OPT1n("replaces")
APK_OPT1n("rinstall-if")
APK_OPT2n("size", "s")
APK_OPT2n("triggers", "t")
APK_OPT2n("webpage", "w")
APK_OPT2n("who-owns", "W");
static int option_parse_applet(void *pctx, struct apk_db_options *dbopts, int opt, const char *optarg)
{
struct info_ctx *ctx = (struct info_ctx *) pctx;
ctx->action = NULL;
switch (optch) {
case 'e':
switch (opt) {
case OPT_INFO_installed:
ctx->action = info_exists;
dbopts->open_flags |= APK_OPENF_NO_REPOS;
break;
case 'W':
case OPT_INFO_who_owns:
ctx->action = info_who_owns;
dbopts->open_flags |= APK_OPENF_NO_REPOS;
break;
case 'w':
case OPT_INFO_webpage:
ctx->subaction_mask |= APK_INFO_URL;
break;
case 'R':
case OPT_INFO_depends:
ctx->subaction_mask |= APK_INFO_DEPENDS;
break;
case 'P':
case OPT_INFO_provides:
ctx->subaction_mask |= APK_INFO_PROVIDES;
break;
case 'r':
case OPT_INFO_rdepends:
ctx->subaction_mask |= APK_INFO_RDEPENDS;
break;
case 0x10002:
case OPT_INFO_install_if:
ctx->subaction_mask |= APK_INFO_INSTALL_IF;
break;
case 0x10003:
case OPT_INFO_rinstall_if:
ctx->subaction_mask |= APK_INFO_RINSTALL_IF;
break;
case 's':
case OPT_INFO_size:
ctx->subaction_mask |= APK_INFO_SIZE;
break;
case 'd':
case OPT_INFO_description:
ctx->subaction_mask |= APK_INFO_DESC;
break;
case 'L':
case OPT_INFO_contents:
ctx->subaction_mask |= APK_INFO_CONTENTS;
break;
case 't':
case OPT_INFO_triggers:
ctx->subaction_mask |= APK_INFO_TRIGGERS;
break;
case 0x10000:
case OPT_INFO_replaces:
ctx->subaction_mask |= APK_INFO_REPLACES;
break;
case 0x10001:
case OPT_INFO_license:
ctx->subaction_mask |= APK_INFO_LICENSE;
break;
case 'a':
case OPT_INFO_all:
ctx->subaction_mask = 0xffffffff;
break;
default:
@ -449,28 +485,8 @@ static int info_main(void *ctx, struct apk_database *db, struct apk_string_array
return ictx->errors;
}
static const struct apk_option options_applet[] = {
{ 'L', "contents" },
{ 'e', "installed" },
{ 'W', "who-owns" },
{ 'R', "depends" },
{ 'P', "provides" },
{ 'r', "rdepends" },
{ 0x10000, "replaces" },
{ 0x10002, "install-if" },
{ 0x10003, "rinstall-if" },
{ 'w', "webpage" },
{ 's', "size" },
{ 'd', "description" },
{ 0x10001, "license" },
{ 't', "triggers" },
{ 'a', "all" },
};
static const struct apk_option_group optgroup_applet = {
.name = "Info",
.options = options_applet,
.num_options = ARRAY_SIZE(options_applet),
.desc = option_desc,
.parse = option_parse_applet,
};

View File

@ -187,38 +187,57 @@ static void print_result(struct apk_database *db, const char *match, struct apk_
iterate_providers(name, ctx);
}
static int option_parse_applet(void *pctx, struct apk_db_options *dbopts, int optch, const char *optarg)
enum {
OPT_LIST_available,
OPT_LIST_installed,
OPT_LIST_depends,
OPT_LIST_origin,
OPT_LIST_orphaned,
OPT_LIST_providers,
OPT_LIST_upgradeable,
};
static const char option_desc[] =
APK_OPTAPPLET
APK_OPT2n("available", "a")
APK_OPT2n("installed", "I")
APK_OPT2n("depends", "d")
APK_OPT2n("origin", "o")
APK_OPT2n("orphaned", "O")
APK_OPT2n("providers", "P")
APK_OPT2n("upgradeable", "u");
static int option_parse_applet(void *pctx, struct apk_db_options *dbopts, int opt, const char *optarg)
{
struct list_ctx *ctx = pctx;
switch (optch)
{
case 'I':
switch (opt) {
case OPT_LIST_available:
ctx->available = 1;
ctx->orphaned = 0;
break;
case OPT_LIST_installed:
ctx->installed = 1;
break;
case 'O':
case OPT_LIST_depends:
ctx->match_depends = 1;
break;
case OPT_LIST_origin:
ctx->match_origin = 1;
break;
case OPT_LIST_orphaned:
ctx->installed = 1;
ctx->orphaned = 1;
break;
case 'u':
case OPT_LIST_providers:
ctx->match_providers = 1;
break;
case OPT_LIST_upgradeable:
ctx->available = 1;
ctx->orphaned = 0;
ctx->installed = 0;
ctx->upgradable = 1;
break;
case 'a':
ctx->available = 1;
ctx->orphaned = 0;
break;
case 'o':
ctx->match_origin = 1;
break;
case 'd':
ctx->match_depends = 1;
break;
case 'P':
ctx->match_providers = 1;
break;
default:
return -ENOTSUP;
}
@ -226,20 +245,8 @@ static int option_parse_applet(void *pctx, struct apk_db_options *dbopts, int op
return 0;
}
static const struct apk_option options_applet[] = {
{ 'I', "installed" },
{ 'O', "orphaned" },
{ 'a', "available" },
{ 'u', "upgradable" },
{ 'o', "origin" },
{ 'd', "depends" },
{ 'P', "providers" },
};
static const struct apk_option_group optgroup_applet = {
.name = "List",
.options = options_applet,
.num_options = ARRAY_SIZE(options_applet),
.desc = option_desc,
.parse = option_parse_applet,
};

View File

@ -74,30 +74,47 @@ static void print_rdepends(struct search_ctx *ctx, struct apk_package *pkg)
apk_pkg_foreach_reverse_dependency(pkg, ctx->matches, print_rdep_pkg, ctx);
}
static int option_parse_applet(void *ctx, struct apk_db_options *dbopts, int optch, const char *optarg)
enum {
OPT_SEARCH_all,
OPT_SEARCH_description,
OPT_SEARCH_exact,
OPT_SEARCH_has_origin,
OPT_SEARCH_origin,
OPT_SEARCH_rdepends,
};
static const char option_desc[] =
APK_OPTAPPLET
APK_OPT2n("all", "a")
APK_OPT2n("description", "d")
APK_OPT2n("exact", "\xf2""ex")
APK_OPT1n("has-origin")
APK_OPT2n("origin", "o")
APK_OPT2n("rdepends", "r");
static int option_parse_applet(void *ctx, struct apk_db_options *dbopts, int opt, const char *optarg)
{
struct search_ctx *ictx = (struct search_ctx *) ctx;
switch (optch) {
case 'a':
switch (opt) {
case OPT_SEARCH_all:
ictx->show_all = 1;
break;
case 'd':
case OPT_SEARCH_description:
ictx->search_description = 1;
ictx->search_exact = 1;
ictx->show_all = 1;
break;
case 'e':
case 'x':
case OPT_SEARCH_exact:
ictx->search_exact = 1;
break;
case 'o':
case OPT_SEARCH_origin:
ictx->print_package = print_origin_name;
break;
case 'r':
case OPT_SEARCH_rdepends:
ictx->print_result = print_rdepends;
break;
case 0x10000:
case OPT_SEARCH_has_origin:
ictx->search_origin = 1;
ictx->search_exact = 1;
ictx->show_all = 1;
@ -108,20 +125,8 @@ static int option_parse_applet(void *ctx, struct apk_db_options *dbopts, int opt
return 0;
}
static const struct apk_option options_applet[] = {
{ 'a', "all" },
{ 'd', "description" },
{ 'x', "exact" },
{ 'e', NULL },
{ 'o', "origin" },
{ 'r', "rdepends" },
{ 0x10000, "has-origin" },
};
static const struct apk_option_group optgroup_applet = {
.name = "Search",
.options = options_applet,
.num_options = ARRAY_SIZE(options_applet),
.desc = option_desc,
.parse = option_parse_applet,
};

View File

@ -25,24 +25,40 @@ struct upgrade_ctx {
int ignore : 1;
};
static int option_parse_applet(void *ctx, struct apk_db_options *dbopts, int optch, const char *optarg)
enum {
OPT_UPGRADE_available,
OPT_UPGRADE_ignore,
OPT_UPGRADE_latest,
OPT_UPGRADE_no_self_upgrade,
OPT_UPGRADE_self_upgrade_only,
};
static const char option_desc[] =
APK_OPTAPPLET
APK_OPT2n("available", "a")
APK_OPT1n("ignore")
APK_OPT2n("latest", "l")
APK_OPT1n("no-self-upgrade")
APK_OPT1n("self-upgrade-only");
static int option_parse_applet(void *ctx, struct apk_db_options *dbopts, int opt, const char *optarg)
{
struct upgrade_ctx *uctx = (struct upgrade_ctx *) ctx;
switch (optch) {
case 0x10000:
switch (opt) {
case OPT_UPGRADE_no_self_upgrade:
uctx->no_self_upgrade = 1;
break;
case 0x10001:
case OPT_UPGRADE_self_upgrade_only:
uctx->self_upgrade_only = 1;
break;
case 0x10002:
case OPT_UPGRADE_ignore:
uctx->ignore = 1;
break;
case 'a':
case OPT_UPGRADE_available:
uctx->solver_flags |= APK_SOLVERF_AVAILABLE;
break;
case 'l':
case OPT_UPGRADE_latest:
uctx->solver_flags |= APK_SOLVERF_LATEST;
break;
default:
@ -51,18 +67,8 @@ static int option_parse_applet(void *ctx, struct apk_db_options *dbopts, int opt
return 0;
}
static const struct apk_option options_applet[] = {
{ 'a', "available" },
{ 'l', "latest" },
{ 0x10000, "no-self-upgrade" },
{ 0x10001, "self-upgrade-only" },
{ 0x10002, "ignore" },
};
static const struct apk_option_group optgroup_applet = {
.name = "Upgrade",
.options = options_applet,
.num_options = ARRAY_SIZE(options_applet),
.desc = option_desc,
.parse = option_parse_applet,
};

View File

@ -68,26 +68,42 @@ static int ver_validate(struct apk_database *db, struct apk_string_array *args)
return errors;
}
static int option_parse_applet(void *ctx, struct apk_db_options *dbopts, int optch, const char *optarg)
enum {
OPT_VERSION_all,
OPT_VERSION_check,
OPT_VERSION_indexes,
OPT_VERSION_limit,
OPT_VERSION_test,
};
static const char option_desc[] =
APK_OPTAPPLET
APK_OPT2n("all", "a")
APK_OPT2n("check", "c")
APK_OPT2n("indexes", "I")
APK_OPT2R("limit", "l")
APK_OPT2n("test", "t");
static int option_parse_applet(void *ctx, struct apk_db_options *dbopts, int opt, const char *optarg)
{
struct ver_ctx *ictx = (struct ver_ctx *) ctx;
switch (optch) {
case 'I':
ictx->action = ver_indexes;
switch (opt) {
case OPT_VERSION_all:
ictx->all_tags = 1;
break;
case 't':
ictx->action = ver_test;
dbopts->open_flags |= APK_OPENF_NO_STATE | APK_OPENF_NO_REPOS;
break;
case 'c':
case OPT_VERSION_check:
ictx->action = ver_validate;
dbopts->open_flags |= APK_OPENF_NO_STATE | APK_OPENF_NO_REPOS;
break;
case 'l':
case OPT_VERSION_indexes:
ictx->action = ver_indexes;
break;
case OPT_VERSION_limit:
ictx->limchars = optarg;
break;
case 'a':
ictx->all_tags = 1;
case OPT_VERSION_test:
ictx->action = ver_test;
dbopts->open_flags |= APK_OPENF_NO_STATE | APK_OPENF_NO_REPOS;
break;
default:
return -ENOTSUP;
@ -95,18 +111,8 @@ static int option_parse_applet(void *ctx, struct apk_db_options *dbopts, int opt
return 0;
}
static const struct apk_option options_applet[] = {
{ 'I', "indexes" },
{ 't', "test" },
{ 'c', "check" },
{ 'a', "all" },
{ 'l', "limit", required_argument },
};
static const struct apk_option_group optgroup_applet = {
.name = "Version",
.options = options_applet,
.num_options = ARRAY_SIZE(options_applet),
.desc = option_desc,
.parse = option_parse_applet,
};

View File

@ -17,7 +17,7 @@ static int is_group(struct apk_applet *applet, const char *topic)
if (!applet) return strcasecmp(topic, "apk") == 0;
if (strcasecmp(topic, applet->name) == 0) return 1;
for (int i = 0; applet->optgroups[i] && i < ARRAY_SIZE(applet->optgroups); i++)
if (strcasecmp(applet->optgroups[i]->name, topic) == 0) return 1;
if (strcasecmp(applet->optgroups[i]->desc, topic) == 0) return 1;
return 0;
}