summaryrefslogtreecommitdiff
path: root/src/apk.c
diff options
context:
space:
mode:
authorTimo Teras <timo.teras@iki.fi>2009-06-25 15:14:07 +0300
committerTimo Teras <timo.teras@iki.fi>2009-06-25 15:14:07 +0300
commit7a29678aac20ac9e113704f8a5743f6051edef8d (patch)
tree11c9583a66fa5fc1122e6d993b92dc7cd591e237 /src/apk.c
parent3a488564753cee51832b6824128249a99eb4613b (diff)
downloadapk-tools-7a29678aac20ac9e113704f8a5743f6051edef8d.tar.gz
apk-tools-7a29678aac20ac9e113704f8a5743f6051edef8d.tar.bz2
apk-tools-7a29678aac20ac9e113704f8a5743f6051edef8d.tar.xz
apk-tools-7a29678aac20ac9e113704f8a5743f6051edef8d.zip
help: auto construct help
And add some more verbosity to the help message.
Diffstat (limited to 'src/apk.c')
-rw-r--r--src/apk.c188
1 files changed, 144 insertions, 44 deletions
diff --git a/src/apk.c b/src/apk.c
index 64b0adb..25e7b07 100644
--- a/src/apk.c
+++ b/src/apk.c
@@ -4,7 +4,7 @@
* Copyright (C) 2008 Timo Teräs <timo.teras@iki.fi>
* All rights reserved.
*
- * This program is free software; you can redistribute it and/or modify it
+ * This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published
* by the Free Software Foundation. See http://www.gnu.org/ for details.
*/
@@ -20,12 +20,29 @@
#include "apk_defines.h"
#include "apk_applet.h"
+#include "apk_blob.h"
const char *apk_root;
struct apk_repository_url apk_repository_list;
int apk_verbosity = 1, apk_cwd_fd;
unsigned int apk_flags = 0;
+static struct apk_option generic_options[] = {
+ { 'h', "help", "Show generic help or applet specific help" },
+ { 'p', "root", "Install packages to DIR",
+ required_argument, "DIR" },
+ { 'X', "repository", "Use packages from REPO",
+ required_argument, "REPO" },
+ { 'q', "quiet", "Print less information" },
+ { 'v', "verbose", "Print more information" },
+ { 'V', "version", "Print program version and exit" },
+ { 'f', "force", "Do what was asked even if it looks dangerous" },
+ { 0x101, "progress", "Show a progress bar" },
+ { 0x102, "clean-protected",
+ "Do not create .apk-new files to configuration dirs" },
+ { 0x104, "simulate", "Show what would be done without actually doing it" },
+};
+
void apk_log(const char *prefix, const char *format, ...)
{
va_list va;
@@ -38,34 +55,116 @@ void apk_log(const char *prefix, const char *format, ...)
fprintf(stderr, "\n");
}
-int version(void)
+static int version(void)
{
printf("apk-tools " APK_VERSION "\n");
return 0;
}
-int generic_usage(void)
+struct apk_indent {
+ int x;
+ int indent;
+};
+
+static int print_indented(struct apk_indent *i, apk_blob_t blob)
{
- struct apk_applet **a;
- printf("usage: apk COMMAND [-h|--help] [-p|--root DIR] [-X|--repository REPO]\n"
- "\t\t [-q|--quiet] [-v|--verbose] [-V|--version] [-f|--force]\n"
- "\t\t [--progress] [--clean-protected] [--simulate] [ARGS]...\n\n"
- "commands: ");
+ static const int wrap_length = 80;
- for (a = &__start_apkapplets; a < &__stop_apkapplets; a++) {
- printf("%s ",
- (*a)->name);
+ if (i->x + blob.len + 1 >= wrap_length) {
+ i->x = i->indent;
+ printf("\n%*s", i->indent - 1, "");
}
- printf("\n\n");
- return 1;
+ i->x += printf(" %.*s", blob.len, blob.ptr);
+ return 0;
+}
+
+static void print_indented_words(struct apk_indent *i, const char *text)
+{
+ apk_blob_for_each_segment(APK_BLOB_STR(text), " ",
+ (apk_blob_cb) print_indented, i);
}
-int usage(struct apk_applet *applet)
+static int format_option(char *buf, size_t len, struct apk_option *o,
+ const char *separator)
{
+ int i = 0;
+
+ if (o->val <= 0xff && isalnum(o->val)) {
+ i += snprintf(&buf[i], len - i, "-%c", o->val);
+ if (o->name != NULL)
+ i += snprintf(&buf[i], len - i, "%s", separator);
+ }
+ if (o->name != NULL)
+ i += snprintf(&buf[i], len - i, "--%s", o->name);
+ if (o->arg_name != NULL)
+ i += snprintf(&buf[i], len - i, " %s", o->arg_name);
+
+ return i;
+}
+
+static void print_usage(const char *cmd, const char *args, int num_opts,
+ struct apk_option *opts)
+{
+ struct apk_indent indent = { 0, 11 };
+ char word[128];
+ int i, j;
+
+ indent.x = printf("\nusage: apk %s", cmd) - 1;
+ for (i = 0; i < num_opts; i++) {
+ j = 0;
+ word[j++] = '[';
+ j += format_option(&word[j], sizeof(word) - j, &opts[i], "|");
+ word[j++] = ']';
+ print_indented(&indent, APK_BLOB_PTR_LEN(word, j));
+ }
+ if (args != NULL)
+ print_indented(&indent, APK_BLOB_STR(args));
+ printf("\n");
+}
+
+static void print_options(int num_opts, struct apk_option *opts)
+{
+ struct apk_indent indent = { 0, 26 };
+ char word[128];
+ int i;
+
+ for (i = 0; i < num_opts; i++) {
+ format_option(word, sizeof(word), &opts[i], ", ");
+ indent.x = printf(" %-*s", indent.indent - 3, word);
+ print_indented_words(&indent, opts[i].help);
+ printf("\n");
+ }
+}
+
+static int usage(struct apk_applet *applet)
+{
+ struct apk_indent indent = { 0, 2 };
+
version();
- if (applet == NULL)
- return generic_usage();
- printf("usage: apk %s %s\n\n", applet->name, applet->usage);
+ if (applet == NULL) {
+ struct apk_applet **a;
+
+ print_usage("COMMAND", "[ARGS]...",
+ ARRAY_SIZE(generic_options), generic_options);
+
+ printf("\navailable commands:\n ");
+ for (a = &__start_apkapplets; a < &__stop_apkapplets; a++)
+ printf("%s ", (*a)->name);
+ } else {
+ print_usage(applet->name, applet->arguments,
+ applet->num_options, applet->options);
+ printf("\ndescription:\n%*s", indent.indent - 1, "");
+ print_indented_words(&indent, applet->help);
+ }
+ printf("\n\ngeneric options:\n");
+ print_options(ARRAY_SIZE(generic_options), generic_options);
+
+ if (applet != NULL && applet->num_options > 0) {
+ printf("\noptions for %s command:\n", applet->name);
+ print_options(applet->num_options, applet->options);
+ }
+ printf("\nThis apk has coffee making abilities.\n\n");
+
return 1;
}
@@ -77,7 +176,7 @@ static struct apk_applet *find_applet(const char *name)
if (strcmp(name, (*a)->name) == 0)
return *a;
}
-
+
return NULL;
}
@@ -110,7 +209,7 @@ static struct apk_applet *deduce_applet(int argc, char **argv)
static struct apk_repository_url *apk_repository_new(const char *url)
{
- struct apk_repository_url *r = calloc(1,
+ struct apk_repository_url *r = calloc(1,
sizeof(struct apk_repository_url));
if (r) {
r->url = url;
@@ -119,26 +218,25 @@ static struct apk_repository_url *apk_repository_new(const char *url)
return r;
}
-#define NUM_GENERIC_OPTS 10
-static struct option generic_options[32] = {
- { "help", no_argument, NULL, 'h'},
- { "root", required_argument, NULL, 'p' },
- { "repository", required_argument, NULL, 'X' },
- { "quiet", no_argument, NULL, 'q' },
- { "verbose", no_argument, NULL, 'v' },
- { "version", no_argument, NULL, 'V' },
- { "force", no_argument, NULL, 'f' },
- { "progress", no_argument, NULL, 0x101 },
- { "clean-protected", no_argument, NULL, 0x102 },
- { "simulate", no_argument, NULL, 0x104 },
-};
+static void merge_options(struct option *opts, struct apk_option *ao, int num)
+{
+ int i;
+
+ 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;
+ }
+ opts->name = NULL;
+}
int main(int argc, char **argv)
{
struct apk_applet *applet;
char short_options[256], *sopt;
- struct option *opt;
- int r, optindex;
+ struct option *opt, *all_options;
+ int r, optindex, num_options;
void *ctx = NULL;
struct apk_repository_url *repo = NULL;
@@ -148,19 +246,20 @@ int main(int argc, char **argv)
list_init(&apk_repository_list.list);
applet = deduce_applet(argc, argv);
+ num_options = ARRAY_SIZE(generic_options) + 1;
+ if (applet != NULL)
+ num_options += applet->num_options;
+ all_options = alloca(sizeof(struct option) * num_options);
+ merge_options(&all_options[0], generic_options,
+ ARRAY_SIZE(generic_options));
if (applet != NULL) {
- if (applet->num_options && applet->options) {
- memcpy(&generic_options[NUM_GENERIC_OPTS],
- applet->options,
- applet->num_options * sizeof(struct option));
- }
-
+ merge_options(&all_options[ARRAY_SIZE(generic_options)],
+ applet->options, applet->num_options);
if (applet->context_size != 0)
ctx = calloc(1, applet->context_size);
}
- for (opt = &generic_options[0], sopt = short_options;
- opt->name != NULL; opt++) {
+ for (opt = all_options, sopt = short_options; opt->name != NULL; opt++) {
if (opt->flag == NULL &&
opt->val <= 0xff && isalnum(opt->val)) {
*(sopt++) = opt->val;
@@ -171,7 +270,7 @@ int main(int argc, char **argv)
optindex = 0;
while ((r = getopt_long(argc, argv, short_options,
- generic_options, &optindex)) != -1) {
+ all_options, &optindex)) != -1) {
switch (r) {
case 0:
break;
@@ -208,7 +307,8 @@ int main(int argc, char **argv)
break;
default:
if (applet == NULL || applet->parse == NULL ||
- applet->parse(ctx, r, optindex - NUM_GENERIC_OPTS,
+ applet->parse(ctx, r,
+ optindex - ARRAY_SIZE(generic_options),
optarg) != 0)
return usage(applet);
break;